Added macro D3D12MA_DEBUG_LOG (empty by default), virtual function BlockMetadata::DebugLogAllAllocations
diff --git a/src/D3D12MemAlloc.cpp b/src/D3D12MemAlloc.cpp
index 060de01..52fc799 100644
--- a/src/D3D12MemAlloc.cpp
+++ b/src/D3D12MemAlloc.cpp
@@ -107,6 +107,16 @@
    #define D3D12MA_DEFAULT_BLOCK_SIZE (64ull * 1024 * 1024)

 #endif

 

+#ifndef D3D12MA_DEBUG_LOG

+   #define D3D12MA_DEBUG_LOG(format, ...)

+   /*

+   #define D3D12MA_DEBUG_LOG(format, ...) do { \

+       wprintf(format, __VA_ARGS__); \

+       wprintf(L"\n"); \

+   } while(false)

+   */

+#endif

+

 #endif // _D3D12MA_CONFIGURATION

 ////////////////////////////////////////////////////////////////////////////////

 ////////////////////////////////////////////////////////////////////////////////

@@ -900,6 +910,7 @@
 public:

     using value_type = T;

     using iterator = T*;

+    using const_iterator = const T*;

 

     // allocationCallbacks externally owned, must outlive this object.

     Vector(const ALLOCATION_CALLBACKS& allocationCallbacks);

@@ -916,13 +927,10 @@
 

     iterator begin() { return m_pArray; }

     iterator end() { return m_pArray + m_Count; }

-    iterator rend() { return begin() - 1; }

-    iterator rbegin() { return end() - 1; }

-

-    const iterator cbegin() const { return m_pArray; }

-    const iterator cend() const { return m_pArray + m_Count; }

-    const iterator crbegin() const { return cend() - 1; }

-    const iterator crend() const { return cbegin() - 1; }

+    const_iterator cbegin() const { return m_pArray; }

+    const_iterator cend() const { return m_pArray + m_Count; }

+    const_iterator begin() const { return cbegin(); }

+    const_iterator end() const { return cend(); }

 

     void push_front(const T& src) { insert(0, src); }

     void push_back(const T& src);

@@ -2968,11 +2976,13 @@
     virtual void AddStatistics(Statistics& inoutStats) const = 0;

     virtual void AddDetailedStatistics(DetailedStatistics& inoutStats) const = 0;

     virtual void WriteAllocationInfoToJson(JsonWriter& json) const = 0;

+    virtual void DebugLogAllAllocations() const = 0;

 

 protected:

     const ALLOCATION_CALLBACKS* GetAllocs() const { return m_pAllocationCallbacks; }

     UINT64 GetDebugMargin() const { return IsVirtual() ? 0 : D3D12MA_DEBUG_MARGIN; }

 

+    void DebugLogAllocation(UINT64 offset, UINT64 size, void* privateData) const;

     void PrintDetailedMap_Begin(JsonWriter& json,

         UINT64 unusedBytes,

         size_t allocationCount,

@@ -3000,6 +3010,25 @@
     D3D12MA_ASSERT(allocationCallbacks);

 }

 

+void BlockMetadata::DebugLogAllocation(UINT64 offset, UINT64 size, void* privateData) const

+{

+    if (IsVirtual())

+    {

+        D3D12MA_DEBUG_LOG(L"UNFREED VIRTUAL ALLOCATION; Offset: %llu; Size: %llu; PrivateData: %p", offset, size, privateData);

+    }

+    else

+    {

+        D3D12MA_ASSERT(privateData != NULL);

+        Allocation* allocation = reinterpret_cast<Allocation*>(privateData);

+

+        privateData = allocation->GetPrivateData();

+        LPCWSTR name = allocation->GetName();

+

+        D3D12MA_DEBUG_LOG(L"UNFREED ALLOCATION; Offset: %llu; Size: %llu; PrivateData: %p; Name: %s",

+            offset, size, privateData, name ? name : L"D3D12MA_Empty");

+    }

+}

+

 void BlockMetadata::PrintDetailedMap_Begin(JsonWriter& json,

     UINT64 unusedBytes, size_t allocationCount, size_t unusedRangeCount) const

 {

@@ -3715,6 +3744,7 @@
     void AddStatistics(Statistics& inoutStats) const override;

     void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;

     void WriteAllocationInfoToJson(JsonWriter& json) const override;

+    void DebugLogAllAllocations() const override;

 

 private:

     /*

@@ -4671,6 +4701,19 @@
     PrintDetailedMap_End(json);

 }

 

+void BlockMetadata_Linear::DebugLogAllAllocations() const

+{

+    const SuballocationVectorType& suballocations1st = AccessSuballocations1st();

+    for (auto it = suballocations1st.begin() + m_1stNullItemsBeginCount; it != suballocations1st.end(); ++it)

+        if (it->type != SUBALLOCATION_TYPE_FREE)

+            DebugLogAllocation(it->offset, it->size, it->privateData);

+

+    const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();

+    for (auto it = suballocations2nd.begin(); it != suballocations2nd.end(); ++it)

+        if (it->type != SUBALLOCATION_TYPE_FREE)

+            DebugLogAllocation(it->offset, it->size, it->privateData);

+}

+

 Suballocation& BlockMetadata_Linear::FindSuballocation(UINT64 offset) const

 {

     const SuballocationVectorType& suballocations1st = AccessSuballocations1st();

@@ -4682,31 +4725,31 @@
 

     // Item from the 1st vector.

     {

-        const SuballocationVectorType::iterator it = BinaryFindSorted(

-            suballocations1st.cbegin() + m_1stNullItemsBeginCount,

-            suballocations1st.cend(),

+        const SuballocationVectorType::const_iterator it = BinaryFindSorted(

+            suballocations1st.begin() + m_1stNullItemsBeginCount,

+            suballocations1st.end(),

             refSuballoc,

             SuballocationOffsetLess());

-        if (it != suballocations1st.cend())

+        if (it != suballocations1st.end())

         {

-            return *it;

+            return const_cast<Suballocation&>(*it);

         }

     }

 

     if (m_2ndVectorMode != SECOND_VECTOR_EMPTY)

     {

         // Rest of members stays uninitialized intentionally for better performance.

-        const SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?

-            BinaryFindSorted(suballocations2nd.cbegin(), suballocations2nd.cend(), refSuballoc, SuballocationOffsetLess()) :

-            BinaryFindSorted(suballocations2nd.cbegin(), suballocations2nd.cend(), refSuballoc, SuballocationOffsetGreater());

-        if (it != suballocations2nd.cend())

+        const SuballocationVectorType::const_iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?

+            BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetLess()) :

+            BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetGreater());

+        if (it != suballocations2nd.end())

         {

-            return *it;

+            return const_cast<Suballocation&>(*it);

         }

     }

 

     D3D12MA_ASSERT(0 && "Allocation not found in linear allocator!");

-    return *suballocations1st.crbegin(); // Should never occur.

+    return const_cast<Suballocation&>(suballocations1st.back()); // Should never occur.

 }

 

 bool BlockMetadata_Linear::ShouldCompact1st() const

@@ -4997,6 +5040,7 @@
     void AddStatistics(Statistics& inoutStats) const override;

     void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;

     void WriteAllocationInfoToJson(JsonWriter& json) const override;

+    void DebugLogAllAllocations() const override;

 

 private:

     // According to original paper it should be preferable 4 or 5:

@@ -5641,6 +5685,17 @@
     PrintDetailedMap_End(json);

 }

 

+void BlockMetadata_TLSF::DebugLogAllAllocations() const

+{

+    for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)

+    {

+        if (!block->IsFree())

+        {

+            DebugLogAllocation(block->offset, block->size, block->PrivateData());

+        }

+    }

+}

+

 UINT8 BlockMetadata_TLSF::SizeToMemoryClass(UINT64 size) const

 {

     if (size > SMALL_BUFFER_SIZE)

@@ -8130,6 +8185,10 @@
 {

     if (m_pMetadata != NULL)

     {

+        // Define macro VMA_DEBUG_LOG to receive the list of the unfreed allocations

+        if (!m_pMetadata->IsEmpty())

+            m_pMetadata->DebugLogAllAllocations();

+

         // THIS IS THE MOST IMPORTANT ASSERT IN THE ENTIRE LIBRARY!

         // Hitting it means you have some memory leak - unreleased Allocation objects.

         D3D12MA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");

diff --git a/src/D3D12Sample.cpp b/src/D3D12Sample.cpp
index ee4a877..31e2451 100644
--- a/src/D3D12Sample.cpp
+++ b/src/D3D12Sample.cpp
@@ -795,6 +795,7 @@
         IID_PPV_ARGS(&g_DepthStencilBuffer)

     ) );

     CHECK_HR( g_DepthStencilBuffer->SetName(L"Depth/Stencil Resource Heap") );

+    g_DepthStencilAllocation->SetName(L"Depth/Stencil Resource Heap");

 

     D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {};

     depthStencilDesc.Format = DEPTH_STENCIL_FORMAT;

@@ -917,6 +918,7 @@
             &g_ConstantBufferUploadAllocation[i],

             IID_PPV_ARGS(&g_ConstantBufferUploadHeap[i])) );

         g_ConstantBufferUploadHeap[i]->SetName(L"Constant Buffer Upload Resource Heap");

+        g_ConstantBufferUploadAllocation[i]->SetName(L"Constant Buffer Upload Resource Heap");

 

         D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};

         cbvDesc.BufferLocation = g_ConstantBufferUploadHeap[i]->GetGPUVirtualAddress();

@@ -1045,6 +1047,7 @@
 

     // we can give resource heaps a name so when we debug with the graphics debugger we know what resource we are looking at

     g_VertexBuffer->SetName(L"Vertex Buffer Resource Heap");

+    g_VertexBufferAllocation->SetName(L"Vertex Buffer Resource Heap");

 

     // create upload heap

     // upload heaps are used to upload data to the GPU. CPU can write to it, GPU can read from it

@@ -1073,6 +1076,7 @@
         &vBufferUploadHeapAllocation,

         IID_PPV_ARGS(&vBufferUploadHeap)) );

     vBufferUploadHeap->SetName(L"Vertex Buffer Upload Resource Heap");

+    vBufferUploadHeapAllocation->SetName(L"Vertex Buffer Upload Resource Heap");

 

     // store vertex buffer in upload heap

     D3D12_SUBRESOURCE_DATA vertexData = {};

@@ -1154,6 +1158,7 @@
 

     // we can give resource heaps a name so when we debug with the graphics debugger we know what resource we are looking at

     g_IndexBuffer->SetName(L"Index Buffer Resource Heap");

+    g_IndexBufferAllocation->SetName(L"Index Buffer Resource Heap");

 

     // create upload heap to upload index buffer

     D3D12MA::ALLOCATION_DESC iBufferUploadAllocDesc = {};

@@ -1180,6 +1185,7 @@
         &iBufferUploadHeapAllocation,

         IID_PPV_ARGS(&iBufferUploadHeap)) );

     CHECK_HR( iBufferUploadHeap->SetName(L"Index Buffer Upload Resource Heap") );

+    iBufferUploadHeapAllocation->SetName(L"Index Buffer Upload Resource Heap");

 

     // store vertex buffer in upload heap

     D3D12_SUBRESOURCE_DATA indexData = {};

@@ -1236,6 +1242,7 @@
             &g_CbPerObjectUploadHeapAllocations[i],

             IID_PPV_ARGS(&g_CbPerObjectUploadHeaps[i])) );

         g_CbPerObjectUploadHeaps[i]->SetName(L"Constant Buffer Upload Resource Heap");

+        g_CbPerObjectUploadHeapAllocations[i]->SetName(L"Constant Buffer Upload Resource Heap");

 

         CHECK_HR( g_CbPerObjectUploadHeaps[i]->Map(0, &EMPTY_RANGE, &g_CbPerObjectAddress[i]) );

     }

@@ -1298,6 +1305,7 @@
         &g_TextureAllocation,

         IID_PPV_ARGS(&g_Texture)) );

     g_Texture->SetName(L"g_Texture");

+    g_TextureAllocation->SetName(L"g_Texture");

 

     UINT64 textureUploadBufferSize;

     device->GetCopyableFootprints(

@@ -1334,6 +1342,7 @@
         &textureUploadAllocation,

         IID_PPV_ARGS(&textureUpload)) );

     textureUpload->SetName(L"textureUpload");

+    textureUploadAllocation->SetName(L"textureUpload");

 

     D3D12_SUBRESOURCE_DATA textureSubresourceData = {};

     textureSubresourceData.pData = imageData.data();