Greg Daniel | 5fc5c81 | 2020-04-23 10:30:23 -0400 | [diff] [blame^] | 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/GrContext.h" |
| 13 | #include "include/gpu/d3d/GrD3DTypes.h" |
| 14 | #include "src/core/SkTraceEvent.h" |
| 15 | #include "src/gpu/GrAutoLocaleSetter.h" |
| 16 | #include "src/gpu/GrContextPriv.h" |
| 17 | #include "src/gpu/GrShaderCaps.h" |
| 18 | #include "src/gpu/GrShaderUtils.h" |
| 19 | #include "src/gpu/GrStencilSettings.h" |
| 20 | #include "src/gpu/d3d/GrD3DGpu.h" |
| 21 | #include "src/gpu/d3d/GrD3DRenderTarget.h" |
| 22 | #include "src/sksl/SkSLCompiler.h" |
| 23 | |
| 24 | #include <d3dcompiler.h> |
| 25 | |
| 26 | typedef size_t shader_size; |
| 27 | |
| 28 | std::unique_ptr<GrD3DPipelineState> GrD3DPipelineStateBuilder::CreatePipelineState( |
| 29 | GrD3DGpu* gpu, |
| 30 | GrRenderTarget* renderTarget, |
| 31 | const GrProgramDesc& desc, |
| 32 | const GrProgramInfo& programInfo) { |
| 33 | // ensure that we use "." as a decimal separator when creating SkSL code |
| 34 | GrAutoLocaleSetter als("C"); |
| 35 | |
| 36 | // create a builder. This will be handed off to effects so they can use it to add |
| 37 | // uniforms, varyings, textures, etc |
| 38 | GrD3DPipelineStateBuilder builder(gpu, renderTarget, desc, programInfo); |
| 39 | |
| 40 | if (!builder.emitAndInstallProcs()) { |
| 41 | return nullptr; |
| 42 | } |
| 43 | |
| 44 | return builder.finalize(); |
| 45 | } |
| 46 | |
| 47 | GrD3DPipelineStateBuilder::GrD3DPipelineStateBuilder(GrD3DGpu* gpu, |
| 48 | GrRenderTarget* renderTarget, |
| 49 | const GrProgramDesc& desc, |
| 50 | const GrProgramInfo& programInfo) |
| 51 | : INHERITED(renderTarget, desc, programInfo) |
| 52 | , fGpu(gpu) |
| 53 | , fVaryingHandler(this) |
| 54 | , fUniformHandler(this) {} |
| 55 | |
| 56 | const GrCaps* GrD3DPipelineStateBuilder::caps() const { |
| 57 | return fGpu->caps(); |
| 58 | } |
| 59 | |
| 60 | void GrD3DPipelineStateBuilder::finalizeFragmentOutputColor(GrShaderVar& outputColor) { |
| 61 | outputColor.addLayoutQualifier("location = 0, index = 0"); |
| 62 | } |
| 63 | |
| 64 | void GrD3DPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) { |
| 65 | outputColor.addLayoutQualifier("location = 0, index = 1"); |
| 66 | } |
| 67 | |
| 68 | void GrD3DPipelineStateBuilder::compileD3DProgram(SkSL::Program::Kind kind, |
| 69 | const SkSL::String& sksl, |
| 70 | const SkSL::Program::Settings& settings, |
| 71 | ID3DBlob** shader, |
| 72 | SkSL::Program::Inputs* outInputs) { |
| 73 | auto errorHandler = fGpu->getContext()->priv().getShaderErrorHandler(); |
| 74 | std::unique_ptr<SkSL::Program> program = fGpu->shaderCompiler()->convertProgram( |
| 75 | kind, sksl, settings); |
| 76 | if (!program) { |
| 77 | errorHandler->compileError(sksl.c_str(), |
| 78 | fGpu->shaderCompiler()->errorText().c_str()); |
| 79 | return; |
| 80 | } |
| 81 | *outInputs = program->fInputs; |
| 82 | SkSL::String outHLSL; |
| 83 | if (!fGpu->shaderCompiler()->toHLSL(*program, &outHLSL)) { |
| 84 | errorHandler->compileError(sksl.c_str(), |
| 85 | fGpu->shaderCompiler()->errorText().c_str()); |
| 86 | return; |
| 87 | } |
| 88 | |
| 89 | const char* compileTarget = nullptr; |
| 90 | switch (kind) { |
| 91 | case SkSL::Program::kVertex_Kind: |
| 92 | compileTarget = "vs_5_1"; |
| 93 | break; |
| 94 | case SkSL::Program::kGeometry_Kind: |
| 95 | compileTarget = "gs_5_1"; |
| 96 | break; |
| 97 | case SkSL::Program::kFragment_Kind: |
| 98 | compileTarget = "ps_5_1"; |
| 99 | break; |
| 100 | default: |
| 101 | SkUNREACHABLE; |
| 102 | } |
| 103 | |
| 104 | uint32_t compileFlags = 0; |
| 105 | #ifdef SK_DEBUG |
| 106 | // Enable better shader debugging with the graphics debugging tools. |
| 107 | compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; |
| 108 | #endif |
| 109 | // SPRIV-cross does matrix multiplication expecting row major matrices |
| 110 | compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR; |
| 111 | |
| 112 | // TODO: D3D Static Function |
| 113 | gr_cp<ID3DBlob> errors; |
| 114 | HRESULT hr = D3DCompile(outHLSL.c_str(), outHLSL.length(), nullptr, nullptr, nullptr, "main", |
| 115 | compileTarget, compileFlags, 0, shader, &errors); |
| 116 | if (!SUCCEEDED(hr)) { |
| 117 | errorHandler->compileError(outHLSL.c_str(), |
| 118 | reinterpret_cast<char*>(errors->GetBufferPointer())); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | std::unique_ptr<GrD3DPipelineState> GrD3DPipelineStateBuilder::finalize() { |
| 123 | TRACE_EVENT0("skia.gpu", TRACE_FUNC); |
| 124 | |
| 125 | // We need to enable the following extensions so that the compiler can correctly make spir-v |
| 126 | // from our glsl shaders. |
| 127 | fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n"); |
| 128 | fFS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n"); |
| 129 | fVS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n"); |
| 130 | fFS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n"); |
| 131 | |
| 132 | this->finalizeShaders(); |
| 133 | |
| 134 | SkSL::Program::Settings settings; |
| 135 | settings.fCaps = this->caps()->shaderCaps(); |
| 136 | settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin; |
| 137 | settings.fSharpenTextures = |
| 138 | this->gpu()->getContext()->priv().options().fSharpenMipmappedTextures; |
| 139 | settings.fRTHeightOffset = fUniformHandler.getRTHeightOffset(); |
| 140 | settings.fRTHeightBinding = 0; |
| 141 | settings.fRTHeightSet = 0; |
| 142 | |
| 143 | gr_cp<ID3DBlob> vertexShader; |
| 144 | gr_cp<ID3DBlob> geometryShader; |
| 145 | gr_cp<ID3DBlob> pixelShader; |
| 146 | SkSL::Program::Inputs vertInputs, fragInputs, geomInputs; |
| 147 | |
| 148 | this->compileD3DProgram(SkSL::Program::kVertex_Kind, fVS.fCompilerString, settings, |
| 149 | &vertexShader, &vertInputs); |
| 150 | this->compileD3DProgram(SkSL::Program::kFragment_Kind, fFS.fCompilerString, settings, |
| 151 | &pixelShader, &fragInputs); |
| 152 | |
| 153 | if (!vertexShader.get() || !pixelShader.get()) { |
| 154 | return nullptr; |
| 155 | } |
| 156 | |
| 157 | if (this->primitiveProcessor().willUseGeoShader()) { |
| 158 | this->compileD3DProgram(SkSL::Program::kGeometry_Kind, fGS.fCompilerString, settings, |
| 159 | &geometryShader, &geomInputs); |
| 160 | if (!geometryShader.get()) { |
| 161 | return nullptr; |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | gr_cp<ID3D12RootSignature> rootSignature; |
| 166 | |
| 167 | const GrD3DRenderTarget* rt = static_cast<const GrD3DRenderTarget*>(fRenderTarget); |
| 168 | return GrD3DPipelineState::Make(fGpu, fProgramInfo, std::move(rootSignature), |
| 169 | std::move(vertexShader), std::move(geometryShader), |
| 170 | std::move(pixelShader), rt->dxgiFormat(), |
| 171 | rt->stencilDxgiFormat(), rt->sampleQualityLevel()); |
| 172 | } |