Add GrD3DPipelineStateBuilder class.

This allows us to create the binary shaders for d3d. We generate spirv
from sksl, then use spirv-cross to turn it into hlsl. Then that gets
compiled into binary to be used in the pipeline.

Adds hooks GrD3DOpsRenderPass to start creating the pipeline.

Change-Id: Ie731dd945cdd9a00cebd78c1371a3d9784e4e1a3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/284526
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Greg Daniel 2020-04-23 10:30:23 -04:00 committed by Skia Commit-Bot
parent 1006a91ee8
commit 5fc5c8128c
15 changed files with 331 additions and 25 deletions

View File

@ -745,6 +745,8 @@ skia_direct3d_sources = [
"$_src/gpu/d3d/GrD3DOpsRenderPass.h",
"$_src/gpu/d3d/GrD3DPipelineState.cpp",
"$_src/gpu/d3d/GrD3DPipelineState.h",
"$_src/gpu/d3d/GrD3DPipelineStateBuilder.cpp",
"$_src/gpu/d3d/GrD3DPipelineStateBuilder.h",
"$_src/gpu/d3d/GrD3DRenderTarget.cpp",
"$_src/gpu/d3d/GrD3DRenderTarget.h",
"$_src/gpu/d3d/GrD3DResourceProvider.cpp",

View File

@ -68,7 +68,9 @@ private:
uint32_t fCurrentUBOOffset = 0;
uint32_t fRTHeightOffset = 0;
friend class GrD3DPipelineStateBuilder;
friend class GrDawnProgramBuilder;
typedef GrGLSLUniformHandler INHERITED;
};

View File

