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/GrD3DResourceProvider.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/gpu/GrContextOptions.h"
11cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
12cb93a386Sopenharmony_ci#include "include/private/SkOpts_spi.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
14cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DBuffer.h"
15cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DCommandList.h"
16cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DGpu.h"
17cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DPipelineState.h"
18cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DPipelineStateBuilder.h"
19cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DRenderTarget.h"
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ciGrD3DResourceProvider::GrD3DResourceProvider(GrD3DGpu* gpu)
22cb93a386Sopenharmony_ci        : fGpu(gpu)
23cb93a386Sopenharmony_ci        , fCpuDescriptorManager(gpu)
24cb93a386Sopenharmony_ci        , fDescriptorTableManager(gpu)
25cb93a386Sopenharmony_ci        , fPipelineStateCache(new PipelineStateCache(gpu))
26cb93a386Sopenharmony_ci        , fShaderResourceDescriptorTableCache(gpu)
27cb93a386Sopenharmony_ci        , fSamplerDescriptorTableCache(gpu) {
28cb93a386Sopenharmony_ci}
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_civoid GrD3DResourceProvider::destroyResources() {
31cb93a386Sopenharmony_ci    fSamplers.reset();
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_ci    fPipelineStateCache->release();
34cb93a386Sopenharmony_ci}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_cistd::unique_ptr<GrD3DDirectCommandList> GrD3DResourceProvider::findOrCreateDirectCommandList() {
37cb93a386Sopenharmony_ci    if (fAvailableDirectCommandLists.count()) {
38cb93a386Sopenharmony_ci        std::unique_ptr<GrD3DDirectCommandList> list =
39cb93a386Sopenharmony_ci                std::move(fAvailableDirectCommandLists.back());
40cb93a386Sopenharmony_ci        fAvailableDirectCommandLists.pop_back();
41cb93a386Sopenharmony_ci        return list;
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci    return GrD3DDirectCommandList::Make(fGpu);
44cb93a386Sopenharmony_ci}
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_civoid GrD3DResourceProvider::recycleDirectCommandList(
47cb93a386Sopenharmony_ci        std::unique_ptr<GrD3DDirectCommandList> commandList) {
48cb93a386Sopenharmony_ci    commandList->reset();
49cb93a386Sopenharmony_ci    fAvailableDirectCommandLists.push_back(std::move(commandList));
50cb93a386Sopenharmony_ci}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_cisk_sp<GrD3DRootSignature> GrD3DResourceProvider::findOrCreateRootSignature(int numTextureSamplers,
53cb93a386Sopenharmony_ci                                                                           int numUAVs) {
54cb93a386Sopenharmony_ci    for (int i = 0; i < fRootSignatures.count(); ++i) {
55cb93a386Sopenharmony_ci        if (fRootSignatures[i]->isCompatible(numTextureSamplers, numUAVs)) {
56cb93a386Sopenharmony_ci            return fRootSignatures[i];
57cb93a386Sopenharmony_ci        }
58cb93a386Sopenharmony_ci    }
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ci    auto rootSig = GrD3DRootSignature::Make(fGpu, numTextureSamplers, numUAVs);
61cb93a386Sopenharmony_ci    if (!rootSig) {
62cb93a386Sopenharmony_ci        return nullptr;
63cb93a386Sopenharmony_ci    }
64cb93a386Sopenharmony_ci    fRootSignatures.push_back(rootSig);
65cb93a386Sopenharmony_ci    return rootSig;
66cb93a386Sopenharmony_ci}
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_cisk_sp<GrD3DCommandSignature> GrD3DResourceProvider::findOrCreateCommandSignature(
69cb93a386Sopenharmony_ci        GrD3DCommandSignature::ForIndexed indexed, unsigned int slot) {
70cb93a386Sopenharmony_ci    for (int i = 0; i < fCommandSignatures.count(); ++i) {
71cb93a386Sopenharmony_ci        if (fCommandSignatures[i]->isCompatible(indexed, slot)) {
72cb93a386Sopenharmony_ci            return fCommandSignatures[i];
73cb93a386Sopenharmony_ci        }
74cb93a386Sopenharmony_ci    }
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci    auto commandSig = GrD3DCommandSignature::Make(fGpu, indexed, slot);
77cb93a386Sopenharmony_ci    if (!commandSig) {
78cb93a386Sopenharmony_ci        return nullptr;
79cb93a386Sopenharmony_ci    }
80cb93a386Sopenharmony_ci    fCommandSignatures.push_back(commandSig);
81cb93a386Sopenharmony_ci    return commandSig;
82cb93a386Sopenharmony_ci}
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ciGrD3DDescriptorHeap::CPUHandle GrD3DResourceProvider::createRenderTargetView(
85cb93a386Sopenharmony_ci        ID3D12Resource* textureResource) {
86cb93a386Sopenharmony_ci    return fCpuDescriptorManager.createRenderTargetView(fGpu, textureResource);
87cb93a386Sopenharmony_ci}
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_civoid GrD3DResourceProvider::recycleRenderTargetView(
90cb93a386Sopenharmony_ci        const GrD3DDescriptorHeap::CPUHandle& rtvDescriptor) {
91cb93a386Sopenharmony_ci    fCpuDescriptorManager.recycleRenderTargetView(rtvDescriptor);
92cb93a386Sopenharmony_ci}
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ciGrD3DDescriptorHeap::CPUHandle GrD3DResourceProvider::createDepthStencilView(
95cb93a386Sopenharmony_ci        ID3D12Resource* textureResource) {
96cb93a386Sopenharmony_ci    return fCpuDescriptorManager.createDepthStencilView(fGpu, textureResource);
97cb93a386Sopenharmony_ci}
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_civoid GrD3DResourceProvider::recycleDepthStencilView(
100cb93a386Sopenharmony_ci        const GrD3DDescriptorHeap::CPUHandle& dsvDescriptor) {
101cb93a386Sopenharmony_ci    fCpuDescriptorManager.recycleDepthStencilView(dsvDescriptor);
102cb93a386Sopenharmony_ci}
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_ciGrD3DDescriptorHeap::CPUHandle GrD3DResourceProvider::createConstantBufferView(
105cb93a386Sopenharmony_ci        ID3D12Resource* bufferResource, size_t offset, size_t size) {
106cb93a386Sopenharmony_ci    return fCpuDescriptorManager.createConstantBufferView(fGpu, bufferResource, offset, size);
107cb93a386Sopenharmony_ci}
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ciGrD3DDescriptorHeap::CPUHandle GrD3DResourceProvider::createShaderResourceView(
110cb93a386Sopenharmony_ci        ID3D12Resource* resource, unsigned int highestMip, unsigned int mipLevels) {
111cb93a386Sopenharmony_ci    return fCpuDescriptorManager.createShaderResourceView(fGpu, resource, highestMip, mipLevels);
112cb93a386Sopenharmony_ci}
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_ciGrD3DDescriptorHeap::CPUHandle GrD3DResourceProvider::createUnorderedAccessView(
115cb93a386Sopenharmony_ci        ID3D12Resource* resource, unsigned int mipSlice) {
116cb93a386Sopenharmony_ci    return fCpuDescriptorManager.createUnorderedAccessView(fGpu, resource, mipSlice);
117cb93a386Sopenharmony_ci}
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_civoid GrD3DResourceProvider::recycleShaderView(
120cb93a386Sopenharmony_ci        const GrD3DDescriptorHeap::CPUHandle& view) {
121cb93a386Sopenharmony_ci    fCpuDescriptorManager.recycleShaderView(view);
122cb93a386Sopenharmony_ci}
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_cistatic D3D12_TEXTURE_ADDRESS_MODE wrap_mode_to_d3d_address_mode(GrSamplerState::WrapMode wrapMode) {
125cb93a386Sopenharmony_ci    switch (wrapMode) {
126cb93a386Sopenharmony_ci    case GrSamplerState::WrapMode::kClamp:
127cb93a386Sopenharmony_ci        return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
128cb93a386Sopenharmony_ci    case GrSamplerState::WrapMode::kRepeat:
129cb93a386Sopenharmony_ci        return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
130cb93a386Sopenharmony_ci    case GrSamplerState::WrapMode::kMirrorRepeat:
131cb93a386Sopenharmony_ci        return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
132cb93a386Sopenharmony_ci    case GrSamplerState::WrapMode::kClampToBorder:
133cb93a386Sopenharmony_ci        return D3D12_TEXTURE_ADDRESS_MODE_BORDER;
134cb93a386Sopenharmony_ci    }
135cb93a386Sopenharmony_ci    SK_ABORT("Unknown wrap mode.");
136cb93a386Sopenharmony_ci}
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_cistatic D3D12_FILTER d3d_filter(GrSamplerState sampler) {
139cb93a386Sopenharmony_ci    switch (sampler.mipmapMode()) {
140cb93a386Sopenharmony_ci        // When the mode is kNone we disable filtering using maxLOD.
141cb93a386Sopenharmony_ci        case GrSamplerState::MipmapMode::kNone:
142cb93a386Sopenharmony_ci        case GrSamplerState::MipmapMode::kNearest:
143cb93a386Sopenharmony_ci            switch (sampler.filter()) {
144cb93a386Sopenharmony_ci                case GrSamplerState::Filter::kNearest: return D3D12_FILTER_MIN_MAG_MIP_POINT;
145cb93a386Sopenharmony_ci                case GrSamplerState::Filter::kLinear:  return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
146cb93a386Sopenharmony_ci            }
147cb93a386Sopenharmony_ci            SkUNREACHABLE;
148cb93a386Sopenharmony_ci        case GrSamplerState::MipmapMode::kLinear:
149cb93a386Sopenharmony_ci            switch (sampler.filter()) {
150cb93a386Sopenharmony_ci                case GrSamplerState::Filter::kNearest: return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
151cb93a386Sopenharmony_ci                case GrSamplerState::Filter::kLinear:  return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
152cb93a386Sopenharmony_ci            }
153cb93a386Sopenharmony_ci            SkUNREACHABLE;
154cb93a386Sopenharmony_ci    }
155cb93a386Sopenharmony_ci    SkUNREACHABLE;
156cb93a386Sopenharmony_ci}
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ciD3D12_CPU_DESCRIPTOR_HANDLE GrD3DResourceProvider::findOrCreateCompatibleSampler(
159cb93a386Sopenharmony_ci        const GrSamplerState& params) {
160cb93a386Sopenharmony_ci    uint32_t key = params.asIndex();
161cb93a386Sopenharmony_ci    D3D12_CPU_DESCRIPTOR_HANDLE* samplerPtr = fSamplers.find(key);
162cb93a386Sopenharmony_ci    if (samplerPtr) {
163cb93a386Sopenharmony_ci        return *samplerPtr;
164cb93a386Sopenharmony_ci    }
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci    D3D12_FILTER filter = d3d_filter(params);
167cb93a386Sopenharmony_ci    // We disable MIP filtering using maxLOD. Otherwise, we want the max LOD to be unbounded.
168cb93a386Sopenharmony_ci    float maxLOD = params.mipmapped() == GrMipmapped::kYes ? std::numeric_limits<float>::max()
169cb93a386Sopenharmony_ci                                                           : 0.f;
170cb93a386Sopenharmony_ci    D3D12_TEXTURE_ADDRESS_MODE addressModeU = wrap_mode_to_d3d_address_mode(params.wrapModeX());
171cb93a386Sopenharmony_ci    D3D12_TEXTURE_ADDRESS_MODE addressModeV = wrap_mode_to_d3d_address_mode(params.wrapModeY());
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci    D3D12_CPU_DESCRIPTOR_HANDLE sampler =
174cb93a386Sopenharmony_ci            fCpuDescriptorManager.createSampler(
175cb93a386Sopenharmony_ci            fGpu, filter, maxLOD, addressModeU, addressModeV).fHandle;
176cb93a386Sopenharmony_ci    fSamplers.set(key, sampler);
177cb93a386Sopenharmony_ci    return sampler;
178cb93a386Sopenharmony_ci}
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_cisk_sp<GrD3DDescriptorTable> GrD3DResourceProvider::findOrCreateShaderViewTable(
181cb93a386Sopenharmony_ci    const std::vector<D3D12_CPU_DESCRIPTOR_HANDLE>& shaderViews) {
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_ci    auto createFunc = [this](GrD3DGpu* gpu, unsigned int numDesc) {
184cb93a386Sopenharmony_ci        return this->fDescriptorTableManager.createShaderViewTable(gpu, numDesc);
185cb93a386Sopenharmony_ci    };
186cb93a386Sopenharmony_ci    return fShaderResourceDescriptorTableCache.findOrCreateDescTable(shaderViews, createFunc);
187cb93a386Sopenharmony_ci}
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_cisk_sp<GrD3DDescriptorTable> GrD3DResourceProvider::findOrCreateSamplerTable(
190cb93a386Sopenharmony_ci        const std::vector<D3D12_CPU_DESCRIPTOR_HANDLE>& samplers) {
191cb93a386Sopenharmony_ci    auto createFunc = [this](GrD3DGpu* gpu, unsigned int numDesc) {
192cb93a386Sopenharmony_ci        return this->fDescriptorTableManager.createSamplerTable(gpu, numDesc);
193cb93a386Sopenharmony_ci    };
194cb93a386Sopenharmony_ci    return fShaderResourceDescriptorTableCache.findOrCreateDescTable(samplers, createFunc);
195cb93a386Sopenharmony_ci}
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ciGrD3DPipelineState* GrD3DResourceProvider::findOrCreateCompatiblePipelineState(
198cb93a386Sopenharmony_ci        GrD3DRenderTarget* rt, const GrProgramInfo& info) {
199cb93a386Sopenharmony_ci    return fPipelineStateCache->refPipelineState(rt, info);
200cb93a386Sopenharmony_ci}
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_cisk_sp<GrD3DPipeline> GrD3DResourceProvider::findOrCreateMipmapPipeline() {
203cb93a386Sopenharmony_ci    if (!fMipmapPipeline) {
204cb93a386Sopenharmony_ci        // Note: filtering for non-even widths and heights samples at the 0.25 and 0.75
205cb93a386Sopenharmony_ci        // locations and averages the result. As the initial samples are bilerped this is
206cb93a386Sopenharmony_ci        // approximately a triangle filter. We should look into doing a better kernel but
207cb93a386Sopenharmony_ci        // this should hold us for now.
208cb93a386Sopenharmony_ci        const char* shader =
209cb93a386Sopenharmony_ci            "SamplerState textureSampler : register(s0, space1);\n"
210cb93a386Sopenharmony_ci            "Texture2D<float4> inputTexture : register(t1, space1);\n"
211cb93a386Sopenharmony_ci            "RWTexture2D<float4> outUAV : register(u2, space1);\n"
212cb93a386Sopenharmony_ci            "\n"
213cb93a386Sopenharmony_ci            "cbuffer UniformBuffer : register(b0, space0) {\n"
214cb93a386Sopenharmony_ci            "    float2 inverseDims;\n"
215cb93a386Sopenharmony_ci            "    uint mipLevel;\n"
216cb93a386Sopenharmony_ci            "    uint sampleMode;\n"
217cb93a386Sopenharmony_ci            "}\n"
218cb93a386Sopenharmony_ci            "\n"
219cb93a386Sopenharmony_ci            "[numthreads(8, 8, 1)]\n"
220cb93a386Sopenharmony_ci            "void main(uint groupIndex : SV_GroupIndex, uint3 threadID : SV_DispatchThreadID) {\n"
221cb93a386Sopenharmony_ci            "    float2 uv = inverseDims * (threadID.xy + 0.5);\n"
222cb93a386Sopenharmony_ci            "    float4 mipVal;\n"
223cb93a386Sopenharmony_ci            "    switch (sampleMode) {\n"
224cb93a386Sopenharmony_ci            "        case 0: {\n"
225cb93a386Sopenharmony_ci            "            mipVal = inputTexture.SampleLevel(textureSampler, uv, mipLevel);\n"
226cb93a386Sopenharmony_ci            "            break;\n"
227cb93a386Sopenharmony_ci            "        }\n"
228cb93a386Sopenharmony_ci            "        case 1: {\n"
229cb93a386Sopenharmony_ci            "            float2 uvdiff = inverseDims * 0.25;\n"
230cb93a386Sopenharmony_ci            "            mipVal = inputTexture.SampleLevel(textureSampler, uv-uvdiff, mipLevel);\n"
231cb93a386Sopenharmony_ci            "            mipVal += inputTexture.SampleLevel(textureSampler, uv+uvdiff, mipLevel);\n"
232cb93a386Sopenharmony_ci            "            uvdiff.y = -uvdiff.y;\n"
233cb93a386Sopenharmony_ci            "            mipVal += inputTexture.SampleLevel(textureSampler, uv-uvdiff, mipLevel);\n"
234cb93a386Sopenharmony_ci            "            mipVal += inputTexture.SampleLevel(textureSampler, uv+uvdiff, mipLevel);\n"
235cb93a386Sopenharmony_ci            "            mipVal *= 0.25;\n"
236cb93a386Sopenharmony_ci            "            break;\n"
237cb93a386Sopenharmony_ci            "        }\n"
238cb93a386Sopenharmony_ci            "        case 2: {\n"
239cb93a386Sopenharmony_ci            "            float2 uvdiff = float2(inverseDims.x * 0.25, 0);\n"
240cb93a386Sopenharmony_ci            "            mipVal = inputTexture.SampleLevel(textureSampler, uv-uvdiff, mipLevel);\n"
241cb93a386Sopenharmony_ci            "            mipVal += inputTexture.SampleLevel(textureSampler, uv+uvdiff, mipLevel);\n"
242cb93a386Sopenharmony_ci            "            mipVal *= 0.5;\n"
243cb93a386Sopenharmony_ci            "            break;\n"
244cb93a386Sopenharmony_ci            "        }\n"
245cb93a386Sopenharmony_ci            "        case 3: {\n"
246cb93a386Sopenharmony_ci            "            float2 uvdiff = float2(0, inverseDims.y * 0.25);\n"
247cb93a386Sopenharmony_ci            "            mipVal = inputTexture.SampleLevel(textureSampler, uv-uvdiff, mipLevel);\n"
248cb93a386Sopenharmony_ci            "            mipVal += inputTexture.SampleLevel(textureSampler, uv+uvdiff, mipLevel);\n"
249cb93a386Sopenharmony_ci            "            mipVal *= 0.5;\n"
250cb93a386Sopenharmony_ci            "            break;\n"
251cb93a386Sopenharmony_ci            "        }\n"
252cb93a386Sopenharmony_ci            "    }\n"
253cb93a386Sopenharmony_ci            "\n"
254cb93a386Sopenharmony_ci            "    outUAV[threadID.xy] = mipVal;\n"
255cb93a386Sopenharmony_ci            "}\n";
256cb93a386Sopenharmony_ci
257cb93a386Sopenharmony_ci        sk_sp<GrD3DRootSignature> rootSig = this->findOrCreateRootSignature(1, 1);
258cb93a386Sopenharmony_ci
259cb93a386Sopenharmony_ci        fMipmapPipeline =
260cb93a386Sopenharmony_ci                GrD3DPipelineStateBuilder::MakeComputePipeline(fGpu, rootSig.get(), shader);
261cb93a386Sopenharmony_ci    }
262cb93a386Sopenharmony_ci
263cb93a386Sopenharmony_ci    return fMipmapPipeline;
264cb93a386Sopenharmony_ci}
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ciD3D12_GPU_VIRTUAL_ADDRESS GrD3DResourceProvider::uploadConstantData(void* data, size_t size) {
267cb93a386Sopenharmony_ci    // constant size has to be aligned to 256
268cb93a386Sopenharmony_ci    constexpr int kConstantAlignment = 256;
269cb93a386Sopenharmony_ci
270cb93a386Sopenharmony_ci    // upload the data
271cb93a386Sopenharmony_ci    size_t paddedSize = SkAlignTo(size, kConstantAlignment);
272cb93a386Sopenharmony_ci    GrRingBuffer::Slice slice = fGpu->uniformsRingBuffer()->suballocate(paddedSize);
273cb93a386Sopenharmony_ci    char* destPtr = static_cast<char*>(slice.fBuffer->map()) + slice.fOffset;
274cb93a386Sopenharmony_ci    memcpy(destPtr, data, size);
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ci    // create the associated constant buffer view descriptor
277cb93a386Sopenharmony_ci    GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer);
278cb93a386Sopenharmony_ci    D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = d3dBuffer->d3dResource()->GetGPUVirtualAddress();
279cb93a386Sopenharmony_ci    return gpuAddress + slice.fOffset;
280cb93a386Sopenharmony_ci}
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_civoid GrD3DResourceProvider::prepForSubmit() {
283cb93a386Sopenharmony_ci    fDescriptorTableManager.prepForSubmit(fGpu);
284cb93a386Sopenharmony_ci    // Any heap memory used for these will be returned when the command buffer finishes,
285cb93a386Sopenharmony_ci    // so we have to invalidate all entries.
286cb93a386Sopenharmony_ci    fShaderResourceDescriptorTableCache.release();
287cb93a386Sopenharmony_ci    fSamplerDescriptorTableCache.release();
288cb93a386Sopenharmony_ci}
289cb93a386Sopenharmony_ci
290cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////////////////////
291cb93a386Sopenharmony_ci
292cb93a386Sopenharmony_ci#ifdef GR_PIPELINE_STATE_CACHE_STATS
293cb93a386Sopenharmony_ci// Display pipeline state cache usage
294cb93a386Sopenharmony_cistatic const bool c_DisplayMtlPipelineCache{false};
295cb93a386Sopenharmony_ci#endif
296cb93a386Sopenharmony_ci
297cb93a386Sopenharmony_cistruct GrD3DResourceProvider::PipelineStateCache::Entry {
298cb93a386Sopenharmony_ci    Entry(GrD3DGpu* gpu, std::unique_ptr<GrD3DPipelineState> pipelineState)
299cb93a386Sopenharmony_ci            : fGpu(gpu), fPipelineState(std::move(pipelineState)) {}
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ci    GrD3DGpu* fGpu;
302cb93a386Sopenharmony_ci    std::unique_ptr<GrD3DPipelineState> fPipelineState;
303cb93a386Sopenharmony_ci};
304cb93a386Sopenharmony_ci
305cb93a386Sopenharmony_ciGrD3DResourceProvider::PipelineStateCache::PipelineStateCache(GrD3DGpu* gpu)
306cb93a386Sopenharmony_ci        : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize)
307cb93a386Sopenharmony_ci        , fGpu(gpu)
308cb93a386Sopenharmony_ci#ifdef GR_PIPELINE_STATE_CACHE_STATS
309cb93a386Sopenharmony_ci        , fTotalRequests(0)
310cb93a386Sopenharmony_ci        , fCacheMisses(0)
311cb93a386Sopenharmony_ci#endif
312cb93a386Sopenharmony_ci{
313cb93a386Sopenharmony_ci}
314cb93a386Sopenharmony_ci
315cb93a386Sopenharmony_ciGrD3DResourceProvider::PipelineStateCache::~PipelineStateCache() {
316cb93a386Sopenharmony_ci    // dump stats
317cb93a386Sopenharmony_ci#ifdef GR_PIPELINE_STATE_CACHE_STATS
318cb93a386Sopenharmony_ci    if (c_DisplayMtlPipelineCache) {
319cb93a386Sopenharmony_ci        SkDebugf("--- Pipeline State Cache ---\n");
320cb93a386Sopenharmony_ci        SkDebugf("Total requests: %d\n", fTotalRequests);
321cb93a386Sopenharmony_ci        SkDebugf("Cache misses: %d\n", fCacheMisses);
322cb93a386Sopenharmony_ci        SkDebugf("Cache miss %%: %f\n",
323cb93a386Sopenharmony_ci                 (fTotalRequests > 0) ? 100.f * fCacheMisses / fTotalRequests : 0.f);
324cb93a386Sopenharmony_ci        SkDebugf("---------------------\n");
325cb93a386Sopenharmony_ci    }
326cb93a386Sopenharmony_ci#endif
327cb93a386Sopenharmony_ci}
328cb93a386Sopenharmony_ci
329cb93a386Sopenharmony_civoid GrD3DResourceProvider::PipelineStateCache::release() {
330cb93a386Sopenharmony_ci    fMap.reset();
331cb93a386Sopenharmony_ci}
332cb93a386Sopenharmony_ci
333cb93a386Sopenharmony_ciGrD3DPipelineState* GrD3DResourceProvider::PipelineStateCache::refPipelineState(
334cb93a386Sopenharmony_ci        GrD3DRenderTarget* renderTarget, const GrProgramInfo& programInfo) {
335cb93a386Sopenharmony_ci#ifdef GR_PIPELINE_STATE_CACHE_STATS
336cb93a386Sopenharmony_ci    ++fTotalRequests;
337cb93a386Sopenharmony_ci#endif
338cb93a386Sopenharmony_ci
339cb93a386Sopenharmony_ci    const GrCaps* caps = fGpu->caps();
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci    GrProgramDesc desc = caps->makeDesc(renderTarget, programInfo);
342cb93a386Sopenharmony_ci    if (!desc.isValid()) {
343cb93a386Sopenharmony_ci        GrCapsDebugf(fGpu->caps(), "Failed to build mtl program descriptor!\n");
344cb93a386Sopenharmony_ci        return nullptr;
345cb93a386Sopenharmony_ci    }
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci    std::unique_ptr<Entry>* entry = fMap.find(desc);
348cb93a386Sopenharmony_ci    if (!entry) {
349cb93a386Sopenharmony_ci#ifdef GR_PIPELINE_STATE_CACHE_STATS
350cb93a386Sopenharmony_ci        ++fCacheMisses;
351cb93a386Sopenharmony_ci#endif
352cb93a386Sopenharmony_ci        std::unique_ptr<GrD3DPipelineState> pipelineState =
353cb93a386Sopenharmony_ci                GrD3DPipelineStateBuilder::MakePipelineState(fGpu, renderTarget, desc, programInfo);
354cb93a386Sopenharmony_ci        if (!pipelineState) {
355cb93a386Sopenharmony_ci            return nullptr;
356cb93a386Sopenharmony_ci        }
357cb93a386Sopenharmony_ci        entry = fMap.insert(desc, std::unique_ptr<Entry>(
358cb93a386Sopenharmony_ci                new Entry(fGpu, std::move(pipelineState))));
359cb93a386Sopenharmony_ci        return ((*entry)->fPipelineState).get();
360cb93a386Sopenharmony_ci    }
361cb93a386Sopenharmony_ci    return ((*entry)->fPipelineState).get();
362cb93a386Sopenharmony_ci}
363cb93a386Sopenharmony_ci
364cb93a386Sopenharmony_civoid GrD3DResourceProvider::PipelineStateCache::markPipelineStateUniformsDirty() {
365cb93a386Sopenharmony_ci    fMap.foreach ([](const GrProgramDesc*, std::unique_ptr<Entry>* entry) {
366cb93a386Sopenharmony_ci        (*entry)->fPipelineState->markUniformsDirty();
367cb93a386Sopenharmony_ci    });
368cb93a386Sopenharmony_ci}
369cb93a386Sopenharmony_ci
370cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////////////////////
371cb93a386Sopenharmony_ci
372cb93a386Sopenharmony_civoid GrD3DResourceProvider::DescriptorTableCache::release() {
373cb93a386Sopenharmony_ci    fMap.reset();
374cb93a386Sopenharmony_ci}
375cb93a386Sopenharmony_ci
376cb93a386Sopenharmony_cisk_sp<GrD3DDescriptorTable> GrD3DResourceProvider::DescriptorTableCache::findOrCreateDescTable(
377cb93a386Sopenharmony_ci        const std::vector<D3D12_CPU_DESCRIPTOR_HANDLE>& cpuDescriptors,
378cb93a386Sopenharmony_ci        std::function<sk_sp<GrD3DDescriptorTable>(GrD3DGpu*, unsigned int numDesc)> createFunc) {
379cb93a386Sopenharmony_ci    sk_sp<GrD3DDescriptorTable>* entry = fMap.find(cpuDescriptors);
380cb93a386Sopenharmony_ci    if (entry) {
381cb93a386Sopenharmony_ci        return *entry;
382cb93a386Sopenharmony_ci    }
383cb93a386Sopenharmony_ci
384cb93a386Sopenharmony_ci    unsigned int numDescriptors = cpuDescriptors.size();
385cb93a386Sopenharmony_ci    SkASSERT(numDescriptors <= kRangeSizesCount);
386cb93a386Sopenharmony_ci    sk_sp<GrD3DDescriptorTable> descTable = createFunc(fGpu, numDescriptors);
387cb93a386Sopenharmony_ci    fGpu->device()->CopyDescriptors(1, descTable->baseCpuDescriptorPtr(), &numDescriptors,
388cb93a386Sopenharmony_ci                                    numDescriptors, cpuDescriptors.data(), fRangeSizes,
389cb93a386Sopenharmony_ci                                    descTable->type());
390cb93a386Sopenharmony_ci    entry = fMap.insert(cpuDescriptors, std::move(descTable));
391cb93a386Sopenharmony_ci    return *entry;
392cb93a386Sopenharmony_ci}
393