Improved TestCustomHeaps
diff --git a/src/Tests.cpp b/src/Tests.cpp index b7db1be..27a9408 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp
@@ -1365,83 +1365,193 @@ CHECK_BOOL(detailedStats.UnusedRangeSizeMax == 0); } -static HRESULT TestCustomHeap(const TestContext& ctx, const D3D12_HEAP_PROPERTIES& heapProps) +static void CheckBudgetBasics(const TestContext& ctx, + const D3D12MA::Budget& localBudget, const D3D12MA::Budget& nonLocalBudget) { - D3D12MA::TotalStatistics globalStatsBeg = {}; - ctx.allocator->CalculateStatistics(&globalStatsBeg); + CHECK_BOOL(localBudget.BudgetBytes > 0); + CHECK_BOOL(localBudget.BudgetBytes <= ctx.allocator->GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL)); + CHECK_BOOL(localBudget.Stats.AllocationBytes <= localBudget.Stats.BlockBytes); - D3D12MA::CPOOL_DESC poolDesc = D3D12MA::CPOOL_DESC{ - heapProps, - D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS, - D3D12MA::POOL_FLAG_NONE, - 10 * MEGABYTE, // blockSize - 1, // minBlockCount - 1 }; // maxBlockCount - - const UINT64 BUFFER_SIZE = 1 * MEGABYTE; - - ComPtr<D3D12MA::Pool> pool; - HRESULT hr = ctx.allocator->CreatePool(&poolDesc, &pool); - if(SUCCEEDED(hr)) + // Discrete graphics card with separate video memory. + if (!ctx.allocator->IsUMA()) { - D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{ pool.Get() }; - - D3D12_RESOURCE_DESC resDesc; - FillResourceDescForBuffer(resDesc, BUFFER_SIZE); - - // Pool already allocated a block. We don't expect CreatePlacedResource to fail. - ComPtr<D3D12MA::Allocation> alloc; - CHECK_HR( ctx.allocator->CreateResource(&allocDesc, &resDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - NULL, // pOptimizedClearValue - &alloc, - __uuidof(ID3D12Resource), NULL) ); // riidResource, ppvResource - - D3D12MA::TotalStatistics globalStatsCurr = {}; - ctx.allocator->CalculateStatistics(&globalStatsCurr); - - // Make sure it is accounted only in CUSTOM heap not any of the standard heaps. - CHECK_BOOL(memcmp(&globalStatsCurr.HeapType[0], &globalStatsBeg.HeapType[0], sizeof(D3D12MA::DetailedStatistics)) == 0); - CHECK_BOOL(memcmp(&globalStatsCurr.HeapType[1], &globalStatsBeg.HeapType[1], sizeof(D3D12MA::DetailedStatistics)) == 0); - CHECK_BOOL(memcmp(&globalStatsCurr.HeapType[2], &globalStatsBeg.HeapType[2], sizeof(D3D12MA::DetailedStatistics)) == 0); - CHECK_BOOL( globalStatsCurr.HeapType[3].Stats.AllocationCount == globalStatsBeg.HeapType[3].Stats.AllocationCount + 1 ); - CHECK_BOOL( globalStatsCurr.HeapType[3].Stats.BlockCount == globalStatsBeg.HeapType[3].Stats.BlockCount + 1 ); - CHECK_BOOL( globalStatsCurr.HeapType[3].Stats.AllocationBytes == globalStatsBeg.HeapType[3].Stats.AllocationBytes + BUFFER_SIZE ); - CHECK_BOOL( globalStatsCurr.Total.Stats.AllocationCount == globalStatsBeg.Total.Stats.AllocationCount + 1 ); - CHECK_BOOL( globalStatsCurr.Total.Stats.BlockCount == globalStatsBeg.Total.Stats.BlockCount + 1 ); - CHECK_BOOL( globalStatsCurr.Total.Stats.AllocationBytes == globalStatsBeg.Total.Stats.AllocationBytes + BUFFER_SIZE ); - - // Map and write some data. - if(heapProps.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE || - heapProps.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_BACK) - { - ID3D12Resource* const res = alloc->GetResource(); - - UINT* mappedPtr = nullptr; - const D3D12_RANGE readRange = {0, 0}; - CHECK_HR(res->Map(0, &readRange, (void**)&mappedPtr)); - - *mappedPtr = 0xDEADC0DE; - - res->Unmap(0, nullptr); - } + CHECK_BOOL(nonLocalBudget.BudgetBytes > 0); + CHECK_BOOL(nonLocalBudget.BudgetBytes <= ctx.allocator->GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)); + CHECK_BOOL(nonLocalBudget.Stats.AllocationBytes <= nonLocalBudget.Stats.BlockBytes); } +} - return hr; +static D3D12MA::DetailedStatistics GetEmptyDetailedStatistics() +{ + D3D12MA::DetailedStatistics out = {}; + out.AllocationSizeMin = UINT64_MAX; + out.UnusedRangeSizeMin = UINT64_MAX; + return out; +} + +static void AddDetailedStatistics(D3D12MA::DetailedStatistics& inoutSum, const D3D12MA::DetailedStatistics& stats) +{ + inoutSum.Stats.AllocationBytes += stats.Stats.AllocationBytes; + inoutSum.Stats.AllocationCount += stats.Stats.AllocationCount; + inoutSum.Stats.BlockBytes += stats.Stats.BlockBytes; + inoutSum.Stats.BlockCount += stats.Stats.BlockCount; + inoutSum.UnusedRangeCount += stats.UnusedRangeCount; + inoutSum.AllocationSizeMax = std::max(inoutSum.AllocationSizeMax, stats.AllocationSizeMax); + inoutSum.AllocationSizeMin = std::min(inoutSum.AllocationSizeMin, stats.AllocationSizeMin); + inoutSum.UnusedRangeSizeMax = std::max(inoutSum.UnusedRangeSizeMax, stats.UnusedRangeSizeMax); + inoutSum.UnusedRangeSizeMin = std::min(inoutSum.UnusedRangeSizeMin, stats.UnusedRangeSizeMin); +} + +static inline bool StatisticsEqual(const D3D12MA::DetailedStatistics& lhs, const D3D12MA::DetailedStatistics& rhs) +{ + return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; +} + +static inline bool StatisticsEqual(const D3D12MA::Statistics& lhs, const D3D12MA::Statistics& rhs) +{ + return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; +} + +static void CheckStatistics(const D3D12MA::DetailedStatistics& stats) +{ + CHECK_BOOL(stats.Stats.AllocationBytes <= stats.Stats.BlockBytes); + if (stats.Stats.AllocationBytes > 0) + { + CHECK_BOOL(stats.Stats.AllocationCount > 0); + CHECK_BOOL(stats.AllocationSizeMin <= stats.AllocationSizeMax); + } + if (stats.UnusedRangeCount > 0) + { + CHECK_BOOL(stats.UnusedRangeSizeMax > 0); + CHECK_BOOL(stats.UnusedRangeSizeMin <= stats.UnusedRangeSizeMax); + } +} + +static void CheckTotalStatistics(const D3D12MA::TotalStatistics& stats) +{ + D3D12MA::DetailedStatistics sum = GetEmptyDetailedStatistics(); + for (size_t i = 0; i < _countof(stats.HeapType); ++i) + { + AddDetailedStatistics(sum, stats.HeapType[i]); + } + CHECK_BOOL(StatisticsEqual(sum, stats.Total)); + + sum = GetEmptyDetailedStatistics(); + for (size_t i = 0; i < _countof(stats.MemorySegmentGroup); ++i) + { + AddDetailedStatistics(sum, stats.MemorySegmentGroup[i]); + } + CHECK_BOOL(StatisticsEqual(sum, stats.Total)); } static void TestCustomHeaps(const TestContext& ctx) { + using namespace D3D12MA; + wprintf(L"Test custom heap\n"); - D3D12_HEAP_PROPERTIES heapProps = {}; - // Use custom pool but the same as READBACK, which should be always available. + D3D12_HEAP_PROPERTIES heapProps = {}; heapProps.Type = D3D12_HEAP_TYPE_CUSTOM; heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK; heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_L0; // System memory - HRESULT hr = TestCustomHeap(ctx, heapProps); - CHECK_HR(hr); + + const UINT64 BUFFER_SIZE = 1 * MEGABYTE; + D3D12_RESOURCE_DESC resDesc; + FillResourceDescForBuffer(resDesc, BUFFER_SIZE); + + Budget localBudgetBeg = {}, nonLocalBudgetBeg = {}; + ctx.allocator->GetBudget(&localBudgetBeg, &nonLocalBudgetBeg); + CheckBudgetBasics(ctx, localBudgetBeg, nonLocalBudgetBeg); + + TotalStatistics globalStatsBeg = {}; + ctx.allocator->CalculateStatistics(&globalStatsBeg); + CheckTotalStatistics(globalStatsBeg); + + // Test 0: Custom pool with fixed block size (it must end up as placed). + // Test 1: Custom pool, requested committed. + + for (size_t testIndex = 0; testIndex < 2; ++testIndex) + { + const bool requestCommitted = testIndex == 1; + + POOL_DESC poolDesc = CPOOL_DESC{ heapProps, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS }; + if (testIndex == 0) + { + poolDesc.BlockSize = 10 * MEGABYTE; + poolDesc.MinBlockCount = 1; + poolDesc.MaxBlockCount = 1; + } + ComPtr<Pool> pool; + CHECK_HR(ctx.allocator->CreatePool(&poolDesc, &pool)); + + ALLOCATION_DESC allocDesc = CALLOCATION_DESC{ pool.Get() }; + if (requestCommitted) + { + allocDesc.Flags = ALLOCATION_FLAG_COMMITTED; + } + + ComPtr<Allocation> alloc; + CHECK_HR(ctx.allocator->CreateResource(&allocDesc, &resDesc, + D3D12_RESOURCE_STATE_COMMON, NULL, &alloc, IID_NULL, NULL)); + + const bool isCommitted = alloc->GetHeap() == NULL; + CHECK_BOOL(isCommitted == requestCommitted); + + Budget localBudgetEnd = {}, nonLocalBudgetEnd = {}; + ctx.allocator->GetBudget(&localBudgetEnd, &nonLocalBudgetEnd); + CheckBudgetBasics(ctx, localBudgetEnd, nonLocalBudgetEnd); + + D3D12MA::TotalStatistics globalStatsEnd = {}; + ctx.allocator->CalculateStatistics(&globalStatsEnd); + CheckTotalStatistics(globalStatsEnd); + + // Make sure it is accounted only in CUSTOM heap not any of the standard heaps. + + const UINT thisMemSegmentGroupIndex = ctx.allocator->IsUMA() ? 0 : 1; + const UINT otherMemSegmentGroupIndex = 1 - thisMemSegmentGroupIndex; + + CHECK_BOOL(globalStatsEnd.Total.Stats.AllocationCount == globalStatsBeg.Total.Stats.AllocationCount + 1); + CHECK_BOOL(globalStatsEnd.Total.Stats.BlockCount == globalStatsBeg.Total.Stats.BlockCount + 1); + CHECK_BOOL(globalStatsEnd.Total.Stats.AllocationBytes == globalStatsBeg.Total.Stats.AllocationBytes + BUFFER_SIZE); + + CHECK_BOOL(memcmp(&globalStatsEnd.HeapType[0], &globalStatsBeg.HeapType[0], sizeof(D3D12MA::DetailedStatistics)) == 0); + CHECK_BOOL(memcmp(&globalStatsEnd.HeapType[1], &globalStatsBeg.HeapType[1], sizeof(D3D12MA::DetailedStatistics)) == 0); + CHECK_BOOL(memcmp(&globalStatsEnd.HeapType[2], &globalStatsBeg.HeapType[2], sizeof(D3D12MA::DetailedStatistics)) == 0); + CHECK_BOOL(memcmp(&globalStatsEnd.HeapType[4], &globalStatsBeg.HeapType[4], sizeof(D3D12MA::DetailedStatistics)) == 0); + + CHECK_BOOL(globalStatsEnd.HeapType[3].Stats.AllocationCount == globalStatsBeg.HeapType[3].Stats.AllocationCount + 1); + CHECK_BOOL(globalStatsEnd.HeapType[3].Stats.BlockCount == globalStatsBeg.HeapType[3].Stats.BlockCount + 1); + CHECK_BOOL(globalStatsEnd.HeapType[3].Stats.AllocationBytes == globalStatsBeg.HeapType[3].Stats.AllocationBytes + BUFFER_SIZE); + + CHECK_BOOL(globalStatsEnd.MemorySegmentGroup[thisMemSegmentGroupIndex].Stats.AllocationCount == + globalStatsBeg.MemorySegmentGroup[thisMemSegmentGroupIndex].Stats.AllocationCount + 1); + CHECK_BOOL(globalStatsEnd.MemorySegmentGroup[thisMemSegmentGroupIndex].Stats.BlockCount == + globalStatsBeg.MemorySegmentGroup[thisMemSegmentGroupIndex].Stats.BlockCount + 1); + CHECK_BOOL(globalStatsEnd.MemorySegmentGroup[thisMemSegmentGroupIndex].Stats.AllocationBytes == + globalStatsBeg.MemorySegmentGroup[thisMemSegmentGroupIndex].Stats.AllocationBytes + BUFFER_SIZE); + + CHECK_BOOL(memcmp(&globalStatsEnd.MemorySegmentGroup[otherMemSegmentGroupIndex], + &globalStatsBeg.MemorySegmentGroup[otherMemSegmentGroupIndex], sizeof(D3D12MA::DetailedStatistics)) == 0); + + const Budget& thisBudgetBeg = ctx.allocator->IsUMA() ? localBudgetBeg : nonLocalBudgetBeg; + const Budget& thisBudgetEnd = ctx.allocator->IsUMA() ? localBudgetEnd : nonLocalBudgetEnd; + + CHECK_BOOL(thisBudgetEnd.Stats.AllocationCount == thisBudgetBeg.Stats.AllocationCount + 1); + CHECK_BOOL(thisBudgetEnd.Stats.BlockCount == thisBudgetBeg.Stats.BlockCount + 1); + CHECK_BOOL(thisBudgetEnd.Stats.AllocationBytes == thisBudgetBeg.Stats.AllocationBytes + BUFFER_SIZE); + + // Map and write some data. + if (heapProps.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE || + heapProps.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_BACK) + { + ID3D12Resource* const res = alloc->GetResource(); + UINT* mappedPtr = nullptr; + CHECK_HR(res->Map(0, &EMPTY_RANGE, (void**)&mappedPtr)); + *mappedPtr = 0xDEADC0DE; + res->Unmap(0, nullptr); + } + } } static void TestStandardCustomCommittedPlaced(const TestContext& ctx) @@ -1694,85 +1804,6 @@ } } -static inline bool StatisticsEqual(const D3D12MA::DetailedStatistics& lhs, const D3D12MA::DetailedStatistics& rhs) -{ - return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; -} - -static inline bool StatisticsEqual(const D3D12MA::Statistics& lhs, const D3D12MA::Statistics& rhs) -{ - return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; -} - -static void CheckStatistics(const D3D12MA::DetailedStatistics& stats) -{ - CHECK_BOOL(stats.Stats.AllocationBytes <= stats.Stats.BlockBytes); - if(stats.Stats.AllocationBytes > 0) - { - CHECK_BOOL(stats.Stats.AllocationCount > 0); - CHECK_BOOL(stats.AllocationSizeMin <= stats.AllocationSizeMax); - } - if(stats.UnusedRangeCount > 0) - { - CHECK_BOOL(stats.UnusedRangeSizeMax > 0); - CHECK_BOOL(stats.UnusedRangeSizeMin <= stats.UnusedRangeSizeMax); - } -} - -static void CheckBudgetBasics(const TestContext& ctx, - const D3D12MA::Budget& localBudget, const D3D12MA::Budget& nonLocalBudget) -{ - CHECK_BOOL(localBudget.BudgetBytes > 0); - CHECK_BOOL(localBudget.BudgetBytes <= ctx.allocator->GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL)); - CHECK_BOOL(localBudget.Stats.AllocationBytes <= localBudget.Stats.BlockBytes); - - // Discrete graphics card with separate video memory. - if (!ctx.allocator->IsUMA()) - { - CHECK_BOOL(nonLocalBudget.BudgetBytes > 0); - CHECK_BOOL(nonLocalBudget.BudgetBytes <= ctx.allocator->GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)); - CHECK_BOOL(nonLocalBudget.Stats.AllocationBytes <= nonLocalBudget.Stats.BlockBytes); - } -} - -static D3D12MA::DetailedStatistics GetEmptyDetailedStatistics() -{ - D3D12MA::DetailedStatistics out = {}; - out.AllocationSizeMin = UINT64_MAX; - out.UnusedRangeSizeMin = UINT64_MAX; - return out; -} - -static void AddDetailedStatistics(D3D12MA::DetailedStatistics& inoutSum, const D3D12MA::DetailedStatistics& stats) -{ - inoutSum.Stats.AllocationBytes += stats.Stats.AllocationBytes; - inoutSum.Stats.AllocationCount += stats.Stats.AllocationCount; - inoutSum.Stats.BlockBytes += stats.Stats.BlockBytes; - inoutSum.Stats.BlockCount += stats.Stats.BlockCount; - inoutSum.UnusedRangeCount += stats.UnusedRangeCount; - inoutSum.AllocationSizeMax = std::max(inoutSum.AllocationSizeMax, stats.AllocationSizeMax); - inoutSum.AllocationSizeMin = std::min(inoutSum.AllocationSizeMin, stats.AllocationSizeMin); - inoutSum.UnusedRangeSizeMax = std::max(inoutSum.UnusedRangeSizeMax, stats.UnusedRangeSizeMax); - inoutSum.UnusedRangeSizeMin = std::min(inoutSum.UnusedRangeSizeMin, stats.UnusedRangeSizeMin); -} - -static void CheckTotalStatistics(const D3D12MA::TotalStatistics& stats) -{ - D3D12MA::DetailedStatistics sum = GetEmptyDetailedStatistics(); - for (size_t i = 0; i < _countof(stats.HeapType); ++i) - { - AddDetailedStatistics(sum, stats.HeapType[i]); - } - CHECK_BOOL(StatisticsEqual(sum, stats.Total)); - - sum = GetEmptyDetailedStatistics(); - for (size_t i = 0; i < _countof(stats.MemorySegmentGroup); ++i) - { - AddDetailedStatistics(sum, stats.MemorySegmentGroup[i]); - } - CHECK_BOOL(StatisticsEqual(sum, stats.Total)); -} - static void TestStats(const TestContext& ctx) { using namespace D3D12MA;