1

I'm making a ray tracing DX12 renderer, but ComPtr doesn't seem to release properly when I exit the process.(Press the x button to exit the window, or exit via WM_CLOSE or WM_DESTROY)

They are ComPtr and I think I didn't do anything about copying or referencing...

I don't know what's wrong with my code.

here's error codes :

D3D12 WARNING: Live ID3D12Device at 0x000001FB2DBFEF60, Refcount: 15 [ STATE_CREATION WARNING #274: LIVE_DEVICE]
D3D12 WARNING:  Live ID3D12CommandQueue at 0x000001FB35FA1520, Name: Unnamed ID3D12CommandQueue: Type=Direct, UniqueId=0x4d33f1f, Refcount: 7, IntRef: 0 [ STATE_CREATION WARNING #570: LIVE_COMMANDQUEUE]
D3D12 WARNING:  Live IDXGISwapChain at 0x000001FB360DA1D0, Refcount: 2 [ STATE_CREATION WARNING #275: LIVE_SWAPCHAIN]
D3D12 WARNING:  Live ID3D12LifetimeTracker at 0x000001FB360DC050, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #1164: LIVE_LIFETIMETRACKER]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FB360DC2C0, Name: Internal DXGI Fence, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FB360E0530, Name: Internal DXGI CommandAllocator, Refcount: 1, IntRef: 2 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12GraphicsCommandList at 0x000001FB360E0DF0, Name: Internal DXGI CommandList, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #573: LIVE_COMMANDLIST12]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FB361455B0, Name: Unnamed Committed ID3D12Resource: Format=R8G8B8A8_UNORM, Dimension=Texture2D, Width=1920, Height=1080, ArraySize: 1, MipLevels=1, UniqueId=0x4d33f39, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FB36146190, Name: Unnamed Committed ID3D12Resource: Format=R8G8B8A8_UNORM, Dimension=Texture2D, Width=1920, Height=1080, ArraySize: 1, MipLevels=1, UniqueId=0x4d33f3c, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FB36146D70, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12DescriptorHeap at 0x000001FB3614A120, Name: Unnamed ID3D12DescriptorHeap: Type=RTVNumDescriptors=2, UniqueId=0x4d33f70, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #576: LIVE_DESCRIPTORHEAP]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FB3614CFF0, Refcount: 1, IntRef: 2 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12GraphicsCommandList at 0x000001FB3614D8B0, Name: Unnamed ID3D12GraphicsCommandList: Type=Direct, UniqueId=0x4d33f75, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #573: LIVE_COMMANDLIST12]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FB361ACAD0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]

All of them is defined with ComPtr, and program is currently just initializing them with D3D12 APIs.

and here's my github repository: https://github.com/kcjsend2/Chulsu

2 Answers2

3

I suspect the problem is that you are relying on the implicit order of destruction of the variables, and you have some of device child objects listed before you have your device variable listed.

In your class you have:

    ComPtr<ID3D12GraphicsCommandList4> mD3dCmdList;
    ComPtr<ID3D12CommandAllocator> mCmdAllocator;

    ComPtr<IDXGIFactory4> mDxgiFactory;
    ComPtr<ID3D12Device5> mD3dDevice;

    D3D12MA::Allocator* mMemAllocator = NULL;

    ComPtr<ID3D12CommandQueue> mCommandQueue;
    ComPtr<ID3D12CommandAllocator> mCommandAllocator;

If you look at my DX12 DeviceResource .h / .cpp implementation, you'll see I have:

        Microsoft::WRL::ComPtr<ID3D12Device>                m_d3dDevice;
        Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList>   m_commandList;
        Microsoft::WRL::ComPtr<ID3D12CommandQueue>          m_commandQueue;
        Microsoft::WRL::ComPtr<ID3D12CommandAllocator>      m_commandAllocators[MAX_BACK_BUFFER_COUNT];

        // Swap chain objects.
        Microsoft::WRL::ComPtr<IDXGIFactory4>               m_dxgiFactory;
        Microsoft::WRL::ComPtr<IDXGISwapChain3>             m_swapChain;

In my case, device is "first" in the variable decalaration, so its "last" to be destructed.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • I tried it, but everything is same... same messages and all that warnings. – Shark_Bladder Aug 03 '22 at 00:51
  • The NVIDIA [link] https://developer.nvidia.com/rtx/raytracing/dxr/dx12-raytracing-tutorial-part-1 (DXR _HelloWorld_) sample suffers from the same problem in that temporary scratch buffers declared as COM pointers are not destroyed when the part of the code they are in falls out of scope. It was necessary to call `Release()` to destroy the ID3D12Resources instead. – Maico De Blasio Aug 03 '22 at 02:19
  • 1
    Then Should I release all that Interfaces Manually on Destructor? in Past Project, this works not that bad actually. in that project, every allocation goes well with ComPtr... Release all that ID3D12Resources manually sounds like terrible. – Shark_Bladder Aug 03 '22 at 02:26
1

You are reporting live objects before the destructors for your members have been invoked. This is how I would do it:

inline void ReportLiveObjects()
{
    Microsoft::WRL::ComPtr<IDXGIDebug1> dxgi_debug;
    if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(dxgi_debug.GetAddressOf()))))
    {
            dxgi_debug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_DETAIL | DXGI_DEBUG_RLO_IGNORE_INTERNAL));
    }
}

and then call this function after the your renderer class destructor has finished, for example using atexit:

std::atexit(ReportLiveObjects); //you can register this in the constructor for example

Alternative to atexit would be to have an object such as LiveObjectsReporter whose destructor would call ReportLiveObjects which you would place above all your members so it's destructor gets called last:

class Renderer
{
    ...
private:
    LiveObjectReporter reporter;
    ComPtr<ID3D12Device> device;
    //etc
};

struct LiveObjectReporter
{
    ~LiveObjectReporter()
    {
        ReportLiveObjects();
    }
};

EDIT:

The reason it's showing live objects is because you actually have live device, not because the method I showed you is wrong. In your DX12Renderer::CreateDevice you are calling QueryInterface which increases reference count (see here). Just write it

 ID3D12Device* allocatorDevice = pDevice.Get();

or call Release on your allocatorDevice.

mateeeeeee
  • 885
  • 1
  • 6
  • 15