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