MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GraphicsSubsystem.cpp
Go to the documentation of this file.
2
7
10
13
14namespace MayaFlux::Core {
15
16std::unique_ptr<IGraphicsBackend> create_graphics_backend(GlobalGraphicsConfig::GraphicsApi api)
17{
18 switch (api) {
20 return std::make_unique<VulkanBackend>();
24 default:
25 return nullptr;
26 }
27}
28
30 : m_backend(create_graphics_backend(graphics_config.requested_api))
31 , m_frame_clock(std::make_shared<Vruta::FrameClock>(60))
32 , m_subsystem_tokens {
33 .Buffer = Buffers::ProcessingToken::GRAPHICS_BACKEND,
34 .Node = Nodes::ProcessingToken::VISUAL_RATE,
35 .Task = Vruta::ProcessingToken::FRAME_ACCURATE
36 }
37 , m_graphics_config(graphics_config)
38{
39}
40
45
47{
49 "Initializing Graphics Subsystem...");
50
51 m_handle = &handle;
52
53 if (!m_backend->initialize(m_graphics_config)) {
54 error<std::runtime_error>(
57 std::source_location::current(),
58 "No graphics backend available");
59 }
60
63 }
64
66
68
69 m_is_ready = true;
70
72 "Graphics Subsystem initialized (Target FPS: {})",
73 m_frame_clock->frame_rate());
74}
75
77{
78 try {
79 if (auto vulkan_backend = dynamic_cast<VulkanBackend*>(m_backend.get())) {
80 Portal::Graphics::initialize(std::shared_ptr<VulkanBackend>(vulkan_backend, [](VulkanBackend*) { }));
81 }
82 } catch (std::exception& e) {
83 error_rethrow(
86 std::source_location::current(),
87 "Failed to initialize Portal::Graphics subsystem: {}",
88 e.what());
89 }
90}
91
93{
94 if (!m_handle) {
95 error<std::runtime_error>(
98 std::source_location::current(),
99 "Cannot register frame processor: no processing handle");
100 }
101
102 auto scheduler = m_handle->tasks;
103 if (!scheduler.is_valid()) {
104 error<std::runtime_error>(
107 std::source_location::current(),
108 "Cannot register frame processor: no scheduler available");
109 }
110
111 scheduler.register_token_processor(
112 [this](const std::vector<std::shared_ptr<Vruta::Routine>>& tasks, uint64_t processing_units) {
113 this->process_frame_coroutines_impl(tasks, processing_units);
114 });
115
117 "Registered custom FRAME_ACCURATE processor");
118}
119
121{
122 if (!m_is_ready) {
123 error<std::runtime_error>(
126 std::source_location::current(),
127 "Subsystem is not initialized. Please initialize before registering callbacks.");
128 }
129
131
133 "Graphics callbacks registered (self-driven mode)");
134}
135
137 const std::vector<std::shared_ptr<Vruta::Routine>>& tasks,
138 uint64_t processing_units)
139{
140 if (tasks.empty()) {
141 return;
142 }
143
144 uint64_t current_frame = m_frame_clock->current_position();
145
146 if (processing_units == 0) {
147 processing_units = 1;
148 }
149
150 for (uint64_t i = 0; i < processing_units; ++i) {
151 uint64_t frame_to_process = current_frame + i;
152
153 for (auto& routine : tasks) {
154 if (!routine || !routine->is_active()) {
155 continue;
156 }
157
158 if (routine->requires_clock_sync()) {
159 if (frame_to_process >= routine->next_execution()) {
160 routine->try_resume(frame_to_process);
161 }
162 } else {
163 routine->try_resume(frame_to_process);
164 }
165 }
166 }
167}
168
170{
171 if (m_running.load(std::memory_order_acquire)) {
173 "Graphics thread already running!");
174 return;
175 }
176
177 m_running.store(true);
178 m_paused.store(false, std::memory_order_release);
179
180 m_frame_clock->reset();
181
182 m_graphics_thread = std::thread([this]() {
183 m_graphics_thread_id = std::this_thread::get_id();
184
186 "Graphics thread started (ID: {}, Target FPS: {})",
187 std::hash<std::thread::id> {}(m_graphics_thread_id),
188 m_frame_clock->frame_rate());
189
190 try {
192 } catch (const std::exception& e) {
193 error_rethrow(
196 std::source_location::current(),
197 "Graphics thread error");
198 }
199
201 "Graphics thread stopped.");
202 });
203}
204
206{
207 if (!m_running.load(std::memory_order_acquire)) {
208 return;
209 }
210
212 "Stopping Graphics Subsystem...");
213
214 m_running.store(false, std::memory_order_release);
215
216 if (m_graphics_thread.joinable()) {
217 m_graphics_thread.join();
218 }
219
220 m_backend->wait_idle();
221
224 }
225
226 for (auto& window : m_registered_windows) {
227 window->set_graphics_registered(false);
228 }
229
231 "Graphics Subsystem stopped.");
232}
233
235{
236 if (!m_running.load(std::memory_order_acquire)) {
238 "Cannot pause - graphics thread not running");
239 return;
240 }
241
242 m_paused.store(true, std::memory_order_release);
243
245 "Graphics processing paused");
246}
247
249{
250 if (!m_running.load(std::memory_order_acquire)) {
252 "Cannot resume - graphics thread not running");
253 return;
254 }
255
256 m_paused.store(false, std::memory_order_release);
257
259 "Graphics processing resumed");
260}
261
263{
264 return m_frame_clock->frame_rate();
265}
266
268{
269 return m_frame_clock->get_measured_fps();
270}
271
273{
274 m_frame_clock->set_target_fps(fps);
275
277 "Target FPS updated to {}", fps);
278}
279
281{
282 if (!m_handle) {
283 return;
284 }
285
286 for (auto& [name, hook] : m_handle->pre_process_hooks) {
287 hook(1);
288 }
289
291
293
295
297 m_backend->handle_window_resize();
299
301
303 for (auto& [name, hook] : m_handle->post_process_hooks) {
304 hook(1);
305 }
306}
307
309{
310 for (auto& window : m_handle->windows.get_processing_windows()) {
311
312 if (window->is_graphics_registered()) {
313 continue;
314 }
315
316 if (m_backend->register_window(window)) {
317 m_registered_windows.push_back(window);
318 } else {
320 "Failed to register window '{}' for graphics processing",
321 window->get_create_info().title);
322 continue;
323 }
324 }
325}
326
328{
329 for (auto& window : m_registered_windows) {
330 if (window->should_close() && window->is_graphics_registered()) {
331 m_backend->unregister_window(window);
332 window->set_graphics_registered(false);
333 }
334 }
335
337 std::remove_if(
339 [](const std::shared_ptr<Window>& win) { return win->should_close(); }),
341}
342
344{
345 for (auto& window : m_registered_windows) {
346 m_backend->unregister_window(window);
347 window->set_graphics_registered(false);
348 }
349
350 m_registered_windows.clear();
351}
352
354{
355 for (auto& window : m_registered_windows) {
356 m_backend->render_window(window);
357 }
358}
359
361{
362 while (m_running.load(std::memory_order_acquire)) {
363 if (m_paused.load(std::memory_order_acquire)) {
364 std::this_thread::sleep_for(std::chrono::milliseconds(16));
365 continue;
366 }
367
368 m_frame_clock->tick();
369
370 process();
371
372 m_frame_clock->wait_for_next_frame();
373
374 if (m_frame_clock->is_frame_late()) {
375 uint64_t lag = m_frame_clock->get_frame_lag();
376 if (lag > 2) {
378 "Frame lag detected: {} frames behind (Measured FPS: {:.1f})",
379 lag, m_frame_clock->get_measured_fps());
380 }
381 }
382 }
383}
384
386{
387 stop();
388
390
392
394
395 m_backend->cleanup();
396
397 m_is_ready = false;
398
400 "Graphics Subsystem shutdown complete.");
401}
402
403}
#define MF_INFO(comp, ctx,...)
#define MF_RT_WARN(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
void process(uint32_t processing_units)
Process all channels in token domain.
void initialize(SubsystemProcessingHandle &handle) override
Initialize with graphics configuration.
void register_frame_processor()
Register custom frame processor with scheduler.
void initialize_graphics_portal()
Initialize Portal::Graphics subsystem.
void cleanup_closed_windows()
Cleanup resources for windows that have been closed.
void start() override
Start the subsystem's processing/event loops.
void pause() override
Pause the subsystem's processing/event loops.
std::vector< std::shared_ptr< Window > > m_registered_windows
void register_windows_for_processing()
Register markend windows from window manager for swapchain processing.
void graphics_thread_loop()
Graphics thread main loop.
uint32_t get_target_fps() const
Get target frame rate.
void process_frame_coroutines_impl(const std::vector< std::shared_ptr< Vruta::Routine > > &tasks, uint64_t processing_units)
Process all FRAME_ACCURATE coroutines for given frames.
void render_all_windows()
Render all registered windows.
SubsystemProcessingHandle * m_handle
Reference to processing handle.
std::shared_ptr< Vruta::FrameClock > m_frame_clock
double get_measured_fps() const
Get actual measured FPS.
void set_target_fps(uint32_t fps)
Set target frame rate (can be changed at runtime)
std::unique_ptr< IGraphicsBackend > m_backend
void stop() override
Stop the subsystem's processing/event loops.
void register_callbacks() override
Register callback hooks for this domain.
GraphicsSubsystem(const GlobalGraphicsConfig &graphics_config)
GraphicsSubsystem constructor.
void teardown_windows()
Teardown all window resources during shutdown.
void resume() override
Resume the subsystem's processing/event loops.
void shutdown() override
Shutdown and cleanup subsystem resources.
GlobalGraphicsConfig m_graphics_config
Graphics/windowing configuration.
void process()
Unified processing callback (alternative to separate methods)
void process(uint32_t num_samples)
Process all nodes in token domain.
std::map< std::string, ProcessHook > post_process_hooks
NodeProcessingHandle nodes
Node processing interface.
std::map< std::string, ProcessHook > pre_process_hooks
BufferProcessingHandle buffers
Buffer processing interface.
Unified interface combining buffer and node processing for subsystems.
void process(uint64_t processing_units)
Process all tasks in token domain.
Vulkan implementation of the IGraphicsBackend interface.
void process()
Process window events and frame hooks.
std::vector< std::shared_ptr< Core::Window > > get_processing_windows() const
Get list of windows that are open and not minimized.
std::unique_ptr< IGraphicsBackend > create_graphics_backend(GlobalGraphicsConfig::GraphicsApi api)
@ GraphicsSubsystem
Graphics subsystem operations (Vulkan, rendering pipeline)
@ Core
Core engine, backend, subsystems.
void stop()
Stop all Portal::Graphics operations.
Definition Graphics.cpp:69
void shutdown()
Shutdown Portal::Graphics subsystem.
Definition Graphics.cpp:87
bool is_initialized()
Check if Portal::Graphics is initialized.
Definition Graphics.cpp:109
bool initialize(const std::shared_ptr< Core::VulkanBackend > &backend)
Initialize Portal::Graphics Glue Layer.
Definition Graphics.cpp:16
void shutdown()
Shutdown Portal::Text.
Definition Text.cpp:61
bool initialize(std::optional< Core::TextConfig > config)
Initialize Portal::Text.
Definition Text.cpp:18
TextConfig text_config
Default font for Portal::Text.
uint32_t target_frame_rate
Target frame rate for visual processing (Hz)