diff --git a/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp b/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp index 599eec74e..1b09bb247 100644 --- a/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp +++ b/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp @@ -764,6 +764,7 @@ namespace gpgmm::d3d12 { DXGI_MEMORY_SEGMENT_GROUP ResidencyManager::GetMemorySegmentGroup( D3D12_MEMORY_POOL memoryPool) const { + ASSERT(memoryPool != D3D12_MEMORY_POOL_UNKNOWN); return d3d12::GetMemorySegmentGroup(memoryPool, mIsUMA); } diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp index 17f67aafc..d6dbbeba0 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp @@ -292,6 +292,36 @@ namespace gpgmm::d3d12 { return hr; } + D3D12_HEAP_PROPERTIES GetHeapProperties(ID3D12Device* device, + D3D12_HEAP_TYPE heapType, + bool isCustomHeapDisabled, + bool isUMA, + bool isResidencyEnabled) { + // Produces the corresponding properties from the corresponding heap type per this table + // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-getcustomheapproperties + if (!isCustomHeapDisabled) { + return device->GetCustomHeapProperties(0, heapType); + } + + D3D12_HEAP_PROPERTIES heapProperties = {}; + heapProperties.Type = heapType; + + // When residency is disabled, the D3D12 memory pool does not need to be specified + // before allocation. + if (!isResidencyEnabled) { + return heapProperties; + } + + // Only L1 exists when non-UMA adapter per MSDN. + if (!isUMA && heapProperties.Type == D3D12_HEAP_TYPE_DEFAULT) { + heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_L1; + } else { + heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0; + } + + return heapProperties; + } + } // namespace // static @@ -444,7 +474,8 @@ namespace gpgmm::d3d12 { mIsAlwaysInBudget(descriptor.Flags & ALLOCATOR_FLAG_ALWAYS_IN_BUDGET), mFlushEventBuffersOnDestruct(descriptor.RecordOptions.EventScope & EVENT_RECORD_SCOPE_PER_INSTANCE), - mUseDetailedTimingEvents(descriptor.RecordOptions.UseDetailedTimingEvents) { + mUseDetailedTimingEvents(descriptor.RecordOptions.UseDetailedTimingEvents), + mIsCustomHeapsDisabled(descriptor.Flags & ALLOCATOR_FLAG_DISABLE_CUSTOM_HEAPS) { GPGMM_TRACE_EVENT_OBJECT_NEW(this); #if defined(GPGMM_ENABLE_ALLOCATOR_LEAK_CHECKS) @@ -458,32 +489,34 @@ namespace gpgmm::d3d12 { const D3D12_HEAP_FLAGS& heapFlags = GetHeapFlags(resourceHeapType, IsCreateHeapNotResident()); + const D3D12_HEAP_TYPE heapType = GetHeapType(resourceHeapType); const uint64_t msaaHeapAlignment = GetHeapAlignment(heapFlags, true); const uint64_t heapAlignment = GetHeapAlignment(heapFlags, false); - const D3D12_HEAP_PROPERTIES customHeapProperties = - mDevice->GetCustomHeapProperties(0, GetHeapType(resourceHeapType)); + const D3D12_HEAP_PROPERTIES heapProperties = + GetHeapProperties(mDevice.Get(), heapType, mIsCustomHeapsDisabled, + mCaps->IsAdapterUMA(), IsResidencyEnabled()); // General-purpose allocators. // Used for dynamic resource allocation or when the resource size is not known at // compile-time. mResourceAllocatorOfType[resourceHeapTypeIndex] = CreateResourceHeapSubAllocator( - descriptor, heapFlags, customHeapProperties, heapAlignment); + descriptor, heapFlags, heapProperties, heapAlignment); mMSAAResourceAllocatorOfType[resourceHeapTypeIndex] = CreateResourceHeapSubAllocator( - descriptor, heapFlags, customHeapProperties, msaaHeapAlignment); + descriptor, heapFlags, heapProperties, msaaHeapAlignment); - mResourceHeapAllocatorOfType[resourceHeapTypeIndex] = CreateResourceHeapAllocator( - descriptor, heapFlags, customHeapProperties, heapAlignment); + mResourceHeapAllocatorOfType[resourceHeapTypeIndex] = + CreateResourceHeapAllocator(descriptor, heapFlags, heapProperties, heapAlignment); mMSAAResourceHeapAllocatorOfType[resourceHeapTypeIndex] = CreateResourceHeapAllocator( - descriptor, heapFlags, customHeapProperties, msaaHeapAlignment); + descriptor, heapFlags, heapProperties, msaaHeapAlignment); // Resource specific allocators. - mSmallBufferAllocatorOfType[resourceHeapTypeIndex] = CreateSmallBufferAllocator( - descriptor, heapFlags, customHeapProperties, heapAlignment, - GetInitialResourceState(GetHeapType(resourceHeapType))); + mSmallBufferAllocatorOfType[resourceHeapTypeIndex] = + CreateSmallBufferAllocator(descriptor, heapFlags, heapProperties, heapAlignment, + GetInitialResourceState(heapType)); // Cache resource sizes commonly requested. // Allows the next memory block to be made available upon request without @@ -864,12 +897,14 @@ namespace gpgmm::d3d12 { } } - D3D12_HEAP_PROPERTIES customHeapProperties = mDevice->GetCustomHeapProperties(0, heapType); + const D3D12_HEAP_PROPERTIES heapProperties = + GetHeapProperties(mDevice.Get(), heapType, mIsCustomHeapsDisabled, + mCaps->IsAdapterUMA(), IsResidencyEnabled()); // Limit available memory to unused budget when residency is enabled. - if (mResidencyManager != nullptr) { + if (IsResidencyEnabled()) { const DXGI_MEMORY_SEGMENT_GROUP segment = - mResidencyManager->GetMemorySegmentGroup(customHeapProperties.MemoryPoolPreference); + mResidencyManager->GetMemorySegmentGroup(heapProperties.MemoryPoolPreference); DXGI_QUERY_VIDEO_MEMORY_INFO* currentVideoInfo = mResidencyManager->GetVideoMemoryInfo(segment); @@ -1040,7 +1075,7 @@ namespace gpgmm::d3d12 { ComPtr committedResource; Heap* resourceHeap = nullptr; - ReturnIfFailed(CreateCommittedResource(customHeapProperties, heapFlags, resourceInfo, + ReturnIfFailed(CreateCommittedResource(heapProperties, heapFlags, resourceInfo, &newResourceDesc, clearValue, initialResourceState, &committedResource, &resourceHeap)); @@ -1161,7 +1196,7 @@ namespace gpgmm::d3d12 { resourceHeapDesc.Alignment = info.Alignment; resourceHeapDesc.AlwaysInBudget = mIsAlwaysInBudget; - if (mResidencyManager != nullptr) { + if (IsResidencyEnabled()) { resourceHeapDesc.MemorySegmentGroup = mResidencyManager->GetMemorySegmentGroup(heapProperties.MemoryPoolPreference); } @@ -1295,7 +1330,11 @@ namespace gpgmm::d3d12 { } bool ResourceAllocator::IsCreateHeapNotResident() const { - return mResidencyManager != nullptr && !mIsAlwaysInBudget; + return IsResidencyEnabled() && !mIsAlwaysInBudget; + } + + bool ResourceAllocator::IsResidencyEnabled() const { + return mResidencyManager != nullptr; } HRESULT ResourceAllocator::CheckFeatureSupport(FEATURE feature, diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.h b/src/gpgmm/d3d12/ResourceAllocatorD3D12.h index f58f1ab2b..014755a7e 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.h +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.h @@ -76,6 +76,13 @@ namespace gpgmm::d3d12 { minimal possible GPU memory footprint or debugging OOM failures. */ ALLOCATOR_FLAG_ALWAYS_ON_DEMAND = 0x8, + + /** \brief Disables use of D3D12_HEAP_TYPE_CUSTOM. + + Used to workaround issues when a custom-equivalent heap is not considered equal to + the corresponding heap type. + */ + ALLOCATOR_FLAG_DISABLE_CUSTOM_HEAPS = 0x10, }; DEFINE_ENUM_FLAG_OPERATORS(ALLOCATOR_FLAGS) @@ -585,6 +592,7 @@ namespace gpgmm::d3d12 { static HRESULT ReportLiveDeviceObjects(ComPtr device); bool IsCreateHeapNotResident() const; + bool IsResidencyEnabled() const; // MemoryAllocator interface void DeallocateMemory(std::unique_ptr allocation) override; @@ -601,6 +609,7 @@ namespace gpgmm::d3d12 { const bool mIsAlwaysInBudget; const bool mFlushEventBuffersOnDestruct; const bool mUseDetailedTimingEvents; + const bool mIsCustomHeapsDisabled; static constexpr uint64_t kNumOfResourceHeapTypes = 8u; diff --git a/src/include/min/gpgmm_d3d12.h b/src/include/min/gpgmm_d3d12.h index a5e6dc734..6a5757545 100644 --- a/src/include/min/gpgmm_d3d12.h +++ b/src/include/min/gpgmm_d3d12.h @@ -224,6 +224,7 @@ namespace gpgmm::d3d12 { ALLOCATOR_FLAG_ALWAYS_IN_BUDGET = 0x2, ALLOCATOR_FLAG_DISABLE_MEMORY_PREFETCH = 0x4, ALLOCATOR_FLAG_ALWAYS_ON_DEMAND = 0x8, + ALLOCATOR_FLAG_DISABLE_CUSTOM_HEAPS = 0x10, }; DEFINE_ENUM_FLAG_OPERATORS(ALLOCATOR_FLAGS) diff --git a/src/tests/end2end/D3D12ResourceAllocatorTests.cpp b/src/tests/end2end/D3D12ResourceAllocatorTests.cpp index 7000d5ace..7542d933d 100644 --- a/src/tests/end2end/D3D12ResourceAllocatorTests.cpp +++ b/src/tests/end2end/D3D12ResourceAllocatorTests.cpp @@ -456,6 +456,23 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferUMA) { EXPECT_EQ(resourceAllocator->GetInfo().FreeMemoryUsage, kDefaultBufferSize * 2); } +TEST_F(D3D12ResourceAllocatorTests, CreateBufferDisableCustomHeaps) { + ALLOCATOR_DESC allocatorDesc = CreateBasicAllocatorDesc(); + allocatorDesc.Flags |= ALLOCATOR_FLAG_DISABLE_CUSTOM_HEAPS; + + ComPtr resourceAllocator; + ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(allocatorDesc, &resourceAllocator)); + + ComPtr allocation; + ASSERT_SUCCEEDED( + resourceAllocator->CreateResource({}, CreateBasicBufferDesc(kDefaultBufferSize), + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, &allocation)); + + D3D12_HEAP_PROPERTIES heapProperties = {}; + ASSERT_SUCCEEDED(allocation->GetResource()->GetHeapProperties(&heapProperties, nullptr)); + EXPECT_NE(heapProperties.Type, D3D12_HEAP_TYPE_CUSTOM); +} + TEST_F(D3D12ResourceAllocatorTests, CreateSmallTexture) { ComPtr resourceAllocator; ASSERT_SUCCEEDED(