Flutter Engine
The Flutter Engine
GrD3DResourceProvider.cpp
Go to the documentation of this file.
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
9
19
21 : fGpu(gpu)
22 , fCpuDescriptorManager(gpu)
23 , fDescriptorTableManager(gpu)
24 , fPipelineStateCache(new PipelineStateCache(gpu))
25 , fShaderResourceDescriptorTableCache(gpu)
26 , fSamplerDescriptorTableCache(gpu) {
27}
28
30 fSamplers.reset();
31
32 fPipelineStateCache->release();
33}
34
35std::unique_ptr<GrD3DDirectCommandList> GrD3DResourceProvider::findOrCreateDirectCommandList() {
36 if (fAvailableDirectCommandLists.size()) {
37 std::unique_ptr<GrD3DDirectCommandList> list =
38 std::move(fAvailableDirectCommandLists.back());
39 fAvailableDirectCommandLists.pop_back();
40 return list;
41 }
43}
44
46 std::unique_ptr<GrD3DDirectCommandList> commandList) {
47 commandList->reset();
48 fAvailableDirectCommandLists.push_back(std::move(commandList));
49}
50
52 int numUAVs) {
53 for (int i = 0; i < fRootSignatures.size(); ++i) {
54 if (fRootSignatures[i]->isCompatible(numTextureSamplers, numUAVs)) {
55 return fRootSignatures[i];
56 }
57 }
58
59 auto rootSig = GrD3DRootSignature::Make(fGpu, numTextureSamplers, numUAVs);
60 if (!rootSig) {
61 return nullptr;
62 }
63 fRootSignatures.push_back(rootSig);
64 return rootSig;
65}
66
68 GrD3DCommandSignature::ForIndexed indexed, unsigned int slot) {
69 for (int i = 0; i < fCommandSignatures.size(); ++i) {
70 if (fCommandSignatures[i]->isCompatible(indexed, slot)) {
71 return fCommandSignatures[i];
72 }
73 }
74
75 auto commandSig = GrD3DCommandSignature::Make(fGpu, indexed, slot);
76 if (!commandSig) {
77 return nullptr;
78 }
79 fCommandSignatures.push_back(commandSig);
80 return commandSig;
81}
82
84 ID3D12Resource* textureResource) {
85 return fCpuDescriptorManager.createRenderTargetView(fGpu, textureResource);
86}
87
89 const GrD3DDescriptorHeap::CPUHandle& rtvDescriptor) {
90 fCpuDescriptorManager.recycleRenderTargetView(rtvDescriptor);
91}
92
94 ID3D12Resource* textureResource) {
95 return fCpuDescriptorManager.createDepthStencilView(fGpu, textureResource);
96}
97
99 const GrD3DDescriptorHeap::CPUHandle& dsvDescriptor) {
100 fCpuDescriptorManager.recycleDepthStencilView(dsvDescriptor);
101}
102
104 ID3D12Resource* bufferResource, size_t offset, size_t size) {
105 return fCpuDescriptorManager.createConstantBufferView(fGpu, bufferResource, offset, size);
106}
107
109 ID3D12Resource* resource, unsigned int highestMip, unsigned int mipLevels) {
110 return fCpuDescriptorManager.createShaderResourceView(fGpu, resource, highestMip, mipLevels);
111}
112
114 ID3D12Resource* resource, unsigned int mipSlice) {
115 return fCpuDescriptorManager.createUnorderedAccessView(fGpu, resource, mipSlice);
116}
117
119 const GrD3DDescriptorHeap::CPUHandle& view) {
120 fCpuDescriptorManager.recycleShaderView(view);
121}
122
123static D3D12_TEXTURE_ADDRESS_MODE wrap_mode_to_d3d_address_mode(GrSamplerState::WrapMode wrapMode) {
124 switch (wrapMode) {
126 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
128 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
130 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
132 return D3D12_TEXTURE_ADDRESS_MODE_BORDER;
133 }
134 SK_ABORT("Unknown wrap mode.");
135}
136
137static D3D12_FILTER d3d_filter(GrSamplerState sampler) {
138 if (sampler.isAniso()) {
139 return D3D12_FILTER_ANISOTROPIC;
140 }
141 switch (sampler.mipmapMode()) {
142 // When the mode is kNone we disable filtering using maxLOD.
145 switch (sampler.filter()) {
146 case GrSamplerState::Filter::kNearest: return D3D12_FILTER_MIN_MAG_MIP_POINT;
147 case GrSamplerState::Filter::kLinear: return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
148 }
151 switch (sampler.filter()) {
152 case GrSamplerState::Filter::kNearest: return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
153 case GrSamplerState::Filter::kLinear: return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
154 }
156 }
158}
159
161 const GrSamplerState& params) {
162 // In D3D anisotropic filtering uses the same field (D3D12_SAMPLER_DESC::Filter) as min/mag/mip
163 // settings and so is not orthogonal to them.
164 uint32_t key = params.asKey(/*anisoIsOrthogonal=*/false);
165 D3D12_CPU_DESCRIPTOR_HANDLE* samplerPtr = fSamplers.find(key);
166 if (samplerPtr) {
167 return *samplerPtr;
168 }
169
170 D3D12_FILTER filter = d3d_filter(params);
171 // We disable MIP filtering using maxLOD. Otherwise, we want the max LOD to be unbounded.
172 float maxLOD =
174 D3D12_TEXTURE_ADDRESS_MODE addressModeU = wrap_mode_to_d3d_address_mode(params.wrapModeX());
175 D3D12_TEXTURE_ADDRESS_MODE addressModeV = wrap_mode_to_d3d_address_mode(params.wrapModeY());
176 unsigned int maxAnisotropy = params.maxAniso();
177 D3D12_CPU_DESCRIPTOR_HANDLE sampler =
178 fCpuDescriptorManager.createSampler(
179 fGpu, filter, maxLOD, maxAnisotropy, addressModeU, addressModeV).fHandle;
180 fSamplers.set(key, sampler);
181 return sampler;
182}
183
185 const std::vector<D3D12_CPU_DESCRIPTOR_HANDLE>& shaderViews) {
186
187 auto createFunc = [this](GrD3DGpu* gpu, unsigned int numDesc) {
188 return this->fDescriptorTableManager.createShaderViewTable(gpu, numDesc);
189 };
190 return fShaderResourceDescriptorTableCache.findOrCreateDescTable(shaderViews, createFunc);
191}
192
194 const std::vector<D3D12_CPU_DESCRIPTOR_HANDLE>& samplers) {
195 auto createFunc = [this](GrD3DGpu* gpu, unsigned int numDesc) {
196 return this->fDescriptorTableManager.createSamplerTable(gpu, numDesc);
197 };
198 return fShaderResourceDescriptorTableCache.findOrCreateDescTable(samplers, createFunc);
199}
200
203 return fPipelineStateCache->refPipelineState(rt, info);
204}
205
207 if (!fMipmapPipeline) {
208 // Note: filtering for non-even widths and heights samples at the 0.25 and 0.75
209 // locations and averages the result. As the initial samples are bilerped this is
210 // approximately a triangle filter. We should look into doing a better kernel but
211 // this should hold us for now.
212 const char* shader =
213 "SamplerState textureSampler : register(s0, space1);\n"
214 "Texture2D<float4> inputTexture : register(t1, space1);\n"
215 "RWTexture2D<float4> outUAV : register(u2, space1);\n"
216 "\n"
217 "cbuffer UniformBuffer : register(b0, space0) {\n"
218 " float2 inverseDims;\n"
219 " uint mipLevel;\n"
220 " uint sampleMode;\n"
221 "}\n"
222 "\n"
223 "[numthreads(8, 8, 1)]\n"
224 "void main(uint groupIndex : SV_GroupIndex, uint3 threadID : SV_DispatchThreadID) {\n"
225 " float2 uv = inverseDims * (threadID.xy + 0.5);\n"
226 " float4 mipVal;\n"
227 " switch (sampleMode) {\n"
228 " case 0: {\n"
229 " mipVal = inputTexture.SampleLevel(textureSampler, uv, mipLevel);\n"
230 " break;\n"
231 " }\n"
232 " case 1: {\n"
233 " float2 uvdiff = inverseDims * 0.25;\n"
234 " mipVal = inputTexture.SampleLevel(textureSampler, uv-uvdiff, mipLevel);\n"
235 " mipVal += inputTexture.SampleLevel(textureSampler, uv+uvdiff, mipLevel);\n"
236 " uvdiff.y = -uvdiff.y;\n"
237 " mipVal += inputTexture.SampleLevel(textureSampler, uv-uvdiff, mipLevel);\n"
238 " mipVal += inputTexture.SampleLevel(textureSampler, uv+uvdiff, mipLevel);\n"
239 " mipVal *= 0.25;\n"
240 " break;\n"
241 " }\n"
242 " case 2: {\n"
243 " float2 uvdiff = float2(inverseDims.x * 0.25, 0);\n"
244 " mipVal = inputTexture.SampleLevel(textureSampler, uv-uvdiff, mipLevel);\n"
245 " mipVal += inputTexture.SampleLevel(textureSampler, uv+uvdiff, mipLevel);\n"
246 " mipVal *= 0.5;\n"
247 " break;\n"
248 " }\n"
249 " case 3: {\n"
250 " float2 uvdiff = float2(0, inverseDims.y * 0.25);\n"
251 " mipVal = inputTexture.SampleLevel(textureSampler, uv-uvdiff, mipLevel);\n"
252 " mipVal += inputTexture.SampleLevel(textureSampler, uv+uvdiff, mipLevel);\n"
253 " mipVal *= 0.5;\n"
254 " break;\n"
255 " }\n"
256 " }\n"
257 "\n"
258 " outUAV[threadID.xy] = mipVal;\n"
259 "}\n";
260
262
263 fMipmapPipeline =
265 }
266
267 return fMipmapPipeline;
268}
269
270D3D12_GPU_VIRTUAL_ADDRESS GrD3DResourceProvider::uploadConstantData(void* data, size_t size) {
271 // constant size has to be aligned to 256
272 constexpr int kConstantAlignment = 256;
273
274 // upload the data
275 size_t paddedSize = SkAlignTo(size, kConstantAlignment);
276 GrRingBuffer::Slice slice = fGpu->uniformsRingBuffer()->suballocate(paddedSize);
277 char* destPtr = static_cast<char*>(slice.fBuffer->map()) + slice.fOffset;
278 memcpy(destPtr, data, size);
279
280 // create the associated constant buffer view descriptor
281 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer);
282 D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = d3dBuffer->d3dResource()->GetGPUVirtualAddress();
283 return gpuAddress + slice.fOffset;
284}
285
287 fDescriptorTableManager.prepForSubmit(fGpu);
288 // Any heap memory used for these will be returned when the command buffer finishes,
289 // so we have to invalidate all entries.
290 fShaderResourceDescriptorTableCache.release();
291 fSamplerDescriptorTableCache.release();
292}
293
294////////////////////////////////////////////////////////////////////////////////////////////////
295
296#ifdef GR_PIPELINE_STATE_CACHE_STATS
297// Display pipeline state cache usage
298static const bool c_DisplayMtlPipelineCache{false};
299#endif
300
302 Entry(GrD3DGpu* gpu, std::unique_ptr<GrD3DPipelineState> pipelineState)
303 : fGpu(gpu), fPipelineState(std::move(pipelineState)) {}
304
306 std::unique_ptr<GrD3DPipelineState> fPipelineState;
307};
308
309GrD3DResourceProvider::PipelineStateCache::PipelineStateCache(GrD3DGpu* gpu)
310 : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize)
311 , fGpu(gpu)
312#ifdef GR_PIPELINE_STATE_CACHE_STATS
313 , fTotalRequests(0)
314 , fCacheMisses(0)
315#endif
316{
317}
318
319GrD3DResourceProvider::PipelineStateCache::~PipelineStateCache() {
320 // dump stats
321#ifdef GR_PIPELINE_STATE_CACHE_STATS
322 if (c_DisplayMtlPipelineCache) {
323 SkDebugf("--- Pipeline State Cache ---\n");
324 SkDebugf("Total requests: %d\n", fTotalRequests);
325 SkDebugf("Cache misses: %d\n", fCacheMisses);
326 SkDebugf("Cache miss %%: %f\n",
327 (fTotalRequests > 0) ? 100.f * fCacheMisses / fTotalRequests : 0.f);
328 SkDebugf("---------------------\n");
329 }
330#endif
331}
332
333void GrD3DResourceProvider::PipelineStateCache::release() {
334 fMap.reset();
335}
336
337GrD3DPipelineState* GrD3DResourceProvider::PipelineStateCache::refPipelineState(
338 GrD3DRenderTarget* renderTarget, const GrProgramInfo& programInfo) {
339#ifdef GR_PIPELINE_STATE_CACHE_STATS
340 ++fTotalRequests;
341#endif
342
343 const GrCaps* caps = fGpu->caps();
344
345 GrProgramDesc desc = caps->makeDesc(renderTarget, programInfo);
346 if (!desc.isValid()) {
347 GrCapsDebugf(fGpu->caps(), "Failed to build mtl program descriptor!\n");
348 return nullptr;
349 }
350
351 std::unique_ptr<Entry>* entry = fMap.find(desc);
352 if (!entry) {
353#ifdef GR_PIPELINE_STATE_CACHE_STATS
354 ++fCacheMisses;
355#endif
356 std::unique_ptr<GrD3DPipelineState> pipelineState =
357 GrD3DPipelineStateBuilder::MakePipelineState(fGpu, renderTarget, desc, programInfo);
358 if (!pipelineState) {
359 return nullptr;
360 }
361 entry = fMap.insert(desc, std::unique_ptr<Entry>(
362 new Entry(fGpu, std::move(pipelineState))));
363 return ((*entry)->fPipelineState).get();
364 }
365 return ((*entry)->fPipelineState).get();
366}
367
368void GrD3DResourceProvider::PipelineStateCache::markPipelineStateUniformsDirty() {
369 fMap.foreach ([](const GrProgramDesc*, std::unique_ptr<Entry>* entry) {
370 (*entry)->fPipelineState->markUniformsDirty();
371 });
372}
373
374////////////////////////////////////////////////////////////////////////////////////////////////
375
376void GrD3DResourceProvider::DescriptorTableCache::release() {
377 fMap.reset();
378}
379
380sk_sp<GrD3DDescriptorTable> GrD3DResourceProvider::DescriptorTableCache::findOrCreateDescTable(
381 const std::vector<D3D12_CPU_DESCRIPTOR_HANDLE>& cpuDescriptors,
382 std::function<sk_sp<GrD3DDescriptorTable>(GrD3DGpu*, unsigned int numDesc)> createFunc) {
383 sk_sp<GrD3DDescriptorTable>* entry = fMap.find(cpuDescriptors);
384 if (entry) {
385 return *entry;
386 }
387
388 unsigned int numDescriptors = cpuDescriptors.size();
389 SkASSERT(numDescriptors <= kRangeSizesCount);
390 sk_sp<GrD3DDescriptorTable> descTable = createFunc(fGpu, numDescriptors);
391 fGpu->device()->CopyDescriptors(1, descTable->baseCpuDescriptorPtr(), &numDescriptors,
392 numDescriptors, cpuDescriptors.data(), fRangeSizes,
393 descTable->type());
394 entry = fMap.insert(cpuDescriptors, std::move(descTable));
395 return *entry;
396}
const char * options
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
constexpr int kConstantAlignment
Definition: GrD3DGpu.cpp:77
static D3D12_FILTER d3d_filter(GrSamplerState sampler)
static D3D12_TEXTURE_ADDRESS_MODE wrap_mode_to_d3d_address_mode(GrSamplerState::WrapMode wrapMode)
#define GrCapsDebugf(caps,...)
Definition: GrTypesPriv.h:490
static constexpr size_t SkAlignTo(size_t x, size_t alignment)
Definition: SkAlign.h:33
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static SkString resource(SkPDFResourceType type, int index)
Definition: GrCaps.h:57
virtual GrProgramDesc makeDesc(GrRenderTarget *, const GrProgramInfo &, ProgramDescOverrideFlags overrideFlags=ProgramDescOverrideFlags::kNone) const =0
ID3D12Resource * d3dResource() const
Definition: GrD3DBuffer.h:24
static sk_sp< GrD3DCommandSignature > Make(GrD3DGpu *gpu, ForIndexed indexed, unsigned int slot)
GrD3DDescriptorHeap::CPUHandle createUnorderedAccessView(GrD3DGpu *, ID3D12Resource *resource, unsigned int mipSlice)
void recycleRenderTargetView(const GrD3DDescriptorHeap::CPUHandle &)
GrD3DDescriptorHeap::CPUHandle createShaderResourceView(GrD3DGpu *, ID3D12Resource *resource, unsigned int mostDetailedMip, unsigned int mipLevels)
GrD3DDescriptorHeap::CPUHandle createDepthStencilView(GrD3DGpu *, ID3D12Resource *textureResource)
GrD3DDescriptorHeap::CPUHandle createConstantBufferView(GrD3DGpu *, ID3D12Resource *bufferResource, size_t offset, size_t size)
GrD3DDescriptorHeap::CPUHandle createSampler(GrD3DGpu *, D3D12_FILTER filter, float maxLOD, unsigned int maxAnisotropy, D3D12_TEXTURE_ADDRESS_MODE addressModeU, D3D12_TEXTURE_ADDRESS_MODE addressModeV)
void recycleDepthStencilView(const GrD3DDescriptorHeap::CPUHandle &)
void recycleShaderView(const GrD3DDescriptorHeap::CPUHandle &)
GrD3DDescriptorHeap::CPUHandle createRenderTargetView(GrD3DGpu *, ID3D12Resource *textureResource)
sk_sp< GrD3DDescriptorTable > createShaderViewTable(GrD3DGpu *, unsigned int count)
sk_sp< GrD3DDescriptorTable > createSamplerTable(GrD3DGpu *, unsigned int count)
static std::unique_ptr< GrD3DDirectCommandList > Make(GrD3DGpu *gpu)
GrRingBuffer * uniformsRingBuffer() override
Definition: GrD3DGpu.h:53
static sk_sp< GrD3DPipeline > MakeComputePipeline(GrD3DGpu *, GrD3DRootSignature *, const char *shader)
static std::unique_ptr< GrD3DPipelineState > MakePipelineState(GrD3DGpu *, GrD3DRenderTarget *, const GrProgramDesc &, const GrProgramInfo &)
void recycleDirectCommandList(std::unique_ptr< GrD3DDirectCommandList >)
GrD3DDescriptorHeap::CPUHandle createUnorderedAccessView(ID3D12Resource *resource, unsigned int mipSlice)
void recycleShaderView(const GrD3DDescriptorHeap::CPUHandle &)
GrD3DDescriptorHeap::CPUHandle createDepthStencilView(ID3D12Resource *textureResource)
sk_sp< GrD3DCommandSignature > findOrCreateCommandSignature(GrD3DCommandSignature::ForIndexed, unsigned int slot)
GrD3DDescriptorHeap::CPUHandle createShaderResourceView(ID3D12Resource *resource, unsigned int mostDetailedMip=0, unsigned int mipLevels=-1)
D3D12_GPU_VIRTUAL_ADDRESS uploadConstantData(void *data, size_t size)
sk_sp< GrD3DDescriptorTable > findOrCreateShaderViewTable(const std::vector< D3D12_CPU_DESCRIPTOR_HANDLE > &shaderViews)
GrD3DDescriptorHeap::CPUHandle createRenderTargetView(ID3D12Resource *textureResource)
D3D12_CPU_DESCRIPTOR_HANDLE findOrCreateCompatibleSampler(const GrSamplerState &params)
GrD3DDescriptorHeap::CPUHandle createConstantBufferView(ID3D12Resource *bufferResource, size_t offset, size_t size)
void recycleRenderTargetView(const GrD3DDescriptorHeap::CPUHandle &)
sk_sp< GrD3DPipeline > findOrCreateMipmapPipeline()
std::unique_ptr< GrD3DDirectCommandList > findOrCreateDirectCommandList()
sk_sp< GrD3DDescriptorTable > findOrCreateSamplerTable(const std::vector< D3D12_CPU_DESCRIPTOR_HANDLE > &samplers)
void recycleDepthStencilView(const GrD3DDescriptorHeap::CPUHandle &)
GrD3DPipelineState * findOrCreateCompatiblePipelineState(GrD3DRenderTarget *, const GrProgramInfo &)
sk_sp< GrD3DRootSignature > findOrCreateRootSignature(int numTextureSamplers, int numUAVs=0)
static sk_sp< GrD3DRootSignature > Make(GrD3DGpu *gpu, int numTextureSamplers, int numUAVs)
void * map()
Definition: GrGpuBuffer.cpp:28
Slice suballocate(size_t size)
bool isAniso() const
constexpr Filter filter() const
constexpr MipmapMode mipmapMode() const
T * get() const
Definition: SkRefCnt.h:303
int size() const
Definition: SkTArray.h:421
V * find(const K &key) const
Definition: SkTHash.h:494
V * set(K key, V val)
Definition: SkTHash.h:487
const EmbeddedViewParams * params
FlPixelBufferTexturePrivate * priv
Dart_NativeFunction function
Definition: fuchsia.cc:51
static float max(float r, float g, float b)
Definition: hsl.cpp:49
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: ref_ptr.h:256
SeparatedVector2 offset
D3D12_CPU_DESCRIPTOR_HANDLE fHandle
std::unique_ptr< GrD3DPipelineState > fPipelineState
Entry(GrD3DGpu *gpu, std::unique_ptr< GrD3DPipelineState > pipelineState)
GrGpuBuffer * fBuffer
Definition: GrRingBuffer.h:40
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63