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