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