• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "common/Math.h"
16 
17 #include "dawn_native/d3d12/D3D12Error.h"
18 #include "dawn_native/d3d12/DeviceD3D12.h"
19 #include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h"
20 
21 namespace dawn_native { namespace d3d12 {
22 
StagingDescriptorAllocator(Device * device,uint32_t descriptorCount,uint32_t heapSize,D3D12_DESCRIPTOR_HEAP_TYPE heapType)23     StagingDescriptorAllocator::StagingDescriptorAllocator(Device* device,
24                                                            uint32_t descriptorCount,
25                                                            uint32_t heapSize,
26                                                            D3D12_DESCRIPTOR_HEAP_TYPE heapType)
27         : mDevice(device),
28           mSizeIncrement(device->GetD3D12Device()->GetDescriptorHandleIncrementSize(heapType)),
29           mBlockSize(descriptorCount * mSizeIncrement),
30           mHeapSize(RoundUp(heapSize, descriptorCount)),
31           mHeapType(heapType) {
32         ASSERT(descriptorCount <= heapSize);
33     }
34 
~StagingDescriptorAllocator()35     StagingDescriptorAllocator::~StagingDescriptorAllocator() {
36         const Index freeBlockIndicesSize = GetFreeBlockIndicesSize();
37         for (auto& buffer : mPool) {
38             ASSERT(buffer.freeBlockIndices.size() == freeBlockIndicesSize);
39         }
40         ASSERT(mAvailableHeaps.size() == mPool.size());
41     }
42 
43     ResultOrError<CPUDescriptorHeapAllocation>
AllocateCPUDescriptors()44     StagingDescriptorAllocator::AllocateCPUDescriptors() {
45         if (mAvailableHeaps.empty()) {
46             DAWN_TRY(AllocateCPUHeap());
47         }
48 
49         ASSERT(!mAvailableHeaps.empty());
50 
51         const uint32_t heapIndex = mAvailableHeaps.back();
52         NonShaderVisibleBuffer& buffer = mPool[heapIndex];
53 
54         ASSERT(!buffer.freeBlockIndices.empty());
55 
56         const Index blockIndex = buffer.freeBlockIndices.back();
57 
58         buffer.freeBlockIndices.pop_back();
59 
60         if (buffer.freeBlockIndices.empty()) {
61             mAvailableHeaps.pop_back();
62         }
63 
64         const D3D12_CPU_DESCRIPTOR_HANDLE baseCPUDescriptor = {
65             buffer.heap->GetCPUDescriptorHandleForHeapStart().ptr + (blockIndex * mBlockSize)};
66 
67         return CPUDescriptorHeapAllocation{baseCPUDescriptor, heapIndex};
68     }
69 
AllocateCPUHeap()70     MaybeError StagingDescriptorAllocator::AllocateCPUHeap() {
71         D3D12_DESCRIPTOR_HEAP_DESC heapDescriptor;
72         heapDescriptor.Type = mHeapType;
73         heapDescriptor.NumDescriptors = mHeapSize;
74         heapDescriptor.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
75         heapDescriptor.NodeMask = 0;
76 
77         ComPtr<ID3D12DescriptorHeap> heap;
78         DAWN_TRY(CheckHRESULT(
79             mDevice->GetD3D12Device()->CreateDescriptorHeap(&heapDescriptor, IID_PPV_ARGS(&heap)),
80             "ID3D12Device::CreateDescriptorHeap"));
81 
82         NonShaderVisibleBuffer newBuffer;
83         newBuffer.heap = std::move(heap);
84 
85         const Index freeBlockIndicesSize = GetFreeBlockIndicesSize();
86         newBuffer.freeBlockIndices.reserve(freeBlockIndicesSize);
87 
88         for (Index blockIndex = 0; blockIndex < freeBlockIndicesSize; blockIndex++) {
89             newBuffer.freeBlockIndices.push_back(blockIndex);
90         }
91 
92         mAvailableHeaps.push_back(mPool.size());
93         mPool.emplace_back(std::move(newBuffer));
94 
95         return {};
96     }
97 
Deallocate(CPUDescriptorHeapAllocation * allocation)98     void StagingDescriptorAllocator::Deallocate(CPUDescriptorHeapAllocation* allocation) {
99         ASSERT(allocation->IsValid());
100 
101         const uint32_t heapIndex = allocation->GetHeapIndex();
102 
103         ASSERT(heapIndex < mPool.size());
104 
105         // Insert the deallocated block back into the free-list. Order does not matter. However,
106         // having blocks be non-contigious could slow down future allocations due to poor cache
107         // locality.
108         // TODO(dawn:155): Consider more optimization.
109         std::vector<Index>& freeBlockIndices = mPool[heapIndex].freeBlockIndices;
110         if (freeBlockIndices.empty()) {
111             mAvailableHeaps.emplace_back(heapIndex);
112         }
113 
114         const D3D12_CPU_DESCRIPTOR_HANDLE heapStart =
115             mPool[heapIndex].heap->GetCPUDescriptorHandleForHeapStart();
116 
117         const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor = allocation->OffsetFrom(0, 0);
118 
119         const Index blockIndex = (baseDescriptor.ptr - heapStart.ptr) / mBlockSize;
120 
121         freeBlockIndices.emplace_back(blockIndex);
122 
123         // Invalidate the handle in case the developer accidentally uses it again.
124         allocation->Invalidate();
125     }
126 
GetSizeIncrement() const127     uint32_t StagingDescriptorAllocator::GetSizeIncrement() const {
128         return mSizeIncrement;
129     }
130 
GetFreeBlockIndicesSize() const131     StagingDescriptorAllocator::Index StagingDescriptorAllocator::GetFreeBlockIndicesSize() const {
132         return ((mHeapSize * mSizeIncrement) / mBlockSize);
133     }
134 
135     ResultOrError<CPUDescriptorHeapAllocation>
AllocateTransientCPUDescriptors()136     StagingDescriptorAllocator::AllocateTransientCPUDescriptors() {
137         CPUDescriptorHeapAllocation allocation;
138         DAWN_TRY_ASSIGN(allocation, AllocateCPUDescriptors());
139         mAllocationsToDelete.Enqueue(allocation, mDevice->GetPendingCommandSerial());
140         return allocation;
141     }
142 
Tick(ExecutionSerial completedSerial)143     void StagingDescriptorAllocator::Tick(ExecutionSerial completedSerial) {
144         for (CPUDescriptorHeapAllocation& allocation :
145              mAllocationsToDelete.IterateUpTo(completedSerial)) {
146             Deallocate(&allocation);
147         }
148 
149         mAllocationsToDelete.ClearUpTo(completedSerial);
150     }
151 
152 }}  // namespace dawn_native::d3d12
153