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); } }