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