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
5 changes: 5 additions & 0 deletions src/gpgmm/d3d12/CapsD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ namespace gpgmm::d3d12 {
ReturnIfFailed(
device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &arch, sizeof(arch)));
caps->mIsAdapterUMA = arch.UMA;
caps->mIsAdapterCacheCoherentUMA = arch.CacheCoherentUMA;

// D3D12 has no feature to detect support and must be set manually.
if (adapterDesc.VendorId == kIntel_VkVendor) {
Expand Down Expand Up @@ -145,6 +146,10 @@ namespace gpgmm::d3d12 {
return mIsAdapterUMA;
}

bool Caps::IsAdapterCacheCoherentUMA() const {
return mIsAdapterCacheCoherentUMA;
}

bool Caps::GetMaxResourceHeapTierSupported() const {
return mMaxResourceHeapTier;
}
Expand Down
4 changes: 4 additions & 0 deletions src/gpgmm/d3d12/CapsD3D12.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ namespace gpgmm::d3d12 {
// Specifies if the adapter uses a Unified Memory Architecture (UMA).
bool IsAdapterUMA() const;

// Specifies if the UMA adapter is also cache-coherent.
bool IsAdapterCacheCoherentUMA() const;

// Specifies if a texture and buffer can belong in the same heap.
bool GetMaxResourceHeapTierSupported() const;

Expand All @@ -53,6 +56,7 @@ namespace gpgmm::d3d12 {
bool mIsCreateHeapNotResidentSupported = false;
bool mIsResourceAccessAlwaysCoherent = false;
bool mIsAdapterUMA = false;
bool mIsAdapterCacheCoherentUMA = false;
};

} // namespace gpgmm::d3d12
Expand Down
16 changes: 15 additions & 1 deletion src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ namespace gpgmm::d3d12 {
return S_OK;
}

return E_UNEXPECTED;
*heapType = D3D12_HEAP_TYPE_DEFAULT;
return S_OK;
}

// RAII wrapper to lock/unlock heap from the residency cache.
Expand Down Expand Up @@ -789,6 +790,19 @@ namespace gpgmm::d3d12 {
D3D12_HEAP_TYPE heapType = allocationDescriptor.HeapType;
if (heapType == 0) {
ReturnIfFailed(GetHeapType(initialResourceState, &heapType));
// Abandon the attribution of heaps when isCacheCoherentUMA is true by always using the
// custom equivelent of upload heap. This allows the same resource allocator to be used.
if (mCaps->IsAdapterCacheCoherentUMA()) {
// CPU read back could be inefficient since upload heaps are usually write-combined
// (vs write-back) pages.
if (heapType != D3D12_HEAP_TYPE_READBACK) {
heapType = D3D12_HEAP_TYPE_UPLOAD;
} else {
DebugLog() << "Resource state" << ToHexStr(initialResourceState)
<< " used heap type " << heapType
<< " which disables UMA optimization.";
}
}
}

const RESOURCE_HEAP_TYPE resourceHeapType = GetResourceHeapType(
Expand Down
7 changes: 6 additions & 1 deletion src/gpgmm/d3d12/ResourceAllocatorD3D12.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,13 @@ namespace gpgmm::d3d12 {

/** \brief Heap type that the resource to be allocated requires.

It is recommended to not specifiy the heap type, if possible. This enables better resource
optimization for UMA adapters by using a single custom-equivelent heap type everywhere. A
D3D12_HEAP_TYPE_READBACK is usually the only heap type that benefits from being explicitly
specified since most UMA adapters could benefit from write-combined CPU reads.

Optional parameter. If the heap type is not provided, the heap type will be inferred by the
parameters used to call CreateResource.
adapter properties and the initial resource state.
*/
D3D12_HEAP_TYPE HeapType;

Expand Down
26 changes: 26 additions & 0 deletions src/tests/end2end/D3D12ResourceAllocatorTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,32 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBuffer) {
}
}

// Verifies there are no attribution of heaps when UMA + no read-back.
TEST_F(D3D12ResourceAllocatorTests, CreateBufferUMA) {
GPGMM_SKIP_TEST_IF(!mIsUMA);

ComPtr<ResourceAllocator> resourceAllocator;
ASSERT_SUCCEEDED(
ResourceAllocator::CreateAllocator(CreateBasicAllocatorDesc(), &resourceAllocator));
ASSERT_NE(resourceAllocator, nullptr);

ASSERT_SUCCEEDED(
resourceAllocator->CreateResource({}, CreateBasicBufferDesc(kDefaultBufferSize),
D3D12_RESOURCE_STATE_COMMON, nullptr, nullptr));

ASSERT_SUCCEEDED(
resourceAllocator->CreateResource({}, CreateBasicBufferDesc(kDefaultBufferSize),
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, nullptr));

EXPECT_EQ(resourceAllocator->GetInfo().FreeMemoryUsage, kDefaultBufferSize);

ASSERT_SUCCEEDED(
resourceAllocator->CreateResource({}, CreateBasicBufferDesc(kDefaultBufferSize),
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, nullptr));

EXPECT_EQ(resourceAllocator->GetInfo().FreeMemoryUsage, kDefaultBufferSize * 2);
}

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