diff options
Diffstat (limited to 'chromium/third_party/dawn/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp')
-rw-r--r-- | chromium/third_party/dawn/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp new file mode 100644 index 00000000000..101ca4b190c --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp @@ -0,0 +1,206 @@ +// 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/ShaderVisibleDescriptorAllocatorD3D12.h" +#include "dawn_native/d3d12/D3D12Error.h" +#include "dawn_native/d3d12/DeviceD3D12.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}; + + uint32_t GetD3D12ShaderVisibleHeapSize(D3D12_DESCRIPTOR_HEAP_TYPE heapType, bool useSmallSize) { + if (useSmallSize) { + return kShaderVisibleSmallHeapSizes[heapType]; + } + + switch (heapType) { + case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: + return D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1; + case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: + return D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE; + default: + UNREACHABLE(); + } + } + + D3D12_DESCRIPTOR_HEAP_FLAGS GetD3D12HeapFlags(D3D12_DESCRIPTOR_HEAP_TYPE heapType) { + switch (heapType) { + case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: + case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: + return D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + default: + UNREACHABLE(); + } + } + + 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), + } { + } + + 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<DescriptorHeapAllocation> + ShaderVisibleDescriptorAllocator::AllocateGPUDescriptors(uint32_t descriptorCount, + Serial pendingSerial, + D3D12_DESCRIPTOR_HEAP_TYPE 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); + if (startOffset == RingBufferAllocator::kInvalidOffset) { + return DescriptorHeapAllocation{}; // Invalid + } + + ID3D12DescriptorHeap* descriptorHeap = mShaderVisibleBuffers[heapType].heap.Get(); + + D3D12_CPU_DESCRIPTOR_HANDLE baseCPUDescriptor = + descriptorHeap->GetCPUDescriptorHandleForHeapStart(); + baseCPUDescriptor.ptr += mSizeIncrements[heapType] * startOffset; + + D3D12_GPU_DESCRIPTOR_HANDLE baseGPUDescriptor = + descriptorHeap->GetGPUDescriptorHandleForHeapStart(); + baseGPUDescriptor.ptr += mSizeIncrements[heapType] * startOffset; + + return DescriptorHeapAllocation{mSizeIncrements[heapType], baseCPUDescriptor, + baseGPUDescriptor}; + } + + std::array<ID3D12DescriptorHeap*, 2> ShaderVisibleDescriptorAllocator::GetShaderVisibleHeaps() + const { + return {mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap.Get(), + mShaderVisibleBuffers[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER].heap.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); + } + } + + // Creates a GPU descriptor heap that manages descriptors in a FIFO queue. + MaybeError ShaderVisibleDescriptorAllocator::AllocateGPUHeap( + ShaderVisibleBuffer* shaderVisibleBuffer) { + ComPtr<ID3D12DescriptorHeap> 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)}); + } + + // 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(); + } + + 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)); + + if (heap == nullptr) { + D3D12_DESCRIPTOR_HEAP_DESC heapDescriptor; + heapDescriptor.Type = heapType; + heapDescriptor.NumDescriptors = descriptorCount; + heapDescriptor.Flags = GetD3D12HeapFlags(heapType); + heapDescriptor.NodeMask = 0; + DAWN_TRY(CheckOutOfMemoryHRESULT(mDevice->GetD3D12Device()->CreateDescriptorHeap( + &heapDescriptor, IID_PPV_ARGS(&heap)), + "ID3D12Device::CreateDescriptorHeap")); + } + + // Create a FIFO buffer from the recently created heap. + shaderVisibleBuffer->heap = std::move(heap); + shaderVisibleBuffer->allocator = RingBufferAllocator(descriptorCount); + return {}; + } + + Serial ShaderVisibleDescriptorAllocator::GetShaderVisibleHeapsSerial() const { + return mShaderVisibleHeapsSerial; + } + + 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(); + } + + ComPtr<ID3D12DescriptorHeap> 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( + 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 { + // Consider valid if allocated for the pending submit and the shader visible heaps + // have not switched over. + return (lastUsageSerial > mDevice->GetCompletedCommandSerial() && + heapSerial == mShaderVisibleHeapsSerial); + } +}} // namespace dawn_native::d3d12
\ No newline at end of file |