From 07cf40a2b8d7f533aece51dc3d0d2a76fc87b888 Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Thu, 2 Apr 2020 17:34:33 +0200 Subject: [PATCH] Add missing reporting from custom pools in Allocator::CalculateStats --- src/D3D12MemAlloc.cpp | 81 ++++++++++++++++++++++++++++++++++++++----- src/Tests.cpp | 50 +++++++++++++++++--------- 2 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/D3D12MemAlloc.cpp b/src/D3D12MemAlloc.cpp index d215a4d..5613a8c 100644 --- a/src/D3D12MemAlloc.cpp +++ b/src/D3D12MemAlloc.cpp @@ -2510,6 +2510,7 @@ public: private: friend class Allocator; + friend class Pool; /* Heuristics that decides whether a resource should better be placed in its own, @@ -2535,6 +2536,10 @@ private: AllocationVectorType* m_pCommittedAllocations[HEAP_TYPE_COUNT]; D3D12MA_RW_MUTEX m_CommittedAllocationsMutex[HEAP_TYPE_COUNT]; + typedef Vector PoolVectorType; + PoolVectorType* m_pPools[HEAP_TYPE_COUNT]; + D3D12MA_RW_MUTEX m_PoolsMutex[HEAP_TYPE_COUNT]; + // Default pools. BlockVector* m_BlockVectors[DEFAULT_POOL_MAX_COUNT]; @@ -2584,6 +2589,11 @@ private: // Unregisters Allocation object from m_pCommittedAllocations. void UnregisterCommittedAllocation(Allocation* alloc, D3D12_HEAP_TYPE heapType); + // Registers Pool object in m_pPools. + void RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType); + // Unregisters Pool object from m_pPools. + void UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType); + HRESULT UpdateD3D12Budget(); D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo(D3D12_RESOURCE_DESC& inOutResourceDesc) const; @@ -3812,6 +3822,8 @@ Pool::Pool(Allocator* allocator, const POOL_DESC &desc) : Pool::~Pool() { + m_Pimpl->GetAllocator()->UnregisterPool(this, m_Pimpl->GetDesc().HeapType); + D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), m_Pimpl); } @@ -3836,11 +3848,13 @@ AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, ZeroMemory(&m_D3D12Options, sizeof(m_D3D12Options)); ZeroMemory(m_pCommittedAllocations, sizeof(m_pCommittedAllocations)); + ZeroMemory(m_pPools, sizeof(m_pPools)); ZeroMemory(m_BlockVectors, sizeof(m_BlockVectors)); for(UINT heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex) { m_pCommittedAllocations[heapTypeIndex] = D3D12MA_NEW(GetAllocs(), AllocationVectorType)(GetAllocs()); + m_pPools[heapTypeIndex] = D3D12MA_NEW(GetAllocs(), PoolVectorType)(GetAllocs()); } m_Device->AddRef(); @@ -3906,6 +3920,16 @@ AllocatorPimpl::~AllocatorPimpl() D3D12MA_DELETE(GetAllocs(), m_BlockVectors[i]); } + for(UINT i = HEAP_TYPE_COUNT; i--; ) + { + if(m_pPools[i] && !m_pPools[i]->empty()) + { + D3D12MA_ASSERT(0 && "Unfreed pools found!"); + } + + D3D12MA_DELETE(GetAllocs(), m_pPools[i]); + } + for(UINT i = HEAP_TYPE_COUNT; i--; ) { if(m_pCommittedAllocations[i] && !m_pCommittedAllocations[i]->empty()) @@ -4447,6 +4471,27 @@ void AllocatorPimpl::UnregisterCommittedAllocation(Allocation* alloc, D3D12_HEAP D3D12MA_ASSERT(success); } +void AllocatorPimpl::RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType) +{ + const UINT heapTypeIndex = HeapTypeToIndex(heapType); + + MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex); + PoolVectorType* const pools = m_pPools[heapTypeIndex]; + D3D12MA_ASSERT(pools); + pools->InsertSorted(pool, PointerLess()); +} + +void AllocatorPimpl::UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType) +{ + const UINT heapTypeIndex = HeapTypeToIndex(heapType); + + MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex); + PoolVectorType* const pools = m_pPools[heapTypeIndex]; + D3D12MA_ASSERT(pools); + bool success = pools->RemoveSorted(pool, PointerLess()); + D3D12MA_ASSERT(success); +} + void AllocatorPimpl::FreeCommittedMemory(Allocation* allocation) { D3D12MA_ASSERT(allocation && allocation->m_PackedData.GetType() == Allocation::TYPE_COMMITTED); @@ -4514,16 +4559,30 @@ void AllocatorPimpl::CalculateStats(Stats& outStats) pBlockVector->AddStats(outStats); } - // Process committed allocations. - for(size_t i = 0; i < HEAP_TYPE_COUNT; ++i) + // Process custom pools + for(size_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex) { - StatInfo& heapStatInfo = outStats.HeapType[i]; - MutexLockRead lock(m_CommittedAllocationsMutex[i], m_UseMutex); - const AllocationVectorType* const allocationVector = m_pCommittedAllocations[i]; - D3D12MA_ASSERT(allocationVector); - for(size_t j = 0, count = allocationVector->size(); j < count; ++j) + StatInfo& heapStatInfo = outStats.HeapType[heapTypeIndex]; + MutexLockRead lock(m_PoolsMutex[heapTypeIndex], m_UseMutex); + const PoolVectorType* const poolVector = m_pPools[heapTypeIndex]; + D3D12MA_ASSERT(poolVector); + for(size_t poolIndex = 0, count = poolVector->size(); poolIndex < count; ++poolIndex) { - UINT64 size = (*allocationVector)[j]->GetSize(); + Pool* pool = (*poolVector)[poolIndex]; + pool->m_Pimpl->GetBlockVector()->AddStats(outStats); + } + } + + // Process committed allocations. + for(size_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex) + { + StatInfo& heapStatInfo = outStats.HeapType[heapTypeIndex]; + MutexLockRead lock(m_CommittedAllocationsMutex[heapTypeIndex], m_UseMutex); + const AllocationVectorType* const allocationVector = m_pCommittedAllocations[heapTypeIndex]; + D3D12MA_ASSERT(allocationVector); + for(size_t allocIndex = 0, count = allocationVector->size(); allocIndex < count; ++allocIndex) + { + UINT64 size = (*allocationVector)[allocIndex]->GetSize(); StatInfo statInfo = {}; statInfo.BlockCount = 1; statInfo.AllocationCount = 1; @@ -5175,7 +5234,11 @@ HRESULT Allocator::CreatePool( D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK *ppPool = D3D12MA_NEW(m_Pimpl->GetAllocs(), Pool)(this, *pPoolDesc); HRESULT hr = (*ppPool)->m_Pimpl->Init(); - if(FAILED(hr)) + if(SUCCEEDED(hr)) + { + m_Pimpl->RegisterPool(*ppPool, pPoolDesc->HeapType); + } + else { D3D12MA_DELETE(m_Pimpl->GetAllocs(), *ppPool); *ppPool = NULL; diff --git a/src/Tests.cpp b/src/Tests.cpp index 9a23bac..8b3b504 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp @@ -407,6 +407,11 @@ static void TestCustomPools(const TestContext& ctx) { wprintf(L"Test custom pools\n"); + // # Fetch global stats 1 + + D3D12MA::Stats globalStatsBeg = {}; + ctx.allocator->CalculateStats(&globalStatsBeg); + // # Create pool, 1..2 blocks of 11 MB D3D12MA::POOL_DESC poolDesc = {}; @@ -422,12 +427,14 @@ static void TestCustomPools(const TestContext& ctx) D3D12MA::Allocation* allocPtr; - D3D12MA::StatInfo stats = {}; - pool->CalculateStats(&stats); - CHECK_BOOL( stats.BlockCount == 1 ); - CHECK_BOOL( stats.AllocationCount == 0 ); - CHECK_BOOL( stats.UsedBytes == 0 ); - CHECK_BOOL( stats.UnusedBytes == poolDesc.BlockSize ); + // # Validate stats for empty pool + + D3D12MA::StatInfo poolStats = {}; + pool->CalculateStats(&poolStats); + CHECK_BOOL( poolStats.BlockCount == 1 ); + CHECK_BOOL( poolStats.AllocationCount == 0 ); + CHECK_BOOL( poolStats.UsedBytes == 0 ); + CHECK_BOOL( poolStats.UnusedBytes == poolDesc.BlockSize ); // # Create buffers 2x 5 MB @@ -451,11 +458,22 @@ static void TestCustomPools(const TestContext& ctx) allocs[i].reset(allocPtr); } - pool->CalculateStats(&stats); - CHECK_BOOL( stats.BlockCount == 1 ); - CHECK_BOOL( stats.AllocationCount == 2 ); - CHECK_BOOL( stats.UsedBytes == 2 * BUFFER_SIZE ); - CHECK_BOOL( stats.UnusedBytes == poolDesc.BlockSize - stats.UsedBytes ); + // # Validate pool stats now + + pool->CalculateStats(&poolStats); + CHECK_BOOL( poolStats.BlockCount == 1 ); + CHECK_BOOL( poolStats.AllocationCount == 2 ); + CHECK_BOOL( poolStats.UsedBytes == 2 * BUFFER_SIZE ); + CHECK_BOOL( poolStats.UnusedBytes == poolDesc.BlockSize - poolStats.UsedBytes ); + + // # Check that global stats are updated as well + + D3D12MA::Stats globalStatsCurr = {}; + ctx.allocator->CalculateStats(&globalStatsCurr); + + CHECK_BOOL( globalStatsCurr.Total.AllocationCount == globalStatsBeg.Total.AllocationCount + poolStats.AllocationCount ); + CHECK_BOOL( globalStatsCurr.Total.BlockCount == globalStatsBeg.Total.BlockCount + poolStats.BlockCount ); + CHECK_BOOL( globalStatsCurr.Total.UsedBytes == globalStatsBeg.Total.UsedBytes + poolStats.UsedBytes ); // # NEVER_ALLOCATE and COMMITTED should fail @@ -493,11 +511,11 @@ static void TestCustomPools(const TestContext& ctx) } } - pool->CalculateStats(&stats); - CHECK_BOOL( stats.BlockCount == 2 ); - CHECK_BOOL( stats.AllocationCount == 4 ); - CHECK_BOOL( stats.UsedBytes == 4 * BUFFER_SIZE ); - CHECK_BOOL( stats.UnusedBytes == stats.BlockCount * poolDesc.BlockSize - stats.UsedBytes ); + pool->CalculateStats(&poolStats); + CHECK_BOOL( poolStats.BlockCount == 2 ); + CHECK_BOOL( poolStats.AllocationCount == 4 ); + CHECK_BOOL( poolStats.UsedBytes == 4 * BUFFER_SIZE ); + CHECK_BOOL( poolStats.UnusedBytes == poolStats.BlockCount * poolDesc.BlockSize - poolStats.UsedBytes ); // # Make room, AllocateMemory, CreateAliasingResource