verus/RendererVulkan/src/CGI/PipelineVulkan.cpp

250 lines
10 KiB
C++

// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
#include "pch.h"
using namespace verus;
using namespace verus::CGI;
PipelineVulkan::PipelineVulkan()
{
}
PipelineVulkan::~PipelineVulkan()
{
Done();
}
void PipelineVulkan::Init(RcPipelineDesc desc)
{
VERUS_INIT();
VERUS_QREF_RENDERER_VULKAN;
VkResult res = VK_SUCCESS;
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++;
}
RcGeometryVulkan geo = static_cast<RcGeometryVulkan>(*desc._geometry);
RcShaderVulkan shader = static_cast<RcShaderVulkan>(*desc._shader);
_vertexInputBindingsFilter = desc._vertexInputBindingsFilter;
const bool tess = desc._topology >= PrimitiveTopology::patchList3 && desc._topology <= PrimitiveTopology::patchList4;
ShaderVulkan::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
Vector<String> entryNames(+BaseShader::Stage::count);
Vector<VkPipelineShaderStageCreateInfo> vShaderStages;
vShaderStages.reserve(compiled._stageCount);
auto PushShaderStage = [&vShaderStages, &compiled, &entryNames](CSZ suffix, BaseShader::Stage stage, VkShaderStageFlagBits shaderStageFlagBits)
{
const VkShaderModule shaderModule = compiled._shaderModules[+stage];
entryNames[+stage] = compiled._entry + suffix;
if (shaderModule != VK_NULL_HANDLE)
{
VkPipelineShaderStageCreateInfo vkpssci = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
vkpssci.stage = shaderStageFlagBits;
vkpssci.module = shaderModule;
vkpssci.pName = _C(entryNames[+stage]);
vShaderStages.push_back(vkpssci);
}
};
PushShaderStage("VS", BaseShader::Stage::vs, VK_SHADER_STAGE_VERTEX_BIT);
PushShaderStage("HS", BaseShader::Stage::hs, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
PushShaderStage("DS", BaseShader::Stage::ds, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
PushShaderStage("GS", BaseShader::Stage::gs, VK_SHADER_STAGE_GEOMETRY_BIT);
PushShaderStage("FS", BaseShader::Stage::fs, VK_SHADER_STAGE_FRAGMENT_BIT);
Vector<VkVertexInputBindingDescription> vVertexInputBindingDesc;
Vector<VkVertexInputAttributeDescription> vVertexInputAttributeDesc;
VkPipelineVertexInputStateCreateInfo vertexInputState = geo.GetVkPipelineVertexInputStateCreateInfo(_vertexInputBindingsFilter,
vVertexInputBindingDesc, vVertexInputAttributeDesc);
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
inputAssemblyState.topology = ToNativePrimitiveTopology(desc._topology);
inputAssemblyState.primitiveRestartEnable = desc._primitiveRestartEnable;
VkPipelineTessellationStateCreateInfo tessellationState = { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO };
tessellationState.patchControlPoints = 3;
switch (desc._topology)
{
case PrimitiveTopology::patchList4: tessellationState.patchControlPoints = 4; break;
}
VkPipelineViewportStateCreateInfo viewportState = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
viewportState.viewportCount = 1;
viewportState.scissorCount = 1;
VkPipelineRasterizationLineStateCreateInfoEXT rasterizationLineState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT };
rasterizationLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
if (desc._colorAttachBlendEqs[0] == VERUS_COLOR_BLEND_ALPHA)
rasterizationLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
VkPipelineRasterizationStateCreateInfo rasterizationState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
rasterizationState.pNext = pRendererVulkan->IsAdvancedLineRasterizationSupported() ? &rasterizationLineState : nullptr;
rasterizationState.depthClampEnable = VK_FALSE;
rasterizationState.polygonMode = ToNativePolygonMode(desc._rasterizationState._polygonMode);
rasterizationState.cullMode = ToNativeCullMode(desc._rasterizationState._cullMode);
rasterizationState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationState.depthBiasEnable = desc._rasterizationState._depthBiasEnable;
rasterizationState.depthBiasConstantFactor = desc._rasterizationState._depthBiasConstantFactor * 0.5f; // Magic value to match D3D12.
rasterizationState.depthBiasClamp = desc._rasterizationState._depthBiasClamp;
rasterizationState.depthBiasSlopeFactor = desc._rasterizationState._depthBiasSlopeFactor;
rasterizationState.lineWidth = 1;
VkPipelineMultisampleStateCreateInfo multisampleState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
multisampleState.rasterizationSamples = ToNativeSampleCount(desc._sampleCount);
VkPipelineDepthStencilStateCreateInfo depthStencilState = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
depthStencilState.depthTestEnable = desc._depthTestEnable;
depthStencilState.depthWriteEnable = desc._depthWriteEnable;
depthStencilState.depthCompareOp = ToNativeCompareOp(desc._depthCompareOp);
depthStencilState.stencilTestEnable = desc._stencilTestEnable;
VkPipelineColorBlendAttachmentState vkpcbas[VERUS_MAX_CA] = {};
FillColorBlendAttachmentStates(desc, attachmentCount, vkpcbas);
VkPipelineColorBlendStateCreateInfo colorBlendState = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
colorBlendState.logicOpEnable = VK_FALSE;
colorBlendState.logicOp = VK_LOGIC_OP_CLEAR;
colorBlendState.attachmentCount = attachmentCount;
colorBlendState.pAttachments = vkpcbas;
colorBlendState.blendConstants[0] = 1;
colorBlendState.blendConstants[1] = 1;
colorBlendState.blendConstants[2] = 1;
colorBlendState.blendConstants[3] = 1;
VkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_BLEND_CONSTANTS };
VkPipelineDynamicStateCreateInfo dynamicState = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
dynamicState.dynamicStateCount = VERUS_COUNT_OF(dynamicStates);
dynamicState.pDynamicStates = dynamicStates;
VkGraphicsPipelineCreateInfo vkgpci = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
vkgpci.stageCount = Utils::Cast32(vShaderStages.size());
vkgpci.pStages = vShaderStages.data();
vkgpci.pVertexInputState = &vertexInputState;
vkgpci.pInputAssemblyState = &inputAssemblyState;
vkgpci.pTessellationState = tess ? &tessellationState : nullptr;
vkgpci.pViewportState = &viewportState;
vkgpci.pRasterizationState = &rasterizationState;
vkgpci.pMultisampleState = &multisampleState;
vkgpci.pDepthStencilState = &depthStencilState;
vkgpci.pColorBlendState = &colorBlendState;
vkgpci.pDynamicState = &dynamicState;
vkgpci.layout = shader.GetVkPipelineLayout();
vkgpci.renderPass = pRendererVulkan->GetRenderPass(desc._renderPassHandle);
vkgpci.subpass = desc._subpass;
vkgpci.basePipelineHandle = VK_NULL_HANDLE;
if (VK_SUCCESS != (res = vkCreateGraphicsPipelines(pRendererVulkan->GetVkDevice(), VK_NULL_HANDLE, 1, &vkgpci, pRendererVulkan->GetAllocator(), &_pipeline)))
throw VERUS_RUNTIME_ERROR << "vkCreateGraphicsPipelines(); res=" << res;
}
void PipelineVulkan::Done()
{
VERUS_QREF_RENDERER_VULKAN;
VERUS_VULKAN_DESTROY(_pipeline, vkDestroyPipeline(pRendererVulkan->GetVkDevice(), _pipeline, pRendererVulkan->GetAllocator()));
VERUS_DONE(PipelineVulkan);
}
void PipelineVulkan::InitCompute(RcPipelineDesc desc)
{
VERUS_QREF_RENDERER_VULKAN;
VkResult res = VK_SUCCESS;
RcShaderVulkan shader = static_cast<RcShaderVulkan>(*desc._shader);
ShaderVulkan::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
const VkShaderModule shaderModule = compiled._shaderModules[+BaseShader::Stage::cs];
String entryName = compiled._entry + "CS";
VkComputePipelineCreateInfo vkcpci = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
vkcpci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vkcpci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
vkcpci.stage.module = shaderModule;
vkcpci.stage.pName = _C(entryName);
vkcpci.layout = shader.GetVkPipelineLayout();
if (VK_SUCCESS != (res = vkCreateComputePipelines(pRendererVulkan->GetVkDevice(), VK_NULL_HANDLE, 1, &vkcpci, pRendererVulkan->GetAllocator(), &_pipeline)))
throw VERUS_RUNTIME_ERROR << "vkCreateComputePipelines(); res=" << res;
}
void PipelineVulkan::FillColorBlendAttachmentStates(RcPipelineDesc desc, int attachmentCount, VkPipelineColorBlendAttachmentState vkpcbas[])
{
VERUS_FOR(i, attachmentCount)
{
CSZ p = _C(desc._colorAttachWriteMasks[i]);
while (*p)
{
switch (*p)
{
case 'r': vkpcbas[i].colorWriteMask |= VK_COLOR_COMPONENT_R_BIT; break;
case 'g': vkpcbas[i].colorWriteMask |= VK_COLOR_COMPONENT_G_BIT; break;
case 'b': vkpcbas[i].colorWriteMask |= VK_COLOR_COMPONENT_B_BIT; break;
case 'a': vkpcbas[i].colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; break;
}
p++;
}
if (desc._colorAttachBlendEqs[i] != "off")
{
vkpcbas[i].blendEnable = VK_TRUE;
static const VkBlendFactor bfs[] =
{
VK_BLEND_FACTOR_ZERO,
VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
VK_BLEND_FACTOR_DST_ALPHA,
VK_BLEND_FACTOR_DST_COLOR,
VK_BLEND_FACTOR_CONSTANT_COLOR,
VK_BLEND_FACTOR_SRC_ALPHA,
VK_BLEND_FACTOR_SRC_ALPHA_SATURATE,
VK_BLEND_FACTOR_SRC_COLOR
};
static const VkBlendOp ops[] =
{
VK_BLEND_OP_ADD,
VK_BLEND_OP_SUBTRACT,
VK_BLEND_OP_REVERSE_SUBTRACT,
VK_BLEND_OP_MIN,
VK_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);
vkpcbas[i].srcColorBlendFactor = bfs[srcColorBlendFactor];
vkpcbas[i].dstColorBlendFactor = bfs[dstColorBlendFactor];
vkpcbas[i].colorBlendOp = ops[colorBlendOp];
vkpcbas[i].srcAlphaBlendFactor = bfs[srcAlphaBlendFactor];
vkpcbas[i].dstAlphaBlendFactor = bfs[dstAlphaBlendFactor];
vkpcbas[i].alphaBlendOp = ops[alphaBlendOp];
}
}
}