From 303a3daf0decb8eaacb251346be317be00dda479 Mon Sep 17 00:00:00 2001 From: Bryan Bernhart Date: Thu, 30 Apr 2020 23:19:16 +0000 Subject: [PATCH] D3D12: Decouple descriptor heap allocations. Allows bindgroups to be populated by heap type. Previously, failing to populate one type of GPU descriptor heap required both GPU heaps to be switched out. This resulted in extra copies and heap allocations should only one heap type overflow. This change also simplifies GPU descriptor heap management: - Allocator no longer needs to operate on both heaps. - Sub-allocation tracking can be moved into handles. A follow-up change will remove duplicated sampler heap allocations. BUG=dawn:155 Change-Id: I1960cf3a8bc3d86d3e8b2775da3d0c92125bcf82 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/19887 Commit-Queue: Bryan Bernhart Reviewed-by: Corentin Wallez --- src/dawn_native/BUILD.gn | 4 +- src/dawn_native/CMakeLists.txt | 4 +- src/dawn_native/d3d12/BindGroupD3D12.cpp | 78 ++++----- src/dawn_native/d3d12/BindGroupD3D12.h | 19 ++- src/dawn_native/d3d12/CommandBufferD3D12.cpp | 47 ++--- .../d3d12/DescriptorHeapAllocationD3D12.cpp | 40 ----- src/dawn_native/d3d12/DeviceD3D12.cpp | 21 ++- src/dawn_native/d3d12/DeviceD3D12.h | 8 +- .../GPUDescriptorHeapAllocationD3D12.cpp | 39 +++++ ...2.h => GPUDescriptorHeapAllocationD3D12.h} | 32 ++-- .../ShaderVisibleDescriptorAllocatorD3D12.cpp | 160 +++++++----------- .../ShaderVisibleDescriptorAllocatorD3D12.h | 64 +++---- .../white_box/D3D12DescriptorHeapTests.cpp | 122 ++++++------- 13 files changed, 311 insertions(+), 327 deletions(-) delete mode 100644 src/dawn_native/d3d12/DescriptorHeapAllocationD3D12.cpp create mode 100644 src/dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.cpp rename src/dawn_native/d3d12/{DescriptorHeapAllocationD3D12.h => GPUDescriptorHeapAllocationD3D12.h} (50%) diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn index 42511960bb..3852fcf190 100644 --- a/src/dawn_native/BUILD.gn +++ b/src/dawn_native/BUILD.gn @@ -299,11 +299,11 @@ source_set("dawn_native_sources") { "d3d12/D3D12Error.h", "d3d12/D3D12Info.cpp", "d3d12/D3D12Info.h", - "d3d12/DescriptorHeapAllocationD3D12.cpp", - "d3d12/DescriptorHeapAllocationD3D12.h", "d3d12/DeviceD3D12.cpp", "d3d12/DeviceD3D12.h", "d3d12/Forward.h", + "d3d12/GPUDescriptorHeapAllocationD3D12.cpp", + "d3d12/GPUDescriptorHeapAllocationD3D12.h", "d3d12/HeapAllocatorD3D12.cpp", "d3d12/HeapAllocatorD3D12.h", "d3d12/HeapD3D12.cpp", diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt index 9d78325508..1465ad010b 100644 --- a/src/dawn_native/CMakeLists.txt +++ b/src/dawn_native/CMakeLists.txt @@ -180,11 +180,11 @@ if (DAWN_ENABLE_D3D12) "d3d12/D3D12Error.h" "d3d12/D3D12Info.cpp" "d3d12/D3D12Info.h" - "d3d12/DescriptorHeapAllocationD3D12.cpp" - "d3d12/DescriptorHeapAllocationD3D12.h" "d3d12/DeviceD3D12.cpp" "d3d12/DeviceD3D12.h" "d3d12/Forward.h" + "d3d12/GPUDescriptorHeapAllocationD3D12.cpp" + "d3d12/GPUDescriptorHeapAllocationD3D12.h" "d3d12/HeapAllocatorD3D12.cpp" "d3d12/HeapAllocatorD3D12.h" "d3d12/HeapD3D12.cpp" diff --git a/src/dawn_native/d3d12/BindGroupD3D12.cpp b/src/dawn_native/d3d12/BindGroupD3D12.cpp index 4d27b521bf..4e328747d1 100644 --- a/src/dawn_native/d3d12/BindGroupD3D12.cpp +++ b/src/dawn_native/d3d12/BindGroupD3D12.cpp @@ -151,71 +151,53 @@ namespace dawn_native { namespace d3d12 { ASSERT(!mCPUSamplerAllocation.IsValid()); } - ResultOrError BindGroup::Populate(ShaderVisibleDescriptorAllocator* allocator) { - Device* device = ToBackend(GetDevice()); + bool BindGroup::PopulateViews(ShaderVisibleDescriptorAllocator* viewAllocator) { + const BindGroupLayout* bgl = ToBackend(GetLayout()); + return Populate(viewAllocator, bgl->GetCbvUavSrvDescriptorCount(), + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, mCPUViewAllocation, + &mGPUViewAllocation); + } - if (allocator->IsAllocationStillValid(mLastUsageSerial, mHeapSerial)) { + bool BindGroup::PopulateSamplers(ShaderVisibleDescriptorAllocator* samplerAllocator) { + const BindGroupLayout* bgl = ToBackend(GetLayout()); + return Populate(samplerAllocator, bgl->GetSamplerDescriptorCount(), + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, mCPUSamplerAllocation, + &mGPUSamplerAllocation); + } + + bool BindGroup::Populate(ShaderVisibleDescriptorAllocator* allocator, + uint32_t descriptorCount, + D3D12_DESCRIPTOR_HEAP_TYPE heapType, + const CPUDescriptorHeapAllocation& stagingAllocation, + GPUDescriptorHeapAllocation* allocation) { + if (descriptorCount == 0 || allocator->IsAllocationStillValid(*allocation)) { return true; } // Attempt to allocate descriptors for the currently bound shader-visible heaps. // If either failed, return early to re-allocate and switch the heaps. - const BindGroupLayout* bgl = ToBackend(GetLayout()); - const Serial pendingSerial = device->GetPendingCommandSerial(); + Device* device = ToBackend(GetDevice()); - ID3D12Device* d3d12Device = device->GetD3D12Device(); + D3D12_CPU_DESCRIPTOR_HANDLE baseCPUDescriptor; + if (!allocator->AllocateGPUDescriptors(descriptorCount, device->GetPendingCommandSerial(), + &baseCPUDescriptor, allocation)) { + return false; + } // CPU bindgroups are sparsely allocated across CPU heaps. Instead of doing // simple copies per bindgroup, a single non-simple copy could be issued. // TODO(dawn:155): Consider doing this optimization. - const uint32_t viewDescriptorCount = bgl->GetCbvUavSrvDescriptorCount(); - if (viewDescriptorCount > 0) { - DescriptorHeapAllocation viewDescriptorHeapAllocation; - DAWN_TRY_ASSIGN( - viewDescriptorHeapAllocation, - allocator->AllocateGPUDescriptors(viewDescriptorCount, pendingSerial, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)); - if (viewDescriptorHeapAllocation.IsInvalid()) { - return false; - } - - d3d12Device->CopyDescriptorsSimple( - viewDescriptorCount, viewDescriptorHeapAllocation.GetBaseCPUDescriptor(), - mCPUViewAllocation.GetBaseDescriptor(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - - mBaseViewDescriptor = viewDescriptorHeapAllocation.GetBaseGPUDescriptor(); - } - - const uint32_t samplerDescriptorCount = bgl->GetSamplerDescriptorCount(); - if (samplerDescriptorCount > 0) { - DescriptorHeapAllocation samplerDescriptorHeapAllocation; - DAWN_TRY_ASSIGN(samplerDescriptorHeapAllocation, - allocator->AllocateGPUDescriptors(samplerDescriptorCount, pendingSerial, - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)); - if (samplerDescriptorHeapAllocation.IsInvalid()) { - return false; - } - - d3d12Device->CopyDescriptorsSimple( - samplerDescriptorCount, samplerDescriptorHeapAllocation.GetBaseCPUDescriptor(), - mCPUSamplerAllocation.GetBaseDescriptor(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - - mBaseSamplerDescriptor = samplerDescriptorHeapAllocation.GetBaseGPUDescriptor(); - } - - // Record both the device and heap serials to determine later if the allocations are still - // valid. - mLastUsageSerial = pendingSerial; - mHeapSerial = allocator->GetShaderVisibleHeapsSerial(); + device->GetD3D12Device()->CopyDescriptorsSimple( + descriptorCount, baseCPUDescriptor, stagingAllocation.GetBaseDescriptor(), heapType); return true; } - D3D12_GPU_DESCRIPTOR_HANDLE BindGroup::GetBaseCbvUavSrvDescriptor() const { - return mBaseViewDescriptor; + D3D12_GPU_DESCRIPTOR_HANDLE BindGroup::GetBaseViewDescriptor() const { + return mGPUViewAllocation.GetBaseDescriptor(); } D3D12_GPU_DESCRIPTOR_HANDLE BindGroup::GetBaseSamplerDescriptor() const { - return mBaseSamplerDescriptor; + return mGPUSamplerAllocation.GetBaseDescriptor(); } }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/BindGroupD3D12.h b/src/dawn_native/d3d12/BindGroupD3D12.h index ac9e71d86a..05d67b4ba3 100644 --- a/src/dawn_native/d3d12/BindGroupD3D12.h +++ b/src/dawn_native/d3d12/BindGroupD3D12.h @@ -19,6 +19,7 @@ #include "common/Serial.h" #include "dawn_native/BindGroup.h" #include "dawn_native/d3d12/CPUDescriptorHeapAllocationD3D12.h" +#include "dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.h" namespace dawn_native { namespace d3d12 { @@ -38,19 +39,23 @@ namespace dawn_native { namespace d3d12 { const CPUDescriptorHeapAllocation& samplerAllocation); // Returns true if the BindGroup was successfully populated. - ResultOrError Populate(ShaderVisibleDescriptorAllocator* allocator); + bool PopulateViews(ShaderVisibleDescriptorAllocator* viewAllocator); + bool PopulateSamplers(ShaderVisibleDescriptorAllocator* samplerAllocator); - D3D12_GPU_DESCRIPTOR_HANDLE GetBaseCbvUavSrvDescriptor() const; + D3D12_GPU_DESCRIPTOR_HANDLE GetBaseViewDescriptor() const; D3D12_GPU_DESCRIPTOR_HANDLE GetBaseSamplerDescriptor() const; private: + bool Populate(ShaderVisibleDescriptorAllocator* allocator, + uint32_t descriptorCount, + D3D12_DESCRIPTOR_HEAP_TYPE heapType, + const CPUDescriptorHeapAllocation& stagingAllocation, + GPUDescriptorHeapAllocation* allocation); + ~BindGroup() override; - Serial mLastUsageSerial = 0; - Serial mHeapSerial = 0; - - D3D12_GPU_DESCRIPTOR_HANDLE mBaseViewDescriptor = {0}; - D3D12_GPU_DESCRIPTOR_HANDLE mBaseSamplerDescriptor = {0}; + GPUDescriptorHeapAllocation mGPUSamplerAllocation; + GPUDescriptorHeapAllocation mGPUViewAllocation; CPUDescriptorHeapAllocation mCPUSamplerAllocation; CPUDescriptorHeapAllocation mCPUViewAllocation; diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp index 9a5b66321f..0a45e2e4f5 100644 --- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp @@ -95,7 +95,8 @@ namespace dawn_native { namespace d3d12 { public: BindGroupStateTracker(Device* device) : BindGroupAndStorageBarrierTrackerBase(), - mAllocator(device->GetShaderVisibleDescriptorAllocator()) { + mViewAllocator(device->GetViewShaderVisibleDescriptorAllocator()), + mSamplerAllocator(device->GetSamplerShaderVisibleDescriptorAllocator()) { } void SetInComputePass(bool inCompute_) { @@ -111,21 +112,27 @@ namespace dawn_native { namespace d3d12 { // Re-populating all bindgroups after the last one fails causes duplicated allocations // to occur on overflow. // TODO(bryan.bernhart@intel.com): Consider further optimization. - bool didCreateBindGroups = true; + bool didCreateBindGroupViews = true; + bool didCreateBindGroupSamplers = true; for (uint32_t index : IterateBitSet(mDirtyBindGroups)) { - DAWN_TRY_ASSIGN(didCreateBindGroups, - ToBackend(mBindGroups[index])->Populate(mAllocator)); - if (!didCreateBindGroups) { + BindGroup* group = ToBackend(mBindGroups[index]); + didCreateBindGroupViews = group->PopulateViews(mViewAllocator); + didCreateBindGroupSamplers = group->PopulateSamplers(mSamplerAllocator); + if (!didCreateBindGroupViews && !didCreateBindGroupSamplers) { break; } } - // This will re-create bindgroups for both heaps even if only one overflowed. - // TODO(bryan.bernhart@intel.com): Consider re-allocating heaps independently - // such that overflowing one doesn't re-allocate the another. ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList(); - if (!didCreateBindGroups) { - DAWN_TRY(mAllocator->AllocateAndSwitchShaderVisibleHeaps()); + + if (!didCreateBindGroupViews || !didCreateBindGroupSamplers) { + if (!didCreateBindGroupViews) { + DAWN_TRY(mViewAllocator->AllocateAndSwitchShaderVisibleHeap()); + } + + if (!didCreateBindGroupSamplers) { + DAWN_TRY(mSamplerAllocator->AllocateAndSwitchShaderVisibleHeap()); + } mDirtyBindGroupsObjectChangedOrIsDynamic |= mBindGroupLayoutsMask; mDirtyBindGroups |= mBindGroupLayoutsMask; @@ -134,9 +141,11 @@ namespace dawn_native { namespace d3d12 { SetID3D12DescriptorHeaps(commandList); for (uint32_t index : IterateBitSet(mBindGroupLayoutsMask)) { - DAWN_TRY_ASSIGN(didCreateBindGroups, - ToBackend(mBindGroups[index])->Populate(mAllocator)); - ASSERT(didCreateBindGroups); + BindGroup* group = ToBackend(mBindGroups[index]); + didCreateBindGroupViews = group->PopulateViews(mViewAllocator); + didCreateBindGroupSamplers = group->PopulateSamplers(mSamplerAllocator); + ASSERT(didCreateBindGroupViews); + ASSERT(didCreateBindGroupSamplers); } } @@ -183,11 +192,11 @@ namespace dawn_native { namespace d3d12 { void SetID3D12DescriptorHeaps(ID3D12GraphicsCommandList* commandList) { ASSERT(commandList != nullptr); - std::array descriptorHeaps = - mAllocator->GetShaderVisibleHeaps(); + std::array descriptorHeaps = { + mViewAllocator->GetShaderVisibleHeap(), mSamplerAllocator->GetShaderVisibleHeap()}; ASSERT(descriptorHeaps[0] != nullptr); ASSERT(descriptorHeaps[1] != nullptr); - commandList->SetDescriptorHeaps(2, descriptorHeaps.data()); + commandList->SetDescriptorHeaps(descriptorHeaps.size(), descriptorHeaps.data()); } private: @@ -269,8 +278,7 @@ namespace dawn_native { namespace d3d12 { if (cbvUavSrvCount > 0) { uint32_t parameterIndex = pipelineLayout->GetCbvUavSrvRootParameterIndex(index); - const D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor = - group->GetBaseCbvUavSrvDescriptor(); + const D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor = group->GetBaseViewDescriptor(); if (mInCompute) { commandList->SetComputeRootDescriptorTable(parameterIndex, baseDescriptor); } else { @@ -292,7 +300,8 @@ namespace dawn_native { namespace d3d12 { bool mInCompute = false; - ShaderVisibleDescriptorAllocator* mAllocator; + ShaderVisibleDescriptorAllocator* mViewAllocator; + ShaderVisibleDescriptorAllocator* mSamplerAllocator; }; namespace { diff --git a/src/dawn_native/d3d12/DescriptorHeapAllocationD3D12.cpp b/src/dawn_native/d3d12/DescriptorHeapAllocationD3D12.cpp deleted file mode 100644 index 2ca7885299..0000000000 --- a/src/dawn_native/d3d12/DescriptorHeapAllocationD3D12.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2020 The Dawn Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "dawn_native/d3d12/DescriptorHeapAllocationD3D12.h" -#include "dawn_native/Error.h" - -namespace dawn_native { namespace d3d12 { - - DescriptorHeapAllocation::DescriptorHeapAllocation( - D3D12_CPU_DESCRIPTOR_HANDLE baseCPUDescriptorHandle, - D3D12_GPU_DESCRIPTOR_HANDLE baseGPUDescriptorHandle) - : mBaseCPUDescriptorHandle(baseCPUDescriptorHandle), - mBaseGPUDescriptorHandle(baseGPUDescriptorHandle) { - } - - D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapAllocation::GetBaseGPUDescriptor() const { - ASSERT(!IsInvalid()); - return mBaseGPUDescriptorHandle; - } - - D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapAllocation::GetBaseCPUDescriptor() const { - ASSERT(!IsInvalid()); - return mBaseCPUDescriptorHandle; - } - - bool DescriptorHeapAllocation::IsInvalid() const { - return mBaseCPUDescriptorHandle.ptr == 0; - } -}} // namespace dawn_native::d3d12 \ No newline at end of file diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp index 8f09bf94a1..fdd620ffe6 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.cpp +++ b/src/dawn_native/d3d12/DeviceD3D12.cpp @@ -82,9 +82,13 @@ namespace dawn_native { namespace d3d12 { // Initialize backend services mCommandAllocatorManager = std::make_unique(this); - mShaderVisibleDescriptorAllocator = - std::make_unique(this); - DAWN_TRY(mShaderVisibleDescriptorAllocator->Initialize()); + DAWN_TRY_ASSIGN( + mViewShaderVisibleDescriptorAllocator, + ShaderVisibleDescriptorAllocator::Create(this, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)); + + DAWN_TRY_ASSIGN( + mSamplerShaderVisibleDescriptorAllocator, + ShaderVisibleDescriptorAllocator::Create(this, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)); // Zero sized allocator is never requested and does not need to exist. for (uint32_t countIndex = 1; countIndex < kNumOfStagingDescriptorAllocators; @@ -212,7 +216,8 @@ namespace dawn_native { namespace d3d12 { mResourceAllocatorManager->Tick(mCompletedSerial); DAWN_TRY(mCommandAllocatorManager->Tick(mCompletedSerial)); - mShaderVisibleDescriptorAllocator->Tick(mCompletedSerial); + mViewShaderVisibleDescriptorAllocator->Tick(mCompletedSerial); + mSamplerShaderVisibleDescriptorAllocator->Tick(mCompletedSerial); mRenderTargetViewAllocator->Tick(mCompletedSerial); mDepthStencilViewAllocator->Tick(mCompletedSerial); mMapRequestTracker->Tick(mCompletedSerial); @@ -471,8 +476,12 @@ namespace dawn_native { namespace d3d12 { ASSERT(!mPendingCommands.IsOpen()); } - ShaderVisibleDescriptorAllocator* Device::GetShaderVisibleDescriptorAllocator() const { - return mShaderVisibleDescriptorAllocator.get(); + ShaderVisibleDescriptorAllocator* Device::GetViewShaderVisibleDescriptorAllocator() const { + return mViewShaderVisibleDescriptorAllocator.get(); + } + + ShaderVisibleDescriptorAllocator* Device::GetSamplerShaderVisibleDescriptorAllocator() const { + return mSamplerShaderVisibleDescriptorAllocator.get(); } StagingDescriptorAllocator* Device::GetViewStagingDescriptorAllocator( diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h index 615f1fb54e..569acbf127 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.h +++ b/src/dawn_native/d3d12/DeviceD3D12.h @@ -100,7 +100,8 @@ namespace dawn_native { namespace d3d12 { void DeallocateMemory(ResourceHeapAllocation& allocation); - ShaderVisibleDescriptorAllocator* GetShaderVisibleDescriptorAllocator() const; + ShaderVisibleDescriptorAllocator* GetViewShaderVisibleDescriptorAllocator() const; + ShaderVisibleDescriptorAllocator* GetSamplerShaderVisibleDescriptorAllocator() const; // Returns nullptr when descriptor count is zero. StagingDescriptorAllocator* GetViewStagingDescriptorAllocator( @@ -180,7 +181,6 @@ namespace dawn_native { namespace d3d12 { std::unique_ptr mMapRequestTracker; std::unique_ptr mResourceAllocatorManager; std::unique_ptr mResidencyManager; - std::unique_ptr mShaderVisibleDescriptorAllocator; // Index corresponds to the descriptor count in the range [0, kMaxBindingsPerGroup]. static constexpr uint32_t kNumOfStagingDescriptorAllocators = kMaxBindingsPerGroup + 1; @@ -194,6 +194,10 @@ namespace dawn_native { namespace d3d12 { std::unique_ptr mRenderTargetViewAllocator; std::unique_ptr mDepthStencilViewAllocator; + + std::unique_ptr mViewShaderVisibleDescriptorAllocator; + + std::unique_ptr mSamplerShaderVisibleDescriptorAllocator; }; }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.cpp b/src/dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.cpp new file mode 100644 index 0000000000..c72605a58b --- /dev/null +++ b/src/dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.cpp @@ -0,0 +1,39 @@ +// Copyright 2020 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.h" + +namespace dawn_native { namespace d3d12 { + + GPUDescriptorHeapAllocation::GPUDescriptorHeapAllocation( + D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor, + Serial lastUsageSerial, + Serial heapSerial) + : mBaseDescriptor(baseDescriptor), + mLastUsageSerial(lastUsageSerial), + mHeapSerial(heapSerial) { + } + + D3D12_GPU_DESCRIPTOR_HANDLE GPUDescriptorHeapAllocation::GetBaseDescriptor() const { + return mBaseDescriptor; + } + + Serial GPUDescriptorHeapAllocation::GetLastUsageSerial() const { + return mLastUsageSerial; + } + + Serial GPUDescriptorHeapAllocation::GetHeapSerial() const { + return mHeapSerial; + } +}} // namespace dawn_native::d3d12 \ No newline at end of file diff --git a/src/dawn_native/d3d12/DescriptorHeapAllocationD3D12.h b/src/dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.h similarity index 50% rename from src/dawn_native/d3d12/DescriptorHeapAllocationD3D12.h rename to src/dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.h index e63d415b31..c18d2662c3 100644 --- a/src/dawn_native/d3d12/DescriptorHeapAllocationD3D12.h +++ b/src/dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.h @@ -12,32 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef DAWNNATIVE_D3D12_DESCRIPTORHEAPALLOCATIOND3D12_H_ -#define DAWNNATIVE_D3D12_DESCRIPTORHEAPALLOCATIOND3D12_H_ +#ifndef DAWNNATIVE_D3D12_GPUDESCRIPTORHEAPALLOCATION_H_ +#define DAWNNATIVE_D3D12_GPUDESCRIPTORHEAPALLOCATION_H_ +#include "common/Serial.h" #include "dawn_native/d3d12/d3d12_platform.h" -#include - namespace dawn_native { namespace d3d12 { // Wrapper for a handle into a GPU-only descriptor heap. - class DescriptorHeapAllocation { + class GPUDescriptorHeapAllocation { public: - DescriptorHeapAllocation() = default; - DescriptorHeapAllocation(D3D12_CPU_DESCRIPTOR_HANDLE baseCPUDescriptorHandle, - D3D12_GPU_DESCRIPTOR_HANDLE baseGPUDescriptorHandle); - ~DescriptorHeapAllocation() = default; + GPUDescriptorHeapAllocation() = default; + GPUDescriptorHeapAllocation(D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor, + Serial lastUsageSerial, + Serial heapSerial); - D3D12_GPU_DESCRIPTOR_HANDLE GetBaseGPUDescriptor() const; - D3D12_CPU_DESCRIPTOR_HANDLE GetBaseCPUDescriptor() const; - - bool IsInvalid() const; + D3D12_GPU_DESCRIPTOR_HANDLE GetBaseDescriptor() const; + Serial GetLastUsageSerial() const; + Serial GetHeapSerial() const; private: - D3D12_CPU_DESCRIPTOR_HANDLE mBaseCPUDescriptorHandle = {0}; - D3D12_GPU_DESCRIPTOR_HANDLE mBaseGPUDescriptorHandle = {0}; + D3D12_GPU_DESCRIPTOR_HANDLE mBaseDescriptor = {0}; + Serial mLastUsageSerial = 0; + Serial mHeapSerial = 0; }; + }} // namespace dawn_native::d3d12 -#endif // DAWNNATIVE_D3D12_DESCRIPTORHEAPALLOCATIOND3D12_H_ \ No newline at end of file +#endif // DAWNNATIVE_D3D12_CPUDESCRIPTORHEAPALLOCATION_H_ \ No newline at end of file diff --git a/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp b/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp index d881f26fce..9c36ac5030 100644 --- a/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp +++ b/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp @@ -15,13 +15,10 @@ #include "dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h" #include "dawn_native/d3d12/D3D12Error.h" #include "dawn_native/d3d12/DeviceD3D12.h" +#include "dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.h" namespace dawn_native { namespace d3d12 { - // Check that d3d heap type enum correctly mirrors the type index used by the static arrays. - static_assert(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV == 0, ""); - static_assert(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER == 1, ""); - // Thresholds should be adjusted (lower == faster) to avoid tests taking too long to complete. static constexpr const uint32_t kShaderVisibleSmallHeapSizes[] = {1024, 512}; @@ -50,119 +47,93 @@ namespace dawn_native { namespace d3d12 { } } - ShaderVisibleDescriptorAllocator::ShaderVisibleDescriptorAllocator(Device* device) - : mDevice(device), - mSizeIncrements{ - device->GetD3D12Device()->GetDescriptorHandleIncrementSize( - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV), - device->GetD3D12Device()->GetDescriptorHandleIncrementSize( - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER), - } { + // static + ResultOrError> + ShaderVisibleDescriptorAllocator::Create(Device* device, D3D12_DESCRIPTOR_HEAP_TYPE heapType) { + std::unique_ptr allocator = + std::make_unique(device, heapType); + DAWN_TRY(allocator->AllocateAndSwitchShaderVisibleHeap()); + return std::move(allocator); } - MaybeError ShaderVisibleDescriptorAllocator::Initialize() { - ASSERT(mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap.Get() == nullptr); - mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heapType = - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - - ASSERT(mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER].heap.Get() == nullptr); - mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER].heapType = - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - - DAWN_TRY(AllocateAndSwitchShaderVisibleHeaps()); - - return {}; - } - - MaybeError ShaderVisibleDescriptorAllocator::AllocateAndSwitchShaderVisibleHeaps() { - DAWN_TRY(AllocateGPUHeap(&mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV])); - DAWN_TRY(AllocateGPUHeap(&mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER])); - - // Invalidate all bindgroup allocations on previously bound heaps by incrementing the heap - // serial. When a bindgroup attempts to re-populate, it will compare with its recorded - // heap serial. - mShaderVisibleHeapsSerial++; - - return {}; - } - - ResultOrError - ShaderVisibleDescriptorAllocator::AllocateGPUDescriptors(uint32_t descriptorCount, - Serial pendingSerial, - D3D12_DESCRIPTOR_HEAP_TYPE heapType) { + ShaderVisibleDescriptorAllocator::ShaderVisibleDescriptorAllocator( + Device* device, + D3D12_DESCRIPTOR_HEAP_TYPE heapType) + : mHeapType(heapType), + mDevice(device), + mSizeIncrement(device->GetD3D12Device()->GetDescriptorHandleIncrementSize(heapType)) { ASSERT(heapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || heapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - ASSERT(mShaderVisibleBuffers[heapType].heap != nullptr); - const uint64_t startOffset = - mShaderVisibleBuffers[heapType].allocator.Allocate(descriptorCount, pendingSerial); + } + + bool ShaderVisibleDescriptorAllocator::AllocateGPUDescriptors( + uint32_t descriptorCount, + Serial pendingSerial, + D3D12_CPU_DESCRIPTOR_HANDLE* baseCPUDescriptor, + GPUDescriptorHeapAllocation* allocation) { + ASSERT(mHeap != nullptr); + const uint64_t startOffset = mAllocator.Allocate(descriptorCount, pendingSerial); if (startOffset == RingBufferAllocator::kInvalidOffset) { - return DescriptorHeapAllocation{}; // Invalid + return false; } - ID3D12DescriptorHeap* descriptorHeap = mShaderVisibleBuffers[heapType].heap.Get(); + ID3D12DescriptorHeap* descriptorHeap = mHeap.Get(); - const uint64_t heapOffset = mSizeIncrements[heapType] * startOffset; + const uint64_t heapOffset = mSizeIncrement * startOffset; // Check for 32-bit overflow since CPU heap start handle uses size_t. const size_t cpuHeapStartPtr = descriptorHeap->GetCPUDescriptorHandleForHeapStart().ptr; ASSERT(heapOffset <= std::numeric_limits::max() - cpuHeapStartPtr); - const D3D12_CPU_DESCRIPTOR_HANDLE baseCPUDescriptor = {cpuHeapStartPtr + - static_cast(heapOffset)}; + *baseCPUDescriptor = {cpuHeapStartPtr + static_cast(heapOffset)}; const D3D12_GPU_DESCRIPTOR_HANDLE baseGPUDescriptor = { descriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr + heapOffset}; - return DescriptorHeapAllocation{baseCPUDescriptor, baseGPUDescriptor}; + // Record both the device and heap serials to determine later if the allocations are + // still valid. + *allocation = GPUDescriptorHeapAllocation{baseGPUDescriptor, pendingSerial, mHeapSerial}; + + return true; } - std::array ShaderVisibleDescriptorAllocator::GetShaderVisibleHeaps() - const { - return {mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap.Get(), - mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER].heap.Get()}; + ID3D12DescriptorHeap* ShaderVisibleDescriptorAllocator::GetShaderVisibleHeap() const { + return mHeap.Get(); } void ShaderVisibleDescriptorAllocator::Tick(uint64_t completedSerial) { - for (uint32_t i = 0; i < mShaderVisibleBuffers.size(); i++) { - ASSERT(mShaderVisibleBuffers[i].heap != nullptr); - mShaderVisibleBuffers[i].allocator.Deallocate(completedSerial); - } + mAllocator.Deallocate(completedSerial); } // Creates a GPU descriptor heap that manages descriptors in a FIFO queue. - MaybeError ShaderVisibleDescriptorAllocator::AllocateGPUHeap( - ShaderVisibleBuffer* shaderVisibleBuffer) { + MaybeError ShaderVisibleDescriptorAllocator::AllocateAndSwitchShaderVisibleHeap() { ComPtr heap; // Return the switched out heap to the pool and retrieve the oldest heap that is no longer // used by GPU. This maintains a heap buffer to avoid frequently re-creating heaps for heavy // users. // TODO(dawn:256): Consider periodically triming to avoid OOM. - if (shaderVisibleBuffer->heap != nullptr) { - shaderVisibleBuffer->pool.push_back( - {mDevice->GetPendingCommandSerial(), std::move(shaderVisibleBuffer->heap)}); + if (mHeap != nullptr) { + mPool.push_back({mDevice->GetPendingCommandSerial(), std::move(mHeap)}); } // Recycle existing heap if possible. - if (!shaderVisibleBuffer->pool.empty() && - shaderVisibleBuffer->pool.front().heapSerial <= mDevice->GetCompletedCommandSerial()) { - heap = std::move(shaderVisibleBuffer->pool.front().heap); - shaderVisibleBuffer->pool.pop_front(); + if (!mPool.empty() && mPool.front().heapSerial <= mDevice->GetCompletedCommandSerial()) { + heap = std::move(mPool.front().heap); + mPool.pop_front(); } - const D3D12_DESCRIPTOR_HEAP_TYPE heapType = shaderVisibleBuffer->heapType; - // TODO(bryan.bernhart@intel.com): Allocating to max heap size wastes memory // should the developer not allocate any bindings for the heap type. // Consider dynamically re-sizing GPU heaps. const uint32_t descriptorCount = GetD3D12ShaderVisibleHeapSize( - heapType, mDevice->IsToggleEnabled(Toggle::UseD3D12SmallShaderVisibleHeapForTesting)); + mHeapType, mDevice->IsToggleEnabled(Toggle::UseD3D12SmallShaderVisibleHeapForTesting)); if (heap == nullptr) { D3D12_DESCRIPTOR_HEAP_DESC heapDescriptor; - heapDescriptor.Type = heapType; + heapDescriptor.Type = mHeapType; heapDescriptor.NumDescriptors = descriptorCount; - heapDescriptor.Flags = GetD3D12HeapFlags(heapType); + heapDescriptor.Flags = GetD3D12HeapFlags(mHeapType); heapDescriptor.NodeMask = 0; DAWN_TRY(CheckOutOfMemoryHRESULT(mDevice->GetD3D12Device()->CreateDescriptorHeap( &heapDescriptor, IID_PPV_ARGS(&heap)), @@ -170,41 +141,34 @@ namespace dawn_native { namespace d3d12 { } // Create a FIFO buffer from the recently created heap. - shaderVisibleBuffer->heap = std::move(heap); - shaderVisibleBuffer->allocator = RingBufferAllocator(descriptorCount); + mHeap = std::move(heap); + mAllocator = RingBufferAllocator(descriptorCount); + + // Invalidate all bindgroup allocations on previously bound heaps by incrementing the heap + // serial. When a bindgroup attempts to re-populate, it will compare with its recorded + // heap serial. + mHeapSerial++; + return {}; } - Serial ShaderVisibleDescriptorAllocator::GetShaderVisibleHeapsSerial() const { - return mShaderVisibleHeapsSerial; + Serial ShaderVisibleDescriptorAllocator::GetShaderVisibleHeapSerialForTesting() const { + return mHeapSerial; } - uint64_t ShaderVisibleDescriptorAllocator::GetShaderVisibleHeapSizeForTesting( - D3D12_DESCRIPTOR_HEAP_TYPE heapType) const { - ASSERT(heapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || - heapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - return mShaderVisibleBuffers[heapType].allocator.GetSize(); + uint64_t ShaderVisibleDescriptorAllocator::GetShaderVisibleHeapSizeForTesting() const { + return mAllocator.GetSize(); } - ComPtr ShaderVisibleDescriptorAllocator::GetShaderVisibleHeapForTesting( - D3D12_DESCRIPTOR_HEAP_TYPE heapType) const { - ASSERT(heapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || - heapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - return mShaderVisibleBuffers[heapType].heap; + uint64_t ShaderVisibleDescriptorAllocator::GetShaderVisiblePoolSizeForTesting() const { + return mPool.size(); } - uint64_t ShaderVisibleDescriptorAllocator::GetShaderVisiblePoolSizeForTesting( - D3D12_DESCRIPTOR_HEAP_TYPE heapType) const { - ASSERT(heapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || - heapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - return mShaderVisibleBuffers[heapType].pool.size(); - } - - bool ShaderVisibleDescriptorAllocator::IsAllocationStillValid(Serial lastUsageSerial, - Serial heapSerial) const { + bool ShaderVisibleDescriptorAllocator::IsAllocationStillValid( + const GPUDescriptorHeapAllocation& allocation) const { // Consider valid if allocated for the pending submit and the shader visible heaps // have not switched over. - return (lastUsageSerial > mDevice->GetCompletedCommandSerial() && - heapSerial == mShaderVisibleHeapsSerial); + return (allocation.GetLastUsageSerial() > mDevice->GetCompletedCommandSerial() && + allocation.GetHeapSerial() == mHeapSerial); } }} // namespace dawn_native::d3d12 \ No newline at end of file diff --git a/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h b/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h index 66f63f55eb..be4e83974d 100644 --- a/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h +++ b/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h @@ -17,39 +17,47 @@ #include "dawn_native/Error.h" #include "dawn_native/RingBufferAllocator.h" -#include "dawn_native/d3d12/DescriptorHeapAllocationD3D12.h" +#include "dawn_native/d3d12/d3d12_platform.h" -#include #include +// |ShaderVisibleDescriptorAllocator| allocates a variable-sized block of descriptors from a GPU +// descriptor heap pool. +// Internally, it manages a list of heaps using a ringbuffer block allocator. The heap is in one +// of two states: switched in or out. Only a switched in heap can be bound to the pipeline. If +// the heap is full, the caller must switch-in a new heap before re-allocating and the old one +// is returned to the pool. namespace dawn_native { namespace d3d12 { class Device; + class GPUDescriptorHeapAllocation; - // Manages descriptor heap allocators used by the device to create descriptors using allocation - // methods based on the heap type. class ShaderVisibleDescriptorAllocator { public: - ShaderVisibleDescriptorAllocator(Device* device); - MaybeError Initialize(); - - ResultOrError AllocateGPUDescriptors( - uint32_t descriptorCount, - Serial pendingSerial, + static ResultOrError> Create( + Device* device, D3D12_DESCRIPTOR_HEAP_TYPE heapType); + ShaderVisibleDescriptorAllocator(Device* device, D3D12_DESCRIPTOR_HEAP_TYPE heapType); + + // Returns true if the allocation was successful, when false is returned the current heap is + // full and AllocateAndSwitchShaderVisibleHeap() must be called. + bool AllocateGPUDescriptors(uint32_t descriptorCount, + Serial pendingSerial, + D3D12_CPU_DESCRIPTOR_HANDLE* baseCPUDescriptor, + GPUDescriptorHeapAllocation* allocation); + void Tick(uint64_t completedSerial); - Serial GetShaderVisibleHeapsSerial() const; - std::array GetShaderVisibleHeaps() const; - MaybeError AllocateAndSwitchShaderVisibleHeaps(); + ID3D12DescriptorHeap* GetShaderVisibleHeap() const; + MaybeError AllocateAndSwitchShaderVisibleHeap(); - uint64_t GetShaderVisibleHeapSizeForTesting(D3D12_DESCRIPTOR_HEAP_TYPE heapType) const; - ComPtr GetShaderVisibleHeapForTesting( - D3D12_DESCRIPTOR_HEAP_TYPE heapType) const; - uint64_t GetShaderVisiblePoolSizeForTesting(D3D12_DESCRIPTOR_HEAP_TYPE heapType) const; + // For testing purposes only. + Serial GetShaderVisibleHeapSerialForTesting() const; + uint64_t GetShaderVisibleHeapSizeForTesting() const; + uint64_t GetShaderVisiblePoolSizeForTesting() const; - bool IsAllocationStillValid(Serial lastUsageSerial, Serial heapSerial) const; + bool IsAllocationStillValid(const GPUDescriptorHeapAllocation& allocation) const; private: struct SerialDescriptorHeap { @@ -57,23 +65,19 @@ namespace dawn_native { namespace d3d12 { ComPtr heap; }; - struct ShaderVisibleBuffer { - ComPtr heap; - RingBufferAllocator allocator; - std::list pool; - D3D12_DESCRIPTOR_HEAP_TYPE heapType; - }; - - MaybeError AllocateGPUHeap(ShaderVisibleBuffer* shaderVisibleBuffer); + ComPtr mHeap; + RingBufferAllocator mAllocator; + std::list mPool; + D3D12_DESCRIPTOR_HEAP_TYPE mHeapType; Device* mDevice; // The serial value of 0 means the shader-visible heaps have not been allocated. - // This value is never returned by GetShaderVisibleHeapsSerial() after Initialize(). - Serial mShaderVisibleHeapsSerial = 0; + // This value is never returned in the GPUDescriptorHeapAllocation after + // AllocateGPUDescriptors() is called. + Serial mHeapSerial = 0; - std::array mShaderVisibleBuffers; - std::array mSizeIncrements; + uint32_t mSizeIncrement; }; }} // namespace dawn_native::d3d12 diff --git a/src/tests/white_box/D3D12DescriptorHeapTests.cpp b/src/tests/white_box/D3D12DescriptorHeapTests.cpp index b996d0a199..bdb18c1425 100644 --- a/src/tests/white_box/D3D12DescriptorHeapTests.cpp +++ b/src/tests/white_box/D3D12DescriptorHeapTests.cpp @@ -75,11 +75,6 @@ class D3D12DescriptorHeapTests : public DawnTest { return utils::BasicRenderPass(width, height, color); } - uint32_t GetShaderVisibleHeapSize(D3D12_DESCRIPTOR_HEAP_TYPE heapType) const { - return mD3DDevice->GetShaderVisibleDescriptorAllocator() - ->GetShaderVisibleHeapSizeForTesting(heapType); - } - std::array GetSolidColor(uint32_t n) const { ASSERT(n >> 24 == 0); float b = (n & 0xFF) / 255.0f; @@ -119,8 +114,8 @@ class DummyStagingDescriptorAllocator { StagingDescriptorAllocator mAllocator; }; -// Verify the shader visible heaps switch over within a single submit. -TEST_P(D3D12DescriptorHeapTests, SwitchOverHeaps) { +// Verify the shader visible sampler heap switch within a single submit. +TEST_P(D3D12DescriptorHeapTests, SwitchOverSamplerHeap) { utils::ComboRenderPipelineDescriptor renderPipelineDescriptor(device); // Fill in a sampler heap with "sampler only" bindgroups (1x sampler per group) by creating a @@ -147,11 +142,11 @@ TEST_P(D3D12DescriptorHeapTests, SwitchOverHeaps) { wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); Device* d3dDevice = reinterpret_cast(device.Get()); - ShaderVisibleDescriptorAllocator* allocator = d3dDevice->GetShaderVisibleDescriptorAllocator(); - const uint64_t samplerHeapSize = - allocator->GetShaderVisibleHeapSizeForTesting(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + ShaderVisibleDescriptorAllocator* allocator = + d3dDevice->GetSamplerShaderVisibleDescriptorAllocator(); + const uint64_t samplerHeapSize = allocator->GetShaderVisibleHeapSizeForTesting(); - const Serial heapSerial = allocator->GetShaderVisibleHeapsSerial(); + const Serial heapSerial = allocator->GetShaderVisibleHeapSerialForTesting(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); { @@ -171,24 +166,22 @@ TEST_P(D3D12DescriptorHeapTests, SwitchOverHeaps) { wgpu::CommandBuffer commands = encoder.Finish(); queue.Submit(1, &commands); - EXPECT_EQ(allocator->GetShaderVisibleHeapsSerial(), heapSerial + 1); + EXPECT_EQ(allocator->GetShaderVisibleHeapSerialForTesting(), heapSerial + 1); } // Verify shader-visible heaps can be recycled for multiple submits. TEST_P(D3D12DescriptorHeapTests, PoolHeapsInMultipleSubmits) { - constexpr D3D12_DESCRIPTOR_HEAP_TYPE heapType = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; + ShaderVisibleDescriptorAllocator* allocator = + mD3DDevice->GetSamplerShaderVisibleDescriptorAllocator(); - ShaderVisibleDescriptorAllocator* allocator = mD3DDevice->GetShaderVisibleDescriptorAllocator(); + std::list> heaps = {allocator->GetShaderVisibleHeap()}; - std::list> heaps = { - allocator->GetShaderVisibleHeapForTesting(heapType)}; - - EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(heapType), 0u); + EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(), 0u); // Allocate + Tick() up to |kFrameDepth| and ensure heaps are always unique. for (uint32_t i = 0; i < kFrameDepth; i++) { - EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeaps().IsSuccess()); - ComPtr heap = allocator->GetShaderVisibleHeapForTesting(heapType); + EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeap().IsSuccess()); + ComPtr heap = allocator->GetShaderVisibleHeap(); EXPECT_TRUE(std::find(heaps.begin(), heaps.end(), heap) == heaps.end()); heaps.push_back(heap); mD3DDevice->Tick(); @@ -198,68 +191,66 @@ TEST_P(D3D12DescriptorHeapTests, PoolHeapsInMultipleSubmits) { // (oldest heaps are recycled first). The "+ 1" is so we also include the very first heap in the // check. for (uint32_t i = 0; i < kFrameDepth + 1; i++) { - EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeaps().IsSuccess()); - ComPtr heap = allocator->GetShaderVisibleHeapForTesting(heapType); + EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeap().IsSuccess()); + ComPtr heap = allocator->GetShaderVisibleHeap(); EXPECT_TRUE(heaps.front() == heap); heaps.pop_front(); mD3DDevice->Tick(); } EXPECT_TRUE(heaps.empty()); - EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(heapType), kFrameDepth); + EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(), kFrameDepth); } // Verify shader-visible heaps do not recycle in a pending submit. TEST_P(D3D12DescriptorHeapTests, PoolHeapsInPendingSubmit) { - constexpr D3D12_DESCRIPTOR_HEAP_TYPE heapType = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; constexpr uint32_t kNumOfSwitches = 5; - ShaderVisibleDescriptorAllocator* allocator = mD3DDevice->GetShaderVisibleDescriptorAllocator(); + ShaderVisibleDescriptorAllocator* allocator = + mD3DDevice->GetSamplerShaderVisibleDescriptorAllocator(); - const Serial heapSerial = allocator->GetShaderVisibleHeapsSerial(); + const Serial heapSerial = allocator->GetShaderVisibleHeapSerialForTesting(); - std::set> heaps = { - allocator->GetShaderVisibleHeapForTesting(heapType)}; + std::set> heaps = {allocator->GetShaderVisibleHeap()}; - EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(heapType), 0u); + EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(), 0u); // Switch-over |kNumOfSwitches| and ensure heaps are always unique. for (uint32_t i = 0; i < kNumOfSwitches; i++) { - EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeaps().IsSuccess()); - ComPtr heap = allocator->GetShaderVisibleHeapForTesting(heapType); + EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeap().IsSuccess()); + ComPtr heap = allocator->GetShaderVisibleHeap(); EXPECT_TRUE(std::find(heaps.begin(), heaps.end(), heap) == heaps.end()); heaps.insert(heap); } // After |kNumOfSwitches|, no heaps are recycled. - EXPECT_EQ(allocator->GetShaderVisibleHeapsSerial(), heapSerial + kNumOfSwitches); - EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(heapType), kNumOfSwitches); + EXPECT_EQ(allocator->GetShaderVisibleHeapSerialForTesting(), heapSerial + kNumOfSwitches); + EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(), kNumOfSwitches); } // Verify switching shader-visible heaps do not recycle in a pending submit but do so // once no longer pending. TEST_P(D3D12DescriptorHeapTests, PoolHeapsInPendingAndMultipleSubmits) { - constexpr D3D12_DESCRIPTOR_HEAP_TYPE heapType = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; constexpr uint32_t kNumOfSwitches = 5; - ShaderVisibleDescriptorAllocator* allocator = mD3DDevice->GetShaderVisibleDescriptorAllocator(); - const Serial heapSerial = allocator->GetShaderVisibleHeapsSerial(); + ShaderVisibleDescriptorAllocator* allocator = + mD3DDevice->GetSamplerShaderVisibleDescriptorAllocator(); + const Serial heapSerial = allocator->GetShaderVisibleHeapSerialForTesting(); - std::set> heaps = { - allocator->GetShaderVisibleHeapForTesting(heapType)}; + std::set> heaps = {allocator->GetShaderVisibleHeap()}; - EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(heapType), 0u); + EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(), 0u); // Switch-over |kNumOfSwitches| to create a pool of unique heaps. for (uint32_t i = 0; i < kNumOfSwitches; i++) { - EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeaps().IsSuccess()); - ComPtr heap = allocator->GetShaderVisibleHeapForTesting(heapType); + EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeap().IsSuccess()); + ComPtr heap = allocator->GetShaderVisibleHeap(); EXPECT_TRUE(std::find(heaps.begin(), heaps.end(), heap) == heaps.end()); heaps.insert(heap); } - EXPECT_EQ(allocator->GetShaderVisibleHeapsSerial(), heapSerial + kNumOfSwitches); - EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(heapType), kNumOfSwitches); + EXPECT_EQ(allocator->GetShaderVisibleHeapSerialForTesting(), heapSerial + kNumOfSwitches); + EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(), kNumOfSwitches); // Ensure switched-over heaps can be recycled by advancing the GPU by at-least |kFrameDepth|. for (uint32_t i = 0; i < kFrameDepth; i++) { @@ -268,15 +259,15 @@ TEST_P(D3D12DescriptorHeapTests, PoolHeapsInPendingAndMultipleSubmits) { // Switch-over |kNumOfSwitches| again reusing the same heaps. for (uint32_t i = 0; i < kNumOfSwitches; i++) { - EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeaps().IsSuccess()); - ComPtr heap = allocator->GetShaderVisibleHeapForTesting(heapType); + EXPECT_TRUE(allocator->AllocateAndSwitchShaderVisibleHeap().IsSuccess()); + ComPtr heap = allocator->GetShaderVisibleHeap(); EXPECT_TRUE(std::find(heaps.begin(), heaps.end(), heap) != heaps.end()); heaps.erase(heap); } // After switching-over |kNumOfSwitches| x 2, ensure no additional heaps exist. - EXPECT_EQ(allocator->GetShaderVisibleHeapsSerial(), heapSerial + kNumOfSwitches * 2); - EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(heapType), kNumOfSwitches); + EXPECT_EQ(allocator->GetShaderVisibleHeapSerialForTesting(), heapSerial + kNumOfSwitches * 2); + EXPECT_EQ(allocator->GetShaderVisiblePoolSizeForTesting(), kNumOfSwitches); } // Verify encoding multiple heaps worth of bindgroups. @@ -316,7 +307,8 @@ TEST_P(D3D12DescriptorHeapTests, EncodeManyUBO) { wgpu::RenderPipeline renderPipeline = device.CreateRenderPipeline(&pipelineDescriptor); - const uint32_t heapSize = GetShaderVisibleHeapSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + const uint32_t heapSize = + mD3DDevice->GetViewShaderVisibleDescriptorAllocator()->GetShaderVisibleHeapSizeForTesting(); constexpr uint32_t kNumOfHeaps = 2; @@ -398,7 +390,8 @@ TEST_P(D3D12DescriptorHeapTests, EncodeUBOOverflowMultipleSubmit) { // Encode a heap worth of descriptors. { - const uint32_t heapSize = GetShaderVisibleHeapSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + const uint32_t heapSize = mD3DDevice->GetSamplerShaderVisibleDescriptorAllocator() + ->GetShaderVisibleHeapSizeForTesting(); std::vector bindGroups; for (uint32_t i = 0; i < heapSize - 1; i++) { @@ -462,7 +455,8 @@ TEST_P(D3D12DescriptorHeapTests, EncodeReuseUBOOverflow) { std::vector bindGroups = {utils::MakeBindGroup( device, pipeline.GetBindGroupLayout(0), {{0, firstUniformBuffer, 0, sizeof(redColor)}})}; - const uint32_t heapSize = GetShaderVisibleHeapSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + const uint32_t heapSize = + mD3DDevice->GetViewShaderVisibleDescriptorAllocator()->GetShaderVisibleHeapSizeForTesting(); for (uint32_t i = 0; i < heapSize; i++) { const std::array& fillColor = GetSolidColor(i + 1); // Avoid black @@ -524,7 +518,8 @@ TEST_P(D3D12DescriptorHeapTests, EncodeReuseUBOMultipleSubmits) { std::vector bindGroups = {utils::MakeBindGroup( device, pipeline.GetBindGroupLayout(0), {{0, firstUniformBuffer, 0, sizeof(redColor)}})}; - const uint32_t heapSize = GetShaderVisibleHeapSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + const uint32_t heapSize = + mD3DDevice->GetViewShaderVisibleDescriptorAllocator()->GetShaderVisibleHeapSizeForTesting(); for (uint32_t i = 0; i < heapSize; i++) { std::array fillColor = GetSolidColor(i + 1); // Avoid black @@ -661,13 +656,16 @@ TEST_P(D3D12DescriptorHeapTests, EncodeManyUBOAndSamplers) { wgpu::SamplerDescriptor samplerDescriptor; wgpu::Sampler sampler = device.CreateSampler(&samplerDescriptor); - ShaderVisibleDescriptorAllocator* allocator = - mD3DDevice->GetShaderVisibleDescriptorAllocator(); + ShaderVisibleDescriptorAllocator* viewAllocator = + mD3DDevice->GetViewShaderVisibleDescriptorAllocator(); - const Serial heapSerial = allocator->GetShaderVisibleHeapsSerial(); + ShaderVisibleDescriptorAllocator* samplerAllocator = + mD3DDevice->GetSamplerShaderVisibleDescriptorAllocator(); - const uint32_t viewHeapSize = - GetShaderVisibleHeapSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + const Serial viewHeapSerial = viewAllocator->GetShaderVisibleHeapSerialForTesting(); + const Serial samplerHeapSerial = samplerAllocator->GetShaderVisibleHeapSerialForTesting(); + + const uint32_t viewHeapSize = viewAllocator->GetShaderVisibleHeapSizeForTesting(); // "Small" view heap is always 2 x sampler heap size and encodes 3x the descriptors per // group. This means the count of heaps switches is determined by the total number of views @@ -724,7 +722,17 @@ TEST_P(D3D12DescriptorHeapTests, EncodeManyUBOAndSamplers) { EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, 0, 0); EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, kRTSize - 1, 0); - EXPECT_EQ(allocator->GetShaderVisibleHeapsSerial(), heapSerial + kNumOfViewHeaps); + EXPECT_EQ(viewAllocator->GetShaderVisiblePoolSizeForTesting(), kNumOfViewHeaps); + EXPECT_EQ(viewAllocator->GetShaderVisibleHeapSerialForTesting(), + viewHeapSerial + kNumOfViewHeaps); + + const uint32_t numOfSamplerHeaps = + numOfEncodedBindGroups / + samplerAllocator->GetShaderVisibleHeapSizeForTesting(); // 1 sampler per group. + + EXPECT_EQ(samplerAllocator->GetShaderVisiblePoolSizeForTesting(), numOfSamplerHeaps); + EXPECT_EQ(samplerAllocator->GetShaderVisibleHeapSerialForTesting(), + samplerHeapSerial + numOfSamplerHeaps); } }