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
31std::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
50GrD3DPipelineStateBuilder::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
60const GrCaps* GrD3DPipelineStateBuilder::caps() const {
61    return fGpu->caps();
62}
63
64SkSL::Compiler* GrD3DPipelineStateBuilder::shaderCompiler() const {
65    return fGpu->shaderCompiler();
66}
67
68void GrD3DPipelineStateBuilder::finalizeFragmentOutputColor(GrShaderVar& outputColor) {
69    outputColor.addLayoutQualifier("location = 0, index = 0");
70}
71
72void GrD3DPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {
73    outputColor.addLayoutQualifier("location = 0, index = 1");
74}
75
76// Print the source code for all shaders generated.
77static const bool gPrintSKSL = false;
78static const bool gPrintHLSL = false;
79
80static 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
115bool 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
136gr_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
177static 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
235static 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
276static 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
316static 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
338static 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
351static 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
380static 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
398static 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
420static 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
442static 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
450static 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
480static 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
497gr_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
558static constexpr SkFourByteTag kHLSL_Tag = SkSetFourByteTag('H', 'L', 'S', 'L');
559static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
560
561std::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
670sk_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