From f61c644e6aa4ddfa5753f94049613a5f116a0cff Mon Sep 17 00:00:00 2001 From: Bryan Bernhart Date: Thu, 15 Sep 2022 10:01:41 -0700 Subject: [PATCH] Add ALLOCATION_FLAG_NEVER_FALLBACK for to ensure allocation method is being tested. --- src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp | 8 +- src/gpgmm/d3d12/ResourceAllocatorD3D12.h | 10 +++ src/include/min/gpgmm_d3d12.h | 1 + src/tests/GPGMMTest.cpp | 22 ++--- .../end2end/D3D12ResourceAllocatorTests.cpp | 81 +++++++++++++++---- 5 files changed, 96 insertions(+), 26 deletions(-) diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp index d1b21f6d8..a00ad3dbc 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp @@ -879,8 +879,11 @@ namespace gpgmm::d3d12 { return E_INVALIDARG; } - // Check memory requirements. + // Resource is always committed when heaps flags are incompatible with the resource heap + // type or if specified by the flag. bool isAlwaysCommitted = mIsAlwaysCommitted; + + // Check memory requirements. D3D12_HEAP_FLAGS heapFlags = GetHeapFlags(resourceHeapType, IsCreateHeapNotResident()); if (!HasAllFlags(heapFlags, allocationDescriptor.ExtraRequiredHeapFlags)) { DebugEvent(GetTypename()) @@ -1107,6 +1110,9 @@ namespace gpgmm::d3d12 { } if (!isAlwaysCommitted) { + if (allocationDescriptor.Flags & ALLOCATION_FLAG_NEVER_FALLBACK) { + return E_FAIL; + } InfoEvent(GetTypename(), EventMessageId::AllocatorFailed) << "Unable to allocate by using a heap, falling back to a committed resource."; } diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.h b/src/gpgmm/d3d12/ResourceAllocatorD3D12.h index 474231e39..89d871765 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.h +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.h @@ -363,6 +363,16 @@ namespace gpgmm::d3d12 { D3D12_HEAP_TYPE_READBACK, or the adapter is not cache-coherent UMA, this flag has no effect. */ ALLOCATION_FLAG_ALWAYS_ATTRIBUTE_HEAPS = 0x20, + + /** \brief Forces the allocator allocation algorithm to be used or E_FAIL. + + By default, the allocation method used may not be used due to incompatible constraints. This + flag will disable the default fall-back behavior of using the safest allocation method + possible. + + Mostly used for debug and testing when certain allocation methods unexpectedly fail. + */ + ALLOCATION_FLAG_NEVER_FALLBACK = 0x40, }; DEFINE_ENUM_FLAG_OPERATORS(ALLOCATION_FLAGS) diff --git a/src/include/min/gpgmm_d3d12.h b/src/include/min/gpgmm_d3d12.h index 6a88ef404..58f17d37b 100644 --- a/src/include/min/gpgmm_d3d12.h +++ b/src/include/min/gpgmm_d3d12.h @@ -271,6 +271,7 @@ namespace gpgmm::d3d12 { ALLOCATION_FLAG_ALWAYS_PREFETCH_MEMORY = 0x8, ALLOCATION_FLAG_ALWAYS_CACHE_SIZE = 0x10, ALLOCATION_FLAG_ALWAYS_ATTRIBUTE_HEAPS = 0x20, + ALLOCATION_FLAG_NEVER_FALLBACK = 0x40, }; DEFINE_ENUM_FLAG_OPERATORS(ALLOCATION_FLAGS) diff --git a/src/tests/GPGMMTest.cpp b/src/tests/GPGMMTest.cpp index 658136781..81fbd3e31 100644 --- a/src/tests/GPGMMTest.cpp +++ b/src/tests/GPGMMTest.cpp @@ -14,6 +14,8 @@ #include "tests/GPGMMTest.h" +#include "gpgmm/common/SizeClass.h" + #include static GPGMMTestEnvironment* gTestEnv = nullptr; @@ -61,20 +63,20 @@ std::vector GPGMMTestBase::GenerateTestAllocations(uin // Common small sizes, likely sub-allocated. {256, alignment, true}, - {1 * 1024, alignment, true}, - {4 * 1024, alignment, true}, + {GPGMM_KB_TO_BYTES(1), alignment, true}, + {GPGMM_KB_TO_BYTES(4), alignment, true}, // Common large sizes, likely standalone. - {16 * 1024 * 1024, 0, true}, - {64 * 1024 * 1024, 0, true}, + {GPGMM_MB_TO_BYTES(16), 0, true}, + {GPGMM_MB_TO_BYTES(64), 0, true}, // Mixed sizes, any method. - {1 * 1024, 1, true}, - {64 * 1024 * 1024, 0, true}, - {1 * 1024, 1, true}, - {64 * 1024 * 1024, 0, true}, - {1 * 1024, 1, true}, - {64 * 1024 * 1024, 0, true}, + {GPGMM_KB_TO_BYTES(1), 1, true}, + {GPGMM_MB_TO_BYTES(64), 0, true}, + {GPGMM_KB_TO_BYTES(1), 1, true}, + {GPGMM_MB_TO_BYTES(64), 0, true}, + {GPGMM_KB_TO_BYTES(1), 1, true}, + {GPGMM_MB_TO_BYTES(64), 0, true}, // Increasing sizes, any method. {alignment * 1, 0, true}, diff --git a/src/tests/end2end/D3D12ResourceAllocatorTests.cpp b/src/tests/end2end/D3D12ResourceAllocatorTests.cpp index 8c2aa6e27..a1f2d02c3 100644 --- a/src/tests/end2end/D3D12ResourceAllocatorTests.cpp +++ b/src/tests/end2end/D3D12ResourceAllocatorTests.cpp @@ -156,17 +156,40 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferOversized) { TEST_F(D3D12ResourceAllocatorTests, CreateBufferSubAllocated) { ALLOCATOR_DESC allocatorDesc = CreateBasicAllocatorDesc(); - // ALLOCATOR_ALGORITHM_SLAB + // Ensure the underlying memory size is large enough so all buffer allocation can fit. + allocatorDesc.PreferredResourceHeapSize = GPGMM_MB_TO_BYTES(64); + + // Ensure the allocation will never fall-back to use any method other than the one being tested. + ALLOCATION_DESC allocationDesc = {}; + allocationDesc.Flags = ALLOCATION_FLAG_NEVER_FALLBACK; + + // ALLOCATOR_ALGORITHM_BUDDY_SYSTEM { ALLOCATOR_DESC newAllocatorDesc = allocatorDesc; - newAllocatorDesc.SubAllocationAlgorithm = ALLOCATOR_ALGORITHM_SLAB; + newAllocatorDesc.SubAllocationAlgorithm = ALLOCATOR_ALGORITHM_BUDDY_SYSTEM; ComPtr resourceAllocator; ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(newAllocatorDesc, &resourceAllocator)); ASSERT_NE(resourceAllocator, nullptr); - ALLOCATION_DESC allocationDesc = {}; - allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + for (auto& alloc : GenerateBufferAllocations()) { + ComPtr allocation; + EXPECT_EQ(SUCCEEDED(resourceAllocator->CreateResource( + allocationDesc, CreateBasicBufferDesc(alloc.size, alloc.alignment), + D3D12_RESOURCE_STATE_COMMON, nullptr, &allocation)), + alloc.succeeds); + } + } + + // ALLOCATOR_ALGORITHM_BUDDY_SYSTEM + ALLOCATOR_ALGORITHM_FIXED_POOL + { + ALLOCATOR_DESC newAllocatorDesc = allocatorDesc; + newAllocatorDesc.SubAllocationAlgorithm = ALLOCATOR_ALGORITHM_BUDDY_SYSTEM; + newAllocatorDesc.PoolAlgorithm = ALLOCATOR_ALGORITHM_FIXED_POOL; + + ComPtr resourceAllocator; + ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(newAllocatorDesc, &resourceAllocator)); + ASSERT_NE(resourceAllocator, nullptr); for (auto& alloc : GenerateBufferAllocations()) { ComPtr allocation; @@ -177,17 +200,33 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferSubAllocated) { } } - // ALLOCATOR_ALGORITHM_BUDDY_SYSTEM + // ALLOCATOR_ALGORITHM_BUDDY_SYSTEM + ALLOCATOR_ALGORITHM_SEGMENTED_POOL { ALLOCATOR_DESC newAllocatorDesc = allocatorDesc; newAllocatorDesc.SubAllocationAlgorithm = ALLOCATOR_ALGORITHM_BUDDY_SYSTEM; + newAllocatorDesc.PoolAlgorithm = ALLOCATOR_ALGORITHM_SEGMENTED_POOL; ComPtr resourceAllocator; ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(newAllocatorDesc, &resourceAllocator)); ASSERT_NE(resourceAllocator, nullptr); - ALLOCATION_DESC allocationDesc = {}; - allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + for (auto& alloc : GenerateBufferAllocations()) { + ComPtr allocation; + EXPECT_EQ(SUCCEEDED(resourceAllocator->CreateResource( + allocationDesc, CreateBasicBufferDesc(alloc.size, alloc.alignment), + D3D12_RESOURCE_STATE_COMMON, nullptr, &allocation)), + alloc.succeeds); + } + } + + // ALLOCATOR_ALGORITHM_SLAB + { + ALLOCATOR_DESC newAllocatorDesc = allocatorDesc; + newAllocatorDesc.SubAllocationAlgorithm = ALLOCATOR_ALGORITHM_SLAB; + + ComPtr resourceAllocator; + ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(newAllocatorDesc, &resourceAllocator)); + ASSERT_NE(resourceAllocator, nullptr); for (auto& alloc : GenerateBufferAllocations()) { ComPtr allocation; @@ -208,8 +247,24 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferSubAllocated) { ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(newAllocatorDesc, &resourceAllocator)); ASSERT_NE(resourceAllocator, nullptr); - ALLOCATION_DESC allocationDesc = {}; - allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + for (auto& alloc : GenerateBufferAllocations()) { + ComPtr allocation; + EXPECT_EQ(SUCCEEDED(resourceAllocator->CreateResource( + allocationDesc, CreateBasicBufferDesc(alloc.size, alloc.alignment), + D3D12_RESOURCE_STATE_COMMON, nullptr, &allocation)), + alloc.succeeds); + } + } + + // ALLOCATOR_ALGORITHM_SLAB + ALLOCATOR_ALGORITHM_SEGMENTED_POOL + { + ALLOCATOR_DESC newAllocatorDesc = allocatorDesc; + newAllocatorDesc.SubAllocationAlgorithm = ALLOCATOR_ALGORITHM_SLAB; + newAllocatorDesc.PoolAlgorithm = ALLOCATOR_ALGORITHM_SEGMENTED_POOL; + + ComPtr resourceAllocator; + ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(newAllocatorDesc, &resourceAllocator)); + ASSERT_NE(resourceAllocator, nullptr); for (auto& alloc : GenerateBufferAllocations()) { ComPtr allocation; @@ -229,9 +284,6 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferSubAllocated) { ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(newAllocatorDesc, &resourceAllocator)); ASSERT_NE(resourceAllocator, nullptr); - ALLOCATION_DESC allocationDesc = {}; - allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; - for (auto& alloc : GenerateBufferAllocations()) { ComPtr allocation; EXPECT_EQ(SUCCEEDED(resourceAllocator->CreateResource( @@ -240,6 +292,8 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferSubAllocated) { alloc.succeeds); } } + + // ALLOCATOR_ALGORITHM_DEDICATED { ALLOCATOR_DESC newAllocatorDesc = allocatorDesc; newAllocatorDesc.SubAllocationAlgorithm = ALLOCATOR_ALGORITHM_DEDICATED; @@ -248,9 +302,6 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferSubAllocated) { ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(newAllocatorDesc, &resourceAllocator)); ASSERT_NE(resourceAllocator, nullptr); - ALLOCATION_DESC allocationDesc = {}; - allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; - for (auto& alloc : GenerateBufferAllocations()) { ComPtr allocation; EXPECT_EQ(SUCCEEDED(resourceAllocator->CreateResource(