MayaFlux 1.0.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
180 /**
181 * @brief Request presentation even if the window has no draw commands.
182 * @param window Window whose rendered composition has changed.
183 *
184 * The next presentation clears the window and draws its collected renderables.
185 * GraphicsBatchProcessor records retained visible geometry for this window
186 * even when buffer processing is paused. An empty draw list requests a
187 * clear-only frame. Ordinary processing inactivity does not request a refresh.
188 */
189 void request_presentation_refresh(const std::shared_ptr<Core::Window>& window)
190 {
191 if (window)
192 m_pending_presentation_refreshes.insert(window);
193 }
194
195 /**
196 * @brief Get explicit refresh requests, retained independently of frame draws.
197 */
198 const std::unordered_set<std::shared_ptr<Core::Window>>& get_pending_presentation_refreshes() const
199 {
200 return m_pending_presentation_refreshes;
201 }
202
203 /**
204 * @brief Consume a refresh after submission, or discard it for a closed window.
205 */
206 void clear_presentation_refresh(const std::shared_ptr<Core::Window>& window)
207 {
208 m_pending_presentation_refreshes.erase(window);
209 }
210
211 /**
212 * @brief Stop all render processors from presenting to a window.
213 *
214 * Child buffers and non-render processors remain attached to this root.
215 */
216 void detach_window(const std::shared_ptr<Core::Window>& window);
217
218private:
220
221 /**
222 * @brief Creates the default graphics batch processor
223 * @return Shared pointer to new GraphicsBatchProcessor
224 */
225 std::shared_ptr<BufferProcessor> create_default_processor();
226
227 /**
228 * @brief Add a buffer to the renderable list
229 *
230 * Called by GraphicsBatchProcessor during batch processing.
231 */
233 {
234 m_renderable_buffers.push_back(info);
235 }
236
237 /**
238 * @brief Stable-sort the collected renderable buffers by each buffer's
239 * RenderConfig::draw_priority, lowest first.
240 */
242 {
243 std::ranges::stable_sort(m_renderable_buffers, {},
244 [](const RenderableBufferInfo& info) {
245 return info.buffer ? info.buffer->get_render_config().draw_priority : int64_t {};
246 });
247 }
248
249 std::vector<RenderableBufferInfo> m_renderable_buffers;
250 std::unordered_set<std::shared_ptr<Core::Window>> m_pending_presentation_refreshes;
251
252 /**
253 * @brief Optional final processor (rarely used in graphics)
254 */
255 std::shared_ptr<BufferProcessor> m_final_processor;
256
257 /**
258 * @brief Flag indicating if this buffer is active for token processing
259 */
260 bool m_token_active {};
261};
262
263/**
264 * @class GraphicsBatchProcessor
265 * @brief Default processor for coordinating batch GPU buffer processing
266 *
267 * GraphicsBatchProcessor manages the execution of processing chains across
268 * multiple GPU buffers in a coordinated manner. Unlike ChannelProcessor which
269 * accumulates audio data, GraphicsBatchProcessor focuses on:
270 * - Coordinating buffer uploads (CPU -> GPU)
271 * - Dispatching compute shader operations
272 * - Managing resource transitions and barriers
273 * - Ensuring proper synchronization between operations
274 *
275 * Token Compatibility:
276 * - Primary Token: GRAPHICS_BACKEND (frame-rate, GPU, parallel processing)
277 * - Compatible with GPU_PROCESS tokens for compute operations
278 * - Handles parallel batch operations on GPU resources
279 */
280class MAYAFLUX_API GraphicsBatchProcessor : public BufferProcessor {
281public:
282 /**
283 * @brief Creates a new graphics batch processor
284 * @param root_buffer Shared pointer to the root buffer this processor manages
285 */
286 GraphicsBatchProcessor(std::shared_ptr<Buffer> root_buffer);
287
288 /**
289 * @brief Processes a buffer by coordinating child buffer operations
290 * @param buffer Buffer to process (should be RootGraphicsBuffer)
291 *
292 * This executes the batch processing loop:
293 * 1. Iterates through all child buffers
294 * 2. Executes each buffer's default processor
295 * 3. Runs each buffer's processing chain
296 * 4. Handles synchronization and error cases
297 */
298 void processing_function(const std::shared_ptr<Buffer>& buffer) override;
299
300 /**
301 * @brief Called when processor is attached to a buffer
302 * @param buffer Buffer being attached to
303 *
304 * Validates that the buffer is a RootGraphicsBuffer and ensures
305 * token compatibility for GPU processing.
306 */
307 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
308
309 /**
310 * @brief Checks compatibility with a specific buffer type
311 * @param buffer Buffer to check compatibility with
312 * @return True if compatible (buffer is RootGraphicsBuffer), false otherwise
313 */
314 [[nodiscard]] bool is_compatible_with(const std::shared_ptr<Buffer>& buffer) const override;
315
316private:
317 /** @brief Root buffer this processor manages. */
318 std::weak_ptr<RootGraphicsBuffer> m_root_buffer;
319};
320
321/**
322 * @class PresentProcessor
323 * @brief Final processor that executes render operations after all buffer processing
324 *
325 * PresentProcessor is designed to be set as the final processor of RootGraphicsBuffer.
326 * It's invoked after all child buffer processing chains have completed, making it
327 * the ideal point to:
328 * - Record render commands using processed GPU buffers
329 * - Coordinate rendering operations across multiple buffers
330 * - Submit command buffers to GPU queues
331 * - Present frames to the swapchain
332 *
333 * Design Philosophy:
334 * - Callback-based for maximum flexibility
335 * - Receives RootGraphicsBuffer with all processed child buffers
336 * - No assumptions about rendering strategy (forward, deferred, etc.)
337 * - Can query buffers by usage type for organized rendering
338 *
339 * Usage Pattern:
340 * ```cpp
341 * auto render_proc = std::make_shared<PresentProcessor>(
342 * [this](RootGraphicsBuffer* root) {
343 * // All buffers processed, ready for rendering
344 * auto vertex_bufs = root->get_buffers_by_usage(VKBuffer::Usage::VERTEX);
345 * auto uniform_bufs = root->get_buffers_by_usage(VKBuffer::Usage::UNIFORM);
346 *
347 * // Record render commands
348 * record_render_pass(vertex_bufs, uniform_bufs);
349 *
350 * // Submit and present
351 * submit_graphics_queue();
352 * present_frame();
353 * }
354 * );
355 *
356 * root_graphics_buffer->set_final_processor(render_proc);
357 * ```
358 *
359 * Token Compatibility:
360 * - Primary Token: GRAPHICS_BACKEND
361 * - Executes at frame rate (after all GPU buffer processing)
362 * - Should NOT perform heavy CPU computations (rendering coordination only)
363 */
364class MAYAFLUX_API PresentProcessor : public BufferProcessor {
365public:
366 /**
367 * @brief Callback signature for render operations
368 * @param root RootGraphicsBuffer with all processed child buffers
369 *
370 * The callback receives the root buffer after all child processing is complete.
371 * Child buffers are accessible via:
372 * - root->get_child_buffers() - all buffers
373 * - root->get_buffers_by_usage(usage) - filtered by usage type
374 */
375 using RenderCallback = std::function<void(const std::shared_ptr<RootGraphicsBuffer>& root)>;
376
377 /**
378 * @brief Creates a render processor with a callback function
379 * @param callback Function to execute for rendering operations
380 *
381 * The callback will be invoked during processing_function() with access
382 * to the RootGraphicsBuffer and all its processed child buffers.
383 */
385
386 /**
387 * @brief Default constructor (no callback set)
388 *
389 * Callback can be set later via set_callback().
390 * Processing will be a no-op until callback is configured.
391 */
393
394 ~PresentProcessor() override = default;
395
396 /**
397 * @brief Executes the render callback
398 * @param buffer Buffer to process (must be RootGraphicsBuffer)
399 *
400 * Validates buffer type and invokes the render callback.
401 * This is the core rendering coordination point - all child buffers
402 * have been processed by the time this executes.
403 */
404 void processing_function(const std::shared_ptr<Buffer>& buffer) override;
405
406 /**
407 * @brief Called when processor is attached to a buffer
408 * @param buffer Buffer being attached to
409 *
410 * Validates that the buffer is a RootGraphicsBuffer and ensures
411 * token compatibility for graphics rendering.
412 */
413 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
414
415 /**
416 * @brief Called when processor is detached from a buffer
417 * @param buffer Buffer being detached from
418 */
419 void on_detach(const std::shared_ptr<Buffer>& buffer) override;
420
421 /**
422 * @brief Checks compatibility with a specific buffer type
423 * @param buffer Buffer to check compatibility with
424 * @return True if buffer is RootGraphicsBuffer, false otherwise
425 */
426 [[nodiscard]] bool is_compatible_with(const std::shared_ptr<Buffer>& buffer) const override;
427
428 /**
429 * @brief Sets or updates the render callback
430 * @param callback New callback function
431 *
432 * Allows runtime reconfiguration of rendering strategy.
433 * Useful for switching between different rendering modes or techniques.
434 */
435 void set_callback(RenderCallback callback);
436
437 /**
438 * @brief Checks if a callback is configured
439 * @return True if callback is set, false otherwise
440 */
441 [[nodiscard]] bool has_callback() const { return static_cast<bool>(m_callback); }
442
443 /**
444 * @brief Clears the current callback
445 *
446 * After clearing, processing will be a no-op until a new callback is set.
447 */
448 void clear_callback() { m_callback = nullptr; }
449
450private:
451 /**
452 * @brief User-provided render callback
453 */
455
456 /** @brief Root buffer this presenter is attached to. */
457 std::weak_ptr<RootGraphicsBuffer> m_root_buffer;
458
459 /** @brief Distinguishes an expired attachment from an unattached presenter. */
460 bool m_attached {};
461
462 void fallback_renderer(const std::shared_ptr<RootGraphicsBuffer>& root);
463};
464
465} // namespace MayaFlux::Buffers
std::shared_ptr< NetworkGeometryBuffer > buffer
PickCallback callback
Definition Picker.cpp:22
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23
uint16_t usage
Central computational transformation interface for continuous buffer processing.
std::weak_ptr< RootGraphicsBuffer > m_root_buffer
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.
std::weak_ptr< RootGraphicsBuffer > m_root_buffer
Root buffer this presenter is attached to.
~PresentProcessor() override=default
void clear_callback()
Clears the current callback.
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::unordered_set< std::shared_ptr< Core::Window > > & get_pending_presentation_refreshes() const
Get explicit refresh requests, retained independently of frame draws.
const std::vector< RenderableBufferInfo > & get_renderable_buffers() const
Get list of buffers ready for rendering.
std::unordered_set< std::shared_ptr< Core::Window > > m_pending_presentation_refreshes
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 sort_renderable_buffers()
Stable-sort the collected renderable buffers by each buffer's RenderConfig::draw_priority,...
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)
void request_presentation_refresh(const std::shared_ptr< Core::Window > &window)
Request presentation even if the window has no draw commands.
void clear_presentation_refresh(const std::shared_ptr< Core::Window > &window)
Consume a refresh after submission, or discard it for a closed window.
Root container for GPU buffer lifecycle management and batch processing.
void initialize()
Definition main.cpp:10
uint64_t RenderPipelineID
Definition VKBuffer.hpp:51
uint64_t CommandBufferID
Definition VKBuffer.hpp:52
BufferUsageHint
Semantic usage hint for buffer allocation and memory properties.
Information about a buffer that's ready to render.