1 /*
2 * Copyright 2020 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/d3d/GrD3DDescriptorTableManager.h"
9
10 #include "src/gpu/d3d/GrD3DGpu.h"
11
GrD3DDescriptorTableManager(GrD3DGpu * gpu)12 GrD3DDescriptorTableManager::GrD3DDescriptorTableManager(GrD3DGpu* gpu)
13 : fShaderViewDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
14 , fSamplerDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) {}
15
16 sk_sp<GrD3DDescriptorTable>
createShaderViewTable(GrD3DGpu * gpu,unsigned int size)17 GrD3DDescriptorTableManager::createShaderViewTable(GrD3DGpu* gpu, unsigned int size) {
18 sk_sp<GrD3DDescriptorTable> table = fShaderViewDescriptorPool.allocateTable(gpu, size);
19 this->setHeaps(gpu);
20 return table;
21 }
22
createSamplerTable(GrD3DGpu * gpu,unsigned int size)23 sk_sp<GrD3DDescriptorTable> GrD3DDescriptorTableManager::createSamplerTable(
24 GrD3DGpu* gpu, unsigned int size) {
25 sk_sp<GrD3DDescriptorTable> table = fSamplerDescriptorPool.allocateTable(gpu, size);
26 this->setHeaps(gpu);
27 return table;
28 }
29
setHeaps(GrD3DGpu * gpu)30 void GrD3DDescriptorTableManager::setHeaps(GrD3DGpu* gpu) {
31 sk_sp<Heap>& currentCBVSRVHeap = fShaderViewDescriptorPool.currentDescriptorHeap();
32 sk_sp<Heap>& currentSamplerHeap = fSamplerDescriptorPool.currentDescriptorHeap();
33 GrD3DDirectCommandList* commandList = gpu->currentCommandList();
34 commandList->setDescriptorHeaps(currentCBVSRVHeap,
35 currentCBVSRVHeap->d3dDescriptorHeap(),
36 currentSamplerHeap,
37 currentSamplerHeap->d3dDescriptorHeap());
38 }
39
prepForSubmit(GrD3DGpu * gpu)40 void GrD3DDescriptorTableManager::prepForSubmit(GrD3DGpu* gpu) {
41 fShaderViewDescriptorPool.prepForSubmit(gpu);
42 fSamplerDescriptorPool.prepForSubmit(gpu);
43 }
44
recycle(Heap * heap)45 void GrD3DDescriptorTableManager::recycle(Heap* heap) {
46 // wrap the heap in an sk_sp and take ownership of it
47 sk_sp<Heap> wrappedHeap(heap);
48
49 SkASSERT(heap);
50 switch (heap->type()) {
51 case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV:
52 fShaderViewDescriptorPool.recycle(std::move(wrappedHeap));
53 break;
54 case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER:
55 fSamplerDescriptorPool.recycle(std::move(wrappedHeap));
56 break;
57 default:
58 SkUNREACHABLE;
59 }
60 }
61
62 ////////////////////////////////////////////////////////////////////////////////////////////////
63
Make(GrD3DGpu * gpu,D3D12_DESCRIPTOR_HEAP_TYPE type,unsigned int descriptorCount)64 sk_sp<GrD3DDescriptorTableManager::Heap> GrD3DDescriptorTableManager::Heap::Make(
65 GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, unsigned int descriptorCount) {
66 std::unique_ptr<GrD3DDescriptorHeap> heap =
67 GrD3DDescriptorHeap::Make(gpu, type, descriptorCount,
68 D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
69 if (!heap) {
70 return nullptr;
71 }
72
73 return sk_sp< GrD3DDescriptorTableManager::Heap>(new Heap(gpu, heap, type, descriptorCount));
74 }
75
allocateTable(unsigned int count)76 sk_sp<GrD3DDescriptorTable> GrD3DDescriptorTableManager::Heap::allocateTable(
77 unsigned int count) {
78 SkASSERT(fDescriptorCount - fNextAvailable >= count);
79 unsigned int startIndex = fNextAvailable;
80 fNextAvailable += count;
81 return sk_sp<GrD3DDescriptorTable>(
82 new GrD3DDescriptorTable(fHeap->getCPUHandle(startIndex).fHandle,
83 fHeap->getGPUHandle(startIndex).fHandle, fType));
84 }
85
onRecycle() const86 void GrD3DDescriptorTableManager::Heap::onRecycle() const {
87 fGpu->resourceProvider().descriptorTableMgr()->recycle(const_cast<Heap*>(this));
88 }
89
90 ////////////////////////////////////////////////////////////////////////////////////////////////
91
HeapPool(GrD3DGpu * gpu,D3D12_DESCRIPTOR_HEAP_TYPE heapType)92 GrD3DDescriptorTableManager::HeapPool::HeapPool(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE heapType)
93 : fHeapType(heapType)
94 , fCurrentHeapDescriptorCount(kInitialHeapDescriptorCount) {
95 sk_sp<Heap> heap = Heap::Make(gpu, fHeapType, fCurrentHeapDescriptorCount);
96 fDescriptorHeaps.push_back(heap);
97 }
98
allocateTable(GrD3DGpu * gpu,unsigned int count)99 sk_sp<GrD3DDescriptorTable> GrD3DDescriptorTableManager::HeapPool::allocateTable(
100 GrD3DGpu* gpu, unsigned int count) {
101 // In back-to-front order, iterate through heaps until we find one we can allocate from.
102 // Any heap we can't allocate from gets removed from the list.
103 // If it was already used, it will have been added to the commandlist,
104 // and then later recycled back to us.
105 while (fDescriptorHeaps.size() > 0) {
106 if (fDescriptorHeaps[fDescriptorHeaps.size() - 1]->canAllocate(count)) {
107 return fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateTable(count);
108 }
109 // No space in current heap, pop off list
110 fDescriptorHeaps.pop_back();
111 }
112
113 // Out of available heaps, need to allocate a new one
114 fCurrentHeapDescriptorCount = std::min(2*fCurrentHeapDescriptorCount, 2048u);
115 sk_sp<GrD3DDescriptorTableManager::Heap> heap =
116 GrD3DDescriptorTableManager::Heap::Make(gpu, fHeapType, fCurrentHeapDescriptorCount);
117 fDescriptorHeaps.push_back(heap);
118 return fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateTable(count);
119 }
120
121 sk_sp<GrD3DDescriptorTableManager::Heap>&
currentDescriptorHeap()122 GrD3DDescriptorTableManager::HeapPool::currentDescriptorHeap() {
123 SkASSERT(fDescriptorHeaps.size() > 0);
124 return fDescriptorHeaps[fDescriptorHeaps.size() - 1];
125 }
126
prepForSubmit(GrD3DGpu * gpu)127 void GrD3DDescriptorTableManager::HeapPool::prepForSubmit(GrD3DGpu* gpu) {
128 // Pop off the current descriptor heap
129 if (fDescriptorHeaps[fDescriptorHeaps.size() - 1]->used()) {
130 fDescriptorHeaps.pop_back();
131 }
132
133 if (fDescriptorHeaps.size() == 0) {
134 fCurrentHeapDescriptorCount = std::min(fCurrentHeapDescriptorCount, 2048u);
135 sk_sp<GrD3DDescriptorTableManager::Heap> heap =
136 GrD3DDescriptorTableManager::Heap::Make(gpu, fHeapType, fCurrentHeapDescriptorCount);
137 fDescriptorHeaps.push_back(heap);
138 }
139 }
140
recycle(sk_sp<Heap> heap)141 void GrD3DDescriptorTableManager::HeapPool::recycle(sk_sp<Heap> heap) {
142 SkASSERT(heap);
143 // only add heaps back if they match our current size
144 // this purges any smaller heaps we no longer need
145 if (heap->descriptorCount() == fCurrentHeapDescriptorCount) {
146 heap->reset();
147 fDescriptorHeaps.push_back(heap);
148 }
149 }
150