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