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