Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,11 +770,13 @@ namespace gpgmm::d3d12 {
isAlwaysCommitted = true;
}

const bool neverSubAllocate =
bool neverSubAllocate =
allocationDescriptor.Flags & ALLOCATION_FLAG_NEVER_SUBALLOCATE_MEMORY;

const bool isMSAA = resourceDescriptor.SampleDesc.Count > 1;

const bool requiresPadding = allocationDescriptor.RequireResourceHeapPadding > 0;

// Attempt to allocate using the most effective allocator.;
MemoryAllocator* allocator = nullptr;

Expand All @@ -795,6 +797,16 @@ namespace gpgmm::d3d12 {
request.AlwaysCacheSize = (allocationDescriptor.Flags & ALLOCATION_FLAG_ALWAYS_CACHE_SIZE);
request.AvailableForAllocation = mCaps->GetMaxResourceHeapSize();

// Apply extra padding to the resource heap size, if specified.
// Padding can only be applied to standalone non-committed resources.
if (GPGMM_UNLIKELY(requiresPadding)) {
request.SizeInBytes += allocationDescriptor.RequireResourceHeapPadding;
if (!neverSubAllocate) {
DebugLog() << "Sub-allocation disabled when padding is requested.";
neverSubAllocate = true;
}
}

// Limit available memory to unused budget when residency is enabled.
if (mResidencyManager != nullptr) {
const DXGI_MEMORY_SEGMENT_GROUP segment =
Expand Down Expand Up @@ -958,6 +970,12 @@ namespace gpgmm::d3d12 {
return E_OUTOFMEMORY;
}

// Committed resources cannot specify resource heap size.
if (GPGMM_UNLIKELY(requiresPadding)) {
ErrorLog() << "A padding was specified but no resource allocator could be used.";
return E_FAIL;
}

if (!isAlwaysCommitted) {
InfoEvent(GetTypename(), EventMessageId::AllocatorFailed)
<< "Unable to allocate by using a heap, falling back to a committed resource.";
Expand Down
12 changes: 12 additions & 0 deletions src/gpgmm/d3d12/ResourceAllocatorD3D12.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,18 @@ namespace gpgmm::d3d12 {
*/
D3D12_HEAP_FLAGS ExtraRequiredHeapFlags = D3D12_HEAP_FLAG_NONE;

/** \brief Require additional bytes to be appended to the resource allocation.

Resource heap size is guarenteed to increase by at-least this number of bytes.
Specifying a padding will disable committed resources and sub-allocated
heaps.

Used to workaround driver bugs related to the heap size being insufficent for the resource.

Optional parameter. No extra padding is applied by default.
*/
uint64_t RequireResourceHeapPadding = 0;

/** \brief Associates a name with the given allocation.

Optional parameter. By default, no name is associated.
Expand Down
55 changes: 55 additions & 0 deletions src/tests/end2end/D3D12ResourceAllocatorTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1320,6 +1320,61 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferCacheSize) {
}
}

// Verify two buffers, with and without padding, allocate the correct size.
TEST_F(D3D12ResourceAllocatorTests, CreateBufferWithPadding) {
ComPtr<ResourceAllocator> resourceAllocator;
ASSERT_SUCCEEDED(
ResourceAllocator::CreateAllocator(CreateBasicAllocatorDesc(), &resourceAllocator));
ASSERT_NE(resourceAllocator, nullptr);

constexpr uint64_t kBufferSize = GPGMM_MB_TO_BYTES(1);

ALLOCATION_DESC allocationDesc = {};
ComPtr<ResourceAllocation> allocationWithoutPadding;
ASSERT_SUCCEEDED(resourceAllocator->CreateResource(
allocationDesc, CreateBasicBufferDesc(kBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr, &allocationWithoutPadding));

allocationDesc.RequireResourceHeapPadding = 63;
ComPtr<ResourceAllocation> allocationWithPadding;
ASSERT_SUCCEEDED(resourceAllocator->CreateResource(
allocationDesc, CreateBasicBufferDesc(kBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr, &allocationWithPadding));

EXPECT_GE(allocationWithPadding->GetSize() - allocationWithoutPadding->GetSize(),
allocationDesc.RequireResourceHeapPadding);

// Padded resources are only supported for standalone allocations.
EXPECT_EQ(allocationWithPadding->GetMethod(), gpgmm::AllocationMethod::kStandalone);
}

// Verify two textures, with and without padding, allocate the correct size.
TEST_F(D3D12ResourceAllocatorTests, CreateTextureWithPadding) {
ComPtr<ResourceAllocator> resourceAllocator;
ASSERT_SUCCEEDED(
ResourceAllocator::CreateAllocator(CreateBasicAllocatorDesc(), &resourceAllocator));
ASSERT_NE(resourceAllocator, nullptr);

ALLOCATION_DESC allocationDesc = {};

ComPtr<ResourceAllocation> allocationWithoutPadding;
ASSERT_SUCCEEDED(resourceAllocator->CreateResource(
allocationDesc, CreateBasicTextureDesc(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1),
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &allocationWithoutPadding));

allocationDesc.RequireResourceHeapPadding = 63;
ComPtr<ResourceAllocation> allocationWithPadding;
ASSERT_SUCCEEDED(resourceAllocator->CreateResource(
allocationDesc, CreateBasicTextureDesc(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1),
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &allocationWithPadding));

EXPECT_GE(allocationWithPadding->GetSize() - allocationWithoutPadding->GetSize(),
allocationDesc.RequireResourceHeapPadding);

// Padded resources are only supported for standalone allocations.
EXPECT_EQ(allocationWithPadding->GetMethod(), gpgmm::AllocationMethod::kStandalone);
}

TEST_F(D3D12ResourceAllocatorTests, CheckFeatureSupport) {
ComPtr<ResourceAllocator> resourceAllocator;
ASSERT_SUCCEEDED(
Expand Down