MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RootGraphicsBuffer.cpp
Go to the documentation of this file.
2
4
7
9
10namespace MayaFlux::Buffers {
11
12GraphicsBatchProcessor::GraphicsBatchProcessor(std::shared_ptr<Buffer> root_buffer)
13 : m_root_buffer(std::dynamic_pointer_cast<RootGraphicsBuffer>(std::move(root_buffer)))
14{
16}
17
18void GraphicsBatchProcessor::processing_function(std::shared_ptr<Buffer> buffer)
19{
20 auto root_buf = std::dynamic_pointer_cast<RootGraphicsBuffer>(buffer);
21 if (!root_buf || root_buf != m_root_buffer) {
23 "GraphicsBatchProcessor can only process its associated RootGraphicsBuffer");
24 return;
25 }
26
27 root_buf->cleanup_marked_buffers();
28
29 for (auto& ch_buffer : root_buf->get_child_buffers()) {
30 if (!ch_buffer)
31 continue;
32
33 if (ch_buffer->needs_removal()) {
34 continue;
35 }
36
37 if (!ch_buffer->has_data_for_cycle()) {
38 continue;
39 }
40
41 try {
42 if (ch_buffer->needs_default_processing() && ch_buffer->get_default_processor()) {
43 ch_buffer->process_default();
44 }
45
46 if (auto chain = ch_buffer->get_processing_chain()) {
47 if (ch_buffer->has_data_for_cycle()) {
48 chain->process(ch_buffer);
49 }
50 }
51
52 auto vk_buffer = std::dynamic_pointer_cast<Buffers::VKBuffer>(ch_buffer);
53 if (vk_buffer && vk_buffer->has_render_pipeline()) {
54 for (const auto& [id, window] : vk_buffer->get_render_pipelines()) {
56 info.buffer = vk_buffer;
57 info.target_window = window;
58 info.pipeline_id = id;
59 info.command_buffer_id = vk_buffer->get_pipeline_command(id);
60
61 root_buf->add_renderable_buffer(info);
62
64 "Registered buffer for rendering to window '{}'",
65 window->get_create_info().title);
66 }
67 }
68
69 } catch (const std::exception& e) {
71 "Error processing graphics buffer: {}", e.what());
72 }
73 }
74}
75
76void GraphicsBatchProcessor::on_attach(std::shared_ptr<Buffer> buffer)
77{
78 auto root_graphics_buffer = std::dynamic_pointer_cast<RootGraphicsBuffer>(buffer);
79 if (!root_graphics_buffer) {
80 error<std::invalid_argument>(
83 std::source_location::current(),
84 "GraphicsBatchProcessor can only be attached to RootGraphicsBuffer");
85 }
86
88 error<std::runtime_error>(
91 std::source_location::current(),
92 "GraphicsBatchProcessor token incompatible with RootGraphicsBuffer requirements");
93 }
94}
95
96bool GraphicsBatchProcessor::is_compatible_with(std::shared_ptr<Buffer> buffer) const
97{
98 return std::dynamic_pointer_cast<RootGraphicsBuffer>(buffer) != nullptr;
99}
100
102 : m_callback(std::move(callback))
103 , m_root_buffer(nullptr)
104{
106}
107
109 : m_callback(nullptr)
110 , m_root_buffer(nullptr)
111{
113}
114
115void PresentProcessor::processing_function(std::shared_ptr<Buffer> buffer)
116{
117 auto root_graphics_buffer = std::dynamic_pointer_cast<RootGraphicsBuffer>(buffer);
118 if (!root_graphics_buffer) {
120 "RenderProcessor received non-RootGraphicsBuffer");
121 return;
122 }
123
124 if (m_root_buffer && root_graphics_buffer != m_root_buffer) {
126 "RenderProcessor processing buffer that doesn't match attached root");
127 return;
128 }
129
130 if (m_callback) {
131 try {
132 m_callback(root_graphics_buffer);
133 } catch (const std::exception& e) {
134 error_rethrow(
137 std::source_location::current(),
138 "RenderProcessor callback threw exception: {}",
139 e.what());
140 }
141 } else {
142 fallback_renderer(root_graphics_buffer);
143 }
144}
145
146void PresentProcessor::on_attach(std::shared_ptr<Buffer> buffer)
147{
148 auto root_graphics_buffer = std::dynamic_pointer_cast<RootGraphicsBuffer>(buffer);
149 if (!root_graphics_buffer) {
150 error<std::invalid_argument>(
153 std::source_location::current(),
154 "RenderProcessor can only be attached to RootGraphicsBuffer");
155 }
156
158 error<std::runtime_error>(
161 std::source_location::current(),
162 "RenderProcessor token incompatible with RootGraphicsBuffer requirements");
163 }
164
165 m_root_buffer = root_graphics_buffer;
166
168 "RenderProcessor attached to RootGraphicsBuffer (has_callback: {})",
169 has_callback());
170}
171
172void PresentProcessor::on_detach(std::shared_ptr<Buffer> buffer)
173{
174 if (auto root = std::dynamic_pointer_cast<RootGraphicsBuffer>(buffer)) {
175 if (root == m_root_buffer) {
176 m_root_buffer = nullptr;
177 }
178 }
179
181 "RenderProcessor detached from RootGraphicsBuffer");
182}
183
184bool PresentProcessor::is_compatible_with(std::shared_ptr<Buffer> buffer) const
185{
186 return std::dynamic_pointer_cast<RootGraphicsBuffer>(buffer) != nullptr;
187}
188
190{
191 m_callback = std::move(callback);
192
194 "RenderProcessor callback {} (attached: {})",
195 m_callback ? "configured" : "cleared",
196 m_root_buffer != nullptr);
197}
198
199void PresentProcessor::fallback_renderer(const std::shared_ptr<RootGraphicsBuffer>& root)
200{
201 auto& foundry = Portal::Graphics::get_shader_foundry();
203
204 const auto& renderable_buffers = root->get_renderable_buffers();
205
206 if (renderable_buffers.empty()) {
208 "No renderable buffers found in fallback renderer");
209 return;
210 }
211
213 "PresentProcessor submitting {} renderable buffers",
214 renderable_buffers.size());
215
216 std::unordered_map<Core::Window*, std::vector<const RootGraphicsBuffer::RenderableBufferInfo*>> buffers_by_window;
217
218 for (const auto& renderable : renderable_buffers) {
219 buffers_by_window[renderable.target_window.get()].push_back(&renderable);
220 }
221
222 for (const auto& [window_ptr, buffer_infos] : buffers_by_window) {
223 auto window = buffer_infos[0]->target_window;
224
225 if (!window) {
227 "Skipping present: window no longer valid");
228 continue;
229 }
230
231 try {
232 for (const auto* info : buffer_infos) {
233 if (info->command_buffer_id != Portal::Graphics::INVALID_COMMAND_BUFFER) {
234 flow.present_rendered_image(
235 info->command_buffer_id,
236 window);
237 }
238 }
239
241 "Presented {} buffers to window '{}'",
242 buffer_infos.size(),
243 window->get_create_info().title);
244
245 } catch (const std::exception& e) {
247 "Failed to submit/present for window '{}': {}",
248 window->get_create_info().title,
249 e.what());
250 }
251
252 for (const auto* info : buffer_infos) {
253 info->buffer->clear_pipeline_commands();
254 }
255 }
256
257 root->clear_renderable_buffers();
258}
259
266
273
275{
276 auto batch_processor = create_default_processor();
277 if (batch_processor) {
278 set_default_processor(batch_processor);
279 }
280}
281
283{
284 if (this->has_pending_operations()) {
286 }
287
288 get_default_processor()->process(shared_from_this());
289}
290
292{
293 if (m_pending_removal.empty()) {
294 return;
295 }
296
297 auto it = std::remove_if(
298 m_child_buffers.begin(),
299 m_child_buffers.end(),
300 [](const std::shared_ptr<Buffer>& buf) {
301 return buf && buf->needs_removal();
302 });
303
304 size_t removed_count = std::distance(it, m_child_buffers.end());
305
306 if (removed_count > 0) {
307 m_child_buffers.erase(it, m_child_buffers.end());
308
310 "Cleaned up {} graphics buffers (remaining: {})",
311 removed_count, m_child_buffers.size());
312 }
313
314 m_pending_removal.clear();
315}
316
317void RootGraphicsBuffer::set_final_processor(std::shared_ptr<BufferProcessor> processor)
318{
319 m_final_processor = std::move(processor);
320}
321
322std::shared_ptr<BufferProcessor> RootGraphicsBuffer::get_final_processor() const
323{
324 return m_final_processor;
325}
326
327bool RootGraphicsBuffer::has_buffer(const std::shared_ptr<VKBuffer>& buffer) const
328{
329 return std::ranges::find(m_child_buffers, buffer) != m_child_buffers.end();
330}
331
332std::vector<std::shared_ptr<VKBuffer>> RootGraphicsBuffer::get_buffers_by_usage(VKBuffer::Usage usage) const
333{
334 std::vector<std::shared_ptr<VKBuffer>> filtered_buffers;
335
336 for (const auto& buffer : m_child_buffers) {
337 if (buffer && buffer->get_usage() == usage) {
338 filtered_buffers.push_back(buffer);
339 }
340 }
341
342 return filtered_buffers;
343}
344
345std::shared_ptr<BufferProcessor> RootGraphicsBuffer::create_default_processor()
346{
347 return std::make_shared<GraphicsBatchProcessor>(shared_from_this());
348}
349
350} // namespace MayaFlux::Buffers
#define MF_INFO(comp, ctx,...)
#define MF_RT_WARN(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
#define MF_RT_DEBUG(comp, ctx,...)
bool is_compatible_with(std::shared_ptr< Buffer > buffer) const override
Checks compatibility with a specific buffer type.
std::shared_ptr< RootGraphicsBuffer > m_root_buffer
Shared pointer to the root buffer this processor manages.
void on_attach(std::shared_ptr< Buffer > buffer) override
Called when processor is attached to a buffer.
GraphicsBatchProcessor(std::shared_ptr< Buffer > root_buffer)
Creates a new graphics batch processor.
void processing_function(std::shared_ptr< Buffer > buffer) override
Processes a buffer by coordinating child buffer operations.
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.
void processing_function(std::shared_ptr< Buffer > buffer) override
Executes the render callback.
void set_callback(RenderCallback callback)
Sets or updates the render callback.
bool is_compatible_with(std::shared_ptr< Buffer > buffer) const override
Checks compatibility with a specific buffer type.
void fallback_renderer(const std::shared_ptr< RootGraphicsBuffer > &root)
void on_attach(std::shared_ptr< Buffer > buffer) override
Called when processor is attached to a buffer.
PresentProcessor()
Default constructor (no callback set)
void on_detach(std::shared_ptr< Buffer > buffer) override
Called when processor is detached from a buffer.
std::shared_ptr< RootGraphicsBuffer > m_root_buffer
Reference to root buffer (for validation and callbacks)
void process_pending_buffer_operations()
Process pending operations - call this at start of processing cycles.
ProcessingToken m_preferred_processing_token
Preferred processing token for this root buffer.
TokenEnforcementStrategy m_token_enforcement_strategy
Current token enforcement strategy for this root buffer.
std::vector< std::shared_ptr< VKBuffer > > m_child_buffers
Vector of tributary buffers that contribute to this root buffer.
void process_default() override
Processes this root buffer using default processing.
std::shared_ptr< BufferProcessor > get_final_processor() const
Gets the current final processor.
void cleanup_marked_buffers()
Removes buffers marked for deletion.
void set_final_processor(std::shared_ptr< BufferProcessor > processor)
Sets an optional final processor.
std::vector< std::shared_ptr< VKBuffer > > get_buffers_by_usage(VKBuffer::Usage usage) const
Gets buffers filtered by usage type.
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)
void initialize()
Initializes the root buffer with default processor.
bool has_buffer(const std::shared_ptr< VKBuffer > &buffer) const
Checks if a specific buffer is registered.
~RootGraphicsBuffer() override
Virtual destructor ensuring proper cleanup.
RootGraphicsBuffer()
Creates a new root graphics buffer.
std::shared_ptr< BufferProcessor > create_default_processor()
Creates the default graphics batch processor.
Root container for GPU buffer lifecycle management and batch processing.
std::shared_ptr< Buffers::BufferProcessor > get_default_processor() const override
Get the currently attached default processor.
Definition VKBuffer.cpp:276
void set_default_processor(std::shared_ptr< Buffers::BufferProcessor > processor) override
Set the buffer's default processor.
Definition VKBuffer.cpp:265
bool are_tokens_compatible(ProcessingToken preferred, ProcessingToken current)
Determines if two processing tokens are compatible for joint execution.
@ GRAPHICS_BACKEND
Standard graphics processing backend configuration.
@ STRICT
Strictly enforces token assignment with no cross-token sharing.
@ BufferManagement
Buffer Management (Buffers::BufferManager, creating buffers)
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
@ Core
Core engine, backend, subsystems.
MAYAFLUX_API RenderFlow & get_render_flow()
Get the global render flow instance.
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
constexpr CommandBufferID INVALID_COMMAND_BUFFER
Information about a buffer that's ready to render.