28 std::vector<Core::VertexBinding>,
29 std::vector<Core::VertexAttribute>>
30 translate_semantic_layout(
const Kakshya::VertexLayout& layout)
37 "Translated semantic vertex layout: {} bindings, {} attributes",
38 vk_bindings.size(), vk_attributes.size());
40 return { vk_bindings, vk_attributes };
53 "RenderFlow already initialized (static flag)");
59 "RenderFlow already initialized");
66 "ShaderFoundry must be initialized before RenderFlow");
75 "DisplayService not found in BackendRegistry");
82 "RenderFlow initialized");
93 "Shutting down RenderFlow...");
97 "Cannot shutdown RenderFlow: ShaderFoundry not initialized");
105 "Cannot shutdown RenderFlow: Vulkan device is null");
110 if (state.pipeline) {
111 state.pipeline->cleanup(device);
115 device.destroyPipelineLayout(state.layout);
121 if (state.render_pass) {
122 state.render_pass->cleanup(device);
135 "RenderFlow shutdown complete");
148 return vk::PrimitiveTopology::ePointList;
150 return vk::PrimitiveTopology::eLineList;
152 return vk::PrimitiveTopology::eLineStrip;
154 return vk::PrimitiveTopology::eTriangleList;
156 return vk::PrimitiveTopology::eTriangleStrip;
158 return vk::PrimitiveTopology::eTriangleFan;
160 return vk::PrimitiveTopology::eTriangleList;
164 vk::PolygonMode to_vk_polygon_mode(
PolygonMode mode)
168 return vk::PolygonMode::eFill;
170 return vk::PolygonMode::eLine;
172 return vk::PolygonMode::ePoint;
174 return vk::PolygonMode::eFill;
178 vk::CullModeFlags to_vk_cull_mode(
CullMode mode)
182 return vk::CullModeFlagBits::eNone;
184 return vk::CullModeFlagBits::eFront;
186 return vk::CullModeFlagBits::eBack;
188 return vk::CullModeFlagBits::eFrontAndBack;
190 return vk::CullModeFlagBits::eBack;
194 vk::CompareOp to_vk_compare_op(
CompareOp op)
198 return vk::CompareOp::eNever;
200 return vk::CompareOp::eLess;
202 return vk::CompareOp::eEqual;
204 return vk::CompareOp::eLessOrEqual;
206 return vk::CompareOp::eGreater;
208 return vk::CompareOp::eNotEqual;
210 return vk::CompareOp::eGreaterOrEqual;
212 return vk::CompareOp::eAlways;
214 return vk::CompareOp::eLess;
218 vk::BlendFactor to_vk_blend_factor(
BlendFactor factor)
222 return vk::BlendFactor::eZero;
224 return vk::BlendFactor::eOne;
226 return vk::BlendFactor::eSrcColor;
228 return vk::BlendFactor::eOneMinusSrcColor;
230 return vk::BlendFactor::eDstColor;
232 return vk::BlendFactor::eOneMinusDstColor;
234 return vk::BlendFactor::eSrcAlpha;
236 return vk::BlendFactor::eOneMinusSrcAlpha;
238 return vk::BlendFactor::eDstAlpha;
240 return vk::BlendFactor::eOneMinusDstAlpha;
242 return vk::BlendFactor::eOne;
246 vk::BlendOp to_vk_blend_op(
BlendOp op)
250 return vk::BlendOp::eAdd;
252 return vk::BlendOp::eSubtract;
254 return vk::BlendOp::eReverseSubtract;
256 return vk::BlendOp::eMin;
258 return vk::BlendOp::eMax;
260 return vk::BlendOp::eAdd;
270 const std::vector<RenderPassAttachment>& attachments)
274 "RenderFlow not initialized");
278 if (attachments.empty()) {
280 "Cannot create render pass with no attachments");
284 auto render_pass = std::make_shared<Core::VKRenderPass>();
288 for (
const auto& att : attachments) {
296 create_info.attachments.push_back(desc);
300 subpass.
bind_point = vk::PipelineBindPoint::eGraphics;
301 for (uint32_t i = 0; i < attachments.size(); ++i) {
302 vk::AttachmentReference ref;
304 ref.layout = vk::ImageLayout::eColorAttachmentOptimal;
307 create_info.subpasses.push_back(subpass);
325 "Failed to create VKRenderPass");
336 "Render pass created (ID: {}, {} attachments)",
337 render_pass_id, attachments.size());
339 return render_pass_id;
347 color_attachment.
format = format;
348 color_attachment.
load_op = load_clear ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad;
349 color_attachment.
store_op = vk::AttachmentStoreOp::eStore;
351 color_attachment.
final_layout = vk::ImageLayout::ePresentSrcKHR;
363 if (it->second.render_pass) {
370 "Destroyed render pass (ID: {})", render_pass_id);
381 "RenderFlow not initialized");
387 "Vertex shader required for graphics pipeline");
393 "Render pass required for graphics pipeline");
422 "Pipeline using semantic VertexLayout ({} vertices, {} attributes)",
426 auto [vk_bindings, vk_attributes] = translate_semantic_layout(
435 "Pipeline using explicit vertex config ({} bindings, {} attributes)",
440 vk_binding.
binding = binding.binding;
441 vk_binding.stride = binding.stride;
442 vk_binding.input_rate = binding.per_instance ? vk::VertexInputRate::eInstance : vk::VertexInputRate::eVertex;
449 vk_attr.binding = attr.binding;
450 vk_attr.format = attr.format;
451 vk_attr.offset = attr.offset;
458 "Pipeline will use shader reflection for vertex input");
489 std::vector<vk::DescriptorSetLayout> layouts;
491 std::vector<vk::DescriptorSetLayoutBinding> bindings;
492 for (
const auto& binding : desc_set) {
493 vk::DescriptorSetLayoutBinding vk_binding;
494 vk_binding.binding = binding.binding;
495 vk_binding.descriptorType = binding.type;
496 vk_binding.descriptorCount = 1;
497 vk_binding.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment;
498 bindings.push_back(vk_binding);
501 vk::DescriptorSetLayoutCreateInfo layout_info;
502 layout_info.bindingCount =
static_cast<uint32_t
>(bindings.size());
503 layout_info.pBindings = bindings.data();
506 layouts.push_back(layout);
511 vk::PushConstantRange range;
512 range.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment;
518 vk_config.
render_pass = rp_it->second.render_pass->get();
522 vk::DynamicState::eViewport,
523 vk::DynamicState::eScissor
526 auto pipeline = std::make_shared<Core::VKGraphicsPipeline>();
529 "Failed to create VKGraphicsPipeline");
531 for (
auto layout : layouts) {
542 state.
layout = pipeline->get_layout();
547 "Graphics pipeline created (ID: {}, {} descriptor sets)",
548 pipeline_id, layouts.size());
584 if (it->second.pipeline) {
585 it->second.pipeline->cleanup(device);
588 if (it->second.layout) {
589 device.destroyPipelineLayout(it->second.layout);
592 for (
auto layout : it->second.layouts) {
594 device.destroyDescriptorSetLayout(layout);
601 "Destroyed graphics pipeline (ID: {})", pipeline_id);
610 const std::shared_ptr<Core::Window>& window,
611 const std::array<float, 4>& clear_color)
616 "Invalid command buffer ID: {}", cmd_id);
622 "Cannot begin render pass for null window");
629 "Window '{}' not registered for rendering. "
630 "Call register_window_for_rendering() first.",
631 window->get_create_info().title);
638 "Invalid render pass ID: {}", assoc_it->second.render_pass_id);
645 "No framebuffer available for window '{}'. "
646 "Ensure window is registered with GraphicsSubsystem.",
647 window->get_create_info().title);
651 uint32_t width = 0, height = 0;
654 if (width == 0 || height == 0) {
656 "Invalid swapchain extent for window '{}': {}x{}",
657 window->get_create_info().title, width, height);
661 vk::RenderPassBeginInfo begin_info;
662 begin_info.renderPass = rp_it->second.render_pass->get();
663 begin_info.framebuffer = fb_handle->
get();
664 begin_info.renderArea.offset = vk::Offset2D { 0, 0 };
665 begin_info.renderArea.extent = vk::Extent2D { width, height };
667 std::vector<vk::ClearValue> clear_values(rp_it->second.attachments.size());
668 for (
auto& clear_value : clear_values) {
669 clear_value.color = vk::ClearColorValue(clear_color);
673 begin_info.clearValueCount =
static_cast<uint32_t
>(clear_values.size());
674 begin_info.pClearValues = clear_values.data();
676 cmd.beginRenderPass(begin_info, vk::SubpassContents::eInline);
679 "Began render pass for window '{}' ({}x{})",
680 window->get_create_info().title, width, height);
688 "Invalid command buffer ID: {}", cmd_id);
700 "Invalid pipeline ID: {}", pipeline_id);
707 "Invalid command buffer ID: {}", cmd_id);
711 pipeline_it->second.pipeline->bind(cmd);
716 const std::vector<std::shared_ptr<Buffers::VKBuffer>>& buffers,
717 uint32_t first_binding)
722 "Invalid command buffer ID: {}", cmd_id);
726 std::vector<vk::Buffer> vk_buffers;
727 std::vector<vk::DeviceSize> offsets(buffers.size(), 0);
729 vk_buffers.reserve(buffers.size());
730 for (
const auto& buf : buffers) {
731 vk_buffers.push_back(buf->get_buffer());
752 cmd.bindVertexBuffers(first_binding, vk_buffers, offsets);
757 const std::shared_ptr<Buffers::VKBuffer>& buffer,
758 vk::IndexType index_type)
763 "Invalid command buffer ID: {}", cmd_id);
767 cmd.bindIndexBuffer(buffer->get_buffer(), 0, index_type);
773 const std::vector<DescriptorSetID>& descriptor_sets)
778 "Invalid pipeline ID: {}", pipeline_id);
785 "Invalid command buffer ID: {}", cmd_id);
789 std::vector<vk::DescriptorSet> vk_sets;
790 vk_sets.reserve(descriptor_sets.size());
791 for (
auto ds_id : descriptor_sets) {
795 cmd.bindDescriptorSets(
796 vk::PipelineBindPoint::eGraphics,
797 pipeline_it->second.layout,
812 "Invalid pipeline ID: {}", pipeline_id);
819 "Invalid command buffer ID: {}", cmd_id);
824 pipeline_it->second.layout,
825 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
827 static_cast<uint32_t
>(size),
833 uint32_t vertex_count,
834 uint32_t instance_count,
835 uint32_t first_vertex,
836 uint32_t first_instance)
841 "Invalid command buffer ID: {}", cmd_id);
845 cmd.draw(vertex_count, instance_count, first_vertex, first_instance);
850 uint32_t index_count,
851 uint32_t instance_count,
852 uint32_t first_index,
853 int32_t vertex_offset,
854 uint32_t first_instance)
861 cmd.drawIndexed(index_count, instance_count, first_index,
862 vertex_offset, first_instance);
867 const std::shared_ptr<Core::Window>& window)
872 "Invalid command buffer ID: {}", cmd_id);
878 "Cannot present rendered image for null window");
884 }
catch (
const std::exception& e) {
886 "Failed to end command buffer: {}", e.what());
890 uint64_t cmd_bits = *
reinterpret_cast<uint64_t*
>(&cmd);
899 const std::shared_ptr<Core::Window>& window,
904 "Cannot register null window");
911 "Invalid render pass ID: {}", render_pass_id);
915 if (!window->is_graphics_registered()) {
917 "Window '{}' not registered with graphics backend yet. "
918 "Ensure GraphicsSubsystem has registered this window.",
919 window->get_create_info().title);
924 "Failed to attach render pass to window '{}'",
925 window->get_create_info().title);
930 association.
window = window;
936 "Registered window '{}' for rendering with render pass ID {}",
937 window->get_create_info().title,
953 "Unregistered window '{}' from rendering",
954 window->get_create_info().title);
965 std::vector<std::shared_ptr<Core::Window>> windows;
969 if (
auto window = association.window.lock()) {
970 windows.push_back(window);
987 "Invalid pipeline ID: {}", pipeline_id);
991 std::vector<DescriptorSetID> descriptor_set_ids;
992 for (
const auto& layout : pipeline_it->second.layouts) {
996 "Failed to allocate descriptor set for pipeline {}", pipeline_id);
999 descriptor_set_ids.push_back(ds_id);
1003 "Allocated {} descriptor sets for pipeline {}",
1004 descriptor_set_ids.size(), pipeline_id);
1006 return descriptor_set_ids;
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_TRACE(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
vk::Framebuffer get() const
Get the framebuffer handle.
Wrapper for Vulkan framebuffer.
void bind_pipeline(CommandBufferID cmd_id, RenderPipelineID pipeline)
Bind graphics pipeline.
std::unordered_map< RenderPassID, RenderPassState > m_render_passes
void begin_render_pass(CommandBufferID cmd_id, const std::shared_ptr< Core::Window > &window, const std::array< float, 4 > &clear_color={ 0.0F, 0.0F, 0.0F, 1.0F })
Begin render pass.
void push_constants(CommandBufferID cmd_id, RenderPipelineID pipeline, const void *data, size_t size)
Push constants.
std::unordered_map< std::shared_ptr< Core::Window >, WindowRenderAssociation > m_window_associations
std::vector< DescriptorSetID > allocate_pipeline_descriptors(RenderPipelineID pipeline)
Allocate descriptor sets for pipeline.
void destroy_pipeline(RenderPipelineID pipeline_id)
RenderPassID create_simple_render_pass(vk::Format format=vk::Format::eB8G8R8A8Unorm, bool load_clear=true)
Create a simple single-color render pass.
RenderPassID create_render_pass(const std::vector< RenderPassAttachment > &attachments)
Create a render pass.
void present_rendered_image(CommandBufferID cmd_id, const std::shared_ptr< Core::Window > &window)
Present rendered image to window.
void destroy_render_pass(RenderPassID render_pass_id)
std::atomic< uint64_t > m_next_render_pass_id
void bind_vertex_buffers(CommandBufferID cmd_id, const std::vector< std::shared_ptr< Buffers::VKBuffer > > &buffers, uint32_t first_binding=0)
Bind vertex buffers.
std::vector< std::shared_ptr< Core::Window > > get_registered_windows() const
Get all registered windows.
void draw_indexed(CommandBufferID cmd_id, uint32_t index_count, uint32_t instance_count=1, uint32_t first_index=0, int32_t vertex_offset=0, uint32_t first_instance=0)
Indexed draw command.
RenderPipelineID create_simple_pipeline(ShaderID vertex_shader, ShaderID fragment_shader, RenderPassID render_pass)
Create simple graphics pipeline (auto-configure most settings)
std::unordered_map< RenderPipelineID, PipelineState > m_pipelines
bool is_initialized() const
void bind_index_buffer(CommandBufferID cmd_id, const std::shared_ptr< Buffers::VKBuffer > &buffer, vk::IndexType index_type=vk::IndexType::eUint32)
Bind index buffer.
void end_render_pass(CommandBufferID cmd_id)
End current render pass.
ShaderFoundry * m_shader_foundry
void bind_descriptor_sets(CommandBufferID cmd_id, RenderPipelineID pipeline, const std::vector< DescriptorSetID > &descriptor_sets)
Bind descriptor sets.
RenderPipelineID create_pipeline(const RenderPipelineConfig &config)
Create graphics pipeline with full configuration.
bool is_window_registered(const std::shared_ptr< Core::Window > &window) const
Check if a window is registered for rendering.
void draw(CommandBufferID cmd_id, uint32_t vertex_count, uint32_t instance_count=1, uint32_t first_vertex=0, uint32_t first_instance=0)
Draw command.
void unregister_window(const std::shared_ptr< Core::Window > &window)
Unregister a window from rendering.
Registry::Service::DisplayService * m_display_service
std::atomic< uint64_t > m_next_pipeline_id
void register_window_for_rendering(const std::shared_ptr< Core::Window > &window, RenderPassID render_pass_id)
Associate a window with a render pass for rendering.
static bool s_initialized
vk::DescriptorSet get_descriptor_set(DescriptorSetID descriptor_set_id)
Get Vulkan descriptor set handle from DescriptorSetID.
vk::Device get_device() const
std::shared_ptr< Core::VKShaderModule > get_vk_shader_module(ShaderID shader_id)
bool is_initialized() const
Check if compiler is initialized.
static ShaderFoundry & instance()
vk::CommandBuffer get_command_buffer(CommandBufferID cmd_id)
Get Vulkan command buffer handle from CommandBufferID.
DescriptorSetID allocate_descriptor_set(vk::DescriptorSetLayout layout)
Allocate descriptor set for a pipeline.
static std::pair< std::vector< Core::VertexBinding >, std::vector< Core::VertexAttribute > > translate_layout(const Kakshya::VertexLayout &layout, uint32_t binding_index=0)
Translate a semantic vertex layout to Vulkan binding/attribute descriptions.
Interface * get_service()
Query for a backend service.
static BackendRegistry & instance()
Get the global registry instance.
@ Rendering
GPU rendering operations (graphics pipeline, frame rendering)
@ Portal
High-level user-facing API layer.
PolygonMode
Rasterization polygon mode.
constexpr RenderPipelineID INVALID_RENDER_PIPELINE
CullMode
Face culling mode.
uint64_t RenderPipelineID
constexpr RenderPassID INVALID_RENDER_PASS
constexpr ShaderID INVALID_SHADER
BlendOp
Blending operation.
BlendFactor
Blending factor.
PrimitiveTopology
Vertex assembly primitive topology.
CompareOp
Depth/stencil comparison operation.
constexpr DescriptorSetID INVALID_DESCRIPTOR_SET
vk::SampleCountFlagBits samples
vk::AttachmentStoreOp store_op
vk::ImageLayout final_layout
vk::ImageLayout initial_layout
vk::AttachmentLoadOp load_op
vk::BlendOp alpha_blend_op
vk::BlendFactor dst_alpha_blend_factor
vk::BlendFactor src_alpha_blend_factor
vk::BlendFactor dst_color_blend_factor
vk::BlendOp color_blend_op
vk::BlendFactor src_color_blend_factor
std::vector< ColorBlendAttachment > color_blend_attachments
bool use_vertex_shader_reflection
vk::CompareOp depth_compare_op
vk::PrimitiveTopology topology
std::shared_ptr< VKShaderModule > fragment_shader
std::vector< vk::DynamicState > dynamic_states
vk::RenderPass render_pass
std::vector< vk::PushConstantRange > push_constant_ranges
vk::PolygonMode polygon_mode
std::shared_ptr< VKShaderModule > vertex_shader
std::vector< vk::DescriptorSetLayout > descriptor_set_layouts
std::vector< VertexBinding > vertex_bindings
bool primitive_restart_enable
vk::CullModeFlags cull_mode
std::vector< VertexAttribute > vertex_attributes
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.
std::vector< vk::AttachmentReference > color_attachments
vk::PipelineBindPoint bind_point
CompareOp depth_compare_op
std::vector< vk::DescriptorSetLayout > layouts
std::shared_ptr< Core::VKGraphicsPipeline > pipeline
vk::PipelineLayout layout
std::vector< ShaderID > shader_ids
std::shared_ptr< Core::VKRenderPass > render_pass
std::vector< RenderPassAttachment > attachments
RenderPassID render_pass_id
std::weak_ptr< Core::Window > window
vk::AttachmentLoadOp load_op
vk::AttachmentStoreOp store_op
vk::ImageLayout initial_layout
vk::ImageLayout final_layout
Render pass attachment configuration.
std::vector< Core::VertexAttribute > vertex_attributes
ShaderID tess_eval_shader
Optional.
std::vector< Core::VertexBinding > vertex_bindings
std::optional< Kakshya::VertexLayout > semantic_vertex_layout
std::vector< std::vector< DescriptorBindingConfig > > descriptor_sets
ShaderID tess_control_shader
Optional.
bool use_vertex_shader_reflection
std::vector< BlendAttachmentConfig > blend_attachments
DepthStencilConfig depth_stencil
size_t push_constant_size
PrimitiveTopology topology
ShaderID geometry_shader
Optional.
RasterizationConfig rasterization
Complete render pipeline configuration.
std::function< void(const std::shared_ptr< void > &, uint64_t)> present_frame
Present a rendered frame to window.
std::function< void *(const std::shared_ptr< void > &)> get_current_framebuffer
Get current framebuffer for a window.
std::function< void(const std::shared_ptr< void > &, uint32_t &, uint32_t &)> get_swapchain_extent
Get swapchain extent for a window.
std::function< bool(const std::shared_ptr< void > &, const std::shared_ptr< void > &)> attach_render_pass
Attach a custom render pass to a window.
Backend display and presentation service interface.