@ -20,6 +20,7 @@
#include "src/gpu/d3d/GrD3DTexture.h"
#include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
#include "src/gpu/d3d/GrD3DUtil.h"
#include "src/sksl/SkSLCompiler.h"
#if GR_TEST_UTILS
#include <DXProgrammableCapture.h>
@ -43,7 +44,8 @@ GrD3DGpu::GrD3DGpu(GrContext* context, const GrContextOptions& contextOptions,
, fQueue(backendContext.fQueue)
, fResourceProvider(this)
, fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt) {
, fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt)
, fCompiler(new SkSL::Compiler()) {
fCaps.reset(new GrD3DCaps(contextOptions,
backendContext.fAdapter.get(),
backendContext.fDevice.get()));

View File

@ -24,6 +24,10 @@ class GrPipeline;
struct IDXGraphicsAnalysis;
#endif
namespace SkSL {
class Compiler;
}
class GrD3DGpu : public GrGpu {
public:
static sk_sp<GrGpu> Make(const GrD3DBackendContext& backendContext, const GrContextOptions&,
@ -94,6 +98,10 @@ public:
void checkFinishProcs() override {}
SkSL::Compiler* shaderCompiler() const {
return fCompiler.get();
}
private:
enum class SyncQueue {
kForce,
@ -236,6 +244,8 @@ private:
IDXGraphicsAnalysis* fGraphicsAnalysis;
#endif
std::unique_ptr<SkSL::Compiler> fCompiler;
typedef GrGpu INHERITED;
};

View File

@ -8,8 +8,11 @@
#include "src/gpu/d3d/GrD3DOpsRenderPass.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrProgramDesc.h"
#include "src/gpu/GrRenderTargetPriv.h"
#include "src/gpu/d3d/GrD3DGpu.h"
#include "src/gpu/d3d/GrD3DPipelineState.h"
#include "src/gpu/d3d/GrD3DPipelineStateBuilder.h"
GrD3DOpsRenderPass::GrD3DOpsRenderPass(GrD3DGpu* gpu) : fGpu(gpu) {}
@ -30,3 +33,13 @@ bool GrD3DOpsRenderPass::set(GrRenderTarget* rt, GrSurfaceOrigin origin, const S
GrD3DOpsRenderPass::~GrD3DOpsRenderPass() {}
GrGpu* GrD3DOpsRenderPass::gpu() { return fGpu; }
bool GrD3DOpsRenderPass::onBindPipeline(const GrProgramInfo& info, const SkRect& drawBounds) {
GrProgramDesc desc = fGpu->caps()->makeDesc(fRenderTarget, info);
std::unique_ptr<GrD3DPipelineState> pipelineState =
GrD3DPipelineStateBuilder::CreatePipelineState(fGpu, fRenderTarget, desc, info);
// TODO: When this gets implemented fully make sure we bind the stencil reference value since
// that is not part of the pipline in d3d12.
return true;
}

View File

@ -33,11 +33,7 @@ public:
private:
GrGpu* gpu() override;
bool onBindPipeline(const GrProgramInfo&, const SkRect& drawBounds) override {
// TODO: When this gets implemented make sure we bind the stencil reference value since that
// is not part of the pipline in d3d12.
return true;
}
bool onBindPipeline(const GrProgramInfo&, const SkRect& drawBounds) override;
void onSetScissorRect(const SkIRect&) override {}
bool onBindTextures(const GrPrimitiveProcessor&, const GrSurfaceProxy* const primProcTextures[],
const GrPipeline&) override {

View File

@ -268,6 +268,7 @@ static void fill_in_depth_stencil_state(const GrProgramInfo& programInfo,
dsDesc->DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
dsDesc->DepthFunc = D3D12_COMPARISON_FUNC_NEVER;
dsDesc->StencilEnable = !stencilSettings.isDisabled();
if (!stencilSettings.isDisabled()) {
if (stencilSettings.isTwoSided()) {
const auto& frontFace = stencilSettings.postOriginCCWFace(origin);
const auto& backFace = stencilSettings.postOriginCCWFace(origin);
@ -285,15 +286,30 @@ static void fill_in_depth_stencil_state(const GrProgramInfo& programInfo,
setup_stencilop_desc(&dsDesc->FrontFace, stencilSettings.singleSidedFace());
dsDesc->BackFace = dsDesc->FrontFace;
}
}
}
std::unique_ptr<GrD3DPipelineState> GrD3DPipelineState::Make(GrD3DGpu* gpu,
const GrProgramInfo& programInfo,
gr_cp<ID3D12RootSignature> rootSig,
gr_cp<ID3DBlob> vertexShader,
gr_cp<ID3DBlob> geometryShader,
gr_cp<ID3DBlob> pixelShader,
DXGI_FORMAT renderTargetFormat,
DXGI_FORMAT depthStencilFormat,
unsigned int sampleQualityLevel) {
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()),
vertexShader->GetBufferSize() };
psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()),
pixelShader->GetBufferSize() };
if (geometryShader.get()) {
psoDesc.GS = { reinterpret_cast<UINT8*>(geometryShader->GetBufferPointer()),
geometryShader->GetBufferSize() };
}
psoDesc.StreamOutput = {nullptr, 0, nullptr, 0, 0};
fill_in_blend_state(programInfo.pipeline(), &psoDesc.BlendState);
@ -327,11 +343,8 @@ std::unique_ptr<GrD3DPipelineState> GrD3DPipelineState::Make(GrD3DGpu* gpu,
psoDesc.CachedPSO = {nullptr, 0};
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
// TODO: fill in the rest of the descriptor.
// TODO: We need to create a real root descriptor before trying to make a pipeline
#if 0
psoDesc.pRootSignature = m_rootSignature.Get();
psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() };
psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() };
ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState)));
#endif

View File

