MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VKGraphicsPipeline.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "VKShaderModule.hpp"
4
5namespace MayaFlux::Core {
6
8 uint32_t binding;
9 uint32_t stride;
11 vk::VertexInputRate input_rate;
12
13 VertexBinding() = default;
14 VertexBinding(uint32_t b, uint32_t s, bool instanced = false, vk::VertexInputRate rate = vk::VertexInputRate::eVertex)
15 : binding(b)
16 , stride(s)
17 , per_instance(instanced)
18 , input_rate(rate)
19 {
20 }
21};
22
24 uint32_t location;
25 uint32_t binding;
26 vk::Format format;
27 uint32_t offset;
28
29 VertexAttribute() = default;
30 VertexAttribute(uint32_t loc, uint32_t bind, vk::Format fmt, uint32_t off)
31 : location(loc)
32 , binding(bind)
33 , format(fmt)
34 , offset(off)
35 {
36 }
37};
38
40 bool blend_enable = false;
41 vk::BlendFactor src_color_blend_factor = vk::BlendFactor::eSrcAlpha;
42 vk::BlendFactor dst_color_blend_factor = vk::BlendFactor::eOneMinusSrcAlpha;
43 vk::BlendOp color_blend_op = vk::BlendOp::eAdd;
44 vk::BlendFactor src_alpha_blend_factor = vk::BlendFactor::eOne;
45 vk::BlendFactor dst_alpha_blend_factor = vk::BlendFactor::eZero;
46 vk::BlendOp alpha_blend_op = vk::BlendOp::eAdd;
47 vk::ColorComponentFlags color_write_mask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
48};
49
50/**
51 * @struct GraphicsPipelineConfig
52 * @brief Configuration for creating a graphics pipeline
53 *
54 * Comprehensive graphics pipeline state. Vulkan requires ALL fixed-function
55 * state to be specified at pipeline creation time.
56 */
58 //==========================================================================
59 // SHADER STAGES
60 //==========================================================================
61
62 std::shared_ptr<VKShaderModule> vertex_shader = nullptr; // Required
63 std::shared_ptr<VKShaderModule> fragment_shader = nullptr; // Optional (depth-only passes)
64 std::shared_ptr<VKShaderModule> geometry_shader = nullptr; // Optional
65 std::shared_ptr<VKShaderModule> tess_control_shader = nullptr; // Optional
66 std::shared_ptr<VKShaderModule> tess_evaluation_shader = nullptr; // Optional
67
68 //==========================================================================
69 // VERTEX INPUT STATE
70 //==========================================================================
71
72 std::vector<VertexBinding> vertex_bindings;
73 std::vector<VertexAttribute> vertex_attributes;
74
76
77 //==========================================================================
78 // INPUT ASSEMBLY STATE
79 //==========================================================================
80
81 vk::PrimitiveTopology topology = vk::PrimitiveTopology::eTriangleList;
83
84 //==========================================================================
85 // TESSELLATION STATE
86 //==========================================================================
87
89
90 //==========================================================================
91 // VIEWPORT STATE
92 //==========================================================================
93
94 bool dynamic_viewport = true;
95 bool dynamic_scissor = true;
96
97 vk::Viewport static_viewport {};
98 vk::Rect2D static_scissor {};
99
100 //==========================================================================
101 // RASTERIZATION STATE
102 //==========================================================================
103
104 bool depth_clamp_enable = false;
106 vk::PolygonMode polygon_mode = vk::PolygonMode::eFill;
107 vk::CullModeFlags cull_mode = vk::CullModeFlagBits::eBack;
108 vk::FrontFace front_face = vk::FrontFace::eCounterClockwise;
109
110 bool depth_bias_enable = false;
112 float depth_bias_clamp = 0.0f;
114
115 float line_width = 1.0f;
116
117 //==========================================================================
118 // MULTISAMPLE STATE
119 //==========================================================================
120
121 vk::SampleCountFlagBits rasterization_samples = vk::SampleCountFlagBits::e1;
123 float min_sample_shading = 1.0f;
124 std::vector<vk::SampleMask> sample_mask;
127
128 //==========================================================================
129 // DEPTH STENCIL STATE
130 //==========================================================================
131
132 bool depth_test_enable = true;
134 vk::CompareOp depth_compare_op = vk::CompareOp::eLess;
136 float min_depth_bounds = 0.0f;
137 float max_depth_bounds = 1.0f;
138
140 vk::StencilOpState front_stencil {};
141 vk::StencilOpState back_stencil {};
142
143 //==========================================================================
144 // COLOR BLEND STATE
145 //==========================================================================
146
147 bool logic_op_enable = false;
148 vk::LogicOp logic_op = vk::LogicOp::eCopy;
149
150 std::vector<ColorBlendAttachment> color_blend_attachments;
151 std::array<float, 4> blend_constants = { 0.0f, 0.0f, 0.0f, 0.0f };
152
153 //==========================================================================
154 // DYNAMIC STATE
155 //==========================================================================
156
157 std::vector<vk::DynamicState> dynamic_states = {
158 vk::DynamicState::eViewport,
159 vk::DynamicState::eScissor
160 };
161
162 //==========================================================================
163 // PIPELINE LAYOUT (descriptors + push constants)
164 //==========================================================================
165
166 std::vector<vk::DescriptorSetLayout> descriptor_set_layouts;
167 std::vector<vk::PushConstantRange> push_constant_ranges;
168
169 //==========================================================================
170 // DYNAMIC RENDERING
171 //==========================================================================
172
173 std::vector<vk::Format> color_attachment_formats;
174 vk::Format depth_attachment_format = vk::Format::eUndefined;
175 vk::Format stencil_attachment_format = vk::Format::eUndefined;
176
177 //==========================================================================
178 // PIPELINE CACHE
179 //==========================================================================
180
181 vk::PipelineCache cache = nullptr;
182
183 //==========================================================================
184 // HELPER METHODS
185 //==========================================================================
186
192
195 void disable_depth_test();
196 void enable_wireframe();
198 void disable_culling();
199};
200
201/**
202 * @class VKGraphicsPipeline
203 * @brief Vulkan graphics pipeline wrapper
204 *
205 * Handles the complex graphics pipeline state machine. Unlike compute pipelines,
206 * graphics pipelines require extensive fixed-function configuration.
207 *
208 * Responsibilities:
209 * - Create graphics pipeline from config
210 * - Manage pipeline layout
211 * - Bind pipeline to command buffer
212 * - Bind vertex/index buffers
213 * - Bind descriptor sets
214 * - Push constants
215 * - Dynamic state updates (viewport, scissor, etc.)
216 * - Draw commands
217 *
218 * Thread Safety:
219 * - NOT thread-safe
220 * - Create on main thread, use on render thread
221 */
223public:
226
230 VKGraphicsPipeline& operator=(VKGraphicsPipeline&&) noexcept;
231
232 //==========================================================================
233 // PIPELINE CREATION
234 //==========================================================================
235
236 /**
237 * @brief Create graphics pipeline from configuration
238 * @param device Logical device
239 * @param config Pipeline configuration
240 * @return true if creation succeeded
241 *
242 * Validates shaders, creates pipeline layout, and creates pipeline.
243 */
244 bool create(vk::Device device, const GraphicsPipelineConfig& config);
245
246 /**
247 * @brief Cleanup pipeline resources
248 */
249 void cleanup(vk::Device device);
250
251 //==========================================================================
252 // PIPELINE BINDING
253 //==========================================================================
254
255 /**
256 * @brief Bind pipeline to command buffer
257 * @param cmd Command buffer
258 */
259 void bind(vk::CommandBuffer cmd);
260
261 /**
262 * @brief Bind descriptor sets
263 * @param cmd Command buffer
264 * @param sets Descriptor sets to bind
265 * @param first_set First set index (for multiple sets)
266 */
267 void bind_descriptor_sets(vk::CommandBuffer cmd,
268 std::span<vk::DescriptorSet> sets,
269 uint32_t first_set = 0);
270
271 /**
272 * @brief Push constants
273 * @param cmd Command buffer
274 * @param stages Shader stages
275 * @param offset Offset in push constant block
276 * @param size Size of data
277 * @param data Pointer to data
278 */
279 void push_constants(vk::CommandBuffer cmd,
280 vk::ShaderStageFlags stages,
281 uint32_t offset, uint32_t size,
282 const void* data);
283
284 /**
285 * @brief Typed push constants
286 */
287 template <typename T>
288 void push_constants_typed(vk::CommandBuffer cmd,
289 vk::ShaderStageFlags stages,
290 const T& data)
291 {
292 push_constants(cmd, stages, 0, sizeof(T), &data);
293 }
294
295 //==========================================================================
296 // VERTEX/INDEX BUFFER BINDING
297 //==========================================================================
298
299 /**
300 * @brief Bind vertex buffers
301 * @param cmd Command buffer
302 * @param first_binding First binding index
303 * @param buffers Vertex buffers
304 * @param offsets Offsets in buffers
305 */
306 void bind_vertex_buffers(vk::CommandBuffer cmd,
307 uint32_t first_binding,
308 std::span<vk::Buffer> buffers,
309 std::span<vk::DeviceSize> offsets);
310
311 /**
312 * @brief Bind single vertex buffer (common case)
313 */
314 void bind_vertex_buffer(vk::CommandBuffer cmd,
315 vk::Buffer buffer,
316 vk::DeviceSize offset = 0,
317 uint32_t binding = 0);
318
319 /**
320 * @brief Bind index buffer
321 * @param cmd Command buffer
322 * @param buffer Index buffer
323 * @param offset Offset in buffer
324 * @param index_type Index type (uint16 or uint32)
325 */
326 void bind_index_buffer(vk::CommandBuffer cmd,
327 vk::Buffer buffer,
328 vk::DeviceSize offset = 0,
329 vk::IndexType index_type = vk::IndexType::eUint32);
330
331 //==========================================================================
332 // DYNAMIC STATE
333 //==========================================================================
334
335 /**
336 * @brief Set viewport (if dynamic)
337 * @param cmd Command buffer
338 * @param viewport Viewport to set
339 */
340 void set_viewport(vk::CommandBuffer cmd, const vk::Viewport& viewport);
341
342 /**
343 * @brief Set scissor (if dynamic)
344 * @param cmd Command buffer
345 * @param scissor Scissor rectangle
346 */
347 void set_scissor(vk::CommandBuffer cmd, const vk::Rect2D& scissor);
348
349 /**
350 * @brief Set line width (if dynamic)
351 */
352 void set_line_width(vk::CommandBuffer cmd, float width);
353
354 /**
355 * @brief Set depth bias (if dynamic)
356 */
357 void set_depth_bias(vk::CommandBuffer cmd,
358 float constant_factor,
359 float clamp,
360 float slope_factor);
361
362 /**
363 * @brief Set blend constants (if dynamic)
364 */
365 void set_blend_constants(vk::CommandBuffer cmd, const float constants[4]);
366
367 //==========================================================================
368 // DRAW COMMANDS
369 //==========================================================================
370
371 /**
372 * @brief Draw vertices
373 * @param cmd Command buffer
374 * @param vertex_count Number of vertices
375 * @param instance_count Number of instances
376 * @param first_vertex First vertex index
377 * @param first_instance First instance index
378 */
379 void draw(vk::CommandBuffer cmd,
380 uint32_t vertex_count,
381 uint32_t instance_count = 1,
382 uint32_t first_vertex = 0,
383 uint32_t first_instance = 0);
384
385 /**
386 * @brief Draw indexed vertices
387 * @param cmd Command buffer
388 * @param index_count Number of indices
389 * @param instance_count Number of instances
390 * @param first_index First index
391 * @param vertex_offset Vertex offset added to index
392 * @param first_instance First instance index
393 */
394 void draw_indexed(vk::CommandBuffer cmd,
395 uint32_t index_count,
396 uint32_t instance_count = 1,
397 uint32_t first_index = 0,
398 int32_t vertex_offset = 0,
399 uint32_t first_instance = 0);
400
401 /**
402 * @brief Draw indirect (dispatch from GPU buffer)
403 * @param cmd Command buffer
404 * @param buffer Buffer containing vk::DrawIndirectCommand
405 * @param offset Offset in buffer
406 * @param draw_count Number of draws
407 * @param stride Stride between commands
408 */
409 void draw_indirect(vk::CommandBuffer cmd,
410 vk::Buffer buffer,
411 vk::DeviceSize offset,
412 uint32_t draw_count,
413 uint32_t stride);
414
415 /**
416 * @brief Draw indexed indirect
417 */
418 void draw_indexed_indirect(vk::CommandBuffer cmd,
419 vk::Buffer buffer,
420 vk::DeviceSize offset,
421 uint32_t draw_count,
422 uint32_t stride);
423
424 //==========================================================================
425 // ACCESSORS
426 //==========================================================================
427
428 [[nodiscard]] vk::Pipeline get() const { return m_pipeline; }
429 [[nodiscard]] vk::PipelineLayout get_layout() const { return m_layout; }
430 [[nodiscard]] bool is_valid() const { return m_pipeline != nullptr; }
431
432 /**
433 * @brief Get shader reflections (for introspection)
434 */
435 [[nodiscard]] const GraphicsPipelineConfig& get_config() const
436 {
437 return m_config;
438 }
439
440private:
441 vk::Device m_device;
442 vk::Pipeline m_pipeline;
443 vk::PipelineLayout m_layout;
444 GraphicsPipelineConfig m_config; // Keep for reference
445
446 /**
447 * @brief Create pipeline layout from config
448 */
449 vk::PipelineLayout create_pipeline_layout(
450 vk::Device device,
451 const GraphicsPipelineConfig& config);
452
453 /**
454 * @brief Validate shader stages
455 */
456 bool validate_shaders(const GraphicsPipelineConfig& config);
457
458 /**
459 * @brief Build vertex input state from config
460 */
461 vk::PipelineVertexInputStateCreateInfo build_vertex_input_state(
462 const GraphicsPipelineConfig& config,
463 std::vector<vk::VertexInputBindingDescription>& bindings,
464 std::vector<vk::VertexInputAttributeDescription>& attributes);
465
466 /**
467 * @brief Build input assembly state
468 */
469 vk::PipelineInputAssemblyStateCreateInfo build_input_assembly_state(
470 const GraphicsPipelineConfig& config);
471
472 /**
473 * @brief Build tessellation state
474 */
475 vk::PipelineTessellationStateCreateInfo build_tessellation_state(
476 const GraphicsPipelineConfig& config);
477
478 /**
479 * @brief Build viewport state
480 */
481 vk::PipelineViewportStateCreateInfo build_viewport_state(
482 const GraphicsPipelineConfig& config,
483 std::vector<vk::Viewport>& viewports,
484 std::vector<vk::Rect2D>& scissors);
485
486 /**
487 * @brief Build rasterization state
488 */
489 vk::PipelineRasterizationStateCreateInfo build_rasterization_state(
490 const GraphicsPipelineConfig& config);
491
492 /**
493 * @brief Build multisample state
494 */
495 vk::PipelineMultisampleStateCreateInfo build_multisample_state(
496 const GraphicsPipelineConfig& config);
497
498 /**
499 * @brief Build depth stencil state
500 */
501 vk::PipelineDepthStencilStateCreateInfo build_depth_stencil_state(
502 const GraphicsPipelineConfig& config);
503
504 /**
505 * @brief Build color blend state
506 */
507 vk::PipelineColorBlendStateCreateInfo build_color_blend_state(
508 const GraphicsPipelineConfig& config,
509 std::vector<vk::PipelineColorBlendAttachmentState>& attachments);
510
511 /**
512 * @brief Build dynamic state
513 */
514 vk::PipelineDynamicStateCreateInfo build_dynamic_state(
515 const GraphicsPipelineConfig& config);
516};
517
518} // namespace MayaFlux::Core
bool validate_shaders(const GraphicsPipelineConfig &config)
Validate shader stages.
void cleanup(vk::Device device)
Cleanup pipeline resources.
void bind(vk::CommandBuffer cmd)
Bind pipeline to command buffer.
void set_line_width(vk::CommandBuffer cmd, float width)
Set line width (if dynamic)
void set_scissor(vk::CommandBuffer cmd, const vk::Rect2D &scissor)
Set scissor (if dynamic)
void bind_descriptor_sets(vk::CommandBuffer cmd, std::span< vk::DescriptorSet > sets, uint32_t first_set=0)
Bind descriptor sets.
vk::PipelineDepthStencilStateCreateInfo build_depth_stencil_state(const GraphicsPipelineConfig &config)
Build depth stencil state.
void draw(vk::CommandBuffer cmd, uint32_t vertex_count, uint32_t instance_count=1, uint32_t first_vertex=0, uint32_t first_instance=0)
Draw vertices.
void set_depth_bias(vk::CommandBuffer cmd, float constant_factor, float clamp, float slope_factor)
Set depth bias (if dynamic)
vk::PipelineInputAssemblyStateCreateInfo build_input_assembly_state(const GraphicsPipelineConfig &config)
Build input assembly state.
VKGraphicsPipeline & operator=(const VKGraphicsPipeline &)=delete
void bind_vertex_buffers(vk::CommandBuffer cmd, uint32_t first_binding, std::span< vk::Buffer > buffers, std::span< vk::DeviceSize > offsets)
Bind vertex buffers.
void set_blend_constants(vk::CommandBuffer cmd, const float constants[4])
Set blend constants (if dynamic)
void push_constants(vk::CommandBuffer cmd, vk::ShaderStageFlags stages, uint32_t offset, uint32_t size, const void *data)
Push constants.
const GraphicsPipelineConfig & get_config() const
Get shader reflections (for introspection)
vk::PipelineMultisampleStateCreateInfo build_multisample_state(const GraphicsPipelineConfig &config)
Build multisample state.
void bind_vertex_buffer(vk::CommandBuffer cmd, vk::Buffer buffer, vk::DeviceSize offset=0, uint32_t binding=0)
Bind single vertex buffer (common case)
vk::PipelineRasterizationStateCreateInfo build_rasterization_state(const GraphicsPipelineConfig &config)
Build rasterization state.
vk::PipelineVertexInputStateCreateInfo build_vertex_input_state(const GraphicsPipelineConfig &config, std::vector< vk::VertexInputBindingDescription > &bindings, std::vector< vk::VertexInputAttributeDescription > &attributes)
Build vertex input state from config.
vk::PipelineTessellationStateCreateInfo build_tessellation_state(const GraphicsPipelineConfig &config)
Build tessellation state.
bool create(vk::Device device, const GraphicsPipelineConfig &config)
Create graphics pipeline from configuration.
vk::PipelineLayout get_layout() const
void push_constants_typed(vk::CommandBuffer cmd, vk::ShaderStageFlags stages, const T &data)
Typed push constants.
VKGraphicsPipeline(const VKGraphicsPipeline &)=delete
void set_viewport(vk::CommandBuffer cmd, const vk::Viewport &viewport)
Set viewport (if dynamic)
void draw_indexed_indirect(vk::CommandBuffer cmd, vk::Buffer buffer, vk::DeviceSize offset, uint32_t draw_count, uint32_t stride)
Draw indexed indirect.
vk::PipelineLayout create_pipeline_layout(vk::Device device, const GraphicsPipelineConfig &config)
Create pipeline layout from config.
void draw_indexed(vk::CommandBuffer cmd, uint32_t index_count, uint32_t instance_count=1, uint32_t first_index=0, int32_t vertex_offset=0, uint32_t first_instance=0)
Draw indexed vertices.
vk::PipelineColorBlendStateCreateInfo build_color_blend_state(const GraphicsPipelineConfig &config, std::vector< vk::PipelineColorBlendAttachmentState > &attachments)
Build color blend state.
vk::PipelineDynamicStateCreateInfo build_dynamic_state(const GraphicsPipelineConfig &config)
Build dynamic state.
vk::PipelineViewportStateCreateInfo build_viewport_state(const GraphicsPipelineConfig &config, std::vector< vk::Viewport > &viewports, std::vector< vk::Rect2D > &scissors)
Build viewport state.
void bind_index_buffer(vk::CommandBuffer cmd, vk::Buffer buffer, vk::DeviceSize offset=0, vk::IndexType index_type=vk::IndexType::eUint32)
Bind index buffer.
void draw_indirect(vk::CommandBuffer cmd, vk::Buffer buffer, vk::DeviceSize offset, uint32_t draw_count, uint32_t stride)
Draw indirect (dispatch from GPU buffer)
Vulkan graphics pipeline wrapper.
std::vector< ColorBlendAttachment > color_blend_attachments
std::vector< vk::Format > color_attachment_formats
static GraphicsPipelineConfig default_3d()
std::shared_ptr< VKShaderModule > fragment_shader
static GraphicsPipelineConfig alpha_blended()
std::vector< vk::DynamicState > dynamic_states
std::vector< vk::PushConstantRange > push_constant_ranges
static GraphicsPipelineConfig additive_blended()
std::shared_ptr< VKShaderModule > vertex_shader
std::vector< vk::DescriptorSetLayout > descriptor_set_layouts
std::vector< vk::SampleMask > sample_mask
std::vector< VertexBinding > vertex_bindings
static GraphicsPipelineConfig depth_only()
std::vector< VertexAttribute > vertex_attributes
static GraphicsPipelineConfig default_2d()
std::shared_ptr< VKShaderModule > geometry_shader
std::shared_ptr< VKShaderModule > tess_evaluation_shader
std::shared_ptr< VKShaderModule > tess_control_shader
Configuration for creating a graphics pipeline.
VertexAttribute(uint32_t loc, uint32_t bind, vk::Format fmt, uint32_t off)
VertexBinding(uint32_t b, uint32_t s, bool instanced=false, vk::VertexInputRate rate=vk::VertexInputRate::eVertex)