4

This program:

#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();
}

gives this in the debug output:

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]

The debug device is reporting that the D3D12 device I created is still alive even after I release it. I know this is indeed true because the debug device itself is actually the only remaining referrer that is keeping the D3D12 device alive, but that is not a leak from my perspective, as I have correctly released my D3D12 device. This is just pollution to my program's output giving the false indication that I have a bug in my code.

My question is: am I indeed doing something wrong here? or is it a bad behavior in how reporting works in the D3D12 debug device? Any ideas on how to solve it?

Thanks!

Roman R.
  • 68,205
  • 6
  • 94
  • 158
Wessam Bahnassi
  • 145
  • 1
  • 8

2 Answers2

6

You should try using the D3D12_RLDO_IGNORE_INTERNAL flag to ignore those items that have a RefCount of 0 but still have an IntRef.

I prefer to use the DXGI debug device reporting instead of Direct3D's for the 'clean shutdown' scenario.

In my DeviceResources implementation, I create the DXGI device as follows:

    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())));

Then when I do shutdown and want to check for 'leaks':

#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

For Win32 apps, there's a clear time to do 'clean exit' report leaks. For UWP apps, lifetime is controlled by PLM so you don't ever get a 'clean exit'--the process is just terminated after a suspend. For UWP, the best place to do leak checks is in the "device lost" handler caused by device removal errors.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • The `D3D12_RLDO_IGNORE_INTERNAL` flag only removed the mention of the internal objects, but the D3D12Device itself still gets reported as leaking. However, the DXGI approach you use in your example works perfectly. Thanks Chuck! – Wessam Bahnassi Oct 18 '17 at 11:12
-1

Use the ComPtr object to define your D3D12 objects like Chuck's example:

ComPtr<ID3D12Debug> debugController;

This is necessary to avoid leaks and there will be no need to do object->Release() calls as the ComPtr object does them in its deconstructor.

developer68
  • 73
  • 1
  • 7