• 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 <d3dcompiler.h>
9 
10 #include "src/gpu/d3d/GrD3DPipelineStateBuilder.h"
11 
12 #include "include/gpu/GrDirectContext.h"
13 #include "include/gpu/d3d/GrD3DTypes.h"
14 #include "src/core/SkReadBuffer.h"
15 #include "src/core/SkTraceEvent.h"
16 #include "src/gpu/GrAutoLocaleSetter.h"
17 #include "src/gpu/GrDirectContextPriv.h"
18 #include "src/gpu/GrPersistentCacheUtils.h"
19 #include "src/gpu/GrShaderCaps.h"
20 #include "src/gpu/GrShaderUtils.h"
21 #include "src/gpu/GrStencilSettings.h"
22 #include "src/gpu/d3d/GrD3DGpu.h"
23 #include "src/gpu/d3d/GrD3DPipeline.h"
24 #include "src/gpu/d3d/GrD3DRenderTarget.h"
25 #include "src/gpu/d3d/GrD3DRootSignature.h"
26 #include "src/gpu/d3d/GrD3DUtil.h"
27 #include "src/sksl/SkSLCompiler.h"
28 
29 #include <d3dcompiler.h>
30 
MakePipelineState(GrD3DGpu * gpu,GrD3DRenderTarget * renderTarget,const GrProgramDesc & desc,const GrProgramInfo & programInfo)31 std::unique_ptr<GrD3DPipelineState> GrD3DPipelineStateBuilder::MakePipelineState(
32         GrD3DGpu* gpu,
33         GrD3DRenderTarget* renderTarget,
34         const GrProgramDesc& desc,
35         const GrProgramInfo& programInfo) {
36     // ensure that we use "." as a decimal separator when creating SkSL code
37     GrAutoLocaleSetter als("C");
38 
39     // create a builder.  This will be handed off to effects so they can use it to add
40     // uniforms, varyings, textures, etc
41     GrD3DPipelineStateBuilder builder(gpu, renderTarget, desc, programInfo);
42 
43     if (!builder.emitAndInstallProcs()) {
44         return nullptr;
45     }
46 
47     return builder.finalize();
48 }
49 
GrD3DPipelineStateBuilder(GrD3DGpu * gpu,GrD3DRenderTarget * renderTarget,const GrProgramDesc & desc,const GrProgramInfo & programInfo)50 GrD3DPipelineStateBuilder::GrD3DPipelineStateBuilder(GrD3DGpu* gpu,
51                                                      GrD3DRenderTarget* renderTarget,
52                                                      const GrProgramDesc& desc,
53                                                      const GrProgramInfo& programInfo)
54         : INHERITED(desc, programInfo)
55         , fGpu(gpu)
56         , fVaryingHandler(this)
57         , fUniformHandler(this)
58         , fRenderTarget(renderTarget) {}
59 
caps() const60 const GrCaps* GrD3DPipelineStateBuilder::caps() const {
61     return fGpu->caps();
62 }
63 
shaderCompiler() const64 SkSL::Compiler* GrD3DPipelineStateBuilder::shaderCompiler() const {
65     return fGpu->shaderCompiler();
66 }
67 
finalizeFragmentOutputColor(GrShaderVar & outputColor)68 void GrD3DPipelineStateBuilder::finalizeFragmentOutputColor(GrShaderVar& outputColor) {
69     outputColor.addLayoutQualifier("location = 0, index = 0");
70 }
71 
finalizeFragmentSecondaryColor(GrShaderVar & outputColor)72 void GrD3DPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {
73     outputColor.addLayoutQualifier("location = 0, index = 1");
74 }
75 
76 // Print the source code for all shaders generated.
77 static const bool gPrintSKSL = false;
78 static const bool gPrintHLSL = false;
79 
GrCompileHLSLShader(GrD3DGpu * gpu,const SkSL::String & hlsl,SkSL::ProgramKind kind)80 static gr_cp<ID3DBlob> GrCompileHLSLShader(GrD3DGpu* gpu,
81                                            const SkSL::String& hlsl,
82                                            SkSL::ProgramKind kind) {
83     TRACE_EVENT0("skia.shaders", "driver_compile_shader");
84     const char* compileTarget = nullptr;
85     switch (kind) {
86         case SkSL::ProgramKind::kVertex:
87             compileTarget = "vs_5_1";
88             break;
89         case SkSL::ProgramKind::kFragment:
90             compileTarget = "ps_5_1";
91             break;
92         default:
93             SkUNREACHABLE;
94     }
95 
96     uint32_t compileFlags = 0;
97 #ifdef SK_DEBUG
98     // Enable better shader debugging with the graphics debugging tools.
99     compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
100 #endif
101     // SPRIV-cross does matrix multiplication expecting row major matrices
102     compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
103 
104     gr_cp<ID3DBlob> shader;
105     gr_cp<ID3DBlob> errors;
106     HRESULT hr = D3DCompile(hlsl.c_str(), hlsl.length(), nullptr, nullptr, nullptr, "main",
107                             compileTarget, compileFlags, 0, &shader, &errors);
108     if (!SUCCEEDED(hr)) {
109         gpu->getContext()->priv().getShaderErrorHandler()->compileError(
110                 hlsl.c_str(), reinterpret_cast<char*>(errors->GetBufferPointer()));
111     }
112     return shader;
113 }
114 
loadHLSLFromCache(SkReadBuffer * reader,gr_cp<ID3DBlob> shaders[])115 bool GrD3DPipelineStateBuilder::loadHLSLFromCache(SkReadBuffer* reader, gr_cp<ID3DBlob> shaders[]) {
116 
117     SkSL::String hlsl[kGrShaderTypeCount];
118     SkSL::Program::Inputs inputs[kGrShaderTypeCount];
119 
120     if (!GrPersistentCacheUtils::UnpackCachedShaders(reader, hlsl, inputs, kGrShaderTypeCount)) {
121         return false;
122     }
123 
124     auto compile = [&](SkSL::ProgramKind kind, GrShaderType shaderType) {
125         if (inputs[shaderType].fUseFlipRTUniform) {
126             this->addRTFlipUniform(SKSL_RTFLIP_NAME);
127         }
128         shaders[shaderType] = GrCompileHLSLShader(fGpu, hlsl[shaderType], kind);
129         return shaders[shaderType].get();
130     };
131 
132     return compile(SkSL::ProgramKind::kVertex, kVertex_GrShaderType) &&
133            compile(SkSL::ProgramKind::kFragment, kFragment_GrShaderType);
134 }
135 
compileD3DProgram(SkSL::ProgramKind kind,const SkSL::String & sksl,const SkSL::Program::Settings & settings,SkSL::Program::Inputs * outInputs,SkSL::String * outHLSL)136 gr_cp<ID3DBlob> GrD3DPipelineStateBuilder::compileD3DProgram(
137         SkSL::ProgramKind kind,
138         const SkSL::String& sksl,
139         const SkSL::Program::Settings& settings,
140         SkSL::Program::Inputs* outInputs,
141         SkSL::String* outHLSL) {
142 #ifdef SK_DEBUG
143     SkSL::String src = GrShaderUtils::PrettyPrint(sksl);
144 #else
145     const SkSL::String& src = sksl;
146 #endif
147 
148     std::unique_ptr<SkSL::Program> program = fGpu->shaderCompiler()->convertProgram(
149             kind, src, settings);
150     if (!program || !fGpu->shaderCompiler()->toHLSL(*program, outHLSL)) {
151         auto errorHandler = fGpu->getContext()->priv().getShaderErrorHandler();
152         errorHandler->compileError(src.c_str(),
153                                    fGpu->shaderCompiler()->errorText().c_str());
154         return gr_cp<ID3DBlob>();
155     }
156     *outInputs = program->fInputs;
157 
158     if (gPrintSKSL || gPrintHLSL) {
159         GrShaderUtils::PrintShaderBanner(kind);
160         if (gPrintSKSL) {
161             SkDebugf("SKSL:\n");
162             GrShaderUtils::PrintLineByLine(GrShaderUtils::PrettyPrint(sksl));
163         }
164         if (gPrintHLSL) {
165             SkDebugf("HLSL:\n");
166             GrShaderUtils::PrintLineByLine(GrShaderUtils::PrettyPrint(*outHLSL));
167         }
168     }
169 
170     if (program->fInputs.fUseFlipRTUniform) {
171         this->addRTFlipUniform(SKSL_RTFLIP_NAME);
172     }
173 
174     return GrCompileHLSLShader(fGpu, *outHLSL, kind);
175 }
176 
attrib_type_to_format(GrVertexAttribType type)177 static DXGI_FORMAT attrib_type_to_format(GrVertexAttribType type) {
178     switch (type) {
179     case kFloat_GrVertexAttribType:
180         return DXGI_FORMAT_R32_FLOAT;
181     case kFloat2_GrVertexAttribType:
182         return DXGI_FORMAT_R32G32_FLOAT;
183     case kFloat3_GrVertexAttribType:
184         return DXGI_FORMAT_R32G32B32_FLOAT;
185     case kFloat4_GrVertexAttribType:
186         return DXGI_FORMAT_R32G32B32A32_FLOAT;
187     case kHalf_GrVertexAttribType:
188         return DXGI_FORMAT_R16_FLOAT;
189     case kHalf2_GrVertexAttribType:
190         return DXGI_FORMAT_R16G16_FLOAT;
191     case kHalf4_GrVertexAttribType:
192         return DXGI_FORMAT_R16G16B16A16_FLOAT;
193     case kInt2_GrVertexAttribType:
194         return DXGI_FORMAT_R32G32_SINT;
195     case kInt3_GrVertexAttribType:
196         return DXGI_FORMAT_R32G32B32_SINT;
197     case kInt4_GrVertexAttribType:
198         return DXGI_FORMAT_R32G32B32A32_SINT;
199     case kByte_GrVertexAttribType:
200         return DXGI_FORMAT_R8_SINT;
201     case kByte2_GrVertexAttribType:
202         return DXGI_FORMAT_R8G8_SINT;
203     case kByte4_GrVertexAttribType:
204         return DXGI_FORMAT_R8G8B8A8_SINT;
205     case kUByte_GrVertexAttribType:
206         return DXGI_FORMAT_R8_UINT;
207     case kUByte2_GrVertexAttribType:
208         return DXGI_FORMAT_R8G8_UINT;
209     case kUByte4_GrVertexAttribType:
210         return DXGI_FORMAT_R8G8B8A8_UINT;
211     case kUByte_norm_GrVertexAttribType:
212         return DXGI_FORMAT_R8_UNORM;
213     case kUByte4_norm_GrVertexAttribType:
214         return DXGI_FORMAT_R8G8B8A8_UNORM;
215     case kShort2_GrVertexAttribType:
216         return DXGI_FORMAT_R16G16_SINT;
217     case kShort4_GrVertexAttribType:
218         return DXGI_FORMAT_R16G16B16A16_SINT;
219     case kUShort2_GrVertexAttribType:
220         return DXGI_FORMAT_R16G16_UINT;
221     case kUShort2_norm_GrVertexAttribType:
222         return DXGI_FORMAT_R16G16_UNORM;
223     case kInt_GrVertexAttribType:
224         return DXGI_FORMAT_R32_SINT;
225     case kUInt_GrVertexAttribType:
226         return DXGI_FORMAT_R32_UINT;
227     case kUShort_norm_GrVertexAttribType:
228         return DXGI_FORMAT_R16_UNORM;
229     case kUShort4_norm_GrVertexAttribType:
230         return DXGI_FORMAT_R16G16B16A16_UNORM;
231     }
232     SK_ABORT("Unknown vertex attrib type");
233 }
234 
setup_vertex_input_layout(const GrGeometryProcessor & geomProc,D3D12_INPUT_ELEMENT_DESC * inputElements)235 static void setup_vertex_input_layout(const GrGeometryProcessor& geomProc,
236                                       D3D12_INPUT_ELEMENT_DESC* inputElements) {
237     unsigned int slotNumber = 0;
238     unsigned int vertexSlot = 0;
239     unsigned int instanceSlot = 0;
240     if (geomProc.hasVertexAttributes()) {
241         vertexSlot = slotNumber++;
242     }
243     if (geomProc.hasInstanceAttributes()) {
244         instanceSlot = slotNumber++;
245     }
246 
247     unsigned int currentAttrib = 0;
248     unsigned int vertexAttributeOffset = 0;
249 
250     for (const auto& attrib : geomProc.vertexAttributes()) {
251         // When using SPIRV-Cross it converts the location modifier in SPIRV to be
252         // TEXCOORD<N> where N is the location value for eveery vertext attribute
253         inputElements[currentAttrib] = { "TEXCOORD", currentAttrib,
254                                         attrib_type_to_format(attrib.cpuType()),
255                                         vertexSlot, vertexAttributeOffset,
256                                         D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
257         vertexAttributeOffset += attrib.sizeAlign4();
258         currentAttrib++;
259     }
260     SkASSERT(vertexAttributeOffset == geomProc.vertexStride());
261 
262     unsigned int instanceAttributeOffset = 0;
263     for (const auto& attrib : geomProc.instanceAttributes()) {
264         // When using SPIRV-Cross it converts the location modifier in SPIRV to be
265         // TEXCOORD<N> where N is the location value for eveery vertext attribute
266         inputElements[currentAttrib] = { "TEXCOORD", currentAttrib,
267                                         attrib_type_to_format(attrib.cpuType()),
268                                         instanceSlot, instanceAttributeOffset,
269                                         D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 };
270         instanceAttributeOffset += attrib.sizeAlign4();
271         currentAttrib++;
272     }
273     SkASSERT(instanceAttributeOffset == geomProc.instanceStride());
274 }
275 
blend_coeff_to_d3d_blend(GrBlendCoeff coeff)276 static D3D12_BLEND blend_coeff_to_d3d_blend(GrBlendCoeff coeff) {
277     switch (coeff) {
278     case kZero_GrBlendCoeff:
279         return D3D12_BLEND_ZERO;
280     case kOne_GrBlendCoeff:
281         return D3D12_BLEND_ONE;
282     case kSC_GrBlendCoeff:
283         return D3D12_BLEND_SRC_COLOR;
284     case kISC_GrBlendCoeff:
285         return D3D12_BLEND_INV_SRC_COLOR;
286     case kDC_GrBlendCoeff:
287         return D3D12_BLEND_DEST_COLOR;
288     case kIDC_GrBlendCoeff:
289         return D3D12_BLEND_INV_DEST_COLOR;
290     case kSA_GrBlendCoeff:
291         return D3D12_BLEND_SRC_ALPHA;
292     case kISA_GrBlendCoeff:
293         return D3D12_BLEND_INV_SRC_ALPHA;
294     case kDA_GrBlendCoeff:
295         return D3D12_BLEND_DEST_ALPHA;
296     case kIDA_GrBlendCoeff:
297         return D3D12_BLEND_INV_DEST_ALPHA;
298     case kConstC_GrBlendCoeff:
299         return D3D12_BLEND_BLEND_FACTOR;
300     case kIConstC_GrBlendCoeff:
301         return D3D12_BLEND_INV_BLEND_FACTOR;
302     case kS2C_GrBlendCoeff:
303         return D3D12_BLEND_SRC1_COLOR;
304     case kIS2C_GrBlendCoeff:
305         return D3D12_BLEND_INV_SRC1_COLOR;
306     case kS2A_GrBlendCoeff:
307         return D3D12_BLEND_SRC1_ALPHA;
308     case kIS2A_GrBlendCoeff:
309         return D3D12_BLEND_INV_SRC1_ALPHA;
310     case kIllegal_GrBlendCoeff:
311         return D3D12_BLEND_ZERO;
312     }
313     SkUNREACHABLE;
314 }
315 
blend_coeff_to_d3d_blend_for_alpha(GrBlendCoeff coeff)316 static D3D12_BLEND blend_coeff_to_d3d_blend_for_alpha(GrBlendCoeff coeff) {
317     switch (coeff) {
318         // Force all srcColor used in alpha slot to alpha version.
319     case kSC_GrBlendCoeff:
320         return D3D12_BLEND_SRC_ALPHA;
321     case kISC_GrBlendCoeff:
322         return D3D12_BLEND_INV_SRC_ALPHA;
323     case kDC_GrBlendCoeff:
324         return D3D12_BLEND_DEST_ALPHA;
325     case kIDC_GrBlendCoeff:
326         return D3D12_BLEND_INV_DEST_ALPHA;
327     case kS2C_GrBlendCoeff:
328         return D3D12_BLEND_SRC1_ALPHA;
329     case kIS2C_GrBlendCoeff:
330         return D3D12_BLEND_INV_SRC1_ALPHA;
331 
332     default:
333         return blend_coeff_to_d3d_blend(coeff);
334     }
335 }
336 
337 
blend_equation_to_d3d_op(GrBlendEquation equation)338 static D3D12_BLEND_OP blend_equation_to_d3d_op(GrBlendEquation equation) {
339     switch (equation) {
340     case kAdd_GrBlendEquation:
341         return D3D12_BLEND_OP_ADD;
342     case kSubtract_GrBlendEquation:
343         return D3D12_BLEND_OP_SUBTRACT;
344     case kReverseSubtract_GrBlendEquation:
345         return D3D12_BLEND_OP_REV_SUBTRACT;
346     default:
347         SkUNREACHABLE;
348     }
349 }
350 
fill_in_blend_state(const GrPipeline & pipeline,D3D12_BLEND_DESC * blendDesc)351 static void fill_in_blend_state(const GrPipeline& pipeline, D3D12_BLEND_DESC* blendDesc) {
352     blendDesc->AlphaToCoverageEnable = false;
353     blendDesc->IndependentBlendEnable = false;
354 
355     const GrXferProcessor::BlendInfo& blendInfo = pipeline.getXferProcessor().getBlendInfo();
356 
357     GrBlendEquation equation = blendInfo.fEquation;
358     GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
359     GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
360     bool blendOff = GrBlendShouldDisable(equation, srcCoeff, dstCoeff);
361 
362     auto& rtBlend = blendDesc->RenderTarget[0];
363     rtBlend.BlendEnable = !blendOff;
364     if (!blendOff) {
365         rtBlend.SrcBlend = blend_coeff_to_d3d_blend(srcCoeff);
366         rtBlend.DestBlend = blend_coeff_to_d3d_blend(dstCoeff);
367         rtBlend.BlendOp = blend_equation_to_d3d_op(equation);
368         rtBlend.SrcBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(srcCoeff);
369         rtBlend.DestBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(dstCoeff);
370         rtBlend.BlendOpAlpha = blend_equation_to_d3d_op(equation);
371     }
372 
373     if (!blendInfo.fWriteColor) {
374         rtBlend.RenderTargetWriteMask = 0;
375     } else {
376         rtBlend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
377     }
378 }
379 
fill_in_rasterizer_state(const GrPipeline & pipeline,bool multisampleEnable,const GrCaps * caps,D3D12_RASTERIZER_DESC * rasterizer)380 static void fill_in_rasterizer_state(const GrPipeline& pipeline,
381                                      bool multisampleEnable,
382                                      const GrCaps* caps,
383                                      D3D12_RASTERIZER_DESC* rasterizer) {
384     rasterizer->FillMode = (caps->wireframeMode() || pipeline.isWireframe()) ?
385         D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID;
386     rasterizer->CullMode = D3D12_CULL_MODE_NONE;
387     rasterizer->FrontCounterClockwise = true;
388     rasterizer->DepthBias = 0;
389     rasterizer->DepthBiasClamp = 0.0f;
390     rasterizer->SlopeScaledDepthBias = 0.0f;
391     rasterizer->DepthClipEnable = false;
392     rasterizer->MultisampleEnable = multisampleEnable;
393     rasterizer->AntialiasedLineEnable = false;
394     rasterizer->ForcedSampleCount = 0;
395     rasterizer->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
396 }
397 
stencil_op_to_d3d_op(GrStencilOp op)398 static D3D12_STENCIL_OP stencil_op_to_d3d_op(GrStencilOp op) {
399     switch (op) {
400     case GrStencilOp::kKeep:
401         return D3D12_STENCIL_OP_KEEP;
402     case GrStencilOp::kZero:
403         return D3D12_STENCIL_OP_ZERO;
404     case GrStencilOp::kReplace:
405         return D3D12_STENCIL_OP_REPLACE;
406     case GrStencilOp::kInvert:
407         return D3D12_STENCIL_OP_INVERT;
408     case GrStencilOp::kIncWrap:
409         return D3D12_STENCIL_OP_INCR;
410     case GrStencilOp::kDecWrap:
411         return D3D12_STENCIL_OP_DECR;
412     case GrStencilOp::kIncClamp:
413         return D3D12_STENCIL_OP_INCR_SAT;
414     case GrStencilOp::kDecClamp:
415         return D3D12_STENCIL_OP_DECR_SAT;
416     }
417     SkUNREACHABLE;
418 }
419 
stencil_test_to_d3d_func(GrStencilTest test)420 static D3D12_COMPARISON_FUNC stencil_test_to_d3d_func(GrStencilTest test) {
421     switch (test) {
422     case GrStencilTest::kAlways:
423         return D3D12_COMPARISON_FUNC_ALWAYS;
424     case GrStencilTest::kNever:
425         return D3D12_COMPARISON_FUNC_NEVER;
426     case GrStencilTest::kGreater:
427         return D3D12_COMPARISON_FUNC_GREATER;
428     case GrStencilTest::kGEqual:
429         return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
430     case GrStencilTest::kLess:
431         return D3D12_COMPARISON_FUNC_LESS;
432     case GrStencilTest::kLEqual:
433         return D3D12_COMPARISON_FUNC_LESS_EQUAL;
434     case GrStencilTest::kEqual:
435         return D3D12_COMPARISON_FUNC_EQUAL;
436     case GrStencilTest::kNotEqual:
437         return D3D12_COMPARISON_FUNC_NOT_EQUAL;
438     }
439     SkUNREACHABLE;
440 }
441 
setup_stencilop_desc(D3D12_DEPTH_STENCILOP_DESC * desc,const GrStencilSettings::Face & stencilFace)442 static void setup_stencilop_desc(D3D12_DEPTH_STENCILOP_DESC* desc,
443                                  const GrStencilSettings::Face& stencilFace) {
444     desc->StencilFailOp = stencil_op_to_d3d_op(stencilFace.fFailOp);
445     desc->StencilDepthFailOp = desc->StencilFailOp;
446     desc->StencilPassOp = stencil_op_to_d3d_op(stencilFace.fPassOp);
447     desc->StencilFunc = stencil_test_to_d3d_func(stencilFace.fTest);
448 }
449 
fill_in_depth_stencil_state(const GrProgramInfo & programInfo,D3D12_DEPTH_STENCIL_DESC * dsDesc)450 static void fill_in_depth_stencil_state(const GrProgramInfo& programInfo,
451                                         D3D12_DEPTH_STENCIL_DESC* dsDesc) {
452     GrStencilSettings stencilSettings = programInfo.nonGLStencilSettings();
453     GrSurfaceOrigin origin = programInfo.origin();
454 
455     dsDesc->DepthEnable = false;
456     dsDesc->DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
457     dsDesc->DepthFunc = D3D12_COMPARISON_FUNC_NEVER;
458     dsDesc->StencilEnable = !stencilSettings.isDisabled();
459     if (!stencilSettings.isDisabled()) {
460         if (stencilSettings.isTwoSided()) {
461             const auto& frontFace = stencilSettings.postOriginCCWFace(origin);
462             const auto& backFace = stencilSettings.postOriginCWFace(origin);
463 
464             SkASSERT(frontFace.fTestMask == backFace.fTestMask);
465             SkASSERT(frontFace.fWriteMask == backFace.fWriteMask);
466             dsDesc->StencilReadMask = frontFace.fTestMask;
467             dsDesc->StencilWriteMask = frontFace.fWriteMask;
468 
469             setup_stencilop_desc(&dsDesc->FrontFace, frontFace);
470             setup_stencilop_desc(&dsDesc->BackFace, backFace);
471         } else {
472             dsDesc->StencilReadMask = stencilSettings.singleSidedFace().fTestMask;
473             dsDesc->StencilWriteMask = stencilSettings.singleSidedFace().fWriteMask;
474             setup_stencilop_desc(&dsDesc->FrontFace, stencilSettings.singleSidedFace());
475             dsDesc->BackFace = dsDesc->FrontFace;
476         }
477     }
478 }
479 
gr_primitive_type_to_d3d(GrPrimitiveType primitiveType)480 static D3D12_PRIMITIVE_TOPOLOGY_TYPE gr_primitive_type_to_d3d(GrPrimitiveType primitiveType) {
481     switch (primitiveType) {
482         case GrPrimitiveType::kTriangles:
483         case GrPrimitiveType::kTriangleStrip: //fall through
484             return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
485         case GrPrimitiveType::kPoints:
486             return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
487         case GrPrimitiveType::kLines: // fall through
488         case GrPrimitiveType::kLineStrip:
489             return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
490         case GrPrimitiveType::kPatches: // fall through, unsupported
491         case GrPrimitiveType::kPath: // fall through, unsupported
492         default:
493             SkUNREACHABLE;
494     }
495 }
496 
create_pipeline_state(GrD3DGpu * gpu,const GrProgramInfo & programInfo,const sk_sp<GrD3DRootSignature> & rootSig,gr_cp<ID3DBlob> vertexShader,gr_cp<ID3DBlob> pixelShader,DXGI_FORMAT renderTargetFormat,DXGI_FORMAT depthStencilFormat,unsigned int sampleQualityPattern)497 gr_cp<ID3D12PipelineState> create_pipeline_state(
498         GrD3DGpu* gpu, const GrProgramInfo& programInfo, const sk_sp<GrD3DRootSignature>& rootSig,
499         gr_cp<ID3DBlob> vertexShader, gr_cp<ID3DBlob> pixelShader,
500         DXGI_FORMAT renderTargetFormat, DXGI_FORMAT depthStencilFormat,
501         unsigned int sampleQualityPattern) {
502     D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
503 
504     psoDesc.pRootSignature = rootSig->rootSignature();
505 
506     psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()),
507                    vertexShader->GetBufferSize() };
508     psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()),
509                    pixelShader->GetBufferSize() };
510 
511     psoDesc.StreamOutput = { nullptr, 0, nullptr, 0, 0 };
512 
513     fill_in_blend_state(programInfo.pipeline(), &psoDesc.BlendState);
514     psoDesc.SampleMask = UINT_MAX;
515 
516     fill_in_rasterizer_state(programInfo.pipeline(), programInfo.numSamples() > 1, gpu->caps(),
517                              &psoDesc.RasterizerState);
518 
519     fill_in_depth_stencil_state(programInfo, &psoDesc.DepthStencilState);
520 
521     unsigned int totalAttributeCnt = programInfo.geomProc().numVertexAttributes() +
522                                      programInfo.geomProc().numInstanceAttributes();
523     SkAutoSTArray<4, D3D12_INPUT_ELEMENT_DESC> inputElements(totalAttributeCnt);
524     setup_vertex_input_layout(programInfo.geomProc(), inputElements.get());
525 
526     psoDesc.InputLayout = { inputElements.get(), totalAttributeCnt };
527 
528     psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
529 
530     // This is for geometry or hull shader primitives
531     psoDesc.PrimitiveTopologyType = gr_primitive_type_to_d3d(programInfo.primitiveType());
532 
533     psoDesc.NumRenderTargets = 1;
534 
535     psoDesc.RTVFormats[0] = renderTargetFormat;
536 
537     psoDesc.DSVFormat = depthStencilFormat;
538 
539     unsigned int numSamples = programInfo.numSamples();
540     psoDesc.SampleDesc = { numSamples, sampleQualityPattern };
541 
542     // Only used for multi-adapter systems.
543     psoDesc.NodeMask = 0;
544 
545     psoDesc.CachedPSO = { nullptr, 0 };
546     psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
547 
548     gr_cp<ID3D12PipelineState> pipelineState;
549     {
550         TRACE_EVENT0("skia.shaders", "CreateGraphicsPipelineState");
551         GR_D3D_CALL_ERRCHECK(
552                 gpu->device()->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)));
553     }
554 
555     return pipelineState;
556 }
557 
558 static constexpr SkFourByteTag kHLSL_Tag = SkSetFourByteTag('H', 'L', 'S', 'L');
559 static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
560 
finalize()561 std::unique_ptr<GrD3DPipelineState> GrD3DPipelineStateBuilder::finalize() {
562     TRACE_EVENT0("skia.shaders", TRACE_FUNC);
563 
564     this->finalizeShaders();
565 
566     SkSL::Program::Settings settings;
567     settings.fSharpenTextures =
568         this->gpu()->getContext()->priv().options().fSharpenMipmappedTextures;
569     settings.fRTFlipOffset = fUniformHandler.getRTFlipOffset();
570     settings.fRTFlipBinding = 0;
571     settings.fRTFlipSet = 0;
572 
573     sk_sp<SkData> cached;
574     SkReadBuffer reader;
575     SkFourByteTag shaderType = 0;
576     auto persistentCache = fGpu->getContext()->priv().getPersistentCache();
577     if (persistentCache) {
578         // Shear off the D3D-specific portion of the Desc to get the persistent key. We only cache
579         // shader code, not entire pipelines.
580         sk_sp<SkData> key =
581                 SkData::MakeWithoutCopy(this->desc().asKey(), this->desc().initialKeyLength());
582         cached = persistentCache->load(*key);
583         if (cached) {
584             reader.setMemory(cached->data(), cached->size());
585             shaderType = GrPersistentCacheUtils::GetType(&reader);
586         }
587     }
588 
589     const GrGeometryProcessor& geomProc = this->geometryProcessor();
590     gr_cp<ID3DBlob> shaders[kGrShaderTypeCount];
591 
592     if (kHLSL_Tag == shaderType && this->loadHLSLFromCache(&reader, shaders)) {
593         // We successfully loaded and compiled HLSL
594     } else {
595         SkSL::Program::Inputs inputs[kGrShaderTypeCount];
596         SkSL::String* sksl[kGrShaderTypeCount] = {
597             &fVS.fCompilerString,
598             &fFS.fCompilerString,
599         };
600         SkSL::String cached_sksl[kGrShaderTypeCount];
601         SkSL::String hlsl[kGrShaderTypeCount];
602 
603         if (kSKSL_Tag == shaderType) {
604             if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs,
605                                                             kGrShaderTypeCount)) {
606                 for (int i = 0; i < kGrShaderTypeCount; ++i) {
607                     sksl[i] = &cached_sksl[i];
608                 }
609             }
610         }
611 
612         auto compile = [&](SkSL::ProgramKind kind, GrShaderType shaderType) {
613             shaders[shaderType] = this->compileD3DProgram(kind, *sksl[shaderType], settings,
614                                                           &inputs[shaderType], &hlsl[shaderType]);
615             return shaders[shaderType].get();
616         };
617 
618         if (!compile(SkSL::ProgramKind::kVertex, kVertex_GrShaderType) ||
619             !compile(SkSL::ProgramKind::kFragment, kFragment_GrShaderType)) {
620             return nullptr;
621         }
622 
623         if (persistentCache && !cached) {
624             const bool cacheSkSL = fGpu->getContext()->priv().options().fShaderCacheStrategy ==
625                                    GrContextOptions::ShaderCacheStrategy::kSkSL;
626             if (cacheSkSL) {
627                 // Replace the HLSL with formatted SkSL to be cached. This looks odd, but this is
628                 // the last time we're going to use these strings, so it's safe.
629                 for (int i = 0; i < kGrShaderTypeCount; ++i) {
630                     hlsl[i] = GrShaderUtils::PrettyPrint(*sksl[i]);
631                 }
632             }
633             sk_sp<SkData> key =
634                     SkData::MakeWithoutCopy(this->desc().asKey(), this->desc().initialKeyLength());
635             SkString description = GrProgramDesc::Describe(fProgramInfo, *this->caps());
636             sk_sp<SkData> data = GrPersistentCacheUtils::PackCachedShaders(
637                     cacheSkSL ? kSKSL_Tag : kHLSL_Tag, hlsl, inputs, kGrShaderTypeCount);
638             persistentCache->store(*key, *data, description);
639         }
640     }
641 
642     sk_sp<GrD3DRootSignature> rootSig =
643             fGpu->resourceProvider().findOrCreateRootSignature(fUniformHandler.fTextures.count());
644     if (!rootSig) {
645         return nullptr;
646     }
647 
648     const GrD3DRenderTarget* rt = static_cast<const GrD3DRenderTarget*>(fRenderTarget);
649     gr_cp<ID3D12PipelineState> pipelineState = create_pipeline_state(
650             fGpu, fProgramInfo, rootSig, std::move(shaders[kVertex_GrShaderType]),
651             std::move(shaders[kFragment_GrShaderType]),
652             rt->dxgiFormat(), rt->stencilDxgiFormat(), rt->sampleQualityPattern());
653     sk_sp<GrD3DPipeline> pipeline = GrD3DPipeline::Make(std::move(pipelineState));
654 
655     return std::unique_ptr<GrD3DPipelineState>(
656             new GrD3DPipelineState(std::move(pipeline),
657                                    std::move(rootSig),
658                                    fUniformHandles,
659                                    fUniformHandler.fUniforms,
660                                    fUniformHandler.fCurrentUBOOffset,
661                                    fUniformHandler.fSamplers.count(),
662                                    std::move(fGPImpl),
663                                    std::move(fXPImpl),
664                                    std::move(fFPImpls),
665                                    geomProc.vertexStride(),
666                                    geomProc.instanceStride()));
667 }
668 
669 
MakeComputePipeline(GrD3DGpu * gpu,GrD3DRootSignature * rootSig,const char * shader)670 sk_sp<GrD3DPipeline> GrD3DPipelineStateBuilder::MakeComputePipeline(GrD3DGpu* gpu,
671                                                                     GrD3DRootSignature* rootSig,
672                                                                     const char* shader) {
673     D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
674     psoDesc.pRootSignature = rootSig->rootSignature();
675 
676     // compile shader
677     gr_cp<ID3DBlob> shaderBlob;
678     {
679         TRACE_EVENT0("skia.shaders", "driver_compile_shader");
680         uint32_t compileFlags = 0;
681 #ifdef SK_DEBUG
682         // Enable better shader debugging with the graphics debugging tools.
683         compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
684 #endif
685 
686         gr_cp<ID3DBlob> errors;
687         HRESULT hr = D3DCompile(shader, strlen(shader), nullptr, nullptr, nullptr, "main",
688                                 "cs_5_1", compileFlags, 0, &shaderBlob, &errors);
689         if (!SUCCEEDED(hr)) {
690             gpu->getContext()->priv().getShaderErrorHandler()->compileError(
691                 shader, reinterpret_cast<char*>(errors->GetBufferPointer()));
692             return nullptr;
693         }
694         psoDesc.CS = { reinterpret_cast<UINT8*>(shaderBlob->GetBufferPointer()),
695                        shaderBlob->GetBufferSize() };
696     }
697 
698     // Only used for multi-adapter systems.
699     psoDesc.NodeMask = 0;
700 
701     psoDesc.CachedPSO = { nullptr, 0 };
702     psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
703 
704     gr_cp<ID3D12PipelineState> pipelineState;
705     {
706         TRACE_EVENT0("skia.shaders", "CreateComputePipelineState");
707         GR_D3D_CALL_ERRCHECK(
708             gpu->device()->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)));
709     }
710 
711     return GrD3DPipeline::Make(std::move(pipelineState));
712 }
713 
714