mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-13 10:51:35 +00:00
This was done with these two commands and a couple manual fixups for namespaces that had more than one space in the comment in the closing brace, as well as vulkan_platform.h git grep -l "namespace .* { namespace " | xargs sed -i "" "s/namespace \(.*\) { namespace /namespace \1::/" git grep -l "}} // namespace" | xargs sed -i "" "s%}} // namespace%} // namespace%" Bug: dawn:824 Change-Id: I6f448b820c12fc1004ea5270bf8e1f466b0c0aab Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/75400 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Loko Kung <lokokung@google.com> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
255 lines
11 KiB
C++
255 lines
11 KiB
C++
// 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"
|
|
#include "dawn_native/d3d12/GPUDescriptorHeapAllocationD3D12.h"
|
|
#include "dawn_native/d3d12/ResidencyManagerD3D12.h"
|
|
|
|
namespace dawn_native::d3d12 {
|
|
|
|
// Limits the min/max heap size to always be some known value for testing.
|
|
// Thresholds should be adjusted (lower == faster) to avoid tests taking too long to complete.
|
|
// We change the value from {1024, 512} to {32, 16} because we use blending
|
|
// for D3D12DescriptorHeapTests.EncodeManyUBO and R16Float has limited range
|
|
// and low precision at big integer.
|
|
static constexpr const uint32_t kShaderVisibleSmallHeapSizes[] = {32, 16};
|
|
|
|
uint32_t GetD3D12ShaderVisibleHeapMinSize(D3D12_DESCRIPTOR_HEAP_TYPE heapType,
|
|
bool useSmallSize) {
|
|
if (useSmallSize) {
|
|
return kShaderVisibleSmallHeapSizes[heapType];
|
|
}
|
|
|
|
// Minimum heap size must be large enough to satisfy the largest descriptor allocation
|
|
// request and to amortize the cost of sub-allocation. But small enough to avoid wasting
|
|
// memory should only a tiny fraction ever be used.
|
|
// TODO(dawn:155): Figure out these values.
|
|
switch (heapType) {
|
|
case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV:
|
|
return 4096;
|
|
case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER:
|
|
return 256;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
uint32_t GetD3D12ShaderVisibleHeapMaxSize(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();
|
|
}
|
|
}
|
|
|
|
// static
|
|
ResultOrError<std::unique_ptr<ShaderVisibleDescriptorAllocator>>
|
|
ShaderVisibleDescriptorAllocator::Create(Device* device, D3D12_DESCRIPTOR_HEAP_TYPE heapType) {
|
|
std::unique_ptr<ShaderVisibleDescriptorAllocator> allocator =
|
|
std::make_unique<ShaderVisibleDescriptorAllocator>(device, heapType);
|
|
DAWN_TRY(allocator->AllocateAndSwitchShaderVisibleHeap());
|
|
return std::move(allocator);
|
|
}
|
|
|
|
ShaderVisibleDescriptorAllocator::ShaderVisibleDescriptorAllocator(
|
|
Device* device,
|
|
D3D12_DESCRIPTOR_HEAP_TYPE heapType)
|
|
: mHeapType(heapType),
|
|
mDevice(device),
|
|
mSizeIncrement(device->GetD3D12Device()->GetDescriptorHandleIncrementSize(heapType)),
|
|
mDescriptorCount(GetD3D12ShaderVisibleHeapMinSize(
|
|
heapType,
|
|
mDevice->IsToggleEnabled(Toggle::UseD3D12SmallShaderVisibleHeapForTesting))) {
|
|
ASSERT(heapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ||
|
|
heapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
|
}
|
|
|
|
bool ShaderVisibleDescriptorAllocator::AllocateGPUDescriptors(
|
|
uint32_t descriptorCount,
|
|
ExecutionSerial pendingSerial,
|
|
D3D12_CPU_DESCRIPTOR_HANDLE* baseCPUDescriptor,
|
|
GPUDescriptorHeapAllocation* allocation) {
|
|
ASSERT(mHeap != nullptr);
|
|
const uint64_t startOffset = mAllocator.Allocate(descriptorCount, pendingSerial);
|
|
if (startOffset == RingBufferAllocator::kInvalidOffset) {
|
|
return false;
|
|
}
|
|
|
|
ID3D12DescriptorHeap* descriptorHeap = mHeap->GetD3D12DescriptorHeap();
|
|
|
|
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<size_t>::max() - cpuHeapStartPtr);
|
|
|
|
*baseCPUDescriptor = {cpuHeapStartPtr + static_cast<size_t>(heapOffset)};
|
|
|
|
const D3D12_GPU_DESCRIPTOR_HANDLE baseGPUDescriptor = {
|
|
descriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr + heapOffset};
|
|
|
|
// Record both the device and heap serials to determine later if the allocations are
|
|
// still valid.
|
|
*allocation = GPUDescriptorHeapAllocation{baseGPUDescriptor, pendingSerial, mHeapSerial};
|
|
|
|
return true;
|
|
}
|
|
|
|
ID3D12DescriptorHeap* ShaderVisibleDescriptorAllocator::GetShaderVisibleHeap() const {
|
|
return mHeap->GetD3D12DescriptorHeap();
|
|
}
|
|
|
|
void ShaderVisibleDescriptorAllocator::Tick(ExecutionSerial completedSerial) {
|
|
mAllocator.Deallocate(completedSerial);
|
|
}
|
|
|
|
ResultOrError<std::unique_ptr<ShaderVisibleDescriptorHeap>>
|
|
ShaderVisibleDescriptorAllocator::AllocateHeap(uint32_t descriptorCount) const {
|
|
// The size in bytes of a descriptor heap is best calculated by the increment size
|
|
// multiplied by the number of descriptors. In practice, this is only an estimate and
|
|
// the actual size may vary depending on the driver.
|
|
const uint64_t kSize = mSizeIncrement * descriptorCount;
|
|
|
|
DAWN_TRY(mDevice->GetResidencyManager()->EnsureCanAllocate(kSize, MemorySegment::Local));
|
|
|
|
ComPtr<ID3D12DescriptorHeap> d3d12DescriptorHeap;
|
|
D3D12_DESCRIPTOR_HEAP_DESC heapDescriptor;
|
|
heapDescriptor.Type = mHeapType;
|
|
heapDescriptor.NumDescriptors = descriptorCount;
|
|
heapDescriptor.Flags = GetD3D12HeapFlags(mHeapType);
|
|
heapDescriptor.NodeMask = 0;
|
|
DAWN_TRY(CheckOutOfMemoryHRESULT(mDevice->GetD3D12Device()->CreateDescriptorHeap(
|
|
&heapDescriptor, IID_PPV_ARGS(&d3d12DescriptorHeap)),
|
|
"ID3D12Device::CreateDescriptorHeap"));
|
|
|
|
std::unique_ptr<ShaderVisibleDescriptorHeap> descriptorHeap =
|
|
std::make_unique<ShaderVisibleDescriptorHeap>(std::move(d3d12DescriptorHeap), kSize);
|
|
|
|
// We must track the allocation in the LRU when it is created, otherwise the residency
|
|
// manager will see the allocation as non-resident in the later call to LockAllocation.
|
|
mDevice->GetResidencyManager()->TrackResidentAllocation(descriptorHeap.get());
|
|
|
|
return std::move(descriptorHeap);
|
|
}
|
|
|
|
// Creates a GPU descriptor heap that manages descriptors in a FIFO queue.
|
|
MaybeError ShaderVisibleDescriptorAllocator::AllocateAndSwitchShaderVisibleHeap() {
|
|
std::unique_ptr<ShaderVisibleDescriptorHeap> descriptorHeap;
|
|
// Dynamically allocate using a two-phase allocation strategy.
|
|
// The first phase increasingly grows a small heap in binary sizes for light users while the
|
|
// second phase pool-allocates largest sized heaps for heavy users.
|
|
if (mHeap != nullptr) {
|
|
mDevice->GetResidencyManager()->UnlockAllocation(mHeap.get());
|
|
|
|
const uint32_t maxDescriptorCount = GetD3D12ShaderVisibleHeapMaxSize(
|
|
mHeapType,
|
|
mDevice->IsToggleEnabled(Toggle::UseD3D12SmallShaderVisibleHeapForTesting));
|
|
if (mDescriptorCount < maxDescriptorCount) {
|
|
// Phase #1. Grow the heaps in powers-of-two.
|
|
mDevice->ReferenceUntilUnused(mHeap->GetD3D12DescriptorHeap());
|
|
mDescriptorCount = std::min(mDescriptorCount * 2, maxDescriptorCount);
|
|
} else {
|
|
// Phase #2. Pool-allocate heaps.
|
|
// 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.
|
|
mPool.push_back({mDevice->GetPendingCommandSerial(), std::move(mHeap)});
|
|
if (mPool.front().heapSerial <= mDevice->GetCompletedCommandSerial()) {
|
|
descriptorHeap = std::move(mPool.front().heap);
|
|
mPool.pop_front();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (descriptorHeap == nullptr) {
|
|
DAWN_TRY_ASSIGN(descriptorHeap, AllocateHeap(mDescriptorCount));
|
|
}
|
|
|
|
DAWN_TRY(mDevice->GetResidencyManager()->LockAllocation(descriptorHeap.get()));
|
|
|
|
// Create a FIFO buffer from the recently created heap.
|
|
mHeap = std::move(descriptorHeap);
|
|
mAllocator = RingBufferAllocator(mDescriptorCount);
|
|
|
|
// 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 {};
|
|
}
|
|
|
|
HeapVersionID ShaderVisibleDescriptorAllocator::GetShaderVisibleHeapSerialForTesting() const {
|
|
return mHeapSerial;
|
|
}
|
|
|
|
uint64_t ShaderVisibleDescriptorAllocator::GetShaderVisibleHeapSizeForTesting() const {
|
|
return mAllocator.GetSize();
|
|
}
|
|
|
|
uint64_t ShaderVisibleDescriptorAllocator::GetShaderVisiblePoolSizeForTesting() const {
|
|
return mPool.size();
|
|
}
|
|
|
|
bool ShaderVisibleDescriptorAllocator::IsShaderVisibleHeapLockedResidentForTesting() const {
|
|
return mHeap->IsResidencyLocked();
|
|
}
|
|
|
|
bool ShaderVisibleDescriptorAllocator::IsLastShaderVisibleHeapInLRUForTesting() const {
|
|
ASSERT(!mPool.empty());
|
|
return mPool.back().heap->IsInResidencyLRUCache();
|
|
}
|
|
|
|
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 (allocation.GetLastUsageSerial() > mDevice->GetCompletedCommandSerial() &&
|
|
allocation.GetHeapSerial() == mHeapSerial);
|
|
}
|
|
|
|
ShaderVisibleDescriptorHeap::ShaderVisibleDescriptorHeap(
|
|
ComPtr<ID3D12DescriptorHeap> d3d12DescriptorHeap,
|
|
uint64_t size)
|
|
: Pageable(d3d12DescriptorHeap, MemorySegment::Local, size),
|
|
mD3d12DescriptorHeap(std::move(d3d12DescriptorHeap)) {
|
|
}
|
|
|
|
ID3D12DescriptorHeap* ShaderVisibleDescriptorHeap::GetD3D12DescriptorHeap() const {
|
|
return mD3d12DescriptorHeap.Get();
|
|
}
|
|
} // namespace dawn_native::d3d12
|