Program Listing for File PipelineBuilder.ixx#
↰ Return to documentation for file (Src/GraphicsEngineVulkan/vulkan_base/PipelineBuilder.ixx)
module;
#include <cstdint>
#include <span>
#include <vector>
#include <vulkan/vulkan.hpp>
export module kataglyphis.vulkan.pipeline_builder;
export namespace Kataglyphis {
// The device-free half of PipelineBuilder::build: every sub-state a
// vk::GraphicsPipelineCreateInfo points at, assembled without touching a
// vk::Device. Freely movable - dynamic_states/color_states are owned here,
// and moving a std::vector never reallocates its buffer, so the pointers
// dynamic_state_create_info.pDynamicStates and color_blending.pAttachments
// stay valid across the move out of PipelineBuilder::buildState().
struct GraphicsPipelineState
{
vk::PipelineVertexInputStateCreateInfo vertex_input_create_info;
vk::PipelineInputAssemblyStateCreateInfo input_assembly;
vk::PipelineViewportStateCreateInfo viewport_state_create_info;
std::vector<vk::DynamicState> dynamic_states;
vk::PipelineDynamicStateCreateInfo dynamic_state_create_info;
vk::PipelineRasterizationStateCreateInfo rasterizer_create_info;
vk::PipelineMultisampleStateCreateInfo multisample_create_info;
vk::PipelineDepthStencilStateCreateInfo depth_stencil_create_info;
std::vector<vk::PipelineColorBlendAttachmentState> color_states;
vk::PipelineColorBlendStateCreateInfo color_blending;
bool use_color_blend_state = true;
};
// Wires the shader stages, pipeline layout, render pass and subpass onto a
// GraphicsPipelineState and returns the top-level create-info ready for
// vk::Device::createGraphicsPipelines. Borrows into both state and stages -
// both must outlive the createGraphicsPipelines call that consumes the
// returned value, the same lifetime rule PipelineLayoutHelper.hpp documents.
[[nodiscard]] vk::GraphicsPipelineCreateInfo linkGraphicsPipelineCreateInfo(const GraphicsPipelineState &state,
std::span<const vk::PipelineShaderStageCreateInfo> stages,
vk::PipelineLayout layout,
vk::RenderPass render_pass,
uint32_t subpass);
// Fluent builder for the graphics pipeline construction that was previously
// copy-pasted across the render stages. Defaults match the most common
// variant: triangle list, dynamic viewport/scissor, fill mode, back-face
// culling, counter-clockwise front face, no blending on a single color
// attachment, depth test + write with CompareOp::eLess, single sample.
// Pipeline LAYOUT creation stays in the stages; this builder only builds
// the vk::Pipeline.
class PipelineBuilder
{
public:
PipelineBuilder();
PipelineBuilder &setShaderStages(std::vector<vk::PipelineShaderStageCreateInfo> shader_stages);
PipelineBuilder &setVertexInput(std::vector<vk::VertexInputBindingDescription> bindings,
std::vector<vk::VertexInputAttributeDescription> attributes);
PipelineBuilder &setCullMode(vk::CullModeFlags cull_mode);
// When enabled uses the standard alpha blending factors
// (srcAlpha/oneMinusSrcAlpha for color, one/zero for alpha, both eAdd).
PipelineBuilder &setAlphaBlending(bool enable);
PipelineBuilder &setColorAttachmentCount(uint32_t count);
// Pass false for depth-only pipelines (no pColorBlendState at all).
PipelineBuilder &setUseColorBlendState(bool use_color_blend_state);
PipelineBuilder &setDepthTest(bool enable);
PipelineBuilder &setDepthWrite(bool enable);
PipelineBuilder &setDepthCompareOp(vk::CompareOp compare_op);
// Depth clamp ("shadow pancaking"): fragments nearer than the near plane
// clamp to depth 0 instead of being CLIPPED. Only legal when the device
// feature is enabled - pass VulkanDevice::supportsDepthClamp().
PipelineBuilder &setDepthClamp(bool enable);
// Adds VK_DYNAMIC_STATE_CULL_MODE so the cull mode set by setCullMode becomes
// a per-draw dynamic state (vkCmdSetCullMode). Core in Vulkan 1.3, which the
// engine targets. Opt-in: off by default, so every other pipeline keeps its
// static cull mode and needs no per-draw setCullMode. Used by the forward
// raster pass to disable back-face culling for doubleSided glTF meshes only.
PipelineBuilder &setDynamicCullMode(bool enable);
// Assembles every sub-state build() needs without touching a vk::Device -
// see GraphicsPipelineState. Pair with linkGraphicsPipelineCreateInfo to
// reproduce build()'s result one call site at a time in a CPU-only test.
[[nodiscard]] GraphicsPipelineState buildState() const;
// Creates the pipeline via createGraphicsPipelines(pipeline_cache, ...);
// aborts through ASSERT_VULKAN with error_message on failure.
// pipeline_cache may be null (no caching).
[[nodiscard]] vk::Pipeline build(vk::Device device,
vk::PipelineLayout pipeline_layout,
vk::RenderPass render_pass,
vk::PipelineCache pipeline_cache = nullptr,
uint32_t subpass = 0,
const char *error_message = "Failed to create a graphics pipeline!") const;
private:
std::vector<vk::PipelineShaderStageCreateInfo> shader_stages;
std::vector<vk::VertexInputBindingDescription> vertex_bindings;
std::vector<vk::VertexInputAttributeDescription> vertex_attributes;
// No setter and never varies - CascadedShadowMap.cpp reasons about this
// exact default explicitly (culling is disabled there instead of flipping
// the front face to match the projection's Y-flip).
static constexpr vk::FrontFace kFrontFace = vk::FrontFace::eCounterClockwise;
vk::CullModeFlags cull_mode = vk::CullModeFlagBits::eBack;
bool alpha_blending = false;
uint32_t color_attachment_count = 1;
bool use_color_blend_state = true;
bool depth_test = true;
bool depth_write = true;
vk::CompareOp depth_compare_op = vk::CompareOp::eLess;
bool depth_clamp = false;
bool dynamic_cull_mode = false;
};
}// namespace Kataglyphis