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