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