diff --git a/src/xenia/ui/vulkan/vulkan_context.cc b/src/xenia/ui/vulkan/vulkan_context.cc index 5d82f4f46..9dd9c7d58 100644 --- a/src/xenia/ui/vulkan/vulkan_context.cc +++ b/src/xenia/ui/vulkan/vulkan_context.cc @@ -115,6 +115,17 @@ void VulkanContext::BeginSwap() { auto provider = static_cast(provider_); auto device = provider->device(); + // If we have a window see if it's been resized since we last swapped. + // If it has been, we'll need to reinitialize the swap chain before we + // start touching it. + if (target_window_) { + if (target_window_->width() != swap_chain_->surface_width() || + target_window_->height() != swap_chain_->surface_height()) { + // Resized! + swap_chain_->Reinitialize(); + } + } + // Acquire the next image and set it up for use. swap_chain_->Begin(); diff --git a/src/xenia/ui/vulkan/vulkan_swap_chain.cc b/src/xenia/ui/vulkan/vulkan_swap_chain.cc index ec640d92f..cb088bb75 100644 --- a/src/xenia/ui/vulkan/vulkan_swap_chain.cc +++ b/src/xenia/ui/vulkan/vulkan_swap_chain.cc @@ -32,31 +32,7 @@ namespace vulkan { VulkanSwapChain::VulkanSwapChain(VulkanInstance* instance, VulkanDevice* device) : instance_(instance), device_(device) {} -VulkanSwapChain::~VulkanSwapChain() { - for (auto& buffer : buffers_) { - DestroyBuffer(&buffer); - } - if (image_available_semaphore_) { - vkDestroySemaphore(*device_, image_available_semaphore_, nullptr); - } - if (render_pass_) { - vkDestroyRenderPass(*device_, render_pass_, nullptr); - } - if (render_cmd_buffer_) { - vkFreeCommandBuffers(*device_, cmd_pool_, 1, &render_cmd_buffer_); - } - if (cmd_pool_) { - vkDestroyCommandPool(*device_, cmd_pool_, nullptr); - } - // images_ doesn't need to be cleaned up as the swapchain does it implicitly. - if (handle) { - vkDestroySwapchainKHR(*device_, handle, nullptr); - handle = nullptr; - } - if (surface_) { - vkDestroySurfaceKHR(*instance_, surface_, nullptr); - } -} +VulkanSwapChain::~VulkanSwapChain() { Shutdown(); } bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) { surface_ = surface; @@ -338,6 +314,47 @@ void VulkanSwapChain::DestroyBuffer(Buffer* buffer) { buffer->image = nullptr; } +bool VulkanSwapChain::Reinitialize() { + // Hacky, but stash the surface so we can reuse it. + auto surface = surface_; + surface_ = nullptr; + Shutdown(); + return Initialize(surface); +} + +void VulkanSwapChain::Shutdown() { + // TODO(benvanik): properly wait for a clean state. + for (auto& buffer : buffers_) { + DestroyBuffer(&buffer); + } + buffers_.clear(); + if (image_available_semaphore_) { + vkDestroySemaphore(*device_, image_available_semaphore_, nullptr); + image_available_semaphore_ = nullptr; + } + if (render_pass_) { + vkDestroyRenderPass(*device_, render_pass_, nullptr); + render_pass_ = nullptr; + } + if (render_cmd_buffer_) { + vkFreeCommandBuffers(*device_, cmd_pool_, 1, &render_cmd_buffer_); + render_cmd_buffer_ = nullptr; + } + if (cmd_pool_) { + vkDestroyCommandPool(*device_, cmd_pool_, nullptr); + cmd_pool_ = nullptr; + } + // images_ doesn't need to be cleaned up as the swapchain does it implicitly. + if (handle) { + vkDestroySwapchainKHR(*device_, handle, nullptr); + handle = nullptr; + } + if (surface_) { + vkDestroySurfaceKHR(*instance_, surface_, nullptr); + surface_ = nullptr; + } +} + bool VulkanSwapChain::Begin() { // Get the index of the next available swapchain image. auto err = diff --git a/src/xenia/ui/vulkan/vulkan_swap_chain.h b/src/xenia/ui/vulkan/vulkan_swap_chain.h index 18bb26cee..1d1f578c3 100644 --- a/src/xenia/ui/vulkan/vulkan_swap_chain.h +++ b/src/xenia/ui/vulkan/vulkan_swap_chain.h @@ -41,7 +41,12 @@ class VulkanSwapChain { // Render command buffer, active inside the render pass from Begin to End. VkCommandBuffer render_cmd_buffer() const { return render_cmd_buffer_; } + // Initializes the swap chain with the given WSI surface. bool Initialize(VkSurfaceKHR surface); + // Reinitializes the swap chain with the initial surface. + // The surface will be retained but all other swap chain resources will be + // torn down and recreated with the new surface properties (size/etc). + bool Reinitialize(); // Begins the swap operation, preparing state for rendering. bool Begin(); @@ -58,6 +63,9 @@ class VulkanSwapChain { bool InitializeBuffer(Buffer* buffer, VkImage target_image); void DestroyBuffer(Buffer* buffer); + // Safely releases all swap chain resources. + void Shutdown(); + VulkanInstance* instance_ = nullptr; VulkanDevice* device_ = nullptr;