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