D3D12不可避免的泄漏报告

时间:2017-10-18 03:51:41

标签: c++ memory-leaks direct3d12

这个程序:

#include <d3d12.h>
#pragma comment(lib,"d3d12")

int main()
{
    ID3D12Debug *pDebug = NULL;
    D3D12GetDebugInterface(__uuidof(ID3D12Debug),(void**)&pDebug);
    pDebug->EnableDebugLayer();
    pDebug->Release();

    ID3D12Device *pDev = NULL;
    D3D12CreateDevice(NULL,D3D_FEATURE_LEVEL_12_1,__uuidof(ID3D12Device),(void**)&pDev);

    ID3D12DebugDevice *pDebugDevice = NULL;
    pDev->QueryInterface(&pDebugDevice);
    pDev->Release();
    pDebugDevice->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL);
    pDebugDevice->Release();
}

在调试输出中给出了这个:

D3D12 WARNING: Live ID3D12Device at 0x000C6BA8, Refcount: 2 [ STATE_CREATION WARNING #274: LIVE_DEVICE]
D3D12 WARNING:  Live ID3D12RootSignature at 0x000E62E8, Refcount: 0, IntRef: 2 [ STATE_CREATION WARNING #577: LIVE_ROOTSIGNATURE]
D3D12 WARNING:  Live ID3D12PipelineState at 0x0011C3C8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #572: LIVE_PIPELINESTATE]
D3D12 WARNING:  Live ID3D12PipelineState at 0x001421D8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #572: LIVE_PIPELINESTATE]
D3D12 WARNING:  Live ID3D12Resource at 0x00138FF8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Heap at 0x00144DD8, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #579: LIVE_HEAP]

调试设备报告我创建的D3D12设备即使在我发布之后仍然存在。我知道这确实是正确的,因为调试设备本身实际上是唯一保持D3D12设备存活的剩余引用,但从我的角度来看,这不是泄漏,因为我已正确发布了我的D3D12设备。这只是对我程序输出的污染,这表明我的代码中有错误。

我的问题是:我的确在做错了吗?或者报告在D3D12调试设备中的工作方式是不好的行为?关于如何解决它的任何想法?

谢谢!

2 个答案:

答案 0 :(得分:5)

您应该尝试使用D3D12_RLDO_IGNORE_INTERNAL标志来忽略那些RefCount为0但仍有IntRef的项目。

我更喜欢使用DXGI调试设备报告而不是Direct3D用于“干净关闭”场景。

在我的DeviceResources实现中,我按如下方式创建了DXGI设备:

    m_dxgiFactoryFlags = 0;

#if defined(_DEBUG)
    // Enable the debug layer (requires the Graphics Tools "optional feature").
    //
    // NOTE: Enabling the debug layer after device creation will invalidate the active device.
    {
        ComPtr<ID3D12Debug> debugController;
        if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(debugController.GetAddressOf()))))
        {
            debugController->EnableDebugLayer();
        }
        else
        {
            OutputDebugStringA("WARNING: Direct3D Debug Device is not available\n");
        }

        ComPtr<IDXGIInfoQueue> dxgiInfoQueue;
        if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(dxgiInfoQueue.GetAddressOf()))))
        {
            m_dxgiFactoryFlags = DXGI_CREATE_FACTORY_DEBUG;

            dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);
            dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);
        }
    }
#endif

    ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));

然后当我关机并想要检查'泄漏'时:

#ifdef _DEBUG
    {
        ComPtr<IDXGIDebug1> dxgiDebug;
        if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug))))
        {
            dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_IGNORE_INTERNAL));
        }
    }
#endif
  

对于Win32应用程序,可以清楚地“清除退出”报告泄漏。对于UWP应用程序,生命周期由PLM控制,因此您不会得到“干净退出” - 该过程在暂停后终止。对于UWP,进行泄漏检查的最佳位置是设备删除错误导致的“设备丢失”处理程序。

答案 1 :(得分:0)

使用ComPtr对象来定义D3D12对象,例如Chuck的示例:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eric"));

if(condition){
    query.addCriteria(Criteria.where("location").is("USA"));
}
List<User> users = mongoTemplate.find(query, User.class);

这是避免泄漏所必需的,并且无需进行object-> Release()调用,因为ComPtr对象在其解构函数中进行了调用。