MayaFlux 0.3.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RenderFlow.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "ShaderFoundry.hpp"
4
6struct DisplayService;
7}
8
9namespace MayaFlux::Core {
10class VKGraphicsPipeline;
11class Window;
12}
13
14namespace MayaFlux::Buffers {
15class RootGraphicsBuffer;
16class VKBuffer;
17}
18
20
21const std::array<float, 4> default_color { 0.0F, 0.0F, 0.0F, 1.0F };
22
23/**
24 * @class RenderFlow
25 * @brief Graphics pipeline orchestration for dynamic rendering
26 *
27 * RenderFlow is the rendering counterpart to ComputePress.
28 * It manages graphics pipelines and draw command recording using Vulkan 1.3 dynamic rendering.
29 *
30 * Responsibilities:
31 * - Create graphics pipelines for dynamic rendering
32 * - Record render commands to secondary command buffers
33 * - Manage dynamic rendering state (begin/end rendering)
34 * - Coordinate with ShaderFoundry for resources
35 *
36 * Design Philosophy (parallel to ComputePress):
37 * - Uses ShaderFoundry for low-level resources
38 * - Provides high-level rendering API
39 * - Backend-agnostic interface
40 * - Integrates with RootGraphicsBuffer
41 * - No render pass objects - uses vkCmdBeginRendering/vkCmdEndRendering
42 *
43 * Usage Pattern:
44 * ```cpp
45 * auto& flow = Portal::Graphics::get_render_flow();
46 * auto& foundry = Portal::Graphics::get_shader_foundry();
47 *
48 * // Create pipeline for dynamic rendering
49 * RenderPipelineConfig config;
50 * config.vertex_shader = vertex_id;
51 * config.fragment_shader = fragment_id;
52 * config.semantic_vertex_layout = buffer->get_vertex_layout();
53 * auto pipeline_id = flow.create_pipeline(config, { swapchain_format });
54 *
55 * // In RenderProcessor - record secondary command buffer:
56 * auto cmd_id = foundry.begin_secondary_commands(swapchain_format);
57 * flow.bind_pipeline(cmd_id, pipeline_id);
58 * flow.bind_vertex_buffers(cmd_id, {buffer});
59 * flow.draw(cmd_id, vertex_count);
60 * foundry.end_commands(cmd_id);
61 *
62 * // In PresentProcessor - execute secondaries in primary:
63 * auto primary_id = foundry.begin_commands(CommandBufferType::GRAPHICS);
64 * flow.begin_rendering(primary_id, window, swapchain_image);
65 * primary_cmd.executeCommands(secondary_buffers);
66 * flow.end_rendering(primary_id, window);
67 * display_service->submit_and_present(window, primary_cmd);
68 * ```
69 */
70class MAYAFLUX_API RenderFlow {
71public:
73 {
74 static RenderFlow flow;
75 return flow;
76 }
77
78 RenderFlow(const RenderFlow&) = delete;
79 RenderFlow& operator=(const RenderFlow&) = delete;
80 RenderFlow(RenderFlow&&) noexcept = delete;
81 RenderFlow& operator=(RenderFlow&&) noexcept = delete;
82
83 bool initialize();
84 void stop();
85 void shutdown();
86
87 [[nodiscard]] bool is_initialized() const { return m_shader_foundry != nullptr; }
88
89 //==========================================================================
90 // Pipeline Creation
91 //==========================================================================
92
93 /**
94 * @brief Create graphics pipeline for dynamic rendering (no render pass object)
95 * @param config Pipeline configuration
96 * @param color_formats Color attachment formats for dynamic rendering
97 * @param depth_format Depth attachment format
98 * @return Pipeline ID or INVALID_RENDER_PIPELINE on error
99 */
100 RenderPipelineID create_pipeline(
101 const RenderPipelineConfig& config,
102 const std::vector<vk::Format>& color_formats,
103 vk::Format depth_format = vk::Format::eUndefined);
104
105 /**
106 * @brief Destroy a graphics pipeline
107 * @param pipeline_id Pipeline ID to destroy
108 */
109 void destroy_pipeline(RenderPipelineID pipeline_id);
110
111 //==========================================================================
112 // Dynamic Rendering
113 //==========================================================================
114
115 /**
116 * @brief Begin dynamic rendering to a window
117 * @param cmd_id Command buffer ID
118 * @param window Target window
119 * @param swapchain_image Swapchain image to render to
120 * @param clear_color Clear color (RGBA)
121 * @param depth_image_view Optional depth attachment view (nullptr = no depth)
122 *
123 * Uses vkCmdBeginRendering - no render pass objects needed.
124 * When depth_image_view is provided, depth clear value is 1.0.
125 */
126 void begin_rendering(
127 CommandBufferID cmd_id,
128 const std::shared_ptr<Core::Window>& window,
129 vk::Image swapchain_image,
130 const std::array<float, 4>& clear_color = default_color,
131 vk::ImageView depth_image_view = nullptr);
132
133 /**
134 * @brief End dynamic rendering
135 * @param cmd_id Command buffer ID
136 * @param window Target window
137 */
138 void end_rendering(CommandBufferID cmd_id, const std::shared_ptr<Core::Window>& window);
139
140 //==========================================================================
141 // Command Recording
142 //==========================================================================
143
144 /**
145 * @brief Bind graphics pipeline
146 * @param cmd_id Command buffer ID
147 * @param pipeline Pipeline ID
148 */
149 void bind_pipeline(CommandBufferID cmd_id, RenderPipelineID pipeline);
150
151 /**
152 * @brief Bind vertex buffers
153 * @param cmd_id Command buffer ID
154 * @param buffers Vertex buffers to bind
155 * @param first_binding First binding index
156 */
157 void bind_vertex_buffers(
158 CommandBufferID cmd_id,
159 const std::vector<std::shared_ptr<Buffers::VKBuffer>>& buffers,
160 uint32_t first_binding = 0);
161
162 /**
163 * @brief Bind index buffer
164 * @param cmd_id Command buffer ID
165 * @param buffer Index buffer
166 * @param index_type Index type (16-bit or 32-bit)
167 */
168 void bind_index_buffer(
169 CommandBufferID cmd_id,
170 const std::shared_ptr<Buffers::VKBuffer>& buffer,
171 vk::IndexType index_type = vk::IndexType::eUint32);
172
173 /**
174 * @brief Bind descriptor sets
175 * @param cmd_id Command buffer ID
176 * @param pipeline Pipeline ID
177 * @param descriptor_sets Descriptor set IDs
178 */
179 void bind_descriptor_sets(
180 CommandBufferID cmd_id,
181 RenderPipelineID pipeline,
182 const std::vector<DescriptorSetID>& descriptor_sets);
183
184 /**
185 * @brief Push constants
186 * @param cmd_id Command buffer ID
187 * @param pipeline Pipeline ID
188 * @param data Constant data
189 * @param size Data size in bytes
190 */
191 void push_constants(
192 CommandBufferID cmd_id,
193 RenderPipelineID pipeline,
194 const void* data,
195 size_t size);
196
197 /**
198 * @brief Draw command
199 * @param cmd_id Command buffer ID
200 * @param vertex_count Number of vertices
201 * @param instance_count Number of instances (default: 1)
202 * @param first_vertex First vertex index
203 * @param first_instance First instance index
204 */
205 void draw(
206 CommandBufferID cmd_id,
207 uint32_t vertex_count,
208 uint32_t instance_count = 1,
209 uint32_t first_vertex = 0,
210 uint32_t first_instance = 0);
211
212 /**
213 * @brief Indexed draw command
214 * @param cmd_id Command buffer ID
215 * @param index_count Number of indices
216 * @param instance_count Number of instances (default: 1)
217 * @param first_index First index
218 * @param vertex_offset Vertex offset
219 * @param first_instance First instance index
220 */
221 void draw_indexed(
222 CommandBufferID cmd_id,
223 uint32_t index_count,
224 uint32_t instance_count = 1,
225 uint32_t first_index = 0,
226 int32_t vertex_offset = 0,
227 uint32_t first_instance = 0);
228
229 /**
230 * @brief Draw mesh tasks (mesh shading pipeline only)
231 */
232 void draw_mesh_tasks(
233 CommandBufferID cmd_id,
234 uint32_t group_count_x,
235 uint32_t group_count_y = 1,
236 uint32_t group_count_z = 1);
237
238 /**
239 * @brief Draw mesh tasks indirect
240 */
241 void draw_mesh_tasks_indirect(
242 CommandBufferID cmd_id,
243 const std::shared_ptr<Buffers::VKBuffer>& buffer,
244 vk::DeviceSize offset = 0,
245 uint32_t draw_count = 1,
246 uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT));
247
248 //==========================================================================
249 // Window Rendering Registration
250 //==========================================================================
251
252 /**
253 * @brief Register a window for dynamic rendering
254 * @param window Target window for rendering
255 *
256 * The window must be registered with GraphicsSubsystem first
257 * (i.e., window->is_graphics_registered() must be true).
258 *
259 * This associates the window with RenderFlow for tracking.
260 * No render pass attachment - dynamic rendering handles this per-frame.
261 */
262 void register_window_for_rendering(const std::shared_ptr<Core::Window>& window);
263
264 /**
265 * @brief Unregister a window from rendering
266 * @param window Window to unregister
267 */
268 void unregister_window(const std::shared_ptr<Core::Window>& window);
269
270 /**
271 * @brief Check if a window is registered for rendering
272 */
273 [[nodiscard]] bool is_window_registered(const std::shared_ptr<Core::Window>& window) const;
274
275 /**
276 * @brief Get all registered windows
277 */
278 [[nodiscard]] std::vector<std::shared_ptr<Core::Window>> get_registered_windows() const;
279
280 //==========================================================================
281 // Convenience Methods
282 //==========================================================================
283
284 /**
285 * @brief Allocate descriptor sets for pipeline
286 * @param pipeline Pipeline ID
287 * @return Vector of allocated descriptor set IDs
288 */
289 std::vector<DescriptorSetID> allocate_pipeline_descriptors(RenderPipelineID pipeline);
290
291private:
293 std::weak_ptr<Core::Window> window;
294 vk::Image swapchain_image {};
295 };
296
298 std::vector<ShaderID> shader_ids;
299 std::shared_ptr<Core::VKGraphicsPipeline> pipeline;
300 std::vector<vk::DescriptorSetLayout> layouts;
301 vk::PipelineLayout layout;
302 vk::ShaderStageFlags push_constant_stages = vk::ShaderStageFlagBits::eVertex
303 | vk::ShaderStageFlagBits::eFragment;
304 };
305
306 std::unordered_map<RenderPipelineID, PipelineState> m_pipelines;
307 std::unordered_map<std::shared_ptr<Core::Window>, WindowRenderAssociation> m_window_associations;
308
309 std::atomic<uint64_t> m_next_pipeline_id { 1 };
310
311 ShaderFoundry* m_shader_foundry = nullptr;
312 Registry::Service::DisplayService* m_display_service = nullptr;
313
314 static bool s_initialized;
315
316 RenderFlow() = default;
318 void cleanup_pipelines();
319
320 /**
321 * @brief Get current image view for window
322 * @param window Target window
323 * @return vk::ImageView of current swapchain image
324 */
325 vk::ImageView get_current_image_view(const std::shared_ptr<Core::Window>& window);
326};
327
328/**
329 * @brief Get the global render flow instance
330 */
331inline MAYAFLUX_API RenderFlow& get_render_flow()
332{
333 return RenderFlow::instance();
334}
335
336} // namespace MayaFlux::Portal::Graphics
RenderFlow(RenderFlow &&) noexcept=delete
std::unordered_map< std::shared_ptr< Core::Window >, WindowRenderAssociation > m_window_associations
RenderFlow & operator=(const RenderFlow &)=delete
std::unordered_map< RenderPipelineID, PipelineState > m_pipelines
RenderFlow(const RenderFlow &)=delete
Graphics pipeline orchestration for dynamic rendering.
Portal-level shader compilation and caching.
void initialize()
Definition main.cpp:11
const std::array< float, 4 > default_color
void shutdown()
Shutdown Portal::Graphics subsystem.
Definition Graphics.cpp:87
MAYAFLUX_API RenderFlow & get_render_flow()
Get the global render flow instance.
std::vector< vk::DescriptorSetLayout > layouts
std::shared_ptr< Core::VKGraphicsPipeline > pipeline
Complete render pipeline configuration.
Backend display and presentation service interface.