60 display_service->submit_and_present = [
this](
61 const std::shared_ptr<void>& window_ptr,
62 uint64_t primary_cmd_bits) {
63 auto window = std::static_pointer_cast<Window>(window_ptr);
64 vk::CommandBuffer primary_cmd = *
reinterpret_cast<vk::CommandBuffer*
>(&primary_cmd_bits);
69 display_service->wait_idle = [
this]() {
73 display_service->resize_surface = [
this](
const std::shared_ptr<void>& window_ptr, uint32_t width, uint32_t height) {
74 auto window = std::static_pointer_cast<Window>(window_ptr);
75 window->set_size(width, height);
77 if (ctx.window == window) {
78 ctx.needs_recreation =
true;
84 display_service->get_swapchain_image_count = [
this](
const std::shared_ptr<void>& window_ptr) -> uint32_t {
85 auto window = std::static_pointer_cast<Window>(window_ptr);
87 if (ctx.window == window) {
88 return static_cast<uint32_t
>(ctx.swapchain->get_image_count());
94 display_service->get_swapchain_format = [
this](
const std::shared_ptr<void>& window_ptr) -> uint32_t {
95 auto window = std::static_pointer_cast<Window>(window_ptr);
97 if (ctx.window == window) {
98 return static_cast<int>(ctx.swapchain->get_image_format());
104 display_service->get_swapchain_extent = [
this](
105 const std::shared_ptr<void>& window_ptr,
107 uint32_t& out_height) {
108 auto window = std::static_pointer_cast<Window>(window_ptr);
111 if (context && context->swapchain) {
112 auto extent = context->swapchain->get_extent();
113 out_width = extent.width;
114 out_height = extent.height;
121 display_service->acquire_next_swapchain_image = [
this](
const std::shared_ptr<void>& window_ptr) -> uint64_t {
122 auto window = std::static_pointer_cast<Window>(window_ptr);
126 "Window '{}' not registered for swapchain acquisition",
127 window->get_create_info().title);
132 size_t frame_index = ctx->current_frame;
133 auto& in_flight = ctx->in_flight[frame_index];
134 auto& image_available = ctx->image_available[frame_index];
136 if (device.waitForFences(1, &in_flight, VK_TRUE, UINT64_MAX) == vk::Result::eTimeout) {
138 "Fence timeout during swapchain acquisition for window '{}'",
139 window->get_create_info().title);
143 auto image_index_opt = ctx->swapchain->acquire_next_image(image_available);
144 if (!image_index_opt.has_value()) {
145 ctx->needs_recreation =
true;
149 ctx->current_image_index = image_index_opt.value();
151 if (device.resetFences(1, &in_flight) != vk::Result::eSuccess) {
153 "Failed to reset fence for window '{}'",
154 window->get_create_info().title);
158 const auto& images = ctx->swapchain->get_images();
159 VkImage raw = images[ctx->current_image_index];
160 return reinterpret_cast<uint64_t
>(raw);
163 display_service->get_current_image_view = [
this](
const std::shared_ptr<void>& window_ptr) ->
void* {
164 auto window = std::static_pointer_cast<Window>(window_ptr);
167 if (!context || !context->swapchain) {
171 const auto& image_views = context->swapchain->get_image_views();
172 if (context->current_image_index >= image_views.size()) {
174 "Invalid current_image_index {} for window '{}' (swapchain has {} images)",
175 context->current_image_index,
176 window->get_create_info().title,
181 static thread_local vk::ImageView view;
182 view = image_views[context->current_image_index];
183 return static_cast<void*
>(&view);
210 "Failed to create Vulkan surface for window '{}'",
211 window->get_create_info().title);
217 "No presentation support for window '{}'", window->get_create_info().title);
225 config.
swapchain = std::make_unique<VKSwapchain>();
229 "Failed to create swapchain for window '{}'", window->get_create_info().title);
235 "Failed to create sync objects for window '{}'",
236 window->get_create_info().title);
243 window->set_graphics_registered(
true);
245 window->set_event_callback([
this, window_ptr = window](
const WindowEvent& event) {
247 auto* config = find_window_context(window_ptr);
249 config->needs_recreation = true;
255 "Registered window '{}' for graphics processing", window->get_create_info().title);
262 auto device = m_context.get_device();
263 uint32_t image_count = config.
swapchain->get_image_count();
270 vk::SemaphoreCreateInfo semaphore_info {};
271 vk::FenceCreateInfo fence_info {};
272 fence_info.flags = vk::FenceCreateFlagBits::eSignaled;
274 for (uint32_t i = 0; i < image_count; ++i) {
280 i = device.createFence(fence_info);
286 }
catch (
const vk::SystemError& e) {
288 "Failed to create sync objects: {}", e.what());
333void BackendWindowHandler::submit_and_present(
334 const std::shared_ptr<Window>& window,
335 const vk::CommandBuffer& command_buffer)
337 auto* ctx = find_window_context(window);
340 "Window not registered for submit_and_present");
344 auto graphics_queue = m_context.get_graphics_queue();
346 size_t frame_index = ctx->current_frame;
347 auto& in_flight = ctx->in_flight[frame_index];
348 auto& image_available = ctx->image_available[frame_index];
349 auto& render_finished = ctx->render_finished[frame_index];
351 vk::SubmitInfo submit_info {};
352 vk::PipelineStageFlags wait_stages[] = { vk::PipelineStageFlagBits::eColorAttachmentOutput };
353 submit_info.waitSemaphoreCount = 1;
354 submit_info.pWaitSemaphores = &image_available;
355 submit_info.pWaitDstStageMask = wait_stages;
356 submit_info.commandBufferCount = 1;
357 submit_info.pCommandBuffers = &command_buffer;
358 submit_info.signalSemaphoreCount = 1;
359 submit_info.pSignalSemaphores = &render_finished;
362 auto result = graphics_queue.submit(1, &submit_info, in_flight);
363 }
catch (
const vk::SystemError& e) {
365 "Failed to submit primary command buffer: {}", e.what());
369 bool present_success = ctx->swapchain->present(
370 ctx->current_image_index, render_finished, graphics_queue);
372 if (!present_success) {
373 ctx->needs_recreation =
true;
376 ctx->current_frame = (frame_index + 1) % ctx->in_flight.size();
379 "Window '{}': frame submitted and presented",
380 window->get_create_info().title);
bool update_present_family(vk::SurfaceKHR surface)
Update presentation support for a surface.
vk::Device get_device() const
Get logical device.
vk::SurfaceKHR create_surface(std::shared_ptr< Window > window)
Create surface from window's native handles.
void destroy_surface(vk::SurfaceKHR surface)
Destroy a specific surface Called when window is unregistered.
High-level wrapper for Vulkan instance and device.
std::vector< vk::Semaphore > image_available
std::unique_ptr< VKSwapchain > swapchain
std::vector< vk::Semaphore > render_finished