verus/RendererDirect3D12/src/CGI/PipelineD3D12.cpp

312 lines
12 KiB
C++

// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
#include "pch.h"
using namespace verus;
using namespace verus::CGI;
PipelineD3D12::PipelineD3D12()
{
}
PipelineD3D12::~PipelineD3D12()
{
Done();
}
void PipelineD3D12::Init(RcPipelineDesc desc)
{
VERUS_INIT();
VERUS_QREF_RENDERER_D3D12;
HRESULT hr = 0;
if (desc._compute)
{
_compute = true;
InitCompute(desc);
return;
}
// Attachment count according to blend equations:
int attachmentCount = 0;
for (const auto& x : desc._colorAttachBlendEqs)
{
if (x.empty())
break;
attachmentCount++;
}
RcGeometryD3D12 geo = static_cast<RcGeometryD3D12>(*desc._geometry);
RcShaderD3D12 shader = static_cast<RcShaderD3D12>(*desc._shader);
_pRootSignature = shader.GetD3DRootSignature();
_topology = ToNativePrimitiveTopology(desc._topology);
_vertexInputBindingsFilter = desc._vertexInputBindingsFilter;
RP::RcD3DRenderPass renderPass = pRendererD3D12->GetRenderPass(desc._renderPassHandle);
RP::RcD3DSubpass subpass = renderPass._vSubpasses[desc._subpass];
auto GetStripCutValue = [&geo]()
{
return geo.Has32BitIndices() ? D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF : D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
};
D3D12_GRAPHICS_PIPELINE_STATE_DESC gpsDesc = {};
gpsDesc.pRootSignature = _pRootSignature;
ShaderD3D12::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
gpsDesc.VS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::vs].Get());
gpsDesc.PS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::fs].Get());
gpsDesc.DS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::ds].Get());
gpsDesc.HS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::hs].Get());
gpsDesc.GS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::gs].Get());
gpsDesc.StreamOutput = {};
gpsDesc.BlendState.AlphaToCoverageEnable = FALSE;
gpsDesc.BlendState.IndependentBlendEnable = TRUE;
FillBlendStateRenderTargets(desc, attachmentCount, gpsDesc.BlendState);
gpsDesc.SampleMask = UINT_MAX;
gpsDesc.RasterizerState.FillMode = ToNativePolygonMode(desc._rasterizationState._polygonMode);
gpsDesc.RasterizerState.CullMode = ToNativeCullMode(desc._rasterizationState._cullMode);
gpsDesc.RasterizerState.FrontCounterClockwise = TRUE;
gpsDesc.RasterizerState.DepthBias = static_cast<INT>(desc._rasterizationState._depthBiasConstantFactor);
gpsDesc.RasterizerState.DepthBiasClamp = desc._rasterizationState._depthBiasClamp;
gpsDesc.RasterizerState.SlopeScaledDepthBias = desc._rasterizationState._depthBiasSlopeFactor;
gpsDesc.RasterizerState.DepthClipEnable = TRUE;
gpsDesc.RasterizerState.MultisampleEnable = FALSE;
gpsDesc.RasterizerState.AntialiasedLineEnable = (desc._colorAttachBlendEqs[0] == VERUS_COLOR_BLEND_ALPHA) ? TRUE : FALSE;
gpsDesc.RasterizerState.ForcedSampleCount = 0;
gpsDesc.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
if (subpass._depthStencil._index >= 0)
{
gpsDesc.DepthStencilState.DepthEnable = desc._depthTestEnable;
gpsDesc.DepthStencilState.DepthWriteMask = desc._depthWriteEnable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
gpsDesc.DepthStencilState.DepthFunc = ToNativeCompareOp(desc._depthCompareOp);
gpsDesc.DepthStencilState.StencilEnable = desc._stencilTestEnable;
}
Vector<D3D12_INPUT_ELEMENT_DESC> vInputElementDescs;
gpsDesc.InputLayout = geo.GetD3DInputLayoutDesc(_vertexInputBindingsFilter, vInputElementDescs);
gpsDesc.IBStripCutValue = desc._primitiveRestartEnable ? GetStripCutValue() : D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
gpsDesc.PrimitiveTopologyType = ToNativePrimitiveTopologyType(desc._topology);
gpsDesc.NumRenderTargets = Utils::Cast32(subpass._vColor.size()); // According to subpass.
VERUS_RT_ASSERT(gpsDesc.NumRenderTargets == attachmentCount); // These two must match.
VERUS_U_FOR(i, gpsDesc.NumRenderTargets)
{
RP::RcD3DAttachment attachment = renderPass._vAttachments[subpass._vColor[i]._index];
gpsDesc.RTVFormats[i] = ToNativeFormat(attachment._format, false);
}
if (subpass._depthStencil._index >= 0)
{
RP::RcD3DAttachment attachment = renderPass._vAttachments[subpass._depthStencil._index];
gpsDesc.DSVFormat = ToNativeFormat(attachment._format, false);
}
gpsDesc.SampleDesc.Count = desc._sampleCount;
gpsDesc.NodeMask = 0;
gpsDesc.CachedPSO = { nullptr, 0 };
gpsDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
if (FAILED(hr = pRendererD3D12->GetD3DDevice()->CreateGraphicsPipelineState(&gpsDesc, IID_PPV_ARGS(&_pPipelineState))))
throw VERUS_RUNTIME_ERROR << "CreateGraphicsPipelineState(); hr=" << VERUS_HR(hr);
_pPipelineState->SetName(_C(Str::Utf8ToWide(String("PipelineState (") + _C(shader.GetSourceName()) + ", " + desc._shaderBranch + ")")));
}
void PipelineD3D12::Done()
{
VERUS_COM_RELEASE_CHECK(_pPipelineState.Get());
_pPipelineState.Reset();
VERUS_DONE(PipelineD3D12);
}
void PipelineD3D12::InitCompute(RcPipelineDesc desc)
{
VERUS_QREF_RENDERER_D3D12;
HRESULT hr = 0;
RcShaderD3D12 shader = static_cast<RcShaderD3D12>(*desc._shader);
_pRootSignature = shader.GetD3DRootSignature();
D3D12_COMPUTE_PIPELINE_STATE_DESC cpsDesc = {};
cpsDesc.pRootSignature = _pRootSignature;
ShaderD3D12::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
cpsDesc.CS = ToBytecode(compiled._pBlobs[+BaseShader::Stage::cs].Get());
cpsDesc.NodeMask = 0;
cpsDesc.CachedPSO = { nullptr, 0 };
cpsDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
if (FAILED(hr = pRendererD3D12->GetD3DDevice()->CreateComputePipelineState(&cpsDesc, IID_PPV_ARGS(&_pPipelineState))))
throw VERUS_RUNTIME_ERROR << "CreateComputePipelineState(); hr=" << VERUS_HR(hr);
_pPipelineState->SetName(_C(Str::Utf8ToWide(String("PipelineState (") + _C(shader.GetSourceName()) + ", " + desc._shaderBranch + ")")));
}
void PipelineD3D12::InitMeshShading(RcPipelineDesc desc)
{
VERUS_QREF_RENDERER_D3D12;
HRESULT hr = 0;
// Attachment count according to blend equations:
int attachmentCount = 0;
for (const auto& x : desc._colorAttachBlendEqs)
{
if (x.empty())
break;
attachmentCount++;
}
RcShaderD3D12 shader = static_cast<RcShaderD3D12>(*desc._shader);
_pRootSignature = shader.GetD3DRootSignature();
_topology = ToNativePrimitiveTopology(desc._topology);
RP::RcD3DRenderPass renderPass = pRendererD3D12->GetRenderPass(desc._renderPassHandle);
RP::RcD3DSubpass subpass = renderPass._vSubpasses[desc._subpass];
D3DX12_MESH_SHADER_PIPELINE_STATE_DESC mspsDesc = {};
mspsDesc.pRootSignature = _pRootSignature;
mspsDesc.AS = ToBytecode(nullptr);
mspsDesc.MS = ToBytecode(nullptr);
mspsDesc.PS = ToBytecode(nullptr);
mspsDesc.BlendState.AlphaToCoverageEnable = FALSE;
mspsDesc.BlendState.IndependentBlendEnable = TRUE;
FillBlendStateRenderTargets(desc, attachmentCount, mspsDesc.BlendState);
mspsDesc.SampleMask = UINT_MAX;
mspsDesc.RasterizerState.FillMode = ToNativePolygonMode(desc._rasterizationState._polygonMode);
mspsDesc.RasterizerState.CullMode = ToNativeCullMode(desc._rasterizationState._cullMode);
mspsDesc.RasterizerState.FrontCounterClockwise = TRUE;
mspsDesc.RasterizerState.DepthBias = static_cast<INT>(desc._rasterizationState._depthBiasConstantFactor);
mspsDesc.RasterizerState.DepthBiasClamp = desc._rasterizationState._depthBiasClamp;
mspsDesc.RasterizerState.SlopeScaledDepthBias = desc._rasterizationState._depthBiasSlopeFactor;
mspsDesc.RasterizerState.DepthClipEnable = TRUE;
mspsDesc.RasterizerState.MultisampleEnable = FALSE;
mspsDesc.RasterizerState.AntialiasedLineEnable = (desc._colorAttachBlendEqs[0] == VERUS_COLOR_BLEND_ALPHA) ? TRUE : FALSE;
mspsDesc.RasterizerState.ForcedSampleCount = 0;
mspsDesc.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
if (subpass._depthStencil._index >= 0)
{
mspsDesc.DepthStencilState.DepthEnable = desc._depthTestEnable;
mspsDesc.DepthStencilState.DepthWriteMask = desc._depthWriteEnable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
mspsDesc.DepthStencilState.DepthFunc = ToNativeCompareOp(desc._depthCompareOp);
mspsDesc.DepthStencilState.StencilEnable = desc._stencilTestEnable;
}
mspsDesc.PrimitiveTopologyType = ToNativePrimitiveTopologyType(desc._topology);
mspsDesc.NumRenderTargets = Utils::Cast32(subpass._vColor.size()); // According to subpass.
VERUS_RT_ASSERT(mspsDesc.NumRenderTargets == attachmentCount); // These two must match.
VERUS_U_FOR(i, mspsDesc.NumRenderTargets)
{
RP::RcD3DAttachment attachment = renderPass._vAttachments[subpass._vColor[i]._index];
mspsDesc.RTVFormats[i] = ToNativeFormat(attachment._format, false);
}
if (subpass._depthStencil._index >= 0)
{
RP::RcD3DAttachment attachment = renderPass._vAttachments[subpass._depthStencil._index];
mspsDesc.DSVFormat = ToNativeFormat(attachment._format, false);
}
mspsDesc.SampleDesc.Count = desc._sampleCount;
mspsDesc.NodeMask = 0;
mspsDesc.CachedPSO = { nullptr, 0 };
mspsDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
auto meshStateStream = CD3DX12_PIPELINE_MESH_STATE_STREAM(mspsDesc);
D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {};
streamDesc.SizeInBytes = sizeof(meshStateStream);
streamDesc.pPipelineStateSubobjectStream = &meshStateStream;
if (FAILED(hr = pRendererD3D12->GetD3DDevice()->CreatePipelineState(&streamDesc, IID_PPV_ARGS(&_pPipelineState))))
throw VERUS_RUNTIME_ERROR << "CreatePipelineState(); hr=" << VERUS_HR(hr);
}
D3D12_SHADER_BYTECODE PipelineD3D12::ToBytecode(ID3DBlob* pBlob)
{
D3D12_SHADER_BYTECODE bytecode = {};
if (pBlob)
{
bytecode.pShaderBytecode = pBlob->GetBufferPointer();
bytecode.BytecodeLength = pBlob->GetBufferSize();
}
return bytecode;
}
void PipelineD3D12::FillBlendStateRenderTargets(RcPipelineDesc desc, int attachmentCount, D3D12_BLEND_DESC& blendDesc)
{
VERUS_FOR(i, attachmentCount)
{
CSZ p = _C(desc._colorAttachWriteMasks[i]);
while (*p)
{
switch (*p)
{
case 'r': blendDesc.RenderTarget[i].RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED; break;
case 'g': blendDesc.RenderTarget[i].RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_GREEN; break;
case 'b': blendDesc.RenderTarget[i].RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_BLUE; break;
case 'a': blendDesc.RenderTarget[i].RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA; break;
}
p++;
}
if (desc._colorAttachBlendEqs[i] != "off")
{
blendDesc.RenderTarget[i].BlendEnable = TRUE;
static const D3D12_BLEND bfs[] =
{
D3D12_BLEND_ZERO,
D3D12_BLEND_ONE,
D3D12_BLEND_INV_DEST_ALPHA,
D3D12_BLEND_INV_DEST_COLOR,
D3D12_BLEND_INV_BLEND_FACTOR,
D3D12_BLEND_INV_SRC_ALPHA,
D3D12_BLEND_INV_SRC_COLOR,
D3D12_BLEND_DEST_ALPHA,
D3D12_BLEND_DEST_COLOR,
D3D12_BLEND_BLEND_FACTOR,
D3D12_BLEND_SRC_ALPHA,
D3D12_BLEND_SRC_ALPHA_SAT,
D3D12_BLEND_SRC_COLOR
};
static const D3D12_BLEND_OP ops[] =
{
D3D12_BLEND_OP_ADD,
D3D12_BLEND_OP_SUBTRACT,
D3D12_BLEND_OP_REV_SUBTRACT,
D3D12_BLEND_OP_MIN,
D3D12_BLEND_OP_MAX
};
int colorBlendOp = -1;
int alphaBlendOp = -1;
int srcColorBlendFactor = -1;
int dstColorBlendFactor = -1;
int srcAlphaBlendFactor = -1;
int dstAlphaBlendFactor = -1;
BaseRenderer::SetAlphaBlendHelper(
_C(desc._colorAttachBlendEqs[i]),
colorBlendOp,
alphaBlendOp,
srcColorBlendFactor,
dstColorBlendFactor,
srcAlphaBlendFactor,
dstAlphaBlendFactor);
blendDesc.RenderTarget[i].SrcBlend = bfs[srcColorBlendFactor];
blendDesc.RenderTarget[i].DestBlend = bfs[dstColorBlendFactor];
blendDesc.RenderTarget[i].BlendOp = ops[colorBlendOp];
blendDesc.RenderTarget[i].SrcBlendAlpha = bfs[srcAlphaBlendFactor];
blendDesc.RenderTarget[i].DestBlendAlpha = bfs[dstAlphaBlendFactor];
blendDesc.RenderTarget[i].BlendOpAlpha = ops[alphaBlendOp];
blendDesc.RenderTarget[i].LogicOp = D3D12_LOGIC_OP_CLEAR;
}
}
}