MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
BackendWindowHandler.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "vulkan/vulkan.hpp"
4
6struct DisplayService;
7}
8
9namespace MayaFlux::Core {
10
11class VKContext;
12class VKImage;
13class VKSwapchain;
14class VKCommandManager;
15class Window;
16class BackendResourceManager;
17
19 vk::Image image {};
20 vk::DeviceMemory mem {};
21 vk::Extent2D extent {};
22 vk::CommandBuffer cmd {};
23 vk::Fence fence {};
24 std::atomic<bool> pending { false };
25};
26
28#ifdef MAYAFLUX_PLATFORM_MACOS
29 std::atomic<const std::vector<uint8_t>*> last_frame { nullptr };
30
31 static constexpr size_t LAST_FRAME_MAX_READERS = 32;
32 mutable std::array<std::atomic<const std::vector<uint8_t>*>, LAST_FRAME_MAX_READERS> last_frame_hazard_ptrs {};
33 mutable std::array<std::atomic<bool>, LAST_FRAME_MAX_READERS> last_frame_slot_active { false };
34
35 void retire_last_frame(const std::vector<uint8_t>* ptr);
36#else
37 std::atomic<std::shared_ptr<std::vector<uint8_t>>> last_frame;
38#endif
39
40 std::vector<std::unique_ptr<CaptureSlot>> slots;
41 size_t slot_index {};
42 vk::Format format {};
43 uint32_t bpp {};
44 std::thread readback_thread;
45 std::atomic<bool> readback_running { false };
46
47 using FrameObserver = std::function<void(
48 const std::shared_ptr<std::vector<uint8_t>>&,
49 uint32_t, uint32_t, uint32_t)>;
50 using ObserverMap = std::unordered_map<uint32_t, FrameObserver>;
51
52 std::atomic<uint32_t> next_observer_id { 1 };
53
54#ifdef MAYAFLUX_PLATFORM_MACOS
55 std::atomic<const ObserverMap*> observers { nullptr };
56
57 static constexpr size_t OBSERVERS_MAX_READERS = 32;
58 mutable std::array<std::atomic<const ObserverMap*>, OBSERVERS_MAX_READERS> observers_hazard_ptrs {};
59 mutable std::array<std::atomic<bool>, OBSERVERS_MAX_READERS> observers_slot_active { false };
60
61 void retire_observers(const ObserverMap* ptr);
62#else
63 std::atomic<std::shared_ptr<ObserverMap>> observers {
64 std::make_shared<ObserverMap>()
65 };
66#endif
67
69 {
70 readback_running.store(false, std::memory_order_release);
71 if (readback_thread.joinable())
72 readback_thread.join();
73
74#ifdef MAYAFLUX_PLATFORM_MACOS
75 auto* old_frame = last_frame.exchange(nullptr);
76 if (old_frame)
77 retire_last_frame(old_frame);
78
79 auto* old_obs = observers.exchange(nullptr);
80 if (old_obs)
81 retire_observers(old_obs);
82#endif
83 }
84};
85
87 std::shared_ptr<Window> window;
88 vk::SurfaceKHR surface;
89 std::unique_ptr<VKSwapchain> swapchain;
90
91 std::vector<vk::Semaphore> image_available;
92 std::vector<vk::Semaphore> render_finished;
93 std::vector<vk::Fence> in_flight;
94
95 std::vector<vk::CommandBuffer> clear_command_buffers;
96 std::shared_ptr<VKImage> depth_image;
97
99 size_t current_frame {};
101
102 std::unique_ptr<CaptureState> capture;
103
106
111
112 void cleanup(VKContext& context);
113};
114
115class MAYAFLUX_API BackendWindowHandler {
116public:
117 BackendWindowHandler(VKContext& context, VKCommandManager& command_manager);
119
120 void setup_backend_service(const std::shared_ptr<Registry::Service::DisplayService>& display_service);
121
124
126 BackendWindowHandler& operator=(BackendWindowHandler&&) noexcept = default;
127
128 // ========================================================================
129 // Window management
130 // ========================================================================
131 bool register_window(const std::shared_ptr<Window>& window);
132 void unregister_window(const std::shared_ptr<Window>& window);
133 [[nodiscard]] bool is_window_registered(const std::shared_ptr<Window>& window) const;
134
135 // ========================================================================
136 // Rendering
137 // ========================================================================
138 void render_window(const std::shared_ptr<Window>& window);
139 void render_all_windows();
140 void handle_window_resize();
141
142 void submit_and_present(
143 const std::shared_ptr<Window>& window,
144 const vk::CommandBuffer& command_buffer);
145
146 // ========================================================================
147 // Access control
148 // ========================================================================
149 WindowRenderContext* find_window_context(const std::shared_ptr<Window>& window);
150 [[nodiscard]] const WindowRenderContext* find_window_context(const std::shared_ptr<Window>& window) const;
151
152 // Information
153 [[nodiscard]] uint32_t get_swapchain_image_count(const std::shared_ptr<Window>& window) const;
154
155 // Cleanup
156 void cleanup();
157
158 void set_resource_manager(BackendResourceManager* resource_manager) { m_resource_manager = resource_manager; }
159
160private:
163 std::vector<WindowRenderContext> m_window_contexts;
164
165 /**
166 * @brief Create synchronization objects for a window's swapchain
167 * @param config Window swapchain configuration to populate
168 * @return True if creation succeeded
169 */
170 bool create_sync_objects(WindowRenderContext& config);
171
172 /**
173 * @brief Recreate the swapchain and related resources for a window
174 * @param context Window render context
175 */
176 void recreate_swapchain_for_context(WindowRenderContext& context);
177
178 /**
179 * @brief Internal logic to recreate swapchain and related resources
180 * @param context Window render context
181 * @return True if recreation succeeded
182 */
183 bool recreate_swapchain_internal(WindowRenderContext& context);
184
185 /**
186 * @brief Ensure depth image exists at current swapchain extent
187 * @param ctx Window context to create depth image for
188 *
189 * Creates or recreates a D32_SFLOAT depth image matching the
190 * swapchain extent. No-op if depth image already matches.
191 */
192 void ensure_depth_image(WindowRenderContext& ctx);
193
194 /**
195 * @brief Render empty windows with clear color
196 * @param ctx Window render context
197 *
198 * For windows that are registered for processing but have no buffers attached,
199 * this performs a minimal clear pass so the window is visible and responsive
200 * to input events.
201 */
202 void render_empty_window(WindowRenderContext& ctx);
203
204 /**
205 * @brief Ensure capture state is initialized for a window context
206 * @param ctx Window render context to initialize capture state for
207 *
208 * If the context does not already have capture state and the associated window has
209 * capture enabled, this initializes the capture state including allocating command buffers
210 * and synchronization objects for readback.
211 */
212 void ensure_capture_state(WindowRenderContext& ctx);
213
214 /**
215 * @brief Capture the current frame from a window's swapchain
216 * @param ctx Window render context to capture from
217 *
218 * This initiates an asynchronous readback of the current swapchain image into
219 * CPU-accessible memory. The result is stored in the capture state for retrieval
220 * via the display service.
221 */
222 void capture_frame(WindowRenderContext& ctx);
223
224 /**
225 * @brief Thread function to perform asynchronous readback of captured frames
226 * @param state Capture state containing pending readbacks
227 * @param dev Vulkan device to use for readback operations
228 *
229 * This thread continuously checks for pending capture slots and performs the necessary
230 * Vulkan commands to read back the image data into CPU memory. The last captured frame
231 * is stored atomically for retrieval by the display service.
232 */
233 void start_readback_thread(CaptureState& state, vk::Device dev);
234
235 BackendResourceManager* m_resource_manager {};
236};
237
238}
const uint8_t * ptr
Manages Vulkan resources (buffers, images, samplers) for the graphics backend.
BackendWindowHandler(BackendWindowHandler &&) noexcept=default
BackendWindowHandler & operator=(const BackendWindowHandler &)=delete
std::vector< WindowRenderContext > m_window_contexts
BackendWindowHandler(const BackendWindowHandler &)=delete
Manages Vulkan command pools and command buffers.
High-level wrapper for Vulkan instance and device.
Definition VKContext.hpp:16
Platform-agnostic window wrapper.
Definition Window.hpp:22
std::vector< std::unique_ptr< CaptureSlot > > slots
std::function< void(const std::shared_ptr< std::vector< uint8_t > > &, uint32_t, uint32_t, uint32_t)> FrameObserver
std::atomic< std::shared_ptr< ObserverMap > > observers
std::atomic< std::shared_ptr< std::vector< uint8_t > > > last_frame
std::unordered_map< uint32_t, FrameObserver > ObserverMap
std::atomic< uint32_t > next_observer_id
std::vector< vk::Semaphore > image_available
std::unique_ptr< CaptureState > capture
std::unique_ptr< VKSwapchain > swapchain
WindowRenderContext(WindowRenderContext &&)=default
std::vector< vk::Semaphore > render_finished
std::vector< vk::CommandBuffer > clear_command_buffers
WindowRenderContext & operator=(WindowRenderContext &&)=default
WindowRenderContext(const WindowRenderContext &)=delete
WindowRenderContext & operator=(const WindowRenderContext &)=delete