MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GraphicsSubsystem.hpp
Go to the documentation of this file.
1#pragma once
2
4#include "Subsystem.hpp"
5
6namespace MayaFlux::Vruta {
7class FrameClock;
8}
9
10namespace MayaFlux::Core {
11
12class IGraphicsBackend;
13
14/**
15 * @class GraphicsSubsystem
16 * @brief Backend agnostic graphics subsystem for visual processing
17 *
18 * Manages graphics thread, backend context, and frame-based processing.
19 * Parallel to AudioSubsystem but with self-driven timing model.
20 *
21 * **Key Architectural Differences from AudioSubsystem:**
22 *
23 * AudioSubsystem:
24 * RTAudio callback → process() → scheduler.tick(samples)
25 * Clock is externally driven by audio hardware
26 *
27 * GraphicsSubsystem:
28 * Graphics thread loop → clock.tick() → process() → scheduler observes
29 * Clock is self-driven based on wall-clock time
30 *
31 * The FrameClock manages its own timing and the subsystem's process
32 * methods are called from the graphics thread loop, not from an
33 * external callback.
34 */
35class MAYAFLUX_API GraphicsSubsystem : public ISubsystem {
36public:
37 /**
38 * @brief GraphicsSubsystem constructor
39 * @param graphics_config Global graphics configuration
40 */
41 GraphicsSubsystem(const GlobalGraphicsConfig& graphics_config);
42 ~GraphicsSubsystem() override;
43
44 /**
45 * @brief Initialize with graphics configuration
46 * @param handle Processing handle for domain registration
47 */
48 void initialize(SubsystemProcessingHandle& handle) override;
49
50 void register_callbacks() override;
51 void start() override;
52 void stop() override;
53 void pause() override;
54 void resume() override;
55
56 [[nodiscard]] SubsystemTokens get_tokens() const override { return m_subsystem_tokens; }
57
58 /**
59 * @brief Get frame clock
60 *
61 * The FrameClock is self-driven and manages its own timing.
62 * The scheduler reads from it but doesn't control it.
63 */
64 [[nodiscard]] Vruta::FrameClock& get_frame_clock() { return *m_frame_clock; }
65 [[nodiscard]] const Vruta::FrameClock& get_frame_clock() const { return *m_frame_clock; }
66
67 /**
68 * @brief Get graphics thread ID
69 */
70 [[nodiscard]] std::thread::id get_graphics_thread_id() const
71 {
72 return m_graphics_thread_id;
73 }
74
75 /**
76 * @brief Check if currently on graphics thread
77 */
78 [[nodiscard]] bool is_graphics_thread() const
79 {
80 return std::this_thread::get_id() == m_graphics_thread_id;
81 }
82
83 /**
84 * @brief Get target frame rate
85 */
86 [[nodiscard]] uint32_t get_target_fps() const;
87
88 /**
89 * @brief Get actual measured FPS
90 */
91 [[nodiscard]] double get_measured_fps() const;
92
93 /**
94 * @brief Set target frame rate (can be changed at runtime)
95 */
96 void set_target_fps(uint32_t fps);
97
98 /**
99 * @brief Unified processing callback (alternative to separate methods)
100 *
101 * This is called once per frame and handles all processing:
102 * - Visual nodes (VISUAL_RATE)
103 * - Graphics buffers (GRAPHICS_BACKEND)
104 * - Frame coroutines (FRAME_ACCURATE)
105 *
106 * Can be overridden or extended via hooks.
107 */
108 void process();
109
110 /**
111 * @brief Register markend windows from window manager for swapchain processing
112 *
113 * Creates surfaces and swapchains for each window.
114 * Called during initialization and whenever new windows are created.
115 */
116 void register_windows_for_processing();
117
118 /**
119 * @brief Render all registered windows
120 *
121 * Acquires swapchain images, records command buffers,
122 * submits to graphics queue, and presents.
123 */
124 void render_all_windows();
125
126 bool is_ready() const override { return m_is_ready; }
127 bool is_running() const override { return m_running.load(std::memory_order_acquire) && !m_paused.load(std::memory_order_acquire); }
128 void shutdown() override;
129 SubsystemType get_type() const override { return SubsystemType::GRAPHICS; }
131
132 /**
133 * @brief Get underlying graphics backend for advanced usage
134 * Can be cast to VulkanBackend* or OpenGLBackend* for backend-specific operations
135 */
136 IGraphicsBackend* get_backend() { return m_backend.get(); }
137 const IGraphicsBackend* get_backend() const { return m_backend.get(); }
138
139 /**
140 * @brief Get the type of the graphics backend
141 * @return GraphicsBackendType enum value representing the backend type
142 */
143 GlobalGraphicsConfig::GraphicsApi get_backend_type() const { return m_graphics_config.requested_api; }
144
145private:
146 std::unique_ptr<IGraphicsBackend> m_backend;
147 std::shared_ptr<Vruta::FrameClock> m_frame_clock;
148
149 std::thread m_graphics_thread;
150 std::thread::id m_graphics_thread_id;
151 std::atomic<bool> m_running { false };
152 std::atomic<bool> m_paused { false };
153
154 std::vector<std::shared_ptr<Window>> m_registered_windows;
155
156 bool m_is_ready {};
157
158 SubsystemTokens m_subsystem_tokens; ///< Processing token configuration
159 SubsystemProcessingHandle* m_handle; ///< Reference to processing handle
160 GlobalGraphicsConfig m_graphics_config; ///< Graphics/windowing configuration
161
162 /**
163 * @brief Initialize Portal::Graphics subsystem
164 *
165 * Sets up all Portal::Graphics managers and resources.
166 * Must be called after graphics backend initialization.
167 */
168 void initialize_graphics_portal();
169
170 /**
171 * @brief Register custom frame processor with scheduler
172 *
173 * This is the key integration point that makes graphics timing work.
174 * Registers a custom processor for FRAME_ACCURATE token that:
175 * - Does NOT tick the clock (already done)
176 * - Just processes coroutines based on current clock position
177 */
178 void register_frame_processor();
179
180 /**
181 * @brief Graphics thread main loop
182 *
183 * Self-driven frame processing:
184 * 1. Tick frame clock (advances based on wall-clock time)
185 * 2. Process visual nodes (VISUAL_RATE nodes)
186 * 3. Process graphics buffers (GRAPHICS_BACKEND buffers)
187 * 4. Tick scheduler coroutines (FRAME_ACCURATE tasks)
188 * 5. Record/submit Vulkan commands or OpenGL draw calls
189 * 6. Wait for next frame (vsync timing)
190 */
191 void graphics_thread_loop();
192
193 /**
194 * @brief Process all FRAME_ACCURATE coroutines for given frames
195 * @param tasks Vector of routines to process
196 * @param processing_units Number of frames to process
197 *
198 * Advances the frame clock and processes all FRAME_ACCURATE tasks
199 * that are ready to execute for each frame. This is called from
200 * the graphics thread loop after ticking the frame clock.
201 */
202 void process_frame_coroutines_impl(const std::vector<std::shared_ptr<Vruta::Routine>>& tasks, uint64_t processing_units);
203
204 /**
205 * @brief Cleanup resources for windows that have been closed
206 */
207 void cleanup_closed_windows();
208};
209}
SubsystemType get_type() const override
Get the type of this subsystem.
std::vector< std::shared_ptr< Window > > m_registered_windows
Vruta::FrameClock & get_frame_clock()
Get frame clock.
SubsystemTokens get_tokens() const override
Get the processing token configuration this subsystem manages.
const Vruta::FrameClock & get_frame_clock() const
SubsystemProcessingHandle * get_processing_context_handle() override
Get the processing context handle for this subsystem.
bool is_ready() const override
Check if subsystem is ready for operation.
const IGraphicsBackend * get_backend() const
SubsystemProcessingHandle * m_handle
Reference to processing handle.
IGraphicsBackend * get_backend()
Get underlying graphics backend for advanced usage Can be cast to VulkanBackend* or OpenGLBackend* fo...
std::shared_ptr< Vruta::FrameClock > m_frame_clock
bool is_running() const override
Check if subsystem is currently processing.
std::unique_ptr< IGraphicsBackend > m_backend
SubsystemTokens m_subsystem_tokens
Processing token configuration.
std::thread::id get_graphics_thread_id() const
Get graphics thread ID.
GlobalGraphicsConfig::GraphicsApi get_backend_type() const
Get the type of the graphics backend.
GlobalGraphicsConfig m_graphics_config
Graphics/windowing configuration.
bool is_graphics_thread() const
Check if currently on graphics thread.
Backend agnostic graphics subsystem for visual processing.
Base interface for all subsystems in the MayaFlux processing architecture.
Definition Subsystem.hpp:25
Unified interface combining buffer and node processing for subsystems.
Frame-accurate timing system for visual processing domain.
Definition Clock.hpp:182
void initialize()
Definition main.cpp:11
Processing token configuration for subsystem operation.