| /* | |
| * 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))); | |
| } | |
| inline DXGI_FORMAT getDXGIFormat(VertexElementFormat format) | |
| { | |
| switch (format) | |
| { | |
| case VertexElementFormat::float1: | |
| return DXGI_FORMAT_R32_FLOAT; | |
| case VertexElementFormat::float2: | |
| return DXGI_FORMAT_R32G32_FLOAT; | |
| case VertexElementFormat::float3: | |
| return DXGI_FORMAT_R32G32B32_FLOAT; | |
| case VertexElementFormat::float4: | |
| return DXGI_FORMAT_R32G32B32A32_FLOAT; | |
| case VertexElementFormat::uint8x4: | |
| return DXGI_FORMAT_R8G8B8A8_UINT; | |
| case VertexElementFormat::sint8x4: | |
| return DXGI_FORMAT_R8G8B8A8_SINT; | |
| case VertexElementFormat::unorm8x4: | |
| return DXGI_FORMAT_R8G8B8A8_UNORM; | |
| case VertexElementFormat::snorm8x4: | |
| return DXGI_FORMAT_R8G8B8A8_SNORM; | |
| case VertexElementFormat::uint16x2: | |
| return DXGI_FORMAT_R16G16_UINT; | |
| case VertexElementFormat::sint16x2: | |
| return DXGI_FORMAT_R16G16_SINT; | |
| case VertexElementFormat::unorm16x2: | |
| return DXGI_FORMAT_R16G16_UNORM; | |
| case VertexElementFormat::snorm16x2: | |
| return DXGI_FORMAT_R16G16_SNORM; | |
| case VertexElementFormat::uint16x4: | |
| return DXGI_FORMAT_R16G16B16A16_UINT; | |
| case VertexElementFormat::sint16x4: | |
| return DXGI_FORMAT_R16G16B16A16_SINT; | |
| case VertexElementFormat::float16x2: | |
| return DXGI_FORMAT_R16G16_FLOAT; | |
| case VertexElementFormat::float16x4: | |
| return DXGI_FORMAT_R16G16B16A16_FLOAT; | |
| case VertexElementFormat::uint32: | |
| return DXGI_FORMAT_R32_UINT; | |
| } | |
| RIVE_UNREACHABLE(); | |
| } | |
| template <typename ImageDrawInstance, uint32_t N> | |
| void addInstanceElements(StackVector<D3D12_INPUT_ELEMENT_DESC, N>& layoutDesc) | |
| { | |
| for (auto& attribute : ImageDrawInstance::getAttributes()) | |
| { | |
| layoutDesc.push_back({ | |
| .SemanticName = attribute.semanticName, | |
| .SemanticIndex = 0, | |
| .Format = getDXGIFormat(attribute.format), | |
| .InputSlot = IMAGE_DRAW_INSTANCE_DATA_SLOT, | |
| .AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT, | |
| .InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, | |
| .InstanceDataStepRate = 1, | |
| }); | |
| } | |
| } | |
| 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.push_back({ | |
| 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.push_back({ | |
| GLSL_a_mirroredVertexData, | |
| 0, | |
| DXGI_FORMAT_R32G32B32A32_FLOAT, | |
| PATCH_VERTEX_DATA_SLOT, | |
| D3D12_APPEND_ALIGNED_ELEMENT, | |
| D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, | |
| 0, | |
| }); | |
| break; | |
| case DrawType::interiorTriangulation: | |
| case DrawType::featherAtlasBlit: | |
| result->m_layoutDesc.push_back({ | |
| GLSL_a_triangleVertex, | |
| 0, | |
| DXGI_FORMAT_R32G32B32_FLOAT, | |
| TRIANGLE_VERTEX_DATA_SLOT, | |
| 0, | |
| D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, | |
| 0, | |
| }); | |
| break; | |
| case DrawType::imageRect: | |
| result->m_layoutDesc.push_back({ | |
| GLSL_a_imageRectVertex, | |
| 0, | |
| DXGI_FORMAT_R32G32B32A32_FLOAT, | |
| IMAGE_RECT_VERTEX_DATA_SLOT, | |
| 0, | |
| D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, | |
| 0, | |
| }); | |
| addInstanceElements<ImageRectInstance>(result->m_layoutDesc); | |
| break; | |
| case DrawType::imageMesh: | |
| result->m_layoutDesc.push_back({ | |
| 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.push_back({ | |
| GLSL_a_texCoord, | |
| 0, | |
| DXGI_FORMAT_R32G32_FLOAT, | |
| IMAGE_MESH_UV_DATA_SLOT, | |
| D3D12_APPEND_ALIGNED_ELEMENT, | |
| D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, | |
| 0, | |
| }); | |
| addInstanceElements<ImageMeshInstance>(result->m_layoutDesc); | |
| break; | |
| case DrawType::renderPassResolve: | |
| break; | |
| case DrawType::depthStrokes: | |
| case DrawType::stencilMidpointFanBorrowedCoverage: | |
| case DrawType::stencilDynamicMidpointFans: | |
| case DrawType::stencilDynamicOuterCubics: | |
| case DrawType::stencilMidpointFans: | |
| case DrawType::stencilMidpointFanReset: | |
| case DrawType::stencilMidpointFanWinding: | |
| case DrawType::stencilMidpointFanCover: | |
| case DrawType::stencilOuterCubicBorrowedCoverage: | |
| case DrawType::stencilOuterCubicReset: | |
| case DrawType::stencilOuterCubicWinding: | |
| case DrawType::stencilOuterCubicCover: | |
| case DrawType::stencilOuterCubics: | |
| case DrawType::clipReset: | |
| 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 = {}; | |
| // Wireframe is a debugging aid. The resolve is a fullscreen operation, so | |
| // leave it solid even in wireframe mode. | |
| rasterDesc.FillMode = | |
| (props.wireframe && props.drawType != DrawType::renderPassResolve) | |
| ? D3D12_FILL_MODE_WIREFRAME | |
| : 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::featherAtlasBlit: | |
| 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::depthStrokes: | |
| case DrawType::stencilMidpointFanBorrowedCoverage: | |
| case DrawType::stencilDynamicMidpointFans: | |
| case DrawType::stencilDynamicOuterCubics: | |
| case DrawType::stencilMidpointFans: | |
| case DrawType::stencilMidpointFanReset: | |
| case DrawType::stencilMidpointFanWinding: | |
| case DrawType::stencilMidpointFanCover: | |
| case DrawType::stencilOuterCubicBorrowedCoverage: | |
| case DrawType::stencilOuterCubicReset: | |
| case DrawType::stencilOuterCubicWinding: | |
| case DrawType::stencilOuterCubicCover: | |
| case DrawType::stencilOuterCubics: | |
| case DrawType::clipReset: | |
| case DrawType::renderPassInitialize: | |
| break; | |
| } | |
| D3D12_BLEND_DESC blendDesc{}; | |
| blendDesc.RenderTarget[0].BlendEnable = | |
| enums::is_flag_set(props.shaderMiscFlags, | |
| ShaderMiscFlags::fixedFunctionColorOutput); | |
| 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 = | |
| enums::any_flag_set(props.shaderMiscFlags, | |
| ShaderMiscFlags::fixedFunctionColorOutput | | |
| ShaderMiscFlags::coalescedResolveAndTransfer) | |
| ? D3D12_COLOR_WRITE_ENABLE_ALL | |
| : 0; | |
| D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; | |
| psoDesc.InputLayout = {vs.m_layoutDesc.data(), vs.m_layoutDesc.size()}; | |
| 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::compileFeatherAtlasPipeline() | |
| { | |
| 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_R16_FLOAT; | |
| psoDesc.SampleDesc.Count = 1; | |
| VERIFY_OK(device()->CreateGraphicsPipelineState( | |
| &psoDesc, | |
| IID_PPV_ARGS(&m_featherAtlasStrokePipeline))); | |
| psoDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; | |
| psoDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; | |
| psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; | |
| psoDesc.PS = {shader::atlas::fill::g_main, | |
| std::size(shader::atlas::fill::g_main)}; | |
| VERIFY_OK(device()->CreateGraphicsPipelineState( | |
| &psoDesc, | |
| IID_PPV_ARGS(&m_featherAtlasFillPipeline))); | |
| } | |
| } // namespace rive::gpu |