DirectX Leak Debugging

DirectX Leak Debugging
Yo my peps,
I have put together a small tutorial on how to use the ID3D11Debug interface to debug memory leaks caused by not properly releasing DirectX objects.
So I recently discovered some warning messages in my C++ DirectX application that are printed to the debug output (not the console) when exiting the program.
(Note: due to a faulty WordPress plugin, some code snippets may be broken with random dashes and tab characters, it should still be comprehensible though)
It looked something like this:

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 0x007464B0, Refcount: 4. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x007476F8, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A07580, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A07264, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A10ACC, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A11204, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A1295C, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A11944, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A11B60, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A120C4, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A133BC, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A1373C, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A14A2C, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A14CB4, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A153AC, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A16D7C, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A22B7C, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x0C17154C, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A26904, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A2A2CC, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x0C1687F4, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x0C16BE0C, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x01A1ADC4, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING: Live                         Object :     22 [ STATE_CREATION WARNING #0: UNKNOWN]
DXGI WARNING: Live Producer at 0x006AE3A8, Refcount: 4. [ STATE_CREATION WARNING #0: ]
DXGI WARNING:   Live Object at 0x006AEA38, Refcount: 2. [ STATE_CREATION WARNING #0: ]
DXGI WARNING: Live                         Object :      1 [ STATE_CREATION WARNING #0: ]

Ok, so live objects refer to objects which hasn’t been properly released (i.e. memory leaks). Most D3D interface classes such as ID3D11DeviceContext and ID3D11Buffer have a -Release function. Indeed, every interface inheriting from the abstract base class IUknown has it (which is mostly all interfaces returned by D3D11 functions).
So how does this help? Well mostly, it doesn’t. It does say that we could acquire more information by calling ReportLiveObjects() , but it’s not really that straightforward. Nevertheless, I will guide you through how it works:

Prerequisites

The first requirement is that you create the D3D device with the D3D11_CREATE_DEVICE_DEBUG flag, preferably only when in debug mode:

printf("Creating contextn");
Result = D3D11CreateDeviceAndSwapChain(
    nullptr,
    D3D_DRIVER_TYPE_HARDWARE,
    nullptr,
    #if defined(_DEBUG) 
    D3D11_CREATE_DEVICE_DEBUG,
    #else 
    0,
    #endif
    &FeatureLevelRequired,
    1,
    D3D11_SDK_VERSION,
    &SwapChainDesc,
    &SwapChain,
    &Device,
    &FeatureLevelAchieved,
    &DeviceContext
);
CHECKERROR

Result is simply a HRESULT used to store the success or failure, and CHECKERROR is a macro handling it.
The critical lines here are marked. Notice how we differ from a debug project and a release project. In the production build we don’t want to create a debug device (we should have figured out all leaks by then and it is also a unecessary performance hit).
The resulting device, here specified with &Device now has a debug interface attached to it.

Reporting live objects

In order to display some valuable debug information we now need to query the debug interface, and call its ReportLiveDeviceObjects(D3D11_RLDO_FLAGS Flags) function.
The querying is done with Device-QueryInterface , specifying the uuid of ID3D11Debug and a pointer to the output pointer, similarly to many of the DirectX11 functions, resulting in a ID3D11Debug* . Consider the example code below:

ID3D11Debug* DebugDevice = nullptr;
HRESULT Result = Device−>QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void**>(&DebugDevice));
CHECKERROR

With this, assuming it succeeds, we now have debug device. The reporting of live object is then simply the action of calling a function of it:

Result = DebugDevice−>ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
CHECKERROR

This will output information to the debug output. D3D11_RLDO_DETAIL specifies that we want a more verbose output, while the D3D11_RLDO_SUMMARY is similar to the automatic output at the start of this post. Don’t forget to release the debug device afterwards.
My code:

void RenderSystem::ReportLiveObjects()
{
    #ifdef _DEBUG
    ID3D11Debug* DebugDevice = nullptr;
    HRESULT Result = Device−QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast       −  **(&DebugDevice));
    CHECKERROR

    Result = DebugDevice−ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
    CHECKERROR

    SAFE_RELEASE(DebugDevice);
    #endif
}

( SAFE_RELEASE is a macro that just checks if the pointer is valid before calling Release ).

Interpreting the output

Sample output:

D3D11 WARNING: Live ID3D11Device at 0x0074643C, Refcount: 6 [ STATE_CREATION WARNING #441: LIVE_DEVICE]
D3D11 WARNING:  Live ID3D11Context at 0x007476F8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #2097226: LIVE_CONTEXT]
D3D11 WARNING:  Live ID3DDeviceContextState at 0x01A07580, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #3145742: LIVE_DEVICECONTEXTSTATE]
D3D11 WARNING:  Live ID3D11BlendState at 0x01A07264, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #435: LIVE_BLENDSTATE]
D3D11 WARNING:  Live ID3D11DepthStencilState at 0x01A10ACC, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #436: LIVE_DEPTHSTENCILSTATE]
D3D11 WARNING:  Live ID3D11RasterizerState at 0x01A11204, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #437: LIVE_RASTERIZERSTATE]
D3D11 WARNING:  Live ID3D11Sampler at 0x01A1295C, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #434: LIVE_SAMPLER]
D3D11 WARNING:  Live ID3D11Query at 0x01A11944, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #438: LIVE_QUERY]
D3D11 WARNING:  Live IDXGISwapChain at 0x01A11B60, Refcount: 0 [ STATE_CREATION WARNING #442: LIVE_SWAPCHAIN]
D3D11 WARNING:  Live ID3D11Texture2D at 0x01A120C4, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #425: LIVE_TEXTURE2D]
D3D11 WARNING:  Live ID3D11RenderTargetView at 0x01A133BC, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #428: LIVE_RENDERTARGETVIEW]
D3D11 WARNING:  Live ID3D11Texture2D at 0x01A1373C, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #425: LIVE_TEXTURE2D]
D3D11 WARNING:  Live ID3D11DepthStencilView at 0x01A14A2C, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #429: LIVE_DEPTHSTENCILVIEW]
D3D11 WARNING:  Live ID3D11DepthStencilState at 0x01A14CB4, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #436: LIVE_DEPTHSTENCILSTATE]
D3D11 WARNING:  Live ID3D11RasterizerState at 0x01A153AC, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #437: LIVE_RASTERIZERSTATE]
D3D11 WARNING:  Live ID3D11VertexShader at 0x01A16D7C, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #430: LIVE_VERTEXSHADER]
D3D11 WARNING:  Live ID3D11PixelShader at 0x01A22B7C, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #432: LIVE_PIXELSHADER]
D3D11 WARNING:  Live ID3D11InputLayout at 0x0C17154C, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #433: LIVE_INPUTLAYOUT]
D3D11 WARNING:  Live ID3D11Buffer at 0x01A26904, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #423: LIVE_BUFFER]
D3D11 WARNING:  Live ID3D11Buffer at 0x01A2A2CC, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #423: LIVE_BUFFER]
D3D11 WARNING:  Live ID3D11Buffer at 0x0C1687F4, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #423: LIVE_BUFFER]
D3D11 WARNING:  Live ID3D11Buffer at 0x0C16BE0C, Refcount: 0, IntRef: 0 [ STATE_CREATION WARNING #423: LIVE_BUFFER]
D3D11 WARNING:  Live ID3D11Texture2D at 0x01A1ADC4, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #425: LIVE_TEXTURE2D]

It reports the similar values as before, such as Refcount and the hex address, but the most important new addition is the that the type is specified. This will help significantly in narrowing down the resources.
I’ve highlighted the important lines here. As you can see, I haven’t released a vertex buffer, an index buffer and an input layout.
The first line is an important notice; it represents the top-level ID3D11Device created at start. In order to even query the debug interface, a valid ID3D11Device pointer must exist. All other resources can be released ahead of calling ReportLiveDeviceObjects , but as the ID3D11Device is not released, it still reports that it is live (which it is).
Another important factor is to differentiate between Refcount and IntRef. IntRef is the internal reference count which are held internally by DirectX objects. For example, ID3D11Context at line 2 has no Refcount as it has already been released, but it is still reference internally (most likely by the ID3D11Device ) because we specified one during creation.
As such, we only need to worry about live objects which has a Refcount greater than 0. From here on you will have to traverse your code, find instances of the specified objects, and check if they are indeed released upon destruction.

Conclusion

You now have learned how to use the debug device feature of DirectX to find, debug and fix memory leaks caused by DirectX related objects.

参考

DirectX Leak Debugging

[DX11调试]检查D3D对象是否释放:ReportLiveObjects()的用法

ID3D11Debug::ReportLiveDeviceObjects method

ID3D12DebugDevice::ReportLiveDeviceObjects method

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值