Kelsidavis-WoWee/src/rendering/vk_pipeline.cpp

272 lines
9.9 KiB
C++
Raw Normal View History

#include "rendering/vk_pipeline.hpp"
#include "core/logger.hpp"
namespace wowee {
namespace rendering {
PipelineBuilder::PipelineBuilder() {
// Default: one blend attachment with blending disabled
colorBlendAttachments_.push_back(blendDisabled());
// Default dynamic states: viewport + scissor (almost always dynamic)
dynamicStates_ = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
}
PipelineBuilder& PipelineBuilder::setShaders(
VkPipelineShaderStageCreateInfo vert, VkPipelineShaderStageCreateInfo frag)
{
shaderStages_ = {vert, frag};
return *this;
}
PipelineBuilder& PipelineBuilder::setVertexInput(
const std::vector<VkVertexInputBindingDescription>& bindings,
const std::vector<VkVertexInputAttributeDescription>& attributes)
{
vertexBindings_ = bindings;
vertexAttributes_ = attributes;
return *this;
}
PipelineBuilder& PipelineBuilder::setNoVertexInput() {
vertexBindings_.clear();
vertexAttributes_.clear();
return *this;
}
PipelineBuilder& PipelineBuilder::setTopology(VkPrimitiveTopology topology,
VkBool32 primitiveRestart)
{
topology_ = topology;
primitiveRestart_ = primitiveRestart;
return *this;
}
PipelineBuilder& PipelineBuilder::setRasterization(VkPolygonMode polygonMode,
VkCullModeFlags cullMode, VkFrontFace frontFace)
{
polygonMode_ = polygonMode;
cullMode_ = cullMode;
frontFace_ = frontFace;
return *this;
}
PipelineBuilder& PipelineBuilder::setDepthTest(bool enable, bool writeEnable,
VkCompareOp compareOp)
{
depthTestEnable_ = enable;
depthWriteEnable_ = writeEnable;
depthCompareOp_ = compareOp;
return *this;
}
PipelineBuilder& PipelineBuilder::setNoDepthTest() {
depthTestEnable_ = false;
depthWriteEnable_ = false;
return *this;
}
PipelineBuilder& PipelineBuilder::setDepthBias(float constantFactor, float slopeFactor) {
depthBiasEnable_ = true;
depthBiasConstant_ = constantFactor;
depthBiasSlope_ = slopeFactor;
return *this;
}
PipelineBuilder& PipelineBuilder::setColorBlendAttachment(
VkPipelineColorBlendAttachmentState blendState)
{
colorBlendAttachments_ = {blendState};
return *this;
}
PipelineBuilder& PipelineBuilder::setNoColorAttachment() {
colorBlendAttachments_.clear();
return *this;
}
PipelineBuilder& PipelineBuilder::setMultisample(VkSampleCountFlagBits samples) {
msaaSamples_ = samples;
return *this;
}
PipelineBuilder& PipelineBuilder::setLayout(VkPipelineLayout layout) {
pipelineLayout_ = layout;
return *this;
}
PipelineBuilder& PipelineBuilder::setRenderPass(VkRenderPass renderPass, uint32_t subpass) {
renderPass_ = renderPass;
subpass_ = subpass;
return *this;
}
PipelineBuilder& PipelineBuilder::setDynamicStates(const std::vector<VkDynamicState>& states) {
dynamicStates_ = states;
return *this;
}
VkPipeline PipelineBuilder::build(VkDevice device) const {
// Vertex input
VkPipelineVertexInputStateCreateInfo vertexInput{};
vertexInput.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInput.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexBindings_.size());
vertexInput.pVertexBindingDescriptions = vertexBindings_.data();
vertexInput.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexAttributes_.size());
vertexInput.pVertexAttributeDescriptions = vertexAttributes_.data();
// Input assembly
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = topology_;
inputAssembly.primitiveRestartEnable = primitiveRestart_;
// Viewport / scissor (dynamic, so just specify count)
VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.scissorCount = 1;
// Rasterization
VkPipelineRasterizationStateCreateInfo rasterizer{};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = polygonMode_;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = cullMode_;
rasterizer.frontFace = frontFace_;
rasterizer.depthBiasEnable = depthBiasEnable_ ? VK_TRUE : VK_FALSE;
rasterizer.depthBiasConstantFactor = depthBiasConstant_;
rasterizer.depthBiasSlopeFactor = depthBiasSlope_;
// Multisampling
VkPipelineMultisampleStateCreateInfo multisampling{};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = msaaSamples_;
// Depth/stencil
VkPipelineDepthStencilStateCreateInfo depthStencil{};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = depthTestEnable_ ? VK_TRUE : VK_FALSE;
depthStencil.depthWriteEnable = depthWriteEnable_ ? VK_TRUE : VK_FALSE;
depthStencil.depthCompareOp = depthCompareOp_;
depthStencil.depthBoundsTestEnable = VK_FALSE;
depthStencil.stencilTestEnable = VK_FALSE;
// Color blending
VkPipelineColorBlendStateCreateInfo colorBlending{};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.attachmentCount = static_cast<uint32_t>(colorBlendAttachments_.size());
colorBlending.pAttachments = colorBlendAttachments_.data();
// Dynamic state
VkPipelineDynamicStateCreateInfo dynamicState{};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates_.size());
dynamicState.pDynamicStates = dynamicStates_.data();
// Create pipeline
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = static_cast<uint32_t>(shaderStages_.size());
pipelineInfo.pStages = shaderStages_.data();
pipelineInfo.pVertexInputState = &vertexInput;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = &depthStencil;
pipelineInfo.pColorBlendState = colorBlendAttachments_.empty() ? nullptr : &colorBlending;
pipelineInfo.pDynamicState = dynamicStates_.empty() ? nullptr : &dynamicState;
pipelineInfo.layout = pipelineLayout_;
pipelineInfo.renderPass = renderPass_;
pipelineInfo.subpass = subpass_;
VkPipeline pipeline = VK_NULL_HANDLE;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo,
nullptr, &pipeline) != VK_SUCCESS)
{
LOG_ERROR("Failed to create graphics pipeline");
return VK_NULL_HANDLE;
}
return pipeline;
}
VkPipelineColorBlendAttachmentState PipelineBuilder::blendDisabled() {
VkPipelineColorBlendAttachmentState state{};
state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
state.blendEnable = VK_FALSE;
return state;
}
VkPipelineColorBlendAttachmentState PipelineBuilder::blendAlpha() {
VkPipelineColorBlendAttachmentState state{};
state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
state.blendEnable = VK_TRUE;
state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
state.colorBlendOp = VK_BLEND_OP_ADD;
state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
state.alphaBlendOp = VK_BLEND_OP_ADD;
return state;
}
VkPipelineColorBlendAttachmentState PipelineBuilder::blendAdditive() {
VkPipelineColorBlendAttachmentState state{};
state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
state.blendEnable = VK_TRUE;
state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
state.colorBlendOp = VK_BLEND_OP_ADD;
state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
state.alphaBlendOp = VK_BLEND_OP_ADD;
return state;
}
VkPipelineLayout createPipelineLayout(VkDevice device,
const std::vector<VkDescriptorSetLayout>& setLayouts,
const std::vector<VkPushConstantRange>& pushConstants)
{
VkPipelineLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layoutInfo.setLayoutCount = static_cast<uint32_t>(setLayouts.size());
layoutInfo.pSetLayouts = setLayouts.data();
layoutInfo.pushConstantRangeCount = static_cast<uint32_t>(pushConstants.size());
layoutInfo.pPushConstantRanges = pushConstants.data();
VkPipelineLayout layout = VK_NULL_HANDLE;
if (vkCreatePipelineLayout(device, &layoutInfo, nullptr, &layout) != VK_SUCCESS) {
LOG_ERROR("Failed to create pipeline layout");
}
return layout;
}
VkDescriptorSetLayout createDescriptorSetLayout(VkDevice device,
const std::vector<VkDescriptorSetLayoutBinding>& bindings)
{
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
layoutInfo.pBindings = bindings.data();
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &layout) != VK_SUCCESS) {
LOG_ERROR("Failed to create descriptor set layout");
}
return layout;
}
} // namespace rendering
} // namespace wowee