diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp index 759b256c4..b83992eed 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp @@ -832,6 +832,13 @@ namespace gpgmm::d3d12 { ReturnIfFailed(GetHeapType(initialResourceState, &heapType)); } + // Attribution of heaps may be abandoned but the original heap type is needed to + // check if sub-allocation within is allowed. Since default heaps do not require a + // persistent resource state once created, they are disallowed. + const bool isCreatedResourceStateRequired = + (heapType != D3D12_HEAP_TYPE_DEFAULT) && + (GetInitialResourceState(heapType) == initialResourceState); + // Abandon the attribution of heaps when isCacheCoherentUMA is true by always using the // custom equivelent of upload heap everywhere. This optimizes resource allocation by // allowing the same resource allocator to be used, improving heap reuse. However, CPU @@ -947,8 +954,7 @@ namespace gpgmm::d3d12 { if (allocationDescriptor.Flags & ALLOCATION_FLAG_ALLOW_SUBALLOCATE_WITHIN_RESOURCE && resourceInfo.Alignment > newResourceDesc.Width && newResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER && - GetInitialResourceState(heapType) == initialResourceState && !isAlwaysCommitted && - !neverSubAllocate) { + isCreatedResourceStateRequired && !isAlwaysCommitted && !neverSubAllocate) { allocator = mSmallBufferAllocatorOfType[static_cast(resourceHeapType)].get(); // GetResourceAllocationInfo() always rejects alignments smaller than 64KB. So if the diff --git a/src/tests/end2end/D3D12ResourceAllocatorTests.cpp b/src/tests/end2end/D3D12ResourceAllocatorTests.cpp index c51238e09..9d6b04a23 100644 --- a/src/tests/end2end/D3D12ResourceAllocatorTests.cpp +++ b/src/tests/end2end/D3D12ResourceAllocatorTests.cpp @@ -665,7 +665,7 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferWithin) { ASSERT_SUCCEEDED(resourceAllocator->CreateResource( smallBufferDesc, CreateBasicBufferDesc(4u, 1), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &smallBuffer)); - ASSERT_NE(smallBuffer, nullptr); + EXPECT_EQ(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); EXPECT_EQ(smallBuffer->GetSize(), 4u); EXPECT_EQ(smallBuffer->GetOffsetFromResource(), 0u); @@ -683,7 +683,7 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferWithin) { ASSERT_SUCCEEDED(resourceAllocator->CreateResource( smallBufferWithinDesc, CreateBasicBufferDesc(4u, 16), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &smallBuffer)); - ASSERT_NE(smallBuffer, nullptr); + EXPECT_EQ(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); EXPECT_EQ(smallBuffer->GetSize(), 16u); EXPECT_EQ(smallBuffer->GetOffsetFromResource(), 0u); @@ -701,7 +701,7 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferWithin) { ASSERT_SUCCEEDED(resourceAllocator->CreateResource( smallBufferWithinDesc, CreateBasicBufferDesc(4u), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &smallBuffer)); - ASSERT_NE(smallBuffer, nullptr); + EXPECT_EQ(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); EXPECT_EQ(smallBuffer->GetSize(), 256u); EXPECT_EQ(smallBuffer->GetOffsetFromResource(), 0u); @@ -719,7 +719,7 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferWithin) { ASSERT_SUCCEEDED(resourceAllocator->CreateResource( smallBufferWithinDesc, CreateBasicBufferDesc(4u), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, &smallBuffer)); - ASSERT_NE(smallBuffer, nullptr); + EXPECT_EQ(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); EXPECT_EQ(smallBuffer->GetSize(), 4u); EXPECT_EQ(smallBuffer->GetOffsetFromResource(), 0u); @@ -733,12 +733,65 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferWithin) { ASSERT_SUCCEEDED(resourceAllocator->CreateResource( smallBufferWithinDesc, CreateBasicBufferDesc(3u), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, &smallBuffer)); - ASSERT_NE(smallBuffer, nullptr); + EXPECT_EQ(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); EXPECT_EQ(smallBuffer->GetSize(), 4u); EXPECT_EQ(smallBuffer->GetOffsetFromResource(), 0u); EXPECT_EQ(smallBuffer->GetAlignment(), 4u); // Re-align } + + // Default heap using a required resource state of another compatible heap type is not allowed. + { + ALLOCATION_DESC invalidSmallBufferWithinDesc = baseAllocationDesc; + invalidSmallBufferWithinDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + + ComPtr smallBuffer; + ASSERT_SUCCEEDED(resourceAllocator->CreateResource( + invalidSmallBufferWithinDesc, CreateBasicBufferDesc(3u), D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, &smallBuffer)); + EXPECT_NE(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); + } + + // Non-compatible heap type is not allowed reguardless of resource state specified. + { + ALLOCATION_DESC invalidSmallBufferWithinDesc = baseAllocationDesc; + invalidSmallBufferWithinDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + + ComPtr smallBuffer; + ASSERT_SUCCEEDED(resourceAllocator->CreateResource( + invalidSmallBufferWithinDesc, CreateBasicBufferDesc(3u), D3D12_RESOURCE_STATE_COMMON, + nullptr, &smallBuffer)); + EXPECT_NE(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); + } + + // Custom heaps should use a heap type inferred by the resource state required. + { + ALLOCATION_DESC smallBufferWithinDesc = baseAllocationDesc; + smallBufferWithinDesc.HeapType = D3D12_HEAP_TYPE_CUSTOM; + + ComPtr smallBuffer; + ASSERT_SUCCEEDED(resourceAllocator->CreateResource( + smallBufferWithinDesc, CreateBasicBufferDesc(3u), D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, &smallBuffer)); + EXPECT_EQ(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); + } + + // Unspecified heap type should use the heap type inferred by the resource state + // required. + { + ComPtr smallBuffer; + ASSERT_SUCCEEDED(resourceAllocator->CreateResource( + baseAllocationDesc, CreateBasicBufferDesc(3u), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + &smallBuffer)); + EXPECT_EQ(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); + } + { + ComPtr smallBuffer; + ASSERT_SUCCEEDED( + resourceAllocator->CreateResource(baseAllocationDesc, CreateBasicBufferDesc(3u), + D3D12_RESOURCE_STATE_COMMON, nullptr, &smallBuffer)); + EXPECT_NE(smallBuffer->GetMethod(), gpgmm::AllocationMethod::kSubAllocatedWithin); + } } TEST_F(D3D12ResourceAllocatorTests, CreateBufferWithinMany) {