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/GrD3DCpuDescriptorManager.h"
9
10#include "src/gpu/d3d/GrD3DGpu.h"
11
12GrD3DCpuDescriptorManager::GrD3DCpuDescriptorManager(GrD3DGpu* gpu)
13    : fRTVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_RTV)
14    , fDSVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_DSV)
15    , fShaderViewDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
16    , fSamplerDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) {}
17
18GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createRenderTargetView(
19        GrD3DGpu* gpu, ID3D12Resource* textureResource) {
20    const GrD3DDescriptorHeap::CPUHandle& descriptor = fRTVDescriptorPool.allocateHandle(gpu);
21    gpu->device()->CreateRenderTargetView(textureResource, nullptr, descriptor.fHandle);
22    return descriptor;
23}
24
25void GrD3DCpuDescriptorManager::recycleRenderTargetView(
26        const GrD3DDescriptorHeap::CPUHandle& rtvDescriptor) {
27    fRTVDescriptorPool.releaseHandle(rtvDescriptor);
28}
29
30GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createDepthStencilView(
31        GrD3DGpu* gpu, ID3D12Resource* textureResource) {
32    const GrD3DDescriptorHeap::CPUHandle& descriptor = fDSVDescriptorPool.allocateHandle(gpu);
33    gpu->device()->CreateDepthStencilView(textureResource, nullptr, descriptor.fHandle);
34    return descriptor;
35}
36
37void GrD3DCpuDescriptorManager::recycleDepthStencilView(
38        const GrD3DDescriptorHeap::CPUHandle& dsvDescriptor) {
39    fDSVDescriptorPool.releaseHandle(dsvDescriptor);
40}
41
42GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createConstantBufferView(
43        GrD3DGpu* gpu, ID3D12Resource* bufferResource, size_t offset, size_t size) {
44    const GrD3DDescriptorHeap::CPUHandle& descriptor =
45            fShaderViewDescriptorPool.allocateHandle(gpu);
46    D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {};
47    desc.BufferLocation = bufferResource->GetGPUVirtualAddress() + offset;
48    desc.SizeInBytes = size;
49    gpu->device()->CreateConstantBufferView(&desc, descriptor.fHandle);
50    return descriptor;
51}
52
53GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createShaderResourceView(
54        GrD3DGpu* gpu, ID3D12Resource* resource,
55        unsigned int mostDetailedMip, unsigned int mipLevels) {
56    const GrD3DDescriptorHeap::CPUHandle& descriptor =
57            fShaderViewDescriptorPool.allocateHandle(gpu);
58    // TODO: for 4:2:0 YUV formats we'll need to map two different views, one for Y and one for UV.
59    // For now map the entire resource.
60    D3D12_SHADER_RESOURCE_VIEW_DESC desc = {};
61    desc.Format = resource->GetDesc().Format;
62    desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
63    desc.Texture2D.MostDetailedMip = mostDetailedMip;
64    desc.Texture2D.MipLevels = mipLevels;
65    desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
66    gpu->device()->CreateShaderResourceView(resource, &desc, descriptor.fHandle);
67    return descriptor;
68}
69
70GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createUnorderedAccessView(
71        GrD3DGpu* gpu, ID3D12Resource* resource, unsigned int mipSlice) {
72    const GrD3DDescriptorHeap::CPUHandle& descriptor =
73            fShaderViewDescriptorPool.allocateHandle(gpu);
74    if (resource->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) {
75        // TODO: figure out buffer setup
76        gpu->device()->CreateUnorderedAccessView(resource, nullptr, nullptr, descriptor.fHandle);
77    } else {
78        D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {};
79        desc.Format = resource->GetDesc().Format;
80        desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
81        desc.Texture2D.MipSlice = mipSlice;
82        gpu->device()->CreateUnorderedAccessView(resource, nullptr, &desc, descriptor.fHandle);
83    }
84    return descriptor;
85}
86
87void GrD3DCpuDescriptorManager::recycleShaderView(
88        const GrD3DDescriptorHeap::CPUHandle& view) {
89    fShaderViewDescriptorPool.releaseHandle(view);
90}
91
92GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createSampler(
93        GrD3DGpu* gpu,
94        D3D12_FILTER filter,
95        float maxLOD,
96        D3D12_TEXTURE_ADDRESS_MODE addressModeU,
97        D3D12_TEXTURE_ADDRESS_MODE addressModeV) {
98    const GrD3DDescriptorHeap::CPUHandle& descriptor = fSamplerDescriptorPool.allocateHandle(gpu);
99    D3D12_SAMPLER_DESC desc = {};
100    desc.Filter = filter;
101    desc.AddressU = addressModeU;
102    desc.AddressV = addressModeV;
103    desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
104    desc.MipLODBias = 0;
105    desc.MaxAnisotropy = 1;
106    desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
107    // desc.BorderColor initialized to { 0, 0, 0, 0 } by default initializer, above.
108    desc.MinLOD = 0;
109    desc.MaxLOD = maxLOD;
110
111    gpu->device()->CreateSampler(&desc, descriptor.fHandle);
112    return descriptor;
113}
114
115void GrD3DCpuDescriptorManager::recycleSampler(
116        const GrD3DDescriptorHeap::CPUHandle& samplerDescriptor) {
117    fSamplerDescriptorPool.releaseHandle(samplerDescriptor);
118}
119
120////////////////////////////////////////////////////////////////////////////////////////////////
121
122std::unique_ptr<GrD3DCpuDescriptorManager::Heap> GrD3DCpuDescriptorManager::Heap::Make(
123        GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, unsigned int numDescriptors) {
124    std::unique_ptr<GrD3DDescriptorHeap> heap =
125            GrD3DDescriptorHeap::Make(gpu, type, numDescriptors, D3D12_DESCRIPTOR_HEAP_FLAG_NONE);
126    if (!heap) {
127        return nullptr;
128    }
129
130    return std::unique_ptr<Heap>(new Heap(heap, numDescriptors));
131}
132
133GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::Heap::allocateCPUHandle() {
134    SkBitSet::OptionalIndex freeBlock = fFreeBlocks.findFirst();
135    SkASSERT(freeBlock.has_value());
136    fFreeBlocks.reset(*freeBlock);
137    --fFreeCount;
138    return fHeap->getCPUHandle(*freeBlock);
139}
140
141void GrD3DCpuDescriptorManager::Heap::freeCPUHandle(const GrD3DDescriptorHeap::CPUHandle& handle) {
142    SkASSERT(this->ownsHandle(handle));
143    size_t index = fHeap->getIndex(handle);
144    fFreeBlocks.set(index);
145    ++fFreeCount;
146}
147
148////////////////////////////////////////////////////////////////////////////////////////////////
149
150GrD3DCpuDescriptorManager::HeapPool::HeapPool(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE heapType)
151    : fMaxAvailableDescriptors(32)
152    , fHeapType(heapType) {
153    std::unique_ptr<GrD3DCpuDescriptorManager::Heap> heap =
154            GrD3DCpuDescriptorManager::Heap::Make(gpu, fHeapType, fMaxAvailableDescriptors);
155    fDescriptorHeaps.push_back(std::move(heap));
156}
157
158GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::HeapPool::allocateHandle(
159        GrD3DGpu* gpu) {
160    for (unsigned int i = 0; i < fDescriptorHeaps.size(); ++i) {
161        if (fDescriptorHeaps[i]->canAllocate()) {
162            GrD3DDescriptorHeap::CPUHandle handle = fDescriptorHeaps[i]->allocateCPUHandle();
163            return handle;
164        }
165    }
166
167    // need to allocate more space
168    std::unique_ptr<GrD3DCpuDescriptorManager::Heap> heap =
169            GrD3DCpuDescriptorManager::Heap::Make(gpu, fHeapType, fMaxAvailableDescriptors);
170    // TODO: handle failed heap creation and/or memory restrictions better
171    // skbug.com/11959
172    SkASSERT(heap);
173
174    fDescriptorHeaps.push_back(std::move(heap));
175    fMaxAvailableDescriptors *= 2;
176    GrD3DDescriptorHeap::CPUHandle handle =
177            fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateCPUHandle();
178    return handle;
179}
180
181void GrD3DCpuDescriptorManager::HeapPool::releaseHandle(
182        const GrD3DDescriptorHeap::CPUHandle& dsvDescriptor) {
183    for (unsigned int i = 0; i < fDescriptorHeaps.size(); ++i) {
184        if (fDescriptorHeaps[i]->ownsHandle(dsvDescriptor)) {
185            fDescriptorHeaps[i]->freeCPUHandle(dsvDescriptor);
186            return;
187        }
188    }
189    SkASSERT(false);
190}
191