From 8ccafddb64b1ae0541b860a9beee8deae488f4d4 Mon Sep 17 00:00:00 2001 From: Riley King-Saunders Date: Thu, 10 Jul 2025 21:48:12 +1000 Subject: [PATCH] Updated swapchain to recreate swapchain with the proper extent required and re-poll the window features on resize. Swapchain will no longer trigger a resize (internally) if the previous (non-zero) size is equal to the current size --- include/vulkan/basalt_swapchain.h | 11 +++++++---- src/vulkan/basalt_swapchain.cpp | 32 +++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/include/vulkan/basalt_swapchain.h b/include/vulkan/basalt_swapchain.h index 18129f3..8ba0cbd 100644 --- a/include/vulkan/basalt_swapchain.h +++ b/include/vulkan/basalt_swapchain.h @@ -22,11 +22,13 @@ namespace basalt void create_framebuffers(VkRenderPass render_pass); u32 wait_acquire_reset(bool wait_all=VK_TRUE, u64 timeout=UINT64_MAX, VkFence fence=VK_NULL_HANDLE); - + + basalt::SwapchainSupportDetails details; basalt::darray semaphores_image_available; basalt::darray semaphores_render_finished; basalt::darray fences_in_flight; - basalt::SwapchainSupportDetails details; + basalt::darray allowed_formats; + basalt::darray allowed_present_modes; basalt::darray swapchain_images; basalt::darray swapchain_image_views; basalt::darray framebuffers; @@ -34,12 +36,13 @@ namespace basalt basalt::Window* window = nullptr; VkSwapchainKHR swapchain = VK_NULL_HANDLE; VkExtent2D swapchain_extent; + VkExtent2D prev_extent; u32 image_count = -1; u32 max_frames_in_flight = 2; u32 current_frame = 0; bool framebuffers_created = false; private: - void create (const std::initializer_list& allowed_formats, - const std::initializer_list allowed_present_modes, VkSwapchainKHR prev_swapchain=VK_NULL_HANDLE); + void create (const basalt::darray& allowed_formats, + const basalt::darray& allowed_present_modes, VkSwapchainKHR prev_swapchain=VK_NULL_HANDLE); }; } \ No newline at end of file diff --git a/src/vulkan/basalt_swapchain.cpp b/src/vulkan/basalt_swapchain.cpp index a893ad7..39670ac 100644 --- a/src/vulkan/basalt_swapchain.cpp +++ b/src/vulkan/basalt_swapchain.cpp @@ -9,10 +9,15 @@ basalt::Swapchain::Swapchain(basalt::Device& device, basalt::Window& window, framebuffers(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY), semaphores_image_available(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY), semaphores_render_finished(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY), - fences_in_flight(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY) + fences_in_flight(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY), + allowed_formats(allowed_formats, MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY), + allowed_present_modes(allowed_present_modes, MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY) { this->framebuffers_created = false; - this->create(allowed_formats, allowed_present_modes, VK_NULL_HANDLE); + this->details.requery(window, device, this->allowed_formats, this->allowed_present_modes); + this->swapchain_extent = details.get_framebuffer_extent(window); + this->prev_extent = { .width = 0, .height = 0 }; + this->create(this->allowed_formats, this->allowed_present_modes, VK_NULL_HANDLE); VkResult err = VK_SUCCESS; VkSemaphoreCreateInfo semaphore_ci = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; @@ -52,23 +57,33 @@ basalt::Swapchain::~Swapchain() void basalt::Swapchain::recreate(VkRenderPass new_renderpass) { - swapchain_extent = details.get_framebuffer_extent(*window); + swapchain_extent = details.get_framebuffer_extent(*window, false); if (swapchain_extent.width == 0 || swapchain_extent.height == 0) return; + details.requery(*window, *device, allowed_formats, allowed_present_modes); + swapchain_extent = details.get_framebuffer_extent(*window, true); + if (prev_extent.width == swapchain_extent.width && prev_extent.height == swapchain_extent.height && framebuffers.m_nelements > 0) + { + this->framebuffers_created = true; + return; + } + prev_extent = swapchain_extent; vkDeviceWaitIdle(device->logical); + BTRACE("Recreating swapchain %p\n"); for (VkImageView& view : this->swapchain_image_views) vkDestroyImageView(*this->device, view, this->device->ctx->vk_alloc); vkDestroySwapchainKHR(*device, this->swapchain, device->ctx->vk_alloc); - // TODO: store the prefered format/present list and use them - this->create({ details.cached_format }, { details.cached_present_mode }, VK_NULL_HANDLE); + this->create(allowed_formats, allowed_present_modes, VK_NULL_HANDLE); if (new_renderpass != VK_NULL_HANDLE) this->create_framebuffers(new_renderpass); } void basalt::Swapchain::create_framebuffers(VkRenderPass render_pass) { + if (swapchain_extent.width == 0 || swapchain_extent.height == 0) + return; if (framebuffers.m_nelements != 0 || framebuffers_created) { vkDeviceWaitIdle(*device); @@ -92,6 +107,7 @@ void basalt::Swapchain::create_framebuffers(VkRenderPass render_pass) } framebuffers.m_nelements = swapchain_image_views.m_nelements; framebuffers_created = true; + BTRACE("Created %u framebuffers of size (%u, %u), for swapchain %p and renderpass %p\n", max_frames_in_flight, swapchain_extent.width, swapchain_extent.height, this, render_pass); } u32 basalt::Swapchain::wait_acquire_reset(bool wait_all, u64 timeout, VkFence fence) @@ -113,8 +129,8 @@ u32 basalt::Swapchain::wait_acquire_reset(bool wait_all, u64 timeout, VkFence fe } -void basalt::Swapchain::create(const std::initializer_list& allowed_formats, - const std::initializer_list allowed_present_modes, VkSwapchainKHR prev_swapchain) +void basalt::Swapchain::create(const basalt::darray& allowed_formats, + const basalt::darray& allowed_present_modes, VkSwapchainKHR prev_swapchain) { this->image_count = details.surface_capabilities.minImageCount + 1; BCLAMP(this->image_count, details.surface_capabilities.minImageCount, details.surface_capabilities.maxImageCount); @@ -150,7 +166,6 @@ void basalt::Swapchain::create(const std::initializer_list& } VkResult err = VK_SUCCESS; - this->swapchain_extent = ci.imageExtent; VK_ASSERT(vkCreateSwapchainKHR(device->logical, &ci, device->ctx->vk_alloc, &this->swapchain), "Failed to create swapchain\n\tAt %s:%d\n\tError %s\n"); u32 n_images = 0; @@ -179,4 +194,5 @@ void basalt::Swapchain::create(const std::initializer_list& VK_ASSERT(vkCreateImageView(device->logical, &view_ci, device->ctx->vk_alloc, &swapchain_image_views[i]), "Failed to create image view\n\tAt %s:%d\n\tError %s\n\tImage index: %u\n", i); } swapchain_image_views.m_nelements = n_images; + BTRACE("Created swapchain %p with %u images and extent %u x %u\n", this, max_frames_in_flight, swapchain_extent.width, swapchain_extent.height); }