参考文章《DirectX Leak Debugging》:http://masterkenth.com/blog/2014/03/07/directx-leak-debugging/
DX11在debug方面有许多改进,其中之一就是能输出未释放的d3d对象,但默认情况下,是输出这个样子:
D3D11 WARNING: Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Producer at 0x00361180, Refcount: 3. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x00362010, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x003713F8, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x0037755C, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x003776FC, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x00377894, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x00377B34, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x00377CC4, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x00378290, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x003787F4, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x0037A884, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x0037AA44, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x0037C7AC, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x0037B784, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x0037CC14, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x0037F29C, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x0037DE1C, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x0037FE3C, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x04191A14, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object at 0x041E0364, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]D3D11 WARNING: Live Object : 19 [ STATE_CREATION WARNING #0: UNKNOWN]DXGI WARNING: Live Producer at 0x00340978, Refcount: 4. [ STATE_CREATION WARNING #0: ]DXGI WARNING: Live Object at 0x00353640, Refcount: 2. [ STATE_CREATION WARNING #0: ]DXGI WARNING: Live Object : 1 [ STATE_CREATION WARNING #0: ]
以上这些不清不楚的警告对我们而言毫无帮助,和没有输出任何东西一样。所以d3d提供了一个ReportLiveObjects()方法,让开发者直接查询当前各个d3d对象的状态
一、
在使用这个方法之前,我们需要先做一些准备 —— 把d3d的device定义为debug模式。在创建device的时候flag参数设置为 D3D11_CREATE_DEVICE_DEBUG。和dx sdk自带的sample里的例子是一样的做法
#if defined(DEBUG) || defined(_DEBUG) createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;#endifD3D11CreateDeviceAndSwapChain(NULL, mDriverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &desc, &mSwapChain, &mDevice, &mFeatureLevel, &mDeviceContext);
二、
接下来我们就可以随时调用ReportLiveObjects()方法了。一般是放在device->Release()之前,用来检查其他对象是否已经正确释放。示范如下:
#if defined(DEBUG) || defined(_DEBUG) ID3D11Debug *d3dDebug; HRESULT hr = mDevice->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void**>(&d3dDebug)); if (SUCCEEDED(hr)) { hr = d3dDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL); } if (d3dDebug != nullptr) d3dDebug->Release();#endif if (mDevice != nullptr) mDevice->Release();
三、
ReportLiveObjects()的参数是一个enum,有3个:
D3D11_RLDO_SUMMARY
显示总概况
D3D11_RLDO_DETAIL
显示详细信息
D3D11_RLDO_IGNORE_INTERNAL
MSDN解释是无用,只是给DX内部使用(那你定义这个做什么啊!)
忽略第三个卖萌的,D3D11_RLDO_SUMMARY和D3D11_RLDO_DETAIL有什么不同呢?我们看下2个的输出
D3D11_RLDO_SUMMARY:
D3D11 WARNING: Using ID3D11Debug::ReportLiveDeviceObjects with D3D11_RLDO_DETAIL will help drill into object lifetimes. Objects with Refcount=0 and IntRef=0 will be eventually destroyed through typical Immediate Context usage. However, if the application requires these objects to be destroyed sooner, ClearState followed by Flush on the Immediate Context will realize their destruction. [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]D3D11 WARNING: Live ID3D11Device at 0x0036110C, Refcount: 5 [ STATE_CREATION WARNING #441: LIVE_DEVICE]D3D11_RLDO_DETAIL:
D3D11 WARNING: Live ID3D11Device at 0x004ED84C, Refcount: 5 [ STATE_CREATION WARNING #441: LIVE_DEVICE]D3D11 WARNING: Live ID3D11Context at 0x004EE5C8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #2097226: LIVE_CONTEXT]D3D11 WARNING: Live ID3DDeviceContextState at 0x005013D8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #3145742: LIVE_DEVICECONTEXTSTATE]D3D11 WARNING: Live ID3D11BlendState at 0x0050753C, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #435: LIVE_BLENDSTATE]D3D11 WARNING: Live ID3D11DepthStencilState at 0x005076DC, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #436: LIVE_DEPTHSTENCILSTATE]D3D11 WARNING: Live ID3D11RasterizerState at 0x0050784C, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #437: LIVE_RASTERIZERSTATE]D3D11 WARNING: Live ID3D11Sampler at 0x00507AEC, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #434: LIVE_SAMPLER]D3D11 WARNING: Live ID3D11Query at 0x00507CA4, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #438: LIVE_QUERY]D3D11 WARNING: Live IDXGISwapChain at 0x00508270, Refcount: 0 [ STATE_CREATION WARNING #442: LIVE_SWAPCHAIN]D3D11 WARNING: Live ID3D11Texture2D at 0x005087D4, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #425: LIVE_TEXTURE2D]D3D11 WARNING: Live ID3D11RasterizerState at 0x0050A89C, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #437: LIVE_RASTERIZERSTATE]D3D11 WARNING: Live ID3D11RenderTargetView at 0x0050AA34, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #428: LIVE_RENDERTARGETVIEW]D3D11 WARNING: Live ID3D11VertexShader at 0x0050C79C, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #430: LIVE_VERTEXSHADER]D3D11 WARNING: Live ID3D11InputLayout at 0x0050B774, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #433: LIVE_INPUTLAYOUT]D3D11 WARNING: Live ID3D11PixelShader at 0x0050CC04, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #432: LIVE_PIXELSHADER]D3D11 WARNING: Live ID3D11VertexShader at 0x0050D0CC, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #430: LIVE_VERTEXSHADER]D3D11 WARNING: Live ID3D11InputLayout at 0x0050DEAC, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #433: LIVE_INPUTLAYOUT]D3D11 WARNING: Live ID3D11PixelShader at 0x00517844, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #432: LIVE_PIXELSHADER]D3D11 WARNING: Live ID3D11Buffer at 0x009066D4, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #423: LIVE_BUFFER]D3D11 WARNING: Live ID3D11Texture2D at 0x00979754, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #425: LIVE_TEXTURE2D]很显而易见吧!
四、
IntRef是d3d内部的对象引用,Refcount是我们程序里未释放的d3d对象,比如我们的ID3D11Context,Refcount是0,但IntRef是1,因为我们在程序里创建过一个context,所以在d3d内部还保留着引用,我们只需要注意Refcount不为0的对象就OK了。
所以上面的那几行信息,告诉我们还有一个ID3D11Device,ID3D11VertexShader和ID3D11PixelShader对象未释放,vs和ps对象可以释放,但因为ReportLiveObjects()方法是device调用的,所以在这之前我们还不能释放device,不过无问题,在确保其他对象的Refcount为0后,我们再安全释放ID3D11Debug和ID3D11Device就OK了。
注:
我这里使用的是VS2013自带的dx sdk,根据 这篇文章 所述,如果使用June 2010 DirectX SDK的话,提示里会出现一个name属性,像这样:
D3D11: INFO: Destroy Buffer: Name="unnamed", Addr=0x002A55A4 [ STATE_CREATION INFO #2097230: DESTROY_BUFFER ]这时候就可以使用D3D对象里的SetPrivateData()方法来为我们的对象设置一个name,就能更加清楚的定位到具体对象