7080 + 1

ゲームプログラミングの記事を書いてます。

IDXGIDebug::ReportLiveObjects()を使うまでの道のり その2

前回の続きです。

結論から言います。出来ました。
奮闘記を書いて教えを請う予定でしたが、出来てしまったのでやり方だけ書きます。

前回も言いましたが、このメソッドはというか、このインターフェース自体が Windows8以降じゃないと使えないとMSDNに書いてありました。

なので、まずはOSのバージョンによって分岐しておく必要があります。 俺の作ったプログラムはWindows8上でしか動かねえぜ!!というのなら不要な処理です。

バージョンの調べ方は自分の書いた記事がありますので、そちらをどうぞ。

IDXGIDebug::ReportLiveObjects()を呼び出す

if( VerifyVersionInfo( &OSver, VER_MAJORVERSION | VER_MINORVERSION, condition))
{
// Widows8.0以上なら
    if( pDxgiDebug == nullptr )
    {
        // 作成
        typedef HRESULT(__stdcall *fPtr)(const IID&, void**); 
        HMODULE hDll = GetModuleHandleW(L"dxgidebug.dll");
        fPtr DXGIGetDebugInterface = (fPtr)GetProcAddress(hDll, "DXGIGetDebugInterface"); 
 
        DXGIGetDebugInterface(__uuidof(IDXGIDebug), (void**)&pDxgiDebug);

        // 出力
        pDxgiDebug->ReportLiveObjects( DXGI_DEBUG_D3D11, DXGI_DEBUG_RLO_DETAIL);
    }
    else
        pDxgiDebug->ReportLiveObjects( DXGI_DEBUG_D3D11, DXGI_DEBUG_RLO_DETAIL);
}
else
{
    return pD3dDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
}

VerifyVersionInfo()はバージョンを調べています。if文の中が重要です。 が、はっきり言って、GetModuleHandle()あたりのところでを何しているかわかりません。コピペしたので。 関数ポインタってこんな使い方出来るんですね。

と、とにかく、これで出来ます。これだけです。
もしかしたら、リンクエラーが出ると思います。そういう時は、InitGUID.hIDXGIDebug.hよりも前にインクルードしてください。それでも駄目なら、d3d11.hよりも前にインクルードしてみてください。

これが出力結果です。ID3D11Debug::ReportLiveDeviceObjects()同様、メソッドを呼んだタイミングでのオブジェクトの状況が出力されます。 f:id:atori708:20150221191010p:plain

これでIDXGIDebug::ReportLiveObjects()によるRelease()忘れの調査が出来るようになりました。 渡している引数がDXGI_DEBUG_D3D11だと、前回の記事の出力と変化はあまりありません。 が、DXGI_DEBUG_DXGIやDXGI_DEBUG_APPなど、出力するものを変えることが出来ます。

以外と知られていないと思いますが、デバッグには必要な物だと思います。 実装してみてはいかがでしょうか。

IDXGIDebug::ReportLiveObjects()を使うまでの道のり その1

記念すべき初投稿は、DirectX11のデバッグレイヤーの話です。

DirectXでは、COMオブジェクトを使った設計がされています。 COMオブジェクトについては詳しく知らないので、ここでは割愛します。

ようは、Release()忘れを絶対にするなよということです。 とはいっても結構やってしまったりします。

そこで、Release忘れが発生しているかを調べる方法があります。それがデバッグレイヤーです。 デバッグレイヤーというのはD3Dデバイスの話です。 CreateDeviceをする時に、D3D11_CREATE_DEVICE_DEBUGを第4引数に渡すことで作成できます。

デバッグレイヤーはRelease忘れのチェックなどの処理をするため、普通よりも重たいです。 デバッグビルド時のみ有効にするとかしておくと便利ですね。

さて、Release忘れはこんなふうに、VisualStudioの出力ウィンドウに表示されます。
出力されるのは、アプリケーションが終了した時です。

f:id:atori708:20150220013441p:plain

ズラリと並んでいます。文字に色が付いているのは、拡張機能を入れているからです。 便利です。
VSColorOutput extension (VS2013です)

これすべてがRelease忘れなんですが、各文の後ろにUNKNOWNと出ています。 これでは何がRelease忘れかわかりません。レンダーターゲットビューやらテクスチャやら色々とあるのに、 これでは困ります。

しかし画像の中の一番上で、

Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting.

と書いてあります。ReportLiveObjects()を呼べば詳細を見れそうな気がします。

ここから私の長い旅が始まります。
ググってみると、IDXGIDebug::ReportLiveObjects()ID3D11Debug::ReportLiveDeviceObjects()が引っかかりました。

前者を解説する前に後者の説明をしたいと思います。 前者はWindows8以降でしか使えないです。
2015年2月現在、実装に至っていません。

ID3DDebug::ReportLiveDeviceObjects()は、D3Dデバイスがデバッグレイヤーであることが前提です。
以下ソースコードです。

// dxgidebug.hをインクルードしてください。

HRESULT hr;

ID3D11Device* pD3dDevice;
ID3D11Debug* pD3dDebug;

// デバイス作成は割愛

// 作成
hr = pD3dDevice->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void**>(&m_pD3dDebug));
if( FAILED(hr))
{
    return E_FAIL;
}

// 詳細表示
hr = m_pD3dDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);

これだけです。超簡単です。注意すべきなのは、詳細が出力ウィンドウに表示されるのは、 メソッドが呼ばれた時です。そのときのCOMオブジェクトの状況を見ることが出来ます。

f:id:atori708:20150220021041p:plain

先ほどと違い、オブジェクトのインターフェースが見えるようになり、InitRefというものも追加されています。 RefCount、InitRefの両方が0になって初めてCOMオブジェクトは解放されます。
(2つの違いは残念ながら私にはわかりません...)

しかし先程の一文、

Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting.

と書いてあります。あくまでReportLiveObjects()の方です。ReportLiveDeviceObjects()ではありません。

次回は、それを実装しようと悪戦苦闘し、あと一歩まで行った記録を記事にします。出来ました。
それではまた次回。