MayaFlux 0.3.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RootGraphicsBuffer.hpp
Go to the documentation of this file.
1// RootGraphicsBuffer.hpp
2#pragma once
3
6#include "RootBuffer.hpp"
7
8namespace MayaFlux::Buffers {
9
10class BufferProcessingChain;
11
12/**
13 * @class RootGraphicsBuffer
14 * @brief Root container for GPU buffer lifecycle management and batch processing
15 *
16 * RootGraphicsBuffer serves as the organizational hub for graphics buffers in a processing
17 * domain. Unlike RootAudioBuffer which accumulates and mixes sample data, RootGraphicsBuffer
18 * focuses on:
19 * - Managing the lifecycle of VKBuffer instances (GPU resources)
20 * - Coordinating batch processing across multiple GPU buffers
21 * - Tracking active GPU resources for backend queries
22 * - Providing cleanup mechanisms for marked buffers
23 *
24 * Key Differences from RootAudioBuffer:
25 * - No data accumulation or mixing (each buffer is independent)
26 * - No "final output" concept (buffers are consumed by shaders/dynamic rendering)
27 * - Focuses on resource management and batch coordination
28 * - Processing means executing BufferProcessor chains (uploads, compute, etc.)
29 *
30 * Token Compatibility:
31 * - Primary Token: GRAPHICS_BACKEND (frame-rate, GPU, parallel)
32 * - Compatible with GPU_PROCESS tokens for compute operations
33 * - Not compatible with AUDIO_BACKEND tokens (different processing model)
34 */
35
36class MAYAFLUX_API RootGraphicsBuffer : public RootBuffer<VKBuffer> {
37public:
38 /**
39 * @brief Information about a buffer that's ready to render
40 */
42 std::shared_ptr<VKBuffer> buffer;
43 std::shared_ptr<Core::Window> target_window;
46 bool needs_depth {};
47 };
48
49 /**
50 * @brief Creates a new root graphics buffer
51 *
52 * Initializes with GRAPHICS_BACKEND token preference and prepares
53 * for managing GPU buffer resources. No Vulkan resources are created
54 * until child buffers are registered and initialized by the backend.
55 */
57
58 /**
59 * @brief Virtual destructor ensuring proper cleanup
60 *
61 * Cleans up all child buffer references and ensures pending removals
62 * are processed. Actual GPU resource cleanup is handled by the backend
63 * through registered cleanup hooks.
64 */
65 ~RootGraphicsBuffer() override;
66
67 /**
68 * @brief Initializes the root buffer with default processor
69 *
70 * For graphics, this sets up a GraphicsBatchProcessor as the default
71 * processor which handles coordinating child buffer processing.
72 */
73 void initialize();
74
75 /**
76 * @brief Processes this root buffer using default processing
77 *
78 * For graphics root buffers, this:
79 * 1. Processes all child buffers through process_children()
80 * 2. Executes final processor if one is set (typically for debug/profiling)
81 * 3. Handles pending buffer operations
82 */
83 void process_default() override;
84
85 /**
86 * @brief Gets all child buffers managed by this root
87 * @return Constant reference to vector of child buffers
88 */
89 inline const std::vector<std::shared_ptr<VKBuffer>>& get_child_buffers() const
90 {
91 return m_child_buffers;
92 }
93
94 /**
95 * @brief Sets an optional final processor
96 * @param processor Processor to execute after all child buffers are processed
97 *
98 * Unlike audio where final processing is critical (limiting, normalization),
99 * graphics rarely needs final processing. This can be used for:
100 * - Debug visualization passes
101 * - Profiling/timing measurements
102 * - Resource synchronization barriers
103 */
104 void set_final_processor(std::shared_ptr<BufferProcessor> processor);
105
106 /**
107 * @brief Gets the current final processor
108 * @return Shared pointer to final processor or nullptr
109 */
110 std::shared_ptr<BufferProcessor> get_final_processor() const;
111
112 /**
113 * @brief Gets buffers filtered by usage type
114 * @param usage VKBuffer::Usage type to filter by
115 * @return Vector of buffers matching the specified usage
116 *
117 * Useful for backend queries like "get all compute buffers" or
118 * "find all staging buffers that need upload".
119 */
120 std::vector<std::shared_ptr<VKBuffer>> get_buffers_by_usage(VKBuffer::Usage usage) const;
121
122 /**
123 * @brief Removes buffers marked for deletion
124 *
125 * Performs the actual removal of buffers that have been marked with
126 * mark_for_removal(). This is called automatically during process_children()
127 * but can be called manually for immediate cleanup.
128 *
129 * The actual GPU resource cleanup is handled by the backend's cleanup hooks.
130 */
131 void cleanup_marked_buffers();
132
133 /**
134 * @brief Gets the number of child buffers
135 * @return Number of buffers currently managed
136 */
137 size_t get_buffer_count() const { return m_child_buffers.size(); }
138
139 /**
140 * @brief Checks if a specific buffer is registered
141 * @param buffer Buffer to check
142 * @return True if buffer is managed by this root, false otherwise
143 */
144 bool has_buffer(const std::shared_ptr<VKBuffer>& buffer) const;
145
146 /**
147 * @brief Activates/deactivates processing for the current token
148 * @param active Whether this buffer should process when its token is active
149 */
150 inline void set_token_active(bool active) override { m_token_active = active; }
151
152 /**
153 * @brief Checks if the buffer is active for its assigned token
154 * @return True if the buffer will process when its token is processed
155 */
156 inline bool is_token_active() const override { return m_token_active; }
157
158 /**
159 * @brief Get list of buffers ready for rendering
160 * @return Vector of renderable buffers with their associated windows and pipelines
161 *
162 * Populated by GraphicsBatchProcessor during batch processing.
163 * Consumed by PresentProcessor to perform actual rendering.
164 */
165 const std::vector<RenderableBufferInfo>& get_renderable_buffers() const
166 {
167 return m_renderable_buffers;
168 }
169
170 /**
171 * @brief Clear the renderable buffers list
172 *
173 * Called after rendering completes to prepare for next frame.
174 */
176 {
177 m_renderable_buffers.clear();
178 }
179
180private:
182
183 /**
184 * @brief Creates the default graphics batch processor
185 * @return Shared pointer to new GraphicsBatchProcessor
186 */
187 std::shared_ptr<BufferProcessor> create_default_processor();
188
189 /**
190 * @brief Add a buffer to the renderable list
191 *
192 * Called by GraphicsBatchProcessor during batch processing.
193 */
195 {
196 m_renderable_buffers.push_back(info);
197 }
198
199 std::vector<RenderableBufferInfo> m_renderable_buffers;
200
201 /**
202 * @brief Optional final processor (rarely used in graphics)
203 */
204 std::shared_ptr<BufferProcessor> m_final_processor;
205
206 /**
207 * @brief Buffers pending removal (cleaned up in next process cycle)
208 */
209 std::vector<std::shared_ptr<VKBuffer>> m_pending_removal;
210
211 /**
212 * @brief Flag indicating if this buffer is active for token processing
213 */
214 bool m_token_active {};
215};
216
217/**
218 * @class GraphicsBatchProcessor
219 * @brief Default processor for coordinating batch GPU buffer processing
220 *
221 * GraphicsBatchProcessor manages the execution of processing chains across
222 * multiple GPU buffers in a coordinated manner. Unlike ChannelProcessor which
223 * accumulates audio data, GraphicsBatchProcessor focuses on:
224 * - Coordinating buffer uploads (CPU -> GPU)
225 * - Dispatching compute shader operations
226 * - Managing resource transitions and barriers
227 * - Ensuring proper synchronization between operations
228 *
229 * Token Compatibility:
230 * - Primary Token: GRAPHICS_BACKEND (frame-rate, GPU, parallel processing)
231 * - Compatible with GPU_PROCESS tokens for compute operations
232 * - Handles parallel batch operations on GPU resources
233 */
234class MAYAFLUX_API GraphicsBatchProcessor : public BufferProcessor {
235public:
236 /**
237 * @brief Creates a new graphics batch processor
238 * @param root_buffer Shared pointer to the root buffer this processor manages
239 */
240 GraphicsBatchProcessor(std::shared_ptr<Buffer> root_buffer);
241
242 /**
243 * @brief Processes a buffer by coordinating child buffer operations
244 * @param buffer Buffer to process (should be RootGraphicsBuffer)
245 *
246 * This executes the batch processing loop:
247 * 1. Iterates through all child buffers
248 * 2. Executes each buffer's default processor
249 * 3. Runs each buffer's processing chain
250 * 4. Handles synchronization and error cases
251 */
252 void processing_function(const std::shared_ptr<Buffer>& buffer) override;
253
254 /**
255 * @brief Called when processor is attached to a buffer
256 * @param buffer Buffer being attached to
257 *
258 * Validates that the buffer is a RootGraphicsBuffer and ensures
259 * token compatibility for GPU processing.
260 */
261 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
262
263 /**
264 * @brief Checks compatibility with a specific buffer type
265 * @param buffer Buffer to check compatibility with
266 * @return True if compatible (buffer is RootGraphicsBuffer), false otherwise
267 */
268 [[nodiscard]] bool is_compatible_with(const std::shared_ptr<Buffer>& buffer) const override;
269
270private:
271 /**
272 * @brief Shared pointer to the root buffer this processor manages
273 */
274 std::shared_ptr<RootGraphicsBuffer> m_root_buffer;
275};
276
277/**
278 * @class PresentProcessor
279 * @brief Final processor that executes render operations after all buffer processing
280 *
281 * PresentProcessor is designed to be set as the final processor of RootGraphicsBuffer.
282 * It's invoked after all child buffer processing chains have completed, making it
283 * the ideal point to:
284 * - Record render commands using processed GPU buffers
285 * - Coordinate rendering operations across multiple buffers
286 * - Submit command buffers to GPU queues
287 * - Present frames to the swapchain
288 *
289 * Design Philosophy:
290 * - Callback-based for maximum flexibility
291 * - Receives RootGraphicsBuffer with all processed child buffers
292 * - No assumptions about rendering strategy (forward, deferred, etc.)
293 * - Can query buffers by usage type for organized rendering
294 *
295 * Usage Pattern:
296 * ```cpp
297 * auto render_proc = std::make_shared<PresentProcessor>(
298 * [this](RootGraphicsBuffer* root) {
299 * // All buffers processed, ready for rendering
300 * auto vertex_bufs = root->get_buffers_by_usage(VKBuffer::Usage::VERTEX);
301 * auto uniform_bufs = root->get_buffers_by_usage(VKBuffer::Usage::UNIFORM);
302 *
303 * // Record render commands
304 * record_render_pass(vertex_bufs, uniform_bufs);
305 *
306 * // Submit and present
307 * submit_graphics_queue();
308 * present_frame();
309 * }
310 * );
311 *
312 * root_graphics_buffer->set_final_processor(render_proc);
313 * ```
314 *
315 * Token Compatibility:
316 * - Primary Token: GRAPHICS_BACKEND
317 * - Executes at frame rate (after all GPU buffer processing)
318 * - Should NOT perform heavy CPU computations (rendering coordination only)
319 */
320class MAYAFLUX_API PresentProcessor : public BufferProcessor {
321public:
322 /**
323 * @brief Callback signature for render operations
324 * @param root RootGraphicsBuffer with all processed child buffers
325 *
326 * The callback receives the root buffer after all child processing is complete.
327 * Child buffers are accessible via:
328 * - root->get_child_buffers() - all buffers
329 * - root->get_buffers_by_usage(usage) - filtered by usage type
330 */
331 using RenderCallback = std::function<void(const std::shared_ptr<RootGraphicsBuffer>& root)>;
332
333 /**
334 * @brief Creates a render processor with a callback function
335 * @param callback Function to execute for rendering operations
336 *
337 * The callback will be invoked during processing_function() with access
338 * to the RootGraphicsBuffer and all its processed child buffers.
339 */
341
342 /**
343 * @brief Default constructor (no callback set)
344 *
345 * Callback can be set later via set_callback().
346 * Processing will be a no-op until callback is configured.
347 */
349
350 ~PresentProcessor() override = default;
351
352 /**
353 * @brief Executes the render callback
354 * @param buffer Buffer to process (must be RootGraphicsBuffer)
355 *
356 * Validates buffer type and invokes the render callback.
357 * This is the core rendering coordination point - all child buffers
358 * have been processed by the time this executes.
359 */
360 void processing_function(const std::shared_ptr<Buffer>& buffer) override;
361
362 /**
363 * @brief Called when processor is attached to a buffer
364 * @param buffer Buffer being attached to
365 *
366 * Validates that the buffer is a RootGraphicsBuffer and ensures
367 * token compatibility for graphics rendering.
368 */
369 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
370
371 /**
372 * @brief Called when processor is detached from a buffer
373 * @param buffer Buffer being detached from
374 */
375 void on_detach(const std::shared_ptr<Buffer>& buffer) override;
376
377 /**
378 * @brief Checks compatibility with a specific buffer type
379 * @param buffer Buffer to check compatibility with
380 * @return True if buffer is RootGraphicsBuffer, false otherwise
381 */
382 [[nodiscard]] bool is_compatible_with(const std::shared_ptr<Buffer>& buffer) const override;
383
384 /**
385 * @brief Sets or updates the render callback
386 * @param callback New callback function
387 *
388 * Allows runtime reconfiguration of rendering strategy.
389 * Useful for switching between different rendering modes or techniques.
390 */
391 void set_callback(RenderCallback callback);
392
393 /**
394 * @brief Checks if a callback is configured
395 * @return True if callback is set, false otherwise
396 */
397 [[nodiscard]] bool has_callback() const { return static_cast<bool>(m_callback); }
398
399 /**
400 * @brief Clears the current callback
401 *
402 * After clearing, processing will be a no-op until a new callback is set.
403 */
404 void clear_callback() { m_callback = nullptr; }
405
406private:
407 /**
408 * @brief User-provided render callback
409 */
411
412 /**
413 * @brief Reference to root buffer (for validation and callbacks)
414 *
415 * We store a raw pointer to avoid circular references, as the root
416 * buffer owns the shared_ptr to this processor.
417 */
418 std::shared_ptr<RootGraphicsBuffer> m_root_buffer;
419
420 void fallback_renderer(const std::shared_ptr<RootGraphicsBuffer>& root);
421};
422
423} // namespace MayaFlux::Buffers
Central computational transformation interface for continuous buffer processing.
std::shared_ptr< RootGraphicsBuffer > m_root_buffer
Shared pointer to the root buffer this processor manages.
Default processor for coordinating batch GPU buffer processing.
std::function< void(const std::shared_ptr< RootGraphicsBuffer > &root)> RenderCallback
Callback signature for render operations.
RenderCallback m_callback
User-provided render callback.
bool has_callback() const
Checks if a callback is configured.
~PresentProcessor() override=default
void clear_callback()
Clears the current callback.
std::shared_ptr< RootGraphicsBuffer > m_root_buffer
Reference to root buffer (for validation and callbacks)
Final processor that executes render operations after all buffer processing.
std::vector< RenderableBufferInfo > m_renderable_buffers
size_t get_buffer_count() const
Gets the number of child buffers.
const std::vector< RenderableBufferInfo > & get_renderable_buffers() const
Get list of buffers ready for rendering.
const std::vector< std::shared_ptr< VKBuffer > > & get_child_buffers() const
Gets all child buffers managed by this root.
void clear_renderable_buffers()
Clear the renderable buffers list.
void add_renderable_buffer(const RenderableBufferInfo &info)
Add a buffer to the renderable list.
void set_token_active(bool active) override
Activates/deactivates processing for the current token.
bool is_token_active() const override
Checks if the buffer is active for its assigned token.
std::shared_ptr< BufferProcessor > m_final_processor
Optional final processor (rarely used in graphics)
std::vector< std::shared_ptr< VKBuffer > > m_pending_removal
Buffers pending removal (cleaned up in next process cycle)
Root container for GPU buffer lifecycle management and batch processing.
void initialize()
Definition main.cpp:11
uint64_t RenderPipelineID
Definition VKBuffer.hpp:27
uint64_t CommandBufferID
Definition VKBuffer.hpp:28
Information about a buffer that's ready to render.