MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VKGraphicsPipeline.cpp
Go to the documentation of this file.
3
4namespace MayaFlux::Core {
5
6// ============================================================================
7// GraphicsPipelineConfig - Static Preset Configurations
8// ============================================================================
9
11{
13 config.topology = vk::PrimitiveTopology::eTriangleList;
14 config.polygon_mode = vk::PolygonMode::eFill;
15 config.cull_mode = vk::CullModeFlagBits::eBack;
16 config.front_face = vk::FrontFace::eCounterClockwise;
17 config.depth_test_enable = true;
18 config.depth_write_enable = true;
19 config.depth_compare_op = vk::CompareOp::eLess;
20
21 ColorBlendAttachment attachment;
22 attachment.blend_enable = false;
23 config.color_blend_attachments.push_back(attachment);
24
25 return config;
26}
27
29{
31 config.topology = vk::PrimitiveTopology::eTriangleList;
32 config.polygon_mode = vk::PolygonMode::eFill;
33 config.cull_mode = vk::CullModeFlagBits::eNone;
34 config.depth_test_enable = false;
35 config.depth_write_enable = false;
36
37 ColorBlendAttachment attachment;
38 attachment.blend_enable = false;
39 config.color_blend_attachments.push_back(attachment);
40
41 return config;
42}
43
50
57
59{
61 config.topology = vk::PrimitiveTopology::eTriangleList;
62 config.polygon_mode = vk::PolygonMode::eFill;
63 config.cull_mode = vk::CullModeFlagBits::eBack;
64 config.rasterizer_discard_enable = false;
65 config.depth_test_enable = true;
66 config.depth_write_enable = true;
67 config.depth_compare_op = vk::CompareOp::eLess;
68 config.color_blend_attachments.clear();
69 return config;
70}
71
72// ============================================================================
73// GraphicsPipelineConfig - Fluent Configuration Methods
74// ============================================================================
75
77{
78 if (color_blend_attachments.empty()) {
79 color_blend_attachments.emplace_back();
80 }
81
82 for (auto& attachment : color_blend_attachments) {
83 attachment.blend_enable = true;
84 attachment.src_color_blend_factor = vk::BlendFactor::eSrcAlpha;
85 attachment.dst_color_blend_factor = vk::BlendFactor::eOneMinusSrcAlpha;
86 attachment.color_blend_op = vk::BlendOp::eAdd;
87 attachment.src_alpha_blend_factor = vk::BlendFactor::eOne;
88 attachment.dst_alpha_blend_factor = vk::BlendFactor::eZero;
89 attachment.alpha_blend_op = vk::BlendOp::eAdd;
90 }
91}
92
94{
95 if (color_blend_attachments.empty()) {
96 color_blend_attachments.emplace_back();
97 }
98
99 for (auto& attachment : color_blend_attachments) {
100 attachment.blend_enable = true;
101 attachment.src_color_blend_factor = vk::BlendFactor::eSrcAlpha;
102 attachment.dst_color_blend_factor = vk::BlendFactor::eOne;
103 attachment.color_blend_op = vk::BlendOp::eAdd;
104 attachment.src_alpha_blend_factor = vk::BlendFactor::eOne;
105 attachment.dst_alpha_blend_factor = vk::BlendFactor::eZero;
106 attachment.alpha_blend_op = vk::BlendOp::eAdd;
107 }
108}
109
115
117{
118 polygon_mode = vk::PolygonMode::eLine;
119}
120
122{
123 cull_mode = vk::CullModeFlagBits::eBack;
124}
125
127{
128 cull_mode = vk::CullModeFlagBits::eNone;
129}
130
131// ============================================================================
132// VKGraphicsPipeline - Lifecycle
133// ============================================================================
134
136{
137 if (m_pipeline || m_layout) {
139 "VKGraphicsPipeline destroyed without cleanup() - potential leak");
140 }
141}
142
144 : m_device(other.m_device)
145 , m_pipeline(other.m_pipeline)
146 , m_layout(other.m_layout)
147 , m_config(std::move(other.m_config))
148{
149 other.m_device = nullptr;
150 other.m_pipeline = nullptr;
151 other.m_layout = nullptr;
152}
153
155{
156 if (this != &other) {
157 if (m_pipeline || m_layout) {
159 "VKGraphicsPipeline move-assigned without cleanup() - potential leak");
160 }
161
162 m_device = other.m_device;
163 m_pipeline = other.m_pipeline;
164 m_layout = other.m_layout;
165 m_config = std::move(other.m_config);
166
167 other.m_device = nullptr;
168 other.m_pipeline = nullptr;
169 other.m_layout = nullptr;
170 }
171 return *this;
172}
173
174void VKGraphicsPipeline::cleanup(vk::Device device)
175{
176 if (m_pipeline) {
177 device.destroyPipeline(m_pipeline);
178 m_pipeline = nullptr;
180 "Graphics pipeline destroyed");
181 }
182
183 if (m_layout) {
184 device.destroyPipelineLayout(m_layout);
185 m_layout = nullptr;
187 "Graphics pipeline layout destroyed");
188 }
189}
190
191// ============================================================================
192// Pipeline Creation
193// ============================================================================
194
195bool VKGraphicsPipeline::create(vk::Device device, const GraphicsPipelineConfig& config)
196{
197 if (!device) {
199 "Cannot create graphics pipeline with null device");
200 return false;
201 }
202
203 m_device = device;
204 m_config = config;
205
206 if (!validate_shaders(config)) {
208 "Shader validation failed");
209 return false;
210 }
211
212 m_layout = create_pipeline_layout(device, config);
213 if (!m_layout) {
215 "Failed to create pipeline layout");
216 return false;
217 }
218
219 std::vector<vk::PipelineShaderStageCreateInfo> shader_stages;
220 if (config.vertex_shader) {
221 shader_stages.push_back(config.vertex_shader->get_stage_create_info());
222 }
223 if (config.fragment_shader) {
224 shader_stages.push_back(config.fragment_shader->get_stage_create_info());
225 }
226 if (config.geometry_shader) {
227 shader_stages.push_back(config.geometry_shader->get_stage_create_info());
228 }
229 if (config.tess_control_shader) {
230 shader_stages.push_back(config.tess_control_shader->get_stage_create_info());
231 }
232 if (config.tess_evaluation_shader) {
233 shader_stages.push_back(config.tess_evaluation_shader->get_stage_create_info());
234 }
235
236 std::vector<vk::VertexInputBindingDescription> vertex_bindings;
237 std::vector<vk::VertexInputAttributeDescription> vertex_attributes;
238 auto vertex_input_state = build_vertex_input_state(config, vertex_bindings, vertex_attributes);
239
240 auto input_assembly_state = build_input_assembly_state(config);
241 auto tessellation_state = build_tessellation_state(config);
242
243 std::vector<vk::Viewport> viewports;
244 std::vector<vk::Rect2D> scissors;
245 auto viewport_state = build_viewport_state(config, viewports, scissors);
246
247 auto rasterization_state = build_rasterization_state(config);
248 auto multisample_state = build_multisample_state(config);
249 auto depth_stencil_state = build_depth_stencil_state(config);
250
251 std::vector<vk::PipelineColorBlendAttachmentState> blend_attachments;
252 auto color_blend_state = build_color_blend_state(config, blend_attachments);
253
254 auto dynamic_state = build_dynamic_state(config);
255
256 vk::GraphicsPipelineCreateInfo pipeline_info;
257 pipeline_info.stageCount = static_cast<uint32_t>(shader_stages.size());
258 pipeline_info.pStages = shader_stages.data();
259 pipeline_info.pVertexInputState = &vertex_input_state;
260 pipeline_info.pInputAssemblyState = &input_assembly_state;
261 pipeline_info.pTessellationState = (config.tess_control_shader || config.tess_evaluation_shader) ? &tessellation_state : nullptr;
262 pipeline_info.pViewportState = &viewport_state;
263 pipeline_info.pRasterizationState = &rasterization_state;
264 pipeline_info.pMultisampleState = &multisample_state;
265 pipeline_info.pDepthStencilState = &depth_stencil_state;
266 pipeline_info.pColorBlendState = &color_blend_state;
267 pipeline_info.pDynamicState = config.dynamic_states.empty() ? nullptr : &dynamic_state;
268 pipeline_info.layout = m_layout;
269 pipeline_info.renderPass = config.render_pass;
270 pipeline_info.subpass = config.subpass;
271 pipeline_info.basePipelineHandle = nullptr;
272 pipeline_info.basePipelineIndex = -1;
273
274 try {
275 auto result = device.createGraphicsPipeline(config.cache, pipeline_info);
276 if (result.result != vk::Result::eSuccess) {
278 "Failed to create graphics pipeline: {}", vk::to_string(result.result));
279 device.destroyPipelineLayout(m_layout);
280 m_layout = nullptr;
281 return false;
282 }
283 m_pipeline = result.value;
284 } catch (const vk::SystemError& e) {
286 "Failed to create graphics pipeline: {}", e.what());
287 device.destroyPipelineLayout(m_layout);
288 m_layout = nullptr;
289 return false;
290 }
291
293 "Graphics pipeline created ({} shader stages)", shader_stages.size());
294
295 return true;
296}
297
299 vk::Device device,
300 const GraphicsPipelineConfig& config)
301{
302 vk::PipelineLayoutCreateInfo layout_info;
303 layout_info.setLayoutCount = static_cast<uint32_t>(config.descriptor_set_layouts.size());
304 layout_info.pSetLayouts = config.descriptor_set_layouts.empty() ? nullptr : config.descriptor_set_layouts.data();
305 layout_info.pushConstantRangeCount = static_cast<uint32_t>(config.push_constant_ranges.size());
306 layout_info.pPushConstantRanges = config.push_constant_ranges.empty() ? nullptr : config.push_constant_ranges.data();
307
308 vk::PipelineLayout layout;
309 try {
310 layout = device.createPipelineLayout(layout_info);
311 } catch (const vk::SystemError& e) {
313 "Failed to create pipeline layout: {}", e.what());
314 return nullptr;
315 }
316
318 "Graphics pipeline layout created ({} sets, {} push constant ranges)",
319 config.descriptor_set_layouts.size(), config.push_constant_ranges.size());
320
321 return layout;
322}
323
325{
326 if (!config.vertex_shader) {
328 "Graphics pipeline requires a vertex shader");
329 return false;
330 }
331
332 if (!config.vertex_shader->is_valid()) {
334 "Vertex shader is not valid");
335 return false;
336 }
337
338 if (config.vertex_shader->get_stage() != vk::ShaderStageFlagBits::eVertex) {
340 "Vertex shader has wrong stage: {}", vk::to_string(config.vertex_shader->get_stage()));
341 return false;
342 }
343
344 if (config.fragment_shader && config.fragment_shader->get_stage() != vk::ShaderStageFlagBits::eFragment) {
346 "Fragment shader has wrong stage: {}", vk::to_string(config.fragment_shader->get_stage()));
347 return false;
348 }
349
350 if (config.geometry_shader && config.geometry_shader->get_stage() != vk::ShaderStageFlagBits::eGeometry) {
352 "Geometry shader has wrong stage");
353 return false;
354 }
355
356 if (config.tess_control_shader && config.tess_control_shader->get_stage() != vk::ShaderStageFlagBits::eTessellationControl) {
358 "Tessellation control shader has wrong stage");
359 return false;
360 }
361
362 if (config.tess_evaluation_shader && config.tess_evaluation_shader->get_stage() != vk::ShaderStageFlagBits::eTessellationEvaluation) {
364 "Tessellation evaluation shader has wrong stage");
365 return false;
366 }
367
368 return true;
369}
370
371// ============================================================================
372// Pipeline State Builders
373// ============================================================================
374
375vk::PipelineVertexInputStateCreateInfo VKGraphicsPipeline::build_vertex_input_state(
376 const GraphicsPipelineConfig& config,
377 std::vector<vk::VertexInputBindingDescription>& bindings,
378 std::vector<vk::VertexInputAttributeDescription>& attributes)
379{
380 if (!config.vertex_bindings.empty() || !config.vertex_attributes.empty()) {
382 "Using explicit vertex bindings/attributes from config "
383 "({} bindings, {} attributes)",
384 config.vertex_bindings.size(), config.vertex_attributes.size());
385
386 for (const auto& binding : config.vertex_bindings) {
387 vk::VertexInputBindingDescription vk_binding;
388 vk_binding.binding = binding.binding;
389 vk_binding.stride = binding.stride;
390 vk_binding.inputRate = binding.input_rate;
391 bindings.push_back(vk_binding);
392 }
393
394 for (const auto& attribute : config.vertex_attributes) {
395 vk::VertexInputAttributeDescription vk_attr;
396 vk_attr.location = attribute.location;
397 vk_attr.binding = attribute.binding;
398 vk_attr.format = attribute.format;
399 vk_attr.offset = attribute.offset;
400 attributes.push_back(vk_attr);
401 }
402 } else if (
404 && config.vertex_shader
405 && config.vertex_shader->has_vertex_input()) {
406
408 "Using vertex input from shader reflection");
409 const auto& vertex_input = config.vertex_shader->get_vertex_input();
410
411 for (const auto& binding : vertex_input.bindings) {
412 vk::VertexInputBindingDescription vk_binding;
413 vk_binding.binding = binding.binding;
414 vk_binding.stride = binding.stride;
415 vk_binding.inputRate = binding.rate;
416 bindings.push_back(vk_binding);
417 }
418
419 for (const auto& attribute : vertex_input.attributes) {
420 vk::VertexInputAttributeDescription vk_attr;
421 vk_attr.location = attribute.location;
422 vk_attr.binding = 0;
423 vk_attr.format = attribute.format;
424 vk_attr.offset = attribute.offset;
425 attributes.push_back(vk_attr);
426 }
427 } else {
429 "No vertex input: using empty vertex state (full-screen quad or compute)");
430 }
431
432 vk::PipelineVertexInputStateCreateInfo vertex_input;
433 vertex_input.vertexBindingDescriptionCount = static_cast<uint32_t>(bindings.size());
434 vertex_input.pVertexBindingDescriptions = bindings.empty() ? nullptr : bindings.data();
435 vertex_input.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributes.size());
436 vertex_input.pVertexAttributeDescriptions = attributes.empty() ? nullptr : attributes.data();
437
438 return vertex_input;
439}
440
441vk::PipelineInputAssemblyStateCreateInfo VKGraphicsPipeline::build_input_assembly_state(
442 const GraphicsPipelineConfig& config)
443{
444 vk::PipelineInputAssemblyStateCreateInfo input_assembly;
445 input_assembly.topology = config.topology;
446 input_assembly.primitiveRestartEnable = config.primitive_restart_enable;
447 return input_assembly;
448}
449
450vk::PipelineTessellationStateCreateInfo VKGraphicsPipeline::build_tessellation_state(
451 const GraphicsPipelineConfig& config)
452{
453 vk::PipelineTessellationStateCreateInfo tessellation;
454 tessellation.patchControlPoints = config.patch_control_points;
455 return tessellation;
456}
457
458vk::PipelineViewportStateCreateInfo VKGraphicsPipeline::build_viewport_state(
459 const GraphicsPipelineConfig& config,
460 std::vector<vk::Viewport>& viewports,
461 std::vector<vk::Rect2D>& scissors)
462{
463 if (!config.dynamic_viewport) {
464 viewports.push_back(config.static_viewport);
465 } else {
466 viewports.emplace_back();
467 }
468
469 if (!config.dynamic_scissor) {
470 scissors.push_back(config.static_scissor);
471 } else {
472 scissors.emplace_back();
473 }
474
475 vk::PipelineViewportStateCreateInfo viewport_state;
476 viewport_state.viewportCount = static_cast<uint32_t>(viewports.size());
477 viewport_state.pViewports = config.dynamic_viewport ? nullptr : viewports.data();
478 viewport_state.scissorCount = static_cast<uint32_t>(scissors.size());
479 viewport_state.pScissors = config.dynamic_scissor ? nullptr : scissors.data();
480
481 return viewport_state;
482}
483
484vk::PipelineRasterizationStateCreateInfo VKGraphicsPipeline::build_rasterization_state(
485 const GraphicsPipelineConfig& config)
486{
487 vk::PipelineRasterizationStateCreateInfo rasterization;
488 rasterization.depthClampEnable = config.depth_clamp_enable;
489 rasterization.rasterizerDiscardEnable = config.rasterizer_discard_enable;
490 rasterization.polygonMode = config.polygon_mode;
491 rasterization.cullMode = config.cull_mode;
492 rasterization.frontFace = config.front_face;
493 rasterization.depthBiasEnable = config.depth_bias_enable;
494 rasterization.depthBiasConstantFactor = config.depth_bias_constant_factor;
495 rasterization.depthBiasClamp = config.depth_bias_clamp;
496 rasterization.depthBiasSlopeFactor = config.depth_bias_slope_factor;
497 rasterization.lineWidth = config.line_width;
498
499 return rasterization;
500}
501
502vk::PipelineMultisampleStateCreateInfo VKGraphicsPipeline::build_multisample_state(
503 const GraphicsPipelineConfig& config)
504{
505 vk::PipelineMultisampleStateCreateInfo multisample;
506 multisample.rasterizationSamples = config.rasterization_samples;
507 multisample.sampleShadingEnable = config.sample_shading_enable;
508 multisample.minSampleShading = config.min_sample_shading;
509 multisample.pSampleMask = config.sample_mask.empty() ? nullptr : config.sample_mask.data();
510 multisample.alphaToCoverageEnable = config.alpha_to_coverage_enable;
511 multisample.alphaToOneEnable = config.alpha_to_one_enable;
512
513 return multisample;
514}
515
516vk::PipelineDepthStencilStateCreateInfo VKGraphicsPipeline::build_depth_stencil_state(
517 const GraphicsPipelineConfig& config)
518{
519 vk::PipelineDepthStencilStateCreateInfo depth_stencil;
520 depth_stencil.depthTestEnable = config.depth_test_enable;
521 depth_stencil.depthWriteEnable = config.depth_write_enable;
522 depth_stencil.depthCompareOp = config.depth_compare_op;
523 depth_stencil.depthBoundsTestEnable = config.depth_bounds_test_enable;
524 depth_stencil.minDepthBounds = config.min_depth_bounds;
525 depth_stencil.maxDepthBounds = config.max_depth_bounds;
526 depth_stencil.stencilTestEnable = config.stencil_test_enable;
527 depth_stencil.front = config.front_stencil;
528 depth_stencil.back = config.back_stencil;
529
530 return depth_stencil;
531}
532
533vk::PipelineColorBlendStateCreateInfo VKGraphicsPipeline::build_color_blend_state(
534 const GraphicsPipelineConfig& config,
535 std::vector<vk::PipelineColorBlendAttachmentState>& attachments)
536{
537 for (const auto& config_attachment : config.color_blend_attachments) {
538 vk::PipelineColorBlendAttachmentState attachment;
539 attachment.blendEnable = config_attachment.blend_enable;
540 attachment.srcColorBlendFactor = config_attachment.src_color_blend_factor;
541 attachment.dstColorBlendFactor = config_attachment.dst_color_blend_factor;
542 attachment.colorBlendOp = config_attachment.color_blend_op;
543 attachment.srcAlphaBlendFactor = config_attachment.src_alpha_blend_factor;
544 attachment.dstAlphaBlendFactor = config_attachment.dst_alpha_blend_factor;
545 attachment.alphaBlendOp = config_attachment.alpha_blend_op;
546 attachment.colorWriteMask = config_attachment.color_write_mask;
547 attachments.push_back(attachment);
548 }
549
550 vk::PipelineColorBlendStateCreateInfo color_blend;
551 color_blend.logicOpEnable = config.logic_op_enable;
552 color_blend.logicOp = config.logic_op;
553 color_blend.attachmentCount = static_cast<uint32_t>(attachments.size());
554 color_blend.pAttachments = attachments.empty() ? nullptr : attachments.data();
555 color_blend.blendConstants[0] = config.blend_constants[0];
556 color_blend.blendConstants[1] = config.blend_constants[1];
557 color_blend.blendConstants[2] = config.blend_constants[2];
558 color_blend.blendConstants[3] = config.blend_constants[3];
559
560 return color_blend;
561}
562
563vk::PipelineDynamicStateCreateInfo VKGraphicsPipeline::build_dynamic_state(
564 const GraphicsPipelineConfig& config)
565{
566 vk::PipelineDynamicStateCreateInfo dynamic_state;
567 dynamic_state.dynamicStateCount = static_cast<uint32_t>(config.dynamic_states.size());
568 dynamic_state.pDynamicStates = config.dynamic_states.data();
569 return dynamic_state;
570}
571
572// ============================================================================
573// Pipeline Binding
574// ============================================================================
575
576void VKGraphicsPipeline::bind(vk::CommandBuffer cmd)
577{
578 if (!m_pipeline) {
580 "Cannot bind invalid graphics pipeline");
581 return;
582 }
583
584 cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, m_pipeline);
585}
586
588 vk::CommandBuffer cmd,
589 std::span<vk::DescriptorSet> sets,
590 uint32_t first_set)
591{
592 if (!m_layout) {
594 "Cannot bind descriptor sets without pipeline layout");
595 return;
596 }
597
598 if (sets.empty()) {
600 "Binding empty descriptor sets");
601 return;
602 }
603
604 cmd.bindDescriptorSets(
605 vk::PipelineBindPoint::eGraphics,
606 m_layout,
607 first_set,
608 static_cast<uint32_t>(sets.size()),
609 sets.data(),
610 0, nullptr);
611}
612
614 vk::CommandBuffer cmd,
615 vk::ShaderStageFlags stages,
616 uint32_t offset,
617 uint32_t size,
618 const void* data)
619{
620 if (!m_layout) {
622 "Cannot push constants without pipeline layout");
623 return;
624 }
625
626 if (!data) {
628 "Cannot push null data");
629 return;
630 }
631
632 cmd.pushConstants(m_layout, stages, offset, size, data);
633}
634
635// ============================================================================
636// Vertex/Index Buffer Binding
637// ============================================================================
638
640 vk::CommandBuffer cmd,
641 uint32_t first_binding,
642 std::span<vk::Buffer> buffers,
643 std::span<vk::DeviceSize> offsets)
644{
645 if (buffers.empty()) {
647 "Binding empty vertex buffers");
648 return;
649 }
650
651 if (buffers.size() != offsets.size()) {
653 "Buffer count ({}) does not match offset count ({})",
654 buffers.size(), offsets.size());
655 return;
656 }
657
658 cmd.bindVertexBuffers(
659 first_binding,
660 static_cast<uint32_t>(buffers.size()),
661 buffers.data(),
662 offsets.data());
663}
664
666 vk::CommandBuffer cmd,
667 vk::Buffer buffer,
668 vk::DeviceSize offset,
669 uint32_t binding)
670{
671 if (!buffer) {
673 "Cannot bind null vertex buffer");
674 return;
675 }
676
677 cmd.bindVertexBuffers(binding, 1, &buffer, &offset);
678}
679
681 vk::CommandBuffer cmd,
682 vk::Buffer buffer,
683 vk::DeviceSize offset,
684 vk::IndexType index_type)
685{
686 if (!buffer) {
688 "Cannot bind null index buffer");
689 return;
690 }
691
692 cmd.bindIndexBuffer(buffer, offset, index_type);
693}
694
695// ============================================================================
696// Dynamic State
697// ============================================================================
698
699void VKGraphicsPipeline::set_viewport(vk::CommandBuffer cmd, const vk::Viewport& viewport)
700{
701 cmd.setViewport(0, 1, &viewport);
702}
703
704void VKGraphicsPipeline::set_scissor(vk::CommandBuffer cmd, const vk::Rect2D& scissor)
705{
706 cmd.setScissor(0, 1, &scissor);
707}
708
709void VKGraphicsPipeline::set_line_width(vk::CommandBuffer cmd, float width)
710{
711 cmd.setLineWidth(width);
712}
713
715 vk::CommandBuffer cmd,
716 float constant_factor,
717 float clamp,
718 float slope_factor)
719{
720 cmd.setDepthBias(constant_factor, clamp, slope_factor);
721}
722
723void VKGraphicsPipeline::set_blend_constants(vk::CommandBuffer cmd, const float constants[4])
724{
725 cmd.setBlendConstants(constants);
726}
727
728// ============================================================================
729// Draw Commands
730// ============================================================================
731
733 vk::CommandBuffer cmd,
734 uint32_t vertex_count,
735 uint32_t instance_count,
736 uint32_t first_vertex,
737 uint32_t first_instance)
738{
739 if (!m_pipeline) {
741 "Cannot draw with invalid pipeline");
742 return;
743 }
744
745 if (vertex_count == 0) {
747 "Drawing with zero vertices");
748 return;
749 }
750
751 cmd.draw(vertex_count, instance_count, first_vertex, first_instance);
752}
753
755 vk::CommandBuffer cmd,
756 uint32_t index_count,
757 uint32_t instance_count,
758 uint32_t first_index,
759 int32_t vertex_offset,
760 uint32_t first_instance)
761{
762 if (!m_pipeline) {
764 "Cannot draw indexed with invalid pipeline");
765 return;
766 }
767
768 if (index_count == 0) {
770 "Drawing with zero indices");
771 return;
772 }
773
774 cmd.drawIndexed(index_count, instance_count, first_index, vertex_offset, first_instance);
775}
776
778 vk::CommandBuffer cmd,
779 vk::Buffer buffer,
780 vk::DeviceSize offset,
781 uint32_t draw_count,
782 uint32_t stride)
783{
784 if (!m_pipeline) {
786 "Cannot draw indirect with invalid pipeline");
787 return;
788 }
789
790 if (!buffer) {
792 "Cannot draw indirect with null buffer");
793 return;
794 }
795
796 if (draw_count == 0) {
798 "Drawing with zero draw count");
799 return;
800 }
801
802 cmd.drawIndirect(buffer, offset, draw_count, stride);
803}
804
806 vk::CommandBuffer cmd,
807 vk::Buffer buffer,
808 vk::DeviceSize offset,
809 uint32_t draw_count,
810 uint32_t stride)
811{
812 if (!m_pipeline) {
814 "Cannot draw indexed indirect with invalid pipeline");
815 return;
816 }
817
818 if (!buffer) {
820 "Cannot draw indexed indirect with null buffer");
821 return;
822 }
823
824 if (draw_count == 0) {
826 "Drawing with zero draw count");
827 return;
828 }
829
830 cmd.drawIndexedIndirect(buffer, offset, draw_count, stride);
831}
832
833} // namespace MayaFlux::Core
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
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.
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.
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.
@ GraphicsBackend
Graphics/visual rendering backend (Vulkan, OpenGL)
@ Core
Core engine, backend, subsystems.
std::vector< ColorBlendAttachment > color_blend_attachments
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.