blob: 7db9c4816a0832895d214d44775607b206dc0a03 [file] [log] [blame]
/*
* Copyright 2025 Rive
*/
#include "rive/renderer/d3d12/d3d12_pipeline_manager.hpp"
#include "rive/renderer/d3d/d3d_constants.hpp"
#include "generated/shaders/tessellate.glsl.exports.h"
// offline shaders
namespace shader
{
namespace tess::vert
{
#include "generated/shaders/d3d/tessellate.vert.h"
}
namespace tess::frag
{
#include "generated/shaders/d3d/tessellate.frag.h"
}
namespace grad::vert
{
#include "generated/shaders/d3d/color_ramp.vert.h"
}
namespace grad::frag
{
#include "generated/shaders/d3d/color_ramp.frag.h"
}
namespace atlas::vert
{
#include "generated/shaders/d3d/render_atlas.vert.h"
}
namespace atlas::fill
{
#include "generated/shaders/d3d/render_atlas_fill.frag.h"
}
namespace atlas::stroke
{
#include "generated/shaders/d3d/render_atlas_stroke.frag.h"
}
} // namespace shader
// offline sigs
namespace sig
{
#include "generated/shaders/d3d/root.sig.h"
} // namespace sig
namespace rive::gpu
{
D3D12PipelineManager::D3D12PipelineManager(
ComPtr<ID3D12Device> device,
const D3DCapabilities& capabilities,
ShaderCompilationMode shaderCompilationMode) :
Super(device, capabilities, shaderCompilationMode, "vs_5_1", "ps_5_1")
{
VERIFY_OK(
this->device()->CreateRootSignature(0,
sig::g_ROOT_SIG,
std::size(sig::g_ROOT_SIG),
IID_PPV_ARGS(&m_rootSignature)));
}
std::unique_ptr<D3D12DrawVertexShader> D3D12PipelineManager::
compileVertexShaderBlobToFinalType(DrawType drawType, ComPtr<ID3DBlob> blob)
{
auto result = std::make_unique<D3D12DrawVertexShader>();
switch (drawType)
{
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
result->m_layoutDesc[0] = {
GLSL_a_patchVertexData,
0,
DXGI_FORMAT_R32G32B32A32_FLOAT,
PATCH_VERTEX_DATA_SLOT,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0};
result->m_layoutDesc[1] = {
GLSL_a_mirroredVertexData,
0,
DXGI_FORMAT_R32G32B32A32_FLOAT,
PATCH_VERTEX_DATA_SLOT,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0};
result->m_vertexAttribCount = 2;
break;
case DrawType::interiorTriangulation:
case DrawType::atlasBlit:
result->m_layoutDesc[0] = {
GLSL_a_triangleVertex,
0,
DXGI_FORMAT_R32G32B32_FLOAT,
TRIANGLE_VERTEX_DATA_SLOT,
0,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0};
result->m_vertexAttribCount = 1;
break;
case DrawType::imageRect:
result->m_layoutDesc[0] = {
GLSL_a_imageRectVertex,
0,
DXGI_FORMAT_R32G32B32A32_FLOAT,
IMAGE_RECT_VERTEX_DATA_SLOT,
0,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0};
result->m_vertexAttribCount = 1;
break;
case DrawType::imageMesh:
result->m_layoutDesc[0] = {
GLSL_a_position,
0,
DXGI_FORMAT_R32G32_FLOAT,
IMAGE_MESH_VERTEX_DATA_SLOT,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0};
result->m_layoutDesc[1] = {
GLSL_a_texCoord,
0,
DXGI_FORMAT_R32G32_FLOAT,
IMAGE_MESH_UV_DATA_SLOT,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0};
result->m_vertexAttribCount = 2;
break;
case DrawType::renderPassResolve:
result->m_vertexAttribCount = 0;
break;
case DrawType::msaaStrokes:
case DrawType::msaaMidpointFanBorrowedCoverage:
case DrawType::msaaMidpointFans:
case DrawType::msaaMidpointFanStencilReset:
case DrawType::msaaMidpointFanPathsStencil:
case DrawType::msaaMidpointFanPathsCover:
case DrawType::msaaOuterCubics:
case DrawType::msaaStencilClipReset:
case DrawType::renderPassInitialize:
RIVE_UNREACHABLE();
}
result->m_shader = blob;
return result;
}
std::unique_ptr<D3D12DrawPixelShader> D3D12PipelineManager::
compilePixelShaderBlobToFinalType(ComPtr<ID3DBlob> blob)
{
auto result = std::make_unique<D3D12DrawPixelShader>();
result->m_shader = std::move(blob);
return result;
}
std::unique_ptr<D3D12Pipeline> D3D12PipelineManager::linkPipeline(
const PipelineProps& props,
const D3D12DrawVertexShader& vs,
const D3D12DrawPixelShader& ps)
{
ComPtr<ID3D12PipelineState> pipelineState;
D3D12_RASTERIZER_DESC rasterDesc = {};
rasterDesc.FillMode = D3D12_FILL_MODE_SOLID;
rasterDesc.FrontCounterClockwise = FALSE;
rasterDesc.DepthBias = 0;
rasterDesc.SlopeScaledDepthBias = 0;
rasterDesc.DepthBiasClamp = 0;
rasterDesc.DepthClipEnable = TRUE;
rasterDesc.MultisampleEnable = FALSE;
rasterDesc.AntialiasedLineEnable = FALSE;
switch (props.drawType)
{
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
case DrawType::interiorTriangulation:
case DrawType::atlasBlit:
rasterDesc.CullMode = D3D12_CULL_MODE_BACK;
break;
case DrawType::imageRect:
case DrawType::imageMesh:
case DrawType::renderPassResolve:
rasterDesc.CullMode = D3D12_CULL_MODE_NONE;
break;
case DrawType::msaaStrokes:
case DrawType::msaaMidpointFanBorrowedCoverage:
case DrawType::msaaMidpointFans:
case DrawType::msaaMidpointFanStencilReset:
case DrawType::msaaMidpointFanPathsStencil:
case DrawType::msaaMidpointFanPathsCover:
case DrawType::msaaOuterCubics:
case DrawType::msaaStencilClipReset:
case DrawType::renderPassInitialize:
break;
}
D3D12_BLEND_DESC blendDesc{};
blendDesc.RenderTarget[0].BlendEnable =
props.shaderMiscFlags & (ShaderMiscFlags::fixedFunctionColorOutput |
ShaderMiscFlags::coalescedResolveAndTransfer);
blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask =
props.shaderMiscFlags & (ShaderMiscFlags::fixedFunctionColorOutput |
ShaderMiscFlags::coalescedResolveAndTransfer)
? D3D12_COLOR_WRITE_ENABLE_ALL
: 0;
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = {vs.m_layoutDesc, vs.m_vertexAttribCount};
psoDesc.pRootSignature = m_rootSignature.Get();
psoDesc.VS = CD3DX12_SHADER_BYTECODE(vs.m_shader.Get());
psoDesc.PS = CD3DX12_SHADER_BYTECODE(ps.m_shader.Get());
psoDesc.RasterizerState = rasterDesc;
psoDesc.BlendState = blendDesc;
psoDesc.DepthStencilState.DepthEnable = FALSE;
psoDesc.DepthStencilState.StencilEnable = FALSE;
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
psoDesc.SampleDesc.Count = 1;
auto result = std::make_unique<D3D12Pipeline>();
#ifdef WITH_RIVE_TOOLS
if (props.synthesizedFailureType ==
SynthesizedFailureType::pipelineCreation ||
props.synthesizedFailureType ==
SynthesizedFailureType::shaderCompilation)
{
// An empty result is what counts as "failed"
return result;
}
#endif
VERIFY_OK(device()->CreateGraphicsPipelineState(
&psoDesc,
IID_PPV_ARGS(&result->m_d3dPipelineState)));
return result;
}
void D3D12PipelineManager::compileTesselationPipeline()
{
D3D12_INPUT_ELEMENT_DESC layoutDesc[] = {
{GLSL_a_p0p1_,
0,
DXGI_FORMAT_R32G32B32A32_FLOAT,
0,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
1},
{GLSL_a_p2p3_,
0,
DXGI_FORMAT_R32G32B32A32_FLOAT,
0,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
1},
{GLSL_a_joinTan_and_ys,
0,
DXGI_FORMAT_R32G32B32A32_FLOAT,
0,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
1},
{GLSL_a_args,
0,
DXGI_FORMAT_R32G32B32A32_UINT,
0,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
1}};
D3D12_RASTERIZER_DESC rasterDesc = {};
rasterDesc.FillMode = D3D12_FILL_MODE_SOLID;
rasterDesc.CullMode = D3D12_CULL_MODE_BACK;
rasterDesc.FrontCounterClockwise = FALSE;
rasterDesc.DepthBias = 0;
rasterDesc.SlopeScaledDepthBias = 0;
rasterDesc.DepthBiasClamp = 0;
rasterDesc.DepthClipEnable = FALSE;
rasterDesc.MultisampleEnable = FALSE;
rasterDesc.AntialiasedLineEnable = FALSE;
D3D12_BLEND_DESC blendDesc{};
blendDesc.RenderTarget[0].BlendEnable = FALSE;
blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask =
D3D12_COLOR_WRITE_ENABLE_ALL;
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = {layoutDesc, _countof(layoutDesc)};
psoDesc.pRootSignature = m_rootSignature.Get();
psoDesc.VS = {shader::tess::vert::g_main,
std::size(shader::tess::vert::g_main)};
psoDesc.PS = {shader::tess::frag::g_main,
std::size(shader::tess::frag::g_main)};
psoDesc.RasterizerState = rasterDesc;
psoDesc.BlendState = blendDesc;
psoDesc.DepthStencilState.DepthEnable = FALSE;
psoDesc.DepthStencilState.StencilEnable = FALSE;
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_R32G32B32A32_UINT;
psoDesc.SampleDesc.Count = 1;
VERIFY_OK(device()->CreateGraphicsPipelineState(
&psoDesc,
IID_PPV_ARGS(&m_tesselationPipeline)));
}
void D3D12PipelineManager::compileGradientPipeline()
{
D3D12_INPUT_ELEMENT_DESC layoutDesc = {
GLSL_a_span,
0,
DXGI_FORMAT_R32G32B32A32_UINT,
0,
0,
D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA,
1};
D3D12_RASTERIZER_DESC rasterDesc = {};
rasterDesc.FillMode = D3D12_FILL_MODE_SOLID;
rasterDesc.CullMode = D3D12_CULL_MODE_BACK;
rasterDesc.FrontCounterClockwise = FALSE;
rasterDesc.DepthBias = 0;
rasterDesc.SlopeScaledDepthBias = 0;
rasterDesc.DepthBiasClamp = 0;
rasterDesc.DepthClipEnable = FALSE;
rasterDesc.MultisampleEnable = FALSE;
rasterDesc.AntialiasedLineEnable = FALSE;
D3D12_BLEND_DESC blendDesc{};
blendDesc.RenderTarget[0].BlendEnable = FALSE;
blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask =
D3D12_COLOR_WRITE_ENABLE_ALL;
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = {&layoutDesc, 1};
psoDesc.pRootSignature = m_rootSignature.Get();
psoDesc.VS = {shader::grad::vert::g_main,
std::size(shader::grad::vert::g_main)};
psoDesc.PS = {shader::grad::frag::g_main,
std::size(shader::grad::frag::g_main)};
psoDesc.RasterizerState = rasterDesc;
psoDesc.BlendState = blendDesc;
psoDesc.DepthStencilState.DepthEnable = FALSE;
psoDesc.DepthStencilState.StencilEnable = FALSE;
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
psoDesc.SampleDesc.Count = 1;
VERIFY_OK(device()->CreateGraphicsPipelineState(
&psoDesc,
IID_PPV_ARGS(&m_gradientPipeline)));
}
void D3D12PipelineManager::compileAtlasPipeline()
{
D3D12_INPUT_ELEMENT_DESC layoutDesc[2];
layoutDesc[0] = {GLSL_a_patchVertexData,
0,
DXGI_FORMAT_R32G32B32A32_FLOAT,
PATCH_VERTEX_DATA_SLOT,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0};
layoutDesc[1] = {GLSL_a_mirroredVertexData,
0,
DXGI_FORMAT_R32G32B32A32_FLOAT,
PATCH_VERTEX_DATA_SLOT,
D3D12_APPEND_ALIGNED_ELEMENT,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0};
D3D12_RASTERIZER_DESC rasterDesc = {};
rasterDesc.FillMode = D3D12_FILL_MODE_SOLID;
rasterDesc.CullMode = D3D12_CULL_MODE_BACK;
rasterDesc.FrontCounterClockwise = FALSE;
rasterDesc.DepthBias = 0;
rasterDesc.SlopeScaledDepthBias = 0;
rasterDesc.DepthBiasClamp = 0;
rasterDesc.DepthClipEnable = FALSE;
rasterDesc.MultisampleEnable = FALSE;
rasterDesc.AntialiasedLineEnable = FALSE;
D3D12_BLEND_DESC blendDesc{};
blendDesc.RenderTarget[0].BlendEnable = TRUE;
blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_MAX;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_MAX;
blendDesc.RenderTarget[0].RenderTargetWriteMask =
D3D12_COLOR_WRITE_ENABLE_ALL;
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = {layoutDesc, 2};
psoDesc.pRootSignature = m_rootSignature.Get();
psoDesc.VS = {shader::atlas::vert::g_main,
std::size(shader::atlas::vert::g_main)};
psoDesc.PS = {shader::atlas::stroke::g_main,
std::size(shader::atlas::stroke::g_main)};
psoDesc.RasterizerState = rasterDesc;
psoDesc.BlendState = blendDesc;
psoDesc.DepthStencilState.DepthEnable = FALSE;
psoDesc.DepthStencilState.StencilEnable = FALSE;
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_R32_FLOAT;
psoDesc.SampleDesc.Count = 1;
VERIFY_OK(device()->CreateGraphicsPipelineState(
&psoDesc,
IID_PPV_ARGS(&m_atlasStrokePipeline)));
psoDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
psoDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
psoDesc.PS = {shader::atlas::fill::g_main,
std::size(shader::atlas::fill::g_main)};
VERIFY_OK(device()->CreateGraphicsPipelineState(
&psoDesc,
IID_PPV_ARGS(&m_atlasFillPipeline)));
}
} // namespace rive::gpu