MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ setup_backend_service()

void MayaFlux::Core::BackendWindowHandler::setup_backend_service ( const std::shared_ptr< Registry::Service::DisplayService > &  display_service)

Definition at line 137 of file BackendWindowHandler.cpp.

138{
139 display_service->submit_and_present = [this](
140 const std::shared_ptr<void>& window_ptr,
141 uint64_t primary_cmd_bits) {
142 auto window = std::static_pointer_cast<Window>(window_ptr);
143 vk::CommandBuffer primary_cmd = *reinterpret_cast<vk::CommandBuffer*>(&primary_cmd_bits);
144
145 this->submit_and_present(window, primary_cmd);
146 };
147
148 display_service->wait_idle = [this]() {
149 m_context.get_device().waitIdle();
150 };
151
152 display_service->resize_surface = [this](const std::shared_ptr<void>& window_ptr, uint32_t width, uint32_t height) {
153 auto window = std::static_pointer_cast<Window>(window_ptr);
154 window->set_size(width, height);
155 for (auto& ctx : m_window_contexts) {
156 if (ctx.window == window) {
157 ctx.needs_recreation = true;
158 break;
159 }
160 }
161 };
162
163 display_service->get_swapchain_image_count = [this](const std::shared_ptr<void>& window_ptr) -> uint32_t {
164 auto window = std::static_pointer_cast<Window>(window_ptr);
165 for (const auto& ctx : m_window_contexts) {
166 if (ctx.window == window) {
167 return static_cast<uint32_t>(ctx.swapchain->get_image_count());
168 }
169 }
170 return 0;
171 };
172
173 display_service->get_swapchain_format = [this](const std::shared_ptr<void>& window_ptr) -> uint32_t {
174 auto window = std::static_pointer_cast<Window>(window_ptr);
175 for (const auto& ctx : m_window_contexts) {
176 if (ctx.window == window) {
177 return static_cast<int>(ctx.swapchain->get_image_format());
178 }
179 }
180 return 0;
181 };
182
183 display_service->get_swapchain_extent = [this](
184 const std::shared_ptr<void>& window_ptr,
185 uint32_t& out_width,
186 uint32_t& out_height) {
187 auto window = std::static_pointer_cast<Window>(window_ptr);
188 auto* context = find_window_context(window);
189
190 if (context && context->swapchain) {
191 auto extent = context->swapchain->get_extent();
192 out_width = extent.width;
193 out_height = extent.height;
194 } else {
195 out_width = 0;
196 out_height = 0;
197 }
198 };
199
200 display_service->acquire_next_swapchain_image = [this](const std::shared_ptr<void>& window_ptr) -> uint64_t {
201 auto window = std::static_pointer_cast<Window>(window_ptr);
202 auto* ctx = find_window_context(window);
203 if (!ctx) {
205 "Window '{}' not registered for swapchain acquisition",
206 window->get_create_info().title);
207 return 0;
208 }
209
210 auto device = m_context.get_device();
211 size_t frame_index = ctx->current_frame;
212 auto& in_flight = ctx->in_flight[frame_index];
213 auto& image_available = ctx->image_available[frame_index];
214
215 if (device.waitForFences(1, &in_flight, VK_TRUE, UINT64_MAX) == vk::Result::eTimeout) {
217 "Fence timeout during swapchain acquisition for window '{}'",
218 window->get_create_info().title);
219 return 0;
220 }
221
222 auto image_index_opt = ctx->swapchain->acquire_next_image(image_available);
223 if (!image_index_opt.has_value()) {
224 ctx->needs_recreation = true;
225 return 0;
226 }
227
228 ctx->current_image_index = image_index_opt.value();
229
230 if (device.resetFences(1, &in_flight) != vk::Result::eSuccess) {
232 "Failed to reset fence for window '{}'",
233 window->get_create_info().title);
234 return 0;
235 }
236
237 const auto& images = ctx->swapchain->get_images();
238 VkImage raw = images[ctx->current_image_index];
239 return reinterpret_cast<uint64_t>(raw);
240 };
241
242 display_service->get_current_image_view = [this](const std::shared_ptr<void>& window_ptr) -> void* {
243 auto window = std::static_pointer_cast<Window>(window_ptr);
244 auto* context = find_window_context(window);
245
246 if (!context || !context->swapchain) {
247 return nullptr;
248 }
249
250 const auto& image_views = context->swapchain->get_image_views();
251 if (context->current_image_index >= image_views.size()) {
253 "Invalid current_image_index {} for window '{}' (swapchain has {} images)",
254 context->current_image_index,
255 window->get_create_info().title,
256 image_views.size());
257 return nullptr;
258 }
259
260 static thread_local vk::ImageView view;
261 view = image_views[context->current_image_index];
262 return static_cast<void*>(&view);
263 };
264
265 display_service->get_current_swapchain_image = [this](const std::shared_ptr<void>& window_ptr) -> uint64_t {
266 auto window = std::static_pointer_cast<Window>(window_ptr);
267 auto* ctx = find_window_context(window);
268 if (!ctx || !ctx->swapchain)
269 return 0;
270
271 const auto& images = ctx->swapchain->get_images();
272 if (ctx->current_image_index >= images.size())
273 return 0;
274
275 return reinterpret_cast<uint64_t>(static_cast<VkImage>(images[ctx->current_image_index]));
276 };
277
278 display_service->readback_swapchain_region = [this](
279 const std::shared_ptr<void>& window_ptr,
280 void* dst,
281 uint32_t /*x_offset*/,
282 uint32_t /*y_offset*/,
283 uint32_t pixel_width,
284 uint32_t pixel_height,
285 size_t byte_count) -> bool {
286 auto window = std::static_pointer_cast<Window>(window_ptr);
287 auto* ctx = find_window_context(window);
288
289 if (!ctx || !ctx->swapchain) {
291 "readback_swapchain_region: window '{}' has no swapchain",
292 window->get_create_info().title);
293 return false;
294 }
295
296 if (!m_resource_manager) {
298 "readback_swapchain_region: resource manager not set");
299 return false;
300 }
301
302 const auto& images = ctx->swapchain->get_images();
303 if (ctx->current_image_index >= images.size()) {
305 "readback_swapchain_region: invalid image index {} for '{}'",
306 ctx->current_image_index, window->get_create_info().title);
307 return false;
308 }
309
310 auto proxy = std::make_shared<VKImage>(
311 pixel_width, pixel_height, 1U,
312 ctx->swapchain->get_image_format(),
315 1U, 1U,
317
318 VKImageResources res {};
319 res.image = images[ctx->current_image_index];
320 proxy->set_image_resources(res);
321 proxy->set_current_layout(vk::ImageLayout::ePresentSrcKHR);
322
324 proxy,
325 dst,
326 byte_count,
327 vk::ImageLayout::ePresentSrcKHR,
328 vk::PipelineStageFlagBits::eBottomOfPipe);
329
330 return true;
331 };
332
333 display_service->ensure_depth_attachment = [this](const std::shared_ptr<void>& window_ptr) {
334 auto window = std::static_pointer_cast<Window>(window_ptr);
335 auto* ctx = find_window_context(window);
336 if (!ctx) {
338 "ensure_depth_attachment: window '{}' not registered",
339 window->get_create_info().title);
340 return;
341 }
342 ensure_depth_image(*ctx);
343 };
344
345 display_service->get_depth_image_view = [this](const std::shared_ptr<void>& window_ptr) -> void* {
346 auto window = std::static_pointer_cast<Window>(window_ptr);
347 auto* ctx = find_window_context(window);
348 if (!ctx || !ctx->depth_image || !ctx->depth_image->is_initialized()) {
349 return nullptr;
350 }
351 static thread_local vk::ImageView view;
352 view = ctx->depth_image->get_image_view();
353 return static_cast<void*>(&view);
354 };
355
356 display_service->get_depth_format = [this](const std::shared_ptr<void>& window_ptr) -> uint32_t {
357 auto window = std::static_pointer_cast<Window>(window_ptr);
358 auto* ctx = find_window_context(window);
359 if (!ctx || !ctx->depth_image || !ctx->depth_image->is_initialized()) {
360 return static_cast<uint32_t>(vk::Format::eUndefined);
361 }
362 return static_cast<uint32_t>(ctx->depth_image->get_format());
363 };
364
365 // ======================================================================
366 // get_last_frame – hazard‑pointer protected read + copy
367 // ======================================================================
368 display_service->get_last_frame = [this](const std::shared_ptr<void>& window_ptr)
369 -> std::shared_ptr<std::vector<uint8_t>> {
370 auto* ctx = find_window_context(std::static_pointer_cast<Window>(window_ptr));
371 if (!ctx || !ctx->capture)
372 return nullptr;
373
374#ifdef MAYAFLUX_PLATFORM_MACOS
375 auto& state = *ctx->capture;
376
377 size_t slot = CaptureState::LAST_FRAME_MAX_READERS;
378 for (size_t i = 0; i < CaptureState::LAST_FRAME_MAX_READERS; ++i) {
379 bool expected = false;
380 if (state.last_frame_slot_active[i].compare_exchange_strong(expected, true, std::memory_order_acquire)) {
381 slot = i;
382 break;
383 }
384 }
385 if (slot == CaptureState::LAST_FRAME_MAX_READERS)
386 return nullptr;
387
388 const std::vector<uint8_t>* raw;
389 do {
390 raw = state.last_frame.load(std::memory_order_acquire);
391 state.last_frame_hazard_ptrs[slot].store(raw, std::memory_order_release);
392 } while (raw != state.last_frame.load(std::memory_order_acquire));
393
394 if (!raw) {
395 state.last_frame_hazard_ptrs[slot].store(nullptr, std::memory_order_release);
396 state.last_frame_slot_active[slot].store(false, std::memory_order_release);
397 return nullptr;
398 }
399
400 return std::shared_ptr<std::vector<uint8_t>>(
401 const_cast<std::vector<uint8_t>*>(raw),
402 [&state, slot](std::vector<uint8_t>*) {
403 state.last_frame_hazard_ptrs[slot].store(nullptr, std::memory_order_release);
404 state.last_frame_slot_active[slot].store(false, std::memory_order_release);
405 });
406#else
407 return ctx->capture->last_frame.load(std::memory_order_acquire);
408#endif
409 };
410
411 // ======================================================================
412 // register_frame_observer – hazard‑pointer update of observer map
413 // ======================================================================
414 display_service->register_frame_observer = [this](
415 const std::shared_ptr<void>& window_ptr,
416 const std::function<void(
417 const std::shared_ptr<std::vector<uint8_t>>&,
418 uint32_t, uint32_t, uint32_t)>&
419 cb) -> uint32_t {
420 auto* ctx = find_window_context(std::static_pointer_cast<Window>(window_ptr));
421 if (!ctx) {
423 "register_frame_observer: window not registered with graphics backend");
424 return 0;
425 }
426 if (!ctx->capture) {
428 }
429
430 auto& state = *ctx->capture;
431 uint32_t id = state.next_observer_id.fetch_add(1, std::memory_order_relaxed);
432
433#ifdef MAYAFLUX_PLATFORM_MACOS
434 size_t obs_slot = CaptureState::OBSERVERS_MAX_READERS;
435 for (size_t i = 0; i < CaptureState::OBSERVERS_MAX_READERS; ++i) {
436 bool expected = false;
437 if (state.observers_slot_active[i].compare_exchange_strong(expected, true, std::memory_order_acquire)) {
438 obs_slot = i;
439 break;
440 }
441 }
442 if (obs_slot == CaptureState::OBSERVERS_MAX_READERS)
443 return 0;
444
446 CaptureState::ObserverMap* new_map = nullptr;
447
448 do {
449 if (new_map)
450 delete new_map;
451
452 do {
453 current = state.observers.load(std::memory_order_acquire);
454 state.observers_hazard_ptrs[obs_slot].store(current, std::memory_order_release);
455 } while (current != state.observers.load(std::memory_order_acquire));
456
457 new_map = new CaptureState::ObserverMap(current ? *current : CaptureState::ObserverMap {});
458 (*new_map)[id] = cb;
459
460 } while (!state.observers.compare_exchange_weak(current, new_map, std::memory_order_acq_rel, std::memory_order_acquire));
461
462 state.observers_hazard_ptrs[obs_slot].store(nullptr, std::memory_order_release);
463 state.observers_slot_active[obs_slot].store(false, std::memory_order_release);
464
465 if (current)
466 state.retire_observers(current);
467#else
468 auto current = state.observers.load(std::memory_order_acquire);
469 std::shared_ptr<CaptureState::ObserverMap> next;
470 do {
471 next = std::make_shared<CaptureState::ObserverMap>(*current);
472 (*next)[id] = cb;
473 } while (!state.observers.compare_exchange_weak(
474 current, next,
475 std::memory_order_release, std::memory_order_acquire));
476#endif
477 return id;
478 };
479
480 // ======================================================================
481 // unregister_frame_observer – hazard‑pointer update
482 // ======================================================================
483 display_service->unregister_frame_observer = [this](
484 const std::shared_ptr<void>& window_ptr, uint32_t id) {
485 auto* ctx = find_window_context(std::static_pointer_cast<Window>(window_ptr));
486 if (!ctx) {
488 "unregister_frame_observer: window not registered with graphics backend");
489 return;
490 }
491 if (!ctx->capture) {
493 "unregister_frame_observer: capture not active for '{}'",
494 ctx->window->get_create_info().title);
495 return;
496 }
497
498 auto& state = *ctx->capture;
499
500#ifdef MAYAFLUX_PLATFORM_MACOS
501 size_t obs_slot = CaptureState::OBSERVERS_MAX_READERS;
502 for (size_t i = 0; i < CaptureState::OBSERVERS_MAX_READERS; ++i) {
503 bool expected = false;
504 if (state.observers_slot_active[i].compare_exchange_strong(expected, true, std::memory_order_acquire)) {
505 obs_slot = i;
506 break;
507 }
508 }
509 if (obs_slot == CaptureState::OBSERVERS_MAX_READERS)
510 return;
511
513 CaptureState::ObserverMap* new_map = nullptr;
514
515 do {
516 if (new_map)
517 delete new_map;
518
519 do {
520 current = state.observers.load(std::memory_order_acquire);
521 state.observers_hazard_ptrs[obs_slot].store(current, std::memory_order_release);
522 } while (current != state.observers.load(std::memory_order_acquire));
523
524 new_map = new CaptureState::ObserverMap(current ? *current : CaptureState::ObserverMap {});
525 new_map->erase(id);
526
527 } while (!state.observers.compare_exchange_weak(current, new_map, std::memory_order_acq_rel, std::memory_order_acquire));
528
529 state.observers_hazard_ptrs[obs_slot].store(nullptr, std::memory_order_release);
530 state.observers_slot_active[obs_slot].store(false, std::memory_order_release);
531
532 if (current)
533 state.retire_observers(current);
534#else
535 auto current = state.observers.load(std::memory_order_acquire);
536 std::shared_ptr<CaptureState::ObserverMap> next;
537 do {
538 next = std::make_shared<CaptureState::ObserverMap>(*current);
539 next->erase(id);
540 } while (!state.observers.compare_exchange_weak(
541 current, next,
542 std::memory_order_release, std::memory_order_acquire));
543#endif
544 };
545}
#define MF_RT_WARN(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
uint32_t width
Definition Decoder.cpp:59
glm::vec2 current
void download_image_data(std::shared_ptr< VKImage > image, void *data, size_t size, vk::ImageLayout restore_layout=vk::ImageLayout::eShaderReadOnlyOptimal, vk::PipelineStageFlags restore_stage=vk::PipelineStageFlagBits::eFragmentShader)
Download data from an image into a caller-supplied buffer.
void ensure_depth_image(WindowRenderContext &ctx)
Ensure depth image exists at current swapchain extent.
std::vector< WindowRenderContext > m_window_contexts
void submit_and_present(const std::shared_ptr< Window > &window, const vk::CommandBuffer &command_buffer)
WindowRenderContext * find_window_context(const std::shared_ptr< Window > &window)
void ensure_capture_state(WindowRenderContext &ctx)
Ensure capture state is initialized for a window context.
vk::Device get_device() const
Get logical device.
Definition VKContext.hpp:49
@ TEXTURE_2D
Sampled texture (shader read)
@ GraphicsBackend
Graphics/visual rendering backend (Vulkan, OpenGL)
@ GraphicsCallback
Graphics/visual rendering callback - frame-rate real-time.
@ Core
Core engine, backend, subsystems.
@ IMAGE_COLOR
2D RGB/RGBA image
std::unordered_map< uint32_t, FrameObserver > ObserverMap

References MayaFlux::Journal::Core, current, MayaFlux::Core::BackendResourceManager::download_image_data(), ensure_capture_state(), ensure_depth_image(), find_window_context(), MayaFlux::Core::VKContext::get_device(), MayaFlux::Journal::GraphicsBackend, MayaFlux::Journal::GraphicsCallback, MayaFlux::Core::VKImageResources::image, MayaFlux::Kakshya::IMAGE_COLOR, m_context, m_resource_manager, m_window_contexts, MF_RT_ERROR, MF_RT_WARN, MF_WARN, submit_and_present(), MayaFlux::Core::VKImage::TEXTURE_2D, MayaFlux::Core::VKImage::TYPE_2D, and width.

+ Here is the call graph for this function: