microsoft / media-foundation

Repository for Windows Media Foundation related tools and samples
MIT License
144 stars 31 forks source link

ID3D12Fence leak #31

Closed robUx4 closed 2 years ago

robUx4 commented 2 years ago

As mentioned in https://github.com/microsoft/media-foundation/issues/21#issuecomment-1010985241 I have tried to get D3D12 decoding with Media Foundation. It more or less works, but eventually it leaks internal ID3D12Fence each time it's created. I can end up with thousands of dead ID3D12Fence in my process.

To exhibit the issue I made this sample code which decodes a frame, attempt to drain, flushes and then exit.

/* compile: g++ d3d12_mft.cpp -o d3d12_mft.exe -ld3d12 -ldxgi -lmfplat -lmfreadwrite */

#undef WINVER
#define WINVER 0x0A00

#define NTDDI_VERSION  0x0A00000B // NTDDI_WIN10_CO

#include <windows.h>

#include <d3dx12.h>
#include <assert.h>

#include <dxgi.h>
#include <dxgi1_5.h>

#include <initguid.h>

#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <mferror.h>
#include <mfd3d12.h>

#include <wrl.h>

#if !defined(NDEBUG)
# include <d3d12sdklayers.h>
#endif

using Microsoft::WRL::ComPtr;

static void init_direct3d(ComPtr<ID3D12Device> &d3device)
{
    HRESULT hr;
    UINT creationFlags = 0;
#ifndef NDEBUG
    {
        ComPtr<ID3D12Debug> debugController;
        if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(debugController.GetAddressOf()))))
        {
            debugController->EnableDebugLayer();
            creationFlags |= DXGI_CREATE_FACTORY_DEBUG;
        }
    }
#endif

    ComPtr<IDXGIFactory2> factory;
    hr = CreateDXGIFactory2(creationFlags, IID_PPV_ARGS(factory.GetAddressOf()));

    ComPtr<IDXGIAdapter1> adapter;
    for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != factory->EnumAdapters1(adapterIndex, adapter.GetAddressOf()); ++adapterIndex)
    {
        DXGI_ADAPTER_DESC1 desc;
        adapter->GetDesc1(&desc);

        if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
            continue;

        if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(d3device.GetAddressOf()))))
            break;
    }
}

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    ComPtr<ID3D12Device> d3device;
    (void)hPrevInstance;
    (void)hInstance;
    (void)nCmdShow;
    (void)lpCmdLine;
    HRESULT hr;

    CoInitializeEx(0, COINIT_MULTITHREADED);

    init_direct3d(d3device);
#ifndef NDEBUG
    ComPtr<ID3D12DebugDevice> debugDevice;
    hr = d3device.As(&debugDevice);
#endif

    MFStartup(MF_VERSION, MFSTARTUP_FULL);

    UINT resetToken;
    ComPtr<IMFDXGIDeviceManager> dxgiDeviceManager;
    MFCreateDXGIDeviceManager(&resetToken, dxgiDeviceManager.GetAddressOf());

    dxgiDeviceManager->ResetDevice(d3device.Get(), resetToken);

    ComPtr<IMFSourceReader> sourceReader;
    {
        ComPtr<IMFAttributes> creationAttributes;
        MFCreateAttributes(creationAttributes.GetAddressOf(), 1);
        creationAttributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, dxgiDeviceManager.Get());
        // creationAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);

        MFCreateSourceReaderFromURL(L"http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4",
                                    creationAttributes.Get(), sourceReader.GetAddressOf());
    }

    {
        ComPtr<IMFMediaType> pVideoMediaType;
        hr = MFCreateMediaType(&pVideoMediaType);

        hr = pVideoMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
        hr = pVideoMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12);
        // hr = pVideoMediaType->SetUINT32(MF_MT_D3D_RESOURCE_VERSION, MF_D3D12_RESOURCE);
        // hr = pVideoMediaType->SetUINT32(MF_MT_D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS, TRUE);

        hr = sourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pVideoMediaType.Get());
        assert(SUCCEEDED(hr));
    }

    ComPtr<IMFTransform> transform;
   {
        ComPtr<IMFSourceReaderEx> sourceReaderEx;
        sourceReader.As(&sourceReaderEx);
        GUID cat = MFT_CATEGORY_VIDEO_DECODER;

        hr = sourceReaderEx->GetTransformForStream(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, &cat, transform.GetAddressOf());

        hr = transform->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)dxgiDeviceManager.Get());
    }

    hr = sourceReader->SetStreamSelection(MF_SOURCE_READER_ALL_STREAMS, FALSE);
    hr = sourceReader->SetStreamSelection(MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE);

    size_t decodedFrames = 0;
    ComPtr<IMFD3D12SynchronizationObjectCommands> pMFSyncCmd;
    ComPtr<IMFD3D12SynchronizationObject> pMFSyncObjs;
    HANDLE sampleResourceReady = CreateEvent(NULL, TRUE, FALSE, NULL);
    HANDLE sampleResourceFinalRelease = CreateEvent(NULL, TRUE, FALSE, NULL);
    while (true)
    {
        DWORD readFlags = decodedFrames == 0 ? 0 : MF_SOURCE_READER_CONTROLF_DRAIN;
        DWORD dwActualStreamIndex;
        DWORD dwStreamFlags;
        LONGLONG llTimestamp;
        ComPtr<IMFSample> sample;
        hr = sourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, readFlags, &dwActualStreamIndex, &dwStreamFlags, &llTimestamp, sample.GetAddressOf());
        assert(SUCCEEDED(hr));

        if (decodedFrames++ == 0)
        {
        }

        if (!sample.Get())
            break; // finished draining

        DWORD bufferCount;
        sample->GetBufferCount(&bufferCount);

        ComPtr<IMFMediaBuffer> output_media_buffer;
        hr = sample->GetBufferByIndex(0, output_media_buffer.GetAddressOf());

        ComPtr<IMFDXGIBuffer> spDXGIBuffer;
        hr = output_media_buffer.As(&spDXGIBuffer);
        if (SUCCEEDED(hr))
        {
            ComPtr<ID3D12Resource> texture;
            hr = spDXGIBuffer->GetResource(IID_PPV_ARGS(&texture));
            assert(SUCCEEDED(hr));
            texture->SetName(L"MFT texture");

            hr = spDXGIBuffer->GetUnknown(MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS(pMFSyncCmd.GetAddressOf()));
            assert(SUCCEEDED(hr));
            hr = spDXGIBuffer->GetUnknown(MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS(pMFSyncObjs.GetAddressOf()));
            assert(SUCCEEDED(hr));

            pMFSyncCmd->SignalEventOnResourceReady(sampleResourceReady);
        }
    }

    hr = WaitForSingleObjectEx(sampleResourceReady, INFINITE, TRUE);
    assert(hr == WAIT_OBJECT_0);

    if (false)
    {
        ComPtr<IMFMediaSource> mediaSource;
        const GUID GUID_NULL = {0x0000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
        sourceReader->GetServiceForStream(MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&mediaSource));
        if (mediaSource.Get())
            mediaSource->Stop();
    }

    sourceReader->Flush(MF_SOURCE_READER_ALL_STREAMS);

    // pMFSyncObjs->Reset();

    pMFSyncObjs->SignalEventOnFinalResourceRelease(sampleResourceFinalRelease);
    hr = WaitForSingleObjectEx(sampleResourceFinalRelease, INFINITE, TRUE);
    assert(hr == WAIT_OBJECT_0);

    // ERROR: A ID3D12Resource is referenced by GPU operations in-flight on Command Queue
    // hr = transform->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, 0);

    transform.Reset();
    hr = dxgiDeviceManager->ResetDevice(nullptr, resetToken);

#ifndef NDEBUG
    if (debugDevice.Get())
        debugDevice->ReportLiveDeviceObjects((D3D12_RLDO_FLAGS)(D3D12_RLDO_IGNORE_INTERNAL | D3D12_RLDO_DETAIL));
#endif

    MFShutdown();
    CloseHandle(sampleResourceReady);
    CloseHandle(sampleResourceFinalRelease);

    d3device.Reset();

    CoUninitialize();

    return 0;
}

When you run this code, you can see a report of live objects before the program exits, with a lot of internal things to the Media Foundation decoder, ie things I did not create myself.

D3D12 WARNING: Live ID3D12Device at 0x000001FF74BB0208, Refcount: 76 [ STATE_CREATION WARNING #274: LIVE_DEVICE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7C1B1120, Name: MFT texture, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA69AC0, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA6BF50, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA6E3E0, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA70870, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA72D00, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA755A0, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA77A30, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA79EC0, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA7C350, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA7E7E0, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA80C70, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA83100, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FF7BA83DC0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA862E0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FF7BA86FA0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA874B0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FF7BA8A180, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7BA8E6A0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FF7BA8EB00, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7C1B5700, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FF7BA8ED80, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7C1B5270, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FF7C1B7C70, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7C1B4950, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FF7C1BA0B0, Refcount: 1, IntRef: 1 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12Resource at 0x000001FF7C1B3710, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #575: LIVE_RESOURCE]
D3D12 WARNING:  Live ID3D12CommandAllocator at 0x000001FF7C1BA5B0, Refcount: 1, IntRef: 1 [ STATE_CREATION WARNING #571: LIVE_COMMANDALLOCATOR]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7B82C890, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12CommandQueue at 0x000001FF7C1BD780, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #1054: LIVE_VIDEODECODECOMMANDQUEUE]
D3D12 WARNING:  Live ID3D12VideoDecodeCommandList at 0x000001FF7C1EE7C0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #982: LIVE_VIDEODECODECOMMANDLIST]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FD410, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2F9A40, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FB160, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FAA70, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2F9EE0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FA130, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FA380, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FBCF0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FCD20, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FA820, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FD1C0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12Fence at 0x000001FF7C2FACC0, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #580: LIVE_MONITOREDFENCE]
D3D12 WARNING:  Live ID3D12VideoDecoder at 0x000001FF74E16A60, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #983: LIVE_VIDEODECODER]
D3D12 WARNING:  Live ID3D12VideoDecoderHeap at 0x000001FF7C1BA330, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #1084: LIVE_VIDEODECODERHEAP]

When the app is closing, there is this report, where the pointers correspond to the ID3D12Fence seen above:

D3D12 WARNING: Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING: Live Producer at 0x000001FF74BB01E8, Refcount: 26. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF72D6A030, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF74E7DF70, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF74E79A30, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF74C48E30, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF74D8ABF0, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF74C49D40, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF74C49F90, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7B7026E0, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FD410, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2F9A40, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FB160, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FAA70, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2F9EE0, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FA130, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FA380, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FBCF0, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FCD20, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FA820, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FD1C0, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING:  Live Object at 0x000001FF7C2FACC0, Refcount: 1. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D12 WARNING: Live                         Object :     20 [ STATE_CREATION WARNING #0: UNKNOWN]

I tried using the IMFD3D12SynchronizationObject and IMFD3D12SynchronizationObjectCommands interfaces but with no luck.

robUx4 commented 2 years ago

It seems that using MF_D3D12_SYNCHRONIZATION_OBJECT is actually only supported in Win11 (and the GDK). The mfd3d12.h header doesn't have any versioning for those, nor for IMFD3D12SynchronizationObjectCommands and IMFD3D12SynchronizationObject.

The code doesn't leak ID3D12Fence on Windows 11, but it does report some object leaks with some RefCount at 0 (similar to the ones on Win10) and an upper object with a RefCount of 2.

mattrwoz commented 2 years ago

The first report is expected. Calling ReportLiveDeviceObjects before calling MFShutdown & releasing the IMFSourceReader pointer will result in lots of live objects. Both MF platform (controlled by MFStartup/Shutdown) and SourceReader tend to cache objects for re-use in the event a user wanted to re-use the decoder/sourcereader object (it will start decoding video faster on re-use). If you see an increasing number of objects on re-use or full cleanup then there would definitely be a leak bug.

There were known issues in Win10's implementation of DX12 support. We actually have a servicing patch which should bring this fix to Win10 within the next month or two.

However, Win11 should be working correctly today. Would you be able to share the log from Win11?

robUx4 commented 2 years ago

The leak doesn't happen on Windows 11.

It is indeed normal to get the first report of live objects. The goal of this log is to identify the type for each pointer. The real issue is the report after we close the app/process. The pointers remaining should not be there and correspond to ID3D12Fence objects.

We noticed the leak on Windows 10 because it does grow significantly over times (by the thousands). This simple example just shows one way to get it. I'll check with the new Windows 10 release if the bug is still there.