@ -18,6 +18,10 @@ class GrProgramInfo;
class GrD3DPipelineState {
public:
static std::unique_ptr<GrD3DPipelineState> Make(GrD3DGpu* gpu, const GrProgramInfo&,
gr_cp<ID3D12RootSignature> rootSig,
gr_cp<ID3DBlob> vertexShader,
gr_cp<ID3DBlob> geometryShader,
gr_cp<ID3DBlob> pixelShader,
DXGI_FORMAT renderTargetFormat,
DXGI_FORMAT depthStencilFormat,
unsigned int sampleQualityLevel);

View File

@ -0,0 +1,172 @@
/*
* 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/sksl/SkSLCompiler.h"
#include <d3dcompiler.h>
typedef size_t shader_size;
std::unique_ptr<GrD3DPipelineState> GrD3DPipelineStateBuilder::CreatePipelineState(
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()));
}
}
std::unique_ptr<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;
}
}
gr_cp<ID3D12RootSignature> rootSignature;
const GrD3DRenderTarget* rt = static_cast<const GrD3DRenderTarget*>(fRenderTarget);
return GrD3DPipelineState::Make(fGpu, fProgramInfo, std::move(rootSignature),
std::move(vertexShader), std::move(geometryShader),
std::move(pixelShader), rt->dxgiFormat(),
rt->stencilDxgiFormat(), rt->sampleQualityLevel());
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrD3DPipelineStateBuilder_DEFINED
#define GrD3DPipelineStateBuilder_DEFINED
#include "src/gpu/GrPipeline.h"
#include "src/gpu/GrSpirvUniformHandler.h"
#include "src/gpu/GrSpirvVaryingHandler.h"
#include "src/gpu/d3d/GrD3DPipelineState.h"
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/sksl/ir/SkSLProgram.h"
class GrProgramDesc;
class GrD3DGpu;
class GrVkRenderPass;
class SkReader32;
class GrD3DPipelineStateBuilder : public GrGLSLProgramBuilder {
public:
/** Generates a pipeline state.
*
* The GrD3DPipelineState implements what is specified in the GrPipeline and
* GrPrimitiveProcessor as input. After successful generation, the builder result objects are
* available to be used.
* @return the created pipeline if generation was successful; nullptr otherwise
*/
static std::unique_ptr<GrD3DPipelineState> CreatePipelineState(GrD3DGpu*,
GrRenderTarget*,
const GrProgramDesc&,
const GrProgramInfo&);
const GrCaps* caps() const override;
GrD3DGpu* gpu() const { return fGpu; }
void finalizeFragmentOutputColor(GrShaderVar& outputColor) override;
void finalizeFragmentSecondaryColor(GrShaderVar& outputColor) override;
private:
GrD3DPipelineStateBuilder(GrD3DGpu*, GrRenderTarget*, const GrProgramDesc&,
const GrProgramInfo&);
std::unique_ptr<GrD3DPipelineState> finalize();
void compileD3DProgram(SkSL::Program::Kind kind,
const SkSL::String& sksl,
const SkSL::Program::Settings& settings,
ID3DBlob** shader,
SkSL::Program::Inputs* outInputs);
GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; }
const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; }
GrGLSLVaryingHandler* varyingHandler() override { return &fVaryingHandler; }
GrD3DGpu* fGpu;
GrSpirvVaryingHandler fVaryingHandler;
GrSpirvUniformHandler fUniformHandler;
typedef GrGLSLProgramBuilder INHERITED;
};
#endif

View File

@ -158,3 +158,11 @@ GrD3DGpu* GrD3DRenderTarget::getD3DGpu() const {
SkASSERT(!this->wasDestroyed());
return static_cast<GrD3DGpu*>(this->getGpu());
}
DXGI_FORMAT GrD3DRenderTarget::stencilDxgiFormat() const {
if (auto stencil = this->renderTargetPriv().getStencilAttachment()) {
auto d3dStencil = static_cast<GrD3DStencilAttachment*>(stencil);
return d3dStencil->dxgiFormat();
}
return DXGI_FORMAT_UNKNOWN;
}

View File

@ -44,6 +44,8 @@ public:
GrBackendRenderTarget getBackendRenderTarget() const override;
DXGI_FORMAT stencilDxgiFormat() const;
protected:
GrD3DRenderTarget(GrD3DGpu* gpu,
SkISize dimensions,

View File

@ -16,7 +16,7 @@
class GrD3DGpu;
class GrD3DStencilAttachment : public GrStencilAttachment, GrD3DTextureResource {
class GrD3DStencilAttachment : public GrStencilAttachment, public GrD3DTextureResource {
public:
struct Format {
DXGI_FORMAT fInternalFormat;

View File

@ -241,6 +241,7 @@ protected:
friend class GrCCCoverageProcessor; // to access code().
friend class GrGLSLProgramBuilder;
friend class GrGLProgramBuilder;
friend class GrD3DPipelineStateBuilder;
friend class GrDawnProgramBuilder;
friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
friend class GrGLPathProgramBuilder; // to access fInputs.

View File

@ -22,6 +22,20 @@ namespace SkSL {
bool SPIRVtoHLSL(const String& spirv, String* hlsl) {
spirv_cross::CompilerHLSL hlslCompiler((const uint32_t*)spirv.c_str(),
spirv.size() / sizeof(uint32_t));
spirv_cross::CompilerGLSL::Options optionsGLSL;
// Force all uninitialized variables to be 0, otherwise they will fail to compile
// by FXC.
optionsGLSL.force_zero_initialized_variables = true;
spirv_cross::CompilerHLSL::Options optionsHLSL;
optionsHLSL.shader_model = 51;
// PointCoord and PointSize are not supported in HLSL
optionsHLSL.point_coord_compat = true;
optionsHLSL.point_size_compat = true;
hlslCompiler.set_common_options(optionsGLSL);
hlslCompiler.set_hlsl_options(optionsHLSL);
hlsl->assign(hlslCompiler.compile());
return true;
}