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