フォト

Google AdSense


  • AdSense
無料ブログはココログ

« VulkanのSDKの入手を解説した記事 | トップページ | ココログだと読みにくいので »

2016.02.17

Direct3D12のデバッグを助けるID3D12Object::SetName

MiniEngineをグラフィックス診断をしていてDescriptorHeapを見ていて気づいたのですが、Direct3D12ではID3D12Resouce(テクスチャ、バッファ、コンスタントバッファ、UAV)などのリソースに任意の名前が付けられるんですね(下図の赤枠)。名前がついてると、DescriptorHeapに大量にリソースがセットされていても内容がチェックしやすくて便利ですね。

debug002
クリックすると大きなサイズになります

ちょっと気になったので、確認のためグラフィックスオブジェクトテーブルを見てみます。

debug003
クリックすると大きなサイズになります

なるほど、Direct3D11時代のときのように従来の「オブジェクト:〇〇」(〇〇は数字)のような表記もあるんですね。

では、名前がついてるものと「オブジェクト:〇〇」表記は何が違うんでしょうか?

・・・ということで、調べてみたところID3D12Objectインターフェイスのメンバ関数のSetName関数で名前をつけたものが表示されることがわかりました。

ID3D12Object::SetName
https://msdn.microsoft.com/ja-jp/library/windows/desktop/dn788701(v=vs.85).aspx

MSDNを見ていると

Associates a name with the device object. This name is for use in debug diagnostics and tools.

とあるので、基本的にデバッグやツールなどで使用するものとして用意されているようですね。

Direct3D12の各種インターフェイスの継承は下記のような構造になっているのですが、

IUnknown - ID3D12Object - ID3D12DeviceChild - ID3D12~インターフェイス

これがDirect3D11だと下記のような構造だったので、新設されたみたいですね。

IUnknown -  ID3D11DeviceChild - ID3D11~インターフェイス

さて、ほかのMicrosoftのサンプル(D3D12HelloWorldのHelloTexture)でDesciptorHeapを見てみます。これはやはりSetNameしていないのでテクスチャのSRVが「オブジェクト:15」という自動的につく名前のままですね。このサンプルはテクスチャを1枚張ってるだけだからいいですが、これが実際のゲーム開発で大量のオブジェクトを使うようになるとこれでは見分けるのが難しいですね。

やはり任意の名前がついてた方がいいので、Direct3D12でID3D12~のインターフェイスに名前が付けられるのはありがたいですね。

debug004

さらに、ID3D12Object::SetName で名前を付けておくことで便利なのがインターフェイスの解放忘れの時ですね。

リークを出すためにD3D12HelloWorldのHelloTextureサンプルのD3D12HelloTexture.hのD3D12HelloTextureのメンバであるm_textureをスマートポインタではなく、

ID3D12Resource* m_texture;

に変えて、Releaseしないでおきます。

Direct3D11の時からありますが、たとえば、Direct3D12ではサンプルにあるような下記のコードのようにDebugLayerを有効にします。

ComPtr<ID3D12Debug> debugController;

if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
{
 debugController->EnableDebugLayer();
}

そのあとに、テクスチャのインターフェイスをわざとReleaseしないでアプリケーションを閉じて、Visual Studio 2015の出力を見ると下記のように解放忘れを報告してくれます。

D3D12 WARNING: Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING: Live Producer at 0x000001376E4FB318, Refcount: 2. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001376E4E6E90, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001376E4E9AE0, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001376E523190, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001376E550510, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001376E54FFD0, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING: Live                         Object :      5 [ STATE_CREATION WARNING #0: UNKNOWN]

とはいえ、これでは何がリークしているか特定が難しいので、下記のコードを使います。

ID3D12DebugDevice* debugInterface;

if (SUCCEEDED(m_device.Get()->QueryInterface(&debugInterface)))
{
 debugInterface->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL | D3D12_RLDO_IGNORE_INTERNAL);
 debugInterface->Release();
}

これは、Direct3D11の時だとID3D11Debug::ReportLiveDeviceObjectsであったと思います。

その結果、下記のような情報に変わります。これで、ID3D12~などのインターフェイスの型でRefcountがわかるようになりました。ここまでは、Direct3D11と同じですね。

D3D12 WARNING: Live ID3D12Device at 0x0000020303619330, Refcount: 23 [ STATE_CREATION WARNING #274: LIVE_DEVICE]
D3D12 WARNING:  Live ID3D12CommandQueue at 0x000002030364E280, Refcount: 5, IntRef: 0 [ STATE_CREATION WARNING #570: LIVE_COMMANDQUEUE]
D3D12 WARNING:  Live IDXGISwapChain at 0x0000020303643060, Refcount: 2 [ STATE_CREATION WARNING #275: LIVE_SWAPCHAIN]
D3D12 WARNING:  Live ID3D12Fence at 0x000002030364C690, Name: Internal DXGI Fence, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x0000020303642010, Name: Internal DXGI CommandAllocator, Refcount: 1, IntRef: 1 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12GraphicsCommandList at 0x0000020303644800, Name: Internal DXGI CommandList, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #573: LIVE_COMMANDLIST12]
D3D12 WARNING:  Live ID3D12Resource at 0x00000203036646B0, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x0000020303665BD0, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12DescriptorHeap at 0x0000020303666BB0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #576: LIVE_DESCRIPTORHEAP]
D3D12 WARNING:  Live ID3D12DescriptorHeap at 0x0000020303666F40, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #576: LIVE_DESCRIPTORHEAP]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x0000020303668180, Refcount: 1, IntRef: 1 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12RootSignature at 0x0000020303668550, Refcount: 1, IntRef: 1 [ STATE_CREATION WARNING #577: LIVE_ROOTSIGNATURE]
D3D12 WARNING:  Live ID3D12PipelineState at 0x00000203036706A0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #572: LIVE_PIPELINESTATE]
D3D12 WARNING:  Live ID3D12GraphicsCommandList at 0x00000203036A1A20, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #573: LIVE_COMMANDLIST12]
D3D12 WARNING:  Live ID3D12Resource at 0x00000203036A0BC0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x00000203036B0200, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Fence at 0x0000020303672C60, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x00000203036828F0, Name: Internal DXGI CommandAllocator, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x0000020303685CD0, Name: Internal DXGI CommandAllocator, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]

で、続いてSetNameで名前を付けてみます。適当なところで、

m_texture->SetName(L"Texture");

としておくと、レポートが下記のようになります。「赤字」の箇所にちゃんとSetNameした名称が出てきています。そしてRefcount: 1.となっているところのアドレスの青字で対応をとると"Texture"はとりあえず解放忘れてるぞ、となるわけですね。

D3D12 WARNING: Live ID3D12Device at 0x0000025D68FCE1B0, Refcount: 23 [ STATE_CREATION WARNING #274: LIVE_DEVICE]
D3D12 WARNING:  Live ID3D12CommandQueue at 0x0000025D69012D80, Refcount: 5, IntRef: 0 [ STATE_CREATION WARNING #570: LIVE_COMMANDQUEUE]
D3D12 WARNING:  Live IDXGISwapChain at 0x0000025D690130D0, Refcount: 2 [ STATE_CREATION WARNING #275: LIVE_SWAPCHAIN]
D3D12 WARNING:  Live ID3D12Fence at 0x0000025D68FBF4F0, Name: Internal DXGI Fence, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x0000025D69014870, Name: Internal DXGI CommandAllocator, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12GraphicsCommandList at 0x0000025D68FF7BB0, Name: Internal DXGI CommandList, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #573: LIVE_COMMANDLIST12]
D3D12 WARNING:  Live ID3D12Resource at 0x0000025D69016260, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x0000025D68FFC370, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12DescriptorHeap at 0x0000025D69016E00, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #576: LIVE_DESCRIPTORHEAP]
D3D12 WARNING:  Live ID3D12DescriptorHeap at 0x0000025D68FFD350, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #576: LIVE_DESCRIPTORHEAP]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x0000025D68FFDB20, Refcount: 1, IntRef: 1 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12RootSignature at 0x0000025D6901DB40, Refcount: 1, IntRef: 1 [ STATE_CREATION WARNING #577: LIVE_ROOTSIGNATURE]
D3D12 WARNING:  Live ID3D12PipelineState at 0x0000025D69025820, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #572: LIVE_PIPELINESTATE]
D3D12 WARNING:  Live ID3D12GraphicsCommandList at 0x0000025D69057C90, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #573: LIVE_COMMANDLIST12]
D3D12 WARNING:  Live ID3D12Resource at 0x0000025D69065F30, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x0000025D69066A50, Name: Texture, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Fence at 0x0000025D69026A30, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x0000025D69056670, Name: Internal DXGI CommandAllocator, Refcount: 1, IntRef: 1 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x0000025D69036810, Name: Internal DXGI CommandAllocator, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING: Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING: Live Producer at 0x0000025D68FCE198, Refcount: 2. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x0000025D68FBBF60, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x0000025D68FF6000, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x0000025D690111B0, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x0000025D69066A50, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x0000025D69066510, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING: Live                         Object :      5 [ STATE_CREATION WARNING #0: UNKNOWN]

まとめ
今回紹介した要素はちょっとした小さい機能追加ではあるのですが、ID3D12~に対して名前が付けられるようになることでデバッグや分析が楽になりそうな感じではありますね。
そんなわけで、開発のことを考えるとID3D12~のものは何かとSetNameして名前どんどん付けていくのがよいかもしれませんね。
ただし、これはこれでメモリの使用量が増えるのでギリギリで作ってるときは注意ではありますが、さすがに今後はこのぐらいのメモリが取れないということはないとは思います。

« VulkanのSDKの入手を解説した記事 | トップページ | ココログだと読みにくいので »

Programming」カテゴリの記事

画像付き」カテゴリの記事

コメント

コメントを書く

コメントは記事投稿者が公開するまで表示されません。

(ウェブ上には掲載しません)

« VulkanのSDKの入手を解説した記事 | トップページ | ココログだと読みにくいので »