MayaFlux 0.3.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 std::shared_ptr<VKShaderModule> mesh_shader = nullptr; // Optional (mesh shading)
68 std::shared_ptr<VKShaderModule> task_shader = nullptr; // Optional (mesh shading)
69
70 bool use_mesh_shading {}; // If true, ignore vertex/fragment shaders and use mesh/task shaders instead
71
72 //==========================================================================
73 // VERTEX INPUT STATE
74 //==========================================================================
75
76 std::vector<VertexBinding> vertex_bindings;
77 std::vector<VertexAttribute> vertex_attributes;
78
80
81 //==========================================================================
82 // INPUT ASSEMBLY STATE
83 //==========================================================================
84
85 vk::PrimitiveTopology topology = vk::PrimitiveTopology::eTriangleList;
87
88 //==========================================================================
89 // TESSELLATION STATE
90 //==========================================================================
91
93
94 //==========================================================================
95 // VIEWPORT STATE
96 //==========================================================================
97
98 bool dynamic_viewport = true;
99 bool dynamic_scissor = true;
100
101 vk::Viewport static_viewport {};
102 vk::Rect2D static_scissor {};
103
104 //==========================================================================
105 // RASTERIZATION STATE
106 //==========================================================================
107
108 bool depth_clamp_enable = false;
110 vk::PolygonMode polygon_mode = vk::PolygonMode::eFill;
111 vk::CullModeFlags cull_mode = vk::CullModeFlagBits::eBack;
112 vk::FrontFace front_face = vk::FrontFace::eCounterClockwise;
113
114 bool depth_bias_enable = false;
116 float depth_bias_clamp = 0.0f;
118
119 float line_width = 1.0f;
120
121 //==========================================================================
122 // MULTISAMPLE STATE
123 //==========================================================================
124
125 vk::SampleCountFlagBits rasterization_samples = vk::SampleCountFlagBits::e1;
127 float min_sample_shading = 1.0f;
128 std::vector<vk::SampleMask> sample_mask;
131
132 //==========================================================================
133 // DEPTH STENCIL STATE
134 //==========================================================================
135
136 bool depth_test_enable = true;
138 vk::CompareOp depth_compare_op = vk::CompareOp::eLess;
140 float min_depth_bounds = 0.0f;
141 float max_depth_bounds = 1.0f;
142
144 vk::StencilOpState front_stencil {};
145 vk::StencilOpState back_stencil {};
146
147 //==========================================================================
148 // COLOR BLEND STATE
149 //==========================================================================
150
151 bool logic_op_enable = false;
152 vk::LogicOp logic_op = vk::LogicOp::eCopy;
153
154 std::vector<ColorBlendAttachment> color_blend_attachments;
155 std::array<float, 4> blend_constants = { 0.0f, 0.0f, 0.0f, 0.0f };
156
157 //==========================================================================
158 // DYNAMIC STATE
159 //==========================================================================
160
161 std::vector<vk::DynamicState> dynamic_states = {
162 vk::DynamicState::eViewport,
163 vk::DynamicState::eScissor
164 };
165
166 //==========================================================================
167 // PIPELINE LAYOUT (descriptors + push constants)
168 //==========================================================================
169
170 std::vector<vk::DescriptorSetLayout> descriptor_set_layouts;
171 std::vector<vk::PushConstantRange> push_constant_ranges;
172
173 //==========================================================================
174 // DYNAMIC RENDERING
175 //==========================================================================
176
177 std::vector<vk::Format> color_attachment_formats;
178 vk::Format depth_attachment_format = vk::Format::eUndefined;
179 vk::Format stencil_attachment_format = vk::Format::eUndefined;
180
181 //==========================================================================
182 // PIPELINE CACHE
183 //==========================================================================
184
185 vk::PipelineCache cache = nullptr;
186
187 //==========================================================================
188 // HELPER METHODS
189 //==========================================================================
190
196
199 void disable_depth_test();
200 void enable_wireframe();
202 void disable_culling();
203};
204
205/**
206 * @class VKGraphicsPipeline
207 * @brief Vulkan graphics pipeline wrapper
208 *
209 * Handles the complex graphics pipeline state machine. Unlike compute pipelines,
210 * graphics pipelines require extensive fixed-function configuration.
211 *
212 * Responsibilities:
213 * - Create graphics pipeline from config
214 * - Manage pipeline layout
215 * - Bind pipeline to command buffer
216 * - Bind vertex/index buffers
217 * - Bind descriptor sets
218 * - Push constants
219 * - Dynamic state updates (viewport, scissor, etc.)
220 * - Draw commands
221 *
222 * Thread Safety:
223 * - NOT thread-safe
224 * - Create on main thread, use on render thread
225 */
227public:
230
234 VKGraphicsPipeline& operator=(VKGraphicsPipeline&&) noexcept;
235
236 //==========================================================================
237 // PIPELINE CREATION
238 //==========================================================================
239
240 /**
241 * @brief Create graphics pipeline from configuration
242 * @param device Logical device
243 * @param config Pipeline configuration
244 * @return true if creation succeeded
245 *
246 * Validates shaders, creates pipeline layout, and creates pipeline.
247 */
248 bool create(vk::Device device, const GraphicsPipelineConfig& config);
249
250 /**
251 * @brief Cleanup pipeline resources
252 */
253 void cleanup(vk::Device device);
254
255 //==========================================================================
256 // PIPELINE BINDING
257 //==========================================================================
258
259 /**
260 * @brief Bind pipeline to command buffer
261 * @param cmd Command buffer
262 */
263 void bind(vk::CommandBuffer cmd);
264
265 /**
266 * @brief Bind descriptor sets
267 * @param cmd Command buffer
268 * @param sets Descriptor sets to bind
269 * @param first_set First set index (for multiple sets)
270 */
271 void bind_descriptor_sets(vk::CommandBuffer cmd,
272 std::span<vk::DescriptorSet> sets,
273 uint32_t first_set = 0);
274
275 /**
276 * @brief Push constants
277 * @param cmd Command buffer
278 * @param stages Shader stages
279 * @param offset Offset in push constant block
280 * @param size Size of data
281 * @param data Pointer to data
282 */
283 void push_constants(vk::CommandBuffer cmd,
284 vk::ShaderStageFlags stages,
285 uint32_t offset, uint32_t size,
286 const void* data);
287
288 /**
289 * @brief Typed push constants
290 */
291 template <typename T>
292 void push_constants_typed(vk::CommandBuffer cmd,
293 vk::ShaderStageFlags stages,
294 const T& data)
295 {
296 push_constants(cmd, stages, 0, sizeof(T), &data);
297 }
298
299 //==========================================================================
300 // VERTEX/INDEX BUFFER BINDING
301 //==========================================================================
302
303 /**
304 * @brief Bind vertex buffers
305 * @param cmd Command buffer
306 * @param first_binding First binding index
307 * @param buffers Vertex buffers
308 * @param offsets Offsets in buffers
309 */
310 void bind_vertex_buffers(vk::CommandBuffer cmd,
311 uint32_t first_binding,
312 std::span<vk::Buffer> buffers,
313 std::span<vk::DeviceSize> offsets);
314
315 /**
316 * @brief Bind single vertex buffer (common case)
317 */
318 void bind_vertex_buffer(vk::CommandBuffer cmd,
319 vk::Buffer buffer,
320 vk::DeviceSize offset = 0,
321 uint32_t binding = 0);
322
323 /**
324 * @brief Bind index buffer
325 * @param cmd Command buffer
326 * @param buffer Index buffer
327 * @param offset Offset in buffer
328 * @param index_type Index type (uint16 or uint32)
329 */
330 void bind_index_buffer(vk::CommandBuffer cmd,
331 vk::Buffer buffer,
332 vk::DeviceSize offset = 0,
333 vk::IndexType index_type = vk::IndexType::eUint32);
334
335 //==========================================================================
336 // DYNAMIC STATE
337 //==========================================================================
338
339 /**
340 * @brief Set viewport (if dynamic)
341 * @param cmd Command buffer
342 * @param viewport Viewport to set
343 */
344 void set_viewport(vk::CommandBuffer cmd, const vk::Viewport& viewport);
345
346 /**
347 * @brief Set scissor (if dynamic)
348 * @param cmd Command buffer
349 * @param scissor Scissor rectangle
350 */
351 void set_scissor(vk::CommandBuffer cmd, const vk::Rect2D& scissor);
352
353 /**
354 * @brief Set line width (if dynamic)
355 */
356 void set_line_width(vk::CommandBuffer cmd, float width);
357
358 /**
359 * @brief Set depth bias (if dynamic)
360 */
361 void set_depth_bias(vk::CommandBuffer cmd,
362 float constant_factor,
363 float clamp,
364 float slope_factor);
365
366 /**
367 * @brief Set blend constants (if dynamic)
368 */
369 void set_blend_constants(vk::CommandBuffer cmd, const float constants[4]);
370
371 //==========================================================================
372 // DRAW COMMANDS
373 //==========================================================================
374
375 /**
376 * @brief Draw vertices
377 * @param cmd Command buffer
378 * @param vertex_count Number of vertices
379 * @param instance_count Number of instances
380 * @param first_vertex First vertex index
381 * @param first_instance First instance index
382 */
383 void draw(vk::CommandBuffer cmd,
384 uint32_t vertex_count,
385 uint32_t instance_count = 1,
386 uint32_t first_vertex = 0,
387 uint32_t first_instance = 0);
388
389 /**
390 * @brief Draw indexed vertices
391 * @param cmd Command buffer
392 * @param index_count Number of indices
393 * @param instance_count Number of instances
394 * @param first_index First index
395 * @param vertex_offset Vertex offset added to index
396 * @param first_instance First instance index
397 */
398 void draw_indexed(vk::CommandBuffer cmd,
399 uint32_t index_count,
400 uint32_t instance_count = 1,
401 uint32_t first_index = 0,
402 int32_t vertex_offset = 0,
403 uint32_t first_instance = 0);
404
405 /**
406 * @brief Draw indirect (dispatch from GPU buffer)
407 * @param cmd Command buffer
408 * @param buffer Buffer containing vk::DrawIndirectCommand
409 * @param offset Offset in buffer
410 * @param draw_count Number of draws
411 * @param stride Stride between commands
412 */
413 void draw_indirect(vk::CommandBuffer cmd,
414 vk::Buffer buffer,
415 vk::DeviceSize offset,
416 uint32_t draw_count,
417 uint32_t stride);
418
419 /**
420 * @brief Draw indexed indirect
421 */
422 void draw_indexed_indirect(vk::CommandBuffer cmd,
423 vk::Buffer buffer,
424 vk::DeviceSize offset,
425 uint32_t draw_count,
426 uint32_t stride);
427
428 /**
429 * @brief Draw mesh tasks (mesh shading pipeline only)
430 */
431 void drawMeshTasks(vk::CommandBuffer cmd,
432 uint32_t groupCountX,
433 uint32_t groupCountY = 1,
434 uint32_t groupCountZ = 1);
435
436 /**
437 * @brief Draw mesh tasks indirect (mesh shading pipeline only)
438 */
439 void drawMeshTasksIndirect(vk::CommandBuffer cmd,
440 vk::Buffer buffer,
441 vk::DeviceSize offset,
442 uint32_t drawCount,
443 uint32_t stride);
444
445 //==========================================================================
446 // ACCESSORS
447 //==========================================================================
448
449 [[nodiscard]] vk::Pipeline get() const { return m_pipeline; }
450 [[nodiscard]] vk::PipelineLayout get_layout() const { return m_layout; }
451 [[nodiscard]] bool is_valid() const { return m_pipeline != nullptr; }
452
453 /**
454 * @brief Get shader reflections (for introspection)
455 */
456 [[nodiscard]] const GraphicsPipelineConfig& get_config() const
457 {
458 return m_config;
459 }
460
461private:
462 vk::Device m_device;
463 vk::Pipeline m_pipeline;
464 vk::PipelineLayout m_layout;
465 GraphicsPipelineConfig m_config; // Keep for reference
466
467 /**
468 * @brief Create pipeline layout from config
469 */
470 vk::PipelineLayout create_pipeline_layout(
471 vk::Device device,
472 const GraphicsPipelineConfig& config);
473
474 /**
475 * @brief Validate shader stages
476 */
477 bool validate_shaders(const GraphicsPipelineConfig& config);
478
479 /**
480 * @brief Build vertex input state from config
481 */
482 vk::PipelineVertexInputStateCreateInfo build_vertex_input_state(
483 const GraphicsPipelineConfig& config,
484 std::vector<vk::VertexInputBindingDescription>& bindings,
485 std::vector<vk::VertexInputAttributeDescription>& attributes);
486
487 /**
488 * @brief Build input assembly state
489 */
490 vk::PipelineInputAssemblyStateCreateInfo build_input_assembly_state(
491 const GraphicsPipelineConfig& config);
492
493 /**
494 * @brief Build tessellation state
495 */
496 vk::PipelineTessellationStateCreateInfo build_tessellation_state(
497 const GraphicsPipelineConfig& config);
498
499 /**
500 * @brief Build viewport state
501 */
502 vk::PipelineViewportStateCreateInfo build_viewport_state(
503 const GraphicsPipelineConfig& config,
504 std::vector<vk::Viewport>& viewports,
505 std::vector<vk::Rect2D>& scissors);
506
507 /**
508 * @brief Build rasterization state
509 */
510 vk::PipelineRasterizationStateCreateInfo build_rasterization_state(
511 const GraphicsPipelineConfig& config);
512
513 /**
514 * @brief Build multisample state
515 */
516 vk::PipelineMultisampleStateCreateInfo build_multisample_state(
517 const GraphicsPipelineConfig& config);
518
519 /**
520 * @brief Build depth stencil state
521 */
522 vk::PipelineDepthStencilStateCreateInfo build_depth_stencil_state(
523 const GraphicsPipelineConfig& config);
524
525 /**
526 * @brief Build color blend state
527 */
528 vk::PipelineColorBlendStateCreateInfo build_color_blend_state(
529 const GraphicsPipelineConfig& config,
530 std::vector<vk::PipelineColorBlendAttachmentState>& attachments);
531
532 /**
533 * @brief Build dynamic state
534 */
535 vk::PipelineDynamicStateCreateInfo build_dynamic_state(
536 const GraphicsPipelineConfig& config);
537};
538
539} // namespace MayaFlux::Core
size_t b
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 drawMeshTasksIndirect(vk::CommandBuffer cmd, vk::Buffer buffer, vk::DeviceSize offset, uint32_t drawCount, uint32_t stride)
Draw mesh tasks indirect (mesh shading pipeline only)
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.
void drawMeshTasks(vk::CommandBuffer cmd, uint32_t groupCountX, uint32_t groupCountY=1, uint32_t groupCountZ=1)
Draw mesh tasks (mesh shading pipeline only)
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 > task_shader
std::shared_ptr< VKShaderModule > fragment_shader
static GraphicsPipelineConfig alpha_blended()
std::shared_ptr< VKShaderModule > mesh_shader
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)