blob: f03858ec83232021e5f7a38fccf8c6efa1810267 [file] [log] [blame]
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
//#include <d3dcompiler.h>
#include "src/gpu/d3d/GrD3DPipelineStateBuilder.h"
#include "include/gpu/GrContext.h"
#include "include/gpu/d3d/GrD3DTypes.h"
#include "src/core/SkTraceEvent.h"
#include "src/gpu/GrAutoLocaleSetter.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrShaderCaps.h"
#include "src/gpu/GrShaderUtils.h"
#include "src/gpu/GrStencilSettings.h"
#include "src/gpu/d3d/GrD3DGpu.h"
#include "src/gpu/d3d/GrD3DRenderTarget.h"
#include "src/gpu/d3d/GrD3DRootSignature.h"
#include "src/sksl/SkSLCompiler.h"
#include <d3dcompiler.h>
typedef size_t shader_size;
sk_sp<GrD3DPipelineState> GrD3DPipelineStateBuilder::MakePipelineState(
GrD3DGpu* gpu,
GrRenderTarget* renderTarget,
const GrProgramDesc& desc,
const GrProgramInfo& programInfo) {
// ensure that we use "." as a decimal separator when creating SkSL code
GrAutoLocaleSetter als("C");
// create a builder. This will be handed off to effects so they can use it to add
// uniforms, varyings, textures, etc
GrD3DPipelineStateBuilder builder(gpu, renderTarget, desc, programInfo);
if (!builder.emitAndInstallProcs()) {
return nullptr;
}
return builder.finalize();
}
GrD3DPipelineStateBuilder::GrD3DPipelineStateBuilder(GrD3DGpu* gpu,
GrRenderTarget* renderTarget,
const GrProgramDesc& desc,
const GrProgramInfo& programInfo)
: INHERITED(renderTarget, desc, programInfo)
, fGpu(gpu)
, fVaryingHandler(this)
, fUniformHandler(this) {}
const GrCaps* GrD3DPipelineStateBuilder::caps() const {
return fGpu->caps();
}
void GrD3DPipelineStateBuilder::finalizeFragmentOutputColor(GrShaderVar& outputColor) {
outputColor.addLayoutQualifier("location = 0, index = 0");
}
void GrD3DPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {
outputColor.addLayoutQualifier("location = 0, index = 1");
}
void GrD3DPipelineStateBuilder::compileD3DProgram(SkSL::Program::Kind kind,
const SkSL::String& sksl,
const SkSL::Program::Settings& settings,
ID3DBlob** shader,
SkSL::Program::Inputs* outInputs) {
auto errorHandler = fGpu->getContext()->priv().getShaderErrorHandler();
std::unique_ptr<SkSL::Program> program = fGpu->shaderCompiler()->convertProgram(
kind, sksl, settings);
if (!program) {
errorHandler->compileError(sksl.c_str(),
fGpu->shaderCompiler()->errorText().c_str());
return;
}
*outInputs = program->fInputs;
SkSL::String outHLSL;
if (!fGpu->shaderCompiler()->toHLSL(*program, &outHLSL)) {
errorHandler->compileError(sksl.c_str(),
fGpu->shaderCompiler()->errorText().c_str());
return;
}
const char* compileTarget = nullptr;
switch (kind) {
case SkSL::Program::kVertex_Kind:
compileTarget = "vs_5_1";
break;
case SkSL::Program::kGeometry_Kind:
compileTarget = "gs_5_1";
break;
case SkSL::Program::kFragment_Kind:
compileTarget = "ps_5_1";
break;
default:
SkUNREACHABLE;
}
uint32_t compileFlags = 0;
#ifdef SK_DEBUG
// Enable better shader debugging with the graphics debugging tools.
compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
// SPRIV-cross does matrix multiplication expecting row major matrices
compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
// TODO: D3D Static Function
gr_cp<ID3DBlob> errors;
HRESULT hr = D3DCompile(outHLSL.c_str(), outHLSL.length(), nullptr, nullptr, nullptr, "main",
compileTarget, compileFlags, 0, shader, &errors);
if (!SUCCEEDED(hr)) {
errorHandler->compileError(outHLSL.c_str(),
reinterpret_cast<char*>(errors->GetBufferPointer()));
}
}
sk_sp<GrD3DPipelineState> GrD3DPipelineStateBuilder::finalize() {
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
// We need to enable the following extensions so that the compiler can correctly make spir-v
// from our glsl shaders.
fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
fFS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
fVS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
fFS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
this->finalizeShaders();
SkSL::Program::Settings settings;
settings.fCaps = this->caps()->shaderCaps();
settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin;
settings.fSharpenTextures =
this->gpu()->getContext()->priv().options().fSharpenMipmappedTextures;
settings.fRTHeightOffset = fUniformHandler.getRTHeightOffset();
settings.fRTHeightBinding = 0;
settings.fRTHeightSet = 0;
gr_cp<ID3DBlob> vertexShader;
gr_cp<ID3DBlob> geometryShader;
gr_cp<ID3DBlob> pixelShader;
SkSL::Program::Inputs vertInputs, fragInputs, geomInputs;
this->compileD3DProgram(SkSL::Program::kVertex_Kind, fVS.fCompilerString, settings,
&vertexShader, &vertInputs);
this->compileD3DProgram(SkSL::Program::kFragment_Kind, fFS.fCompilerString, settings,
&pixelShader, &fragInputs);
if (!vertexShader.get() || !pixelShader.get()) {
return nullptr;
}
if (this->primitiveProcessor().willUseGeoShader()) {
this->compileD3DProgram(SkSL::Program::kGeometry_Kind, fGS.fCompilerString, settings,
&geometryShader, &geomInputs);
if (!geometryShader.get()) {
return nullptr;
}
}
sk_sp<GrD3DRootSignature> rootSig =
fGpu->resourceProvider().findOrCreateRootSignature(fUniformHandler.fTextures.count());
if (!rootSig) {
return nullptr;
}
const GrD3DRenderTarget* rt = static_cast<const GrD3DRenderTarget*>(fRenderTarget);
return GrD3DPipelineState::Make(fGpu, fProgramInfo, std::move(rootSig),
std::move(vertexShader), std::move(geometryShader),
std::move(pixelShader), rt->dxgiFormat(),
rt->stencilDxgiFormat(), rt->sampleQualityLevel());
}