From 19ca102b40e6ac5654d497096f6ce44d1b4e30c6 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 8 Apr 2021 03:03:12 +1000 Subject: [PATCH] VulkanHostDisplay: Handle surface loss gracefully Also skips a full swap chain recreate on resize. --- src/common/vulkan/swap_chain.cpp | 17 ++++++++++------- src/frontend-common/vulkan_host_display.cpp | 12 ++++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/common/vulkan/swap_chain.cpp b/src/common/vulkan/swap_chain.cpp index 810b6b64e..f5009ea56 100644 --- a/src/common/vulkan/swap_chain.cpp +++ b/src/common/vulkan/swap_chain.cpp @@ -723,13 +723,15 @@ void SwapChain::DestroySwapChain() VkResult SwapChain::AcquireNextImage() { + if (!m_swap_chain) + return VK_ERROR_SURFACE_LOST_KHR; + return vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX, m_image_available_semaphore, VK_NULL_HANDLE, &m_current_image); } bool SwapChain::ResizeSwapChain(u32 new_width /* = 0 */, u32 new_height /* = 0 */) { - DestroySemaphores(); DestroySwapChainImages(); if (new_width != 0 && new_height != 0) @@ -738,7 +740,7 @@ bool SwapChain::ResizeSwapChain(u32 new_width /* = 0 */, u32 new_height /* = 0 * m_window_info.surface_height = new_height; } - if (!CreateSwapChain() || !SetupSwapChainImages() || !CreateSemaphores()) + if (!CreateSwapChain() || !SetupSwapChainImages()) { Panic("Failed to re-configure swap chain images, this is fatal (for now)"); return false; @@ -749,10 +751,9 @@ bool SwapChain::ResizeSwapChain(u32 new_width /* = 0 */, u32 new_height /* = 0 * bool SwapChain::RecreateSwapChain() { - DestroySemaphores(); DestroySwapChainImages(); - DestroySwapChain(); - if (!CreateSwapChain() || !SetupSwapChainImages() || !CreateSemaphores()) + + if (!CreateSwapChain() || !SetupSwapChainImages()) { Panic("Failed to re-configure swap chain images, this is fatal (for now)"); return false; @@ -774,7 +775,6 @@ bool SwapChain::SetVSync(bool enabled) bool SwapChain::RecreateSurface(const WindowInfo& new_wi) { // Destroy the old swap chain, images, and surface. - DestroySemaphores(); DestroySwapChainImages(); DestroySwapChain(); DestroySurface(); @@ -803,7 +803,7 @@ bool SwapChain::RecreateSurface(const WindowInfo& new_wi) } // Finally re-create the swap chain - if (!CreateSwapChain() || !SetupSwapChainImages() || !CreateSemaphores()) + if (!CreateSwapChain() || !SetupSwapChainImages()) return false; return true; @@ -811,6 +811,9 @@ bool SwapChain::RecreateSurface(const WindowInfo& new_wi) void SwapChain::DestroySurface() { + if (m_surface == VK_NULL_HANDLE) + return; + DestroyVulkanSurface(g_vulkan_context->GetVulkanInstance(), &m_window_info, m_surface); m_surface = VK_NULL_HANDLE; } diff --git a/src/frontend-common/vulkan_host_display.cpp b/src/frontend-common/vulkan_host_display.cpp index 493cf601d..a2e7cec3f 100644 --- a/src/frontend-common/vulkan_host_display.cpp +++ b/src/frontend-common/vulkan_host_display.cpp @@ -580,6 +580,18 @@ bool VulkanHostDisplay::Render() ResizeRenderWindow(0, 0); res = m_swap_chain->AcquireNextImage(); } + else if (res == VK_ERROR_SURFACE_LOST_KHR) + { + Log_WarningPrint("Surface lost, attempting to recreate"); + if (!m_swap_chain->RecreateSurface(m_window_info)) + { + Log_ErrorPrint("Failed to recreate surface after loss"); + g_vulkan_context->ExecuteCommandBuffer(false); + return false; + } + + res = m_swap_chain->AcquireNextImage(); + } // This can happen when multiple resize events happen in quick succession. // In this case, just wait until the next frame to try again.