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 @@ especially to test compatibility with D3D12_RESOURCE_HEAP_TIER_1 on modern GPUs. #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 @@ class Vector 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 @@ public: 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 @@ public: 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 @@ BlockMetadata::BlockMetadata(const ALLOCATION_CALLBACKS* allocationCallbacks, bo 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(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 @@ public: 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 @@ void BlockMetadata_Linear::WriteAllocationInfoToJson(JsonWriter& json) const 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 @@ Suballocation& BlockMetadata_Linear::FindSuballocation(UINT64 offset) const // 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(*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(*it); } } D3D12MA_ASSERT(0 && "Allocation not found in linear allocator!"); - return *suballocations1st.crbegin(); // Should never occur. + return const_cast(suballocations1st.back()); // Should never occur. } bool BlockMetadata_Linear::ShouldCompact1st() const @@ -4997,6 +5040,7 @@ public: 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 @@ void BlockMetadata_TLSF::WriteAllocationInfoToJson(JsonWriter& json) const 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 @@ NormalBlock::~NormalBlock() { 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 @@ static void InitD3D() // initializes direct3d 12 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 @@ static void InitD3D() // initializes direct3d 12 &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 @@ static void InitD3D() // initializes direct3d 12 // 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 @@ static void InitD3D() // initializes direct3d 12 &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 @@ static void InitD3D() // initializes direct3d 12 // 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 @@ static void InitD3D() // initializes direct3d 12 &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 @@ static void InitD3D() // initializes direct3d 12 &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 @@ static void InitD3D() // initializes direct3d 12 &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 @@ static void InitD3D() // initializes direct3d 12 &textureUploadAllocation, IID_PPV_ARGS(&textureUpload)) ); textureUpload->SetName(L"textureUpload"); + textureUploadAllocation->SetName(L"textureUpload"); D3D12_SUBRESOURCE_DATA textureSubresourceData = {}; textureSubresourceData.pData = imageData.data();