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