From 52aff6dd12d1b5e84187d9eaa224655b5ecd5feb Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Mon, 1 Apr 2019 12:48:22 -0500 Subject: [PATCH 1/3] [vulkan] Recreate the surface on surface loss. According to the Vulkan spec: > Several WSI functions return `VK_ERROR_SURFACE_LOST_KHR` if the > surface becomes no longer available. After such an error, the surface > (and any child swapchain, if one exists) **should** be destroyed, as > there is no way to restore them to a not-lost state. So if we get this error, we need to recreate the surface in addition to the swapchain. --- src/vulkan/vulkan_presenter.cpp | 28 ++++++++++++++++++++-------- src/vulkan/vulkan_presenter.h | 5 +++-- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/vulkan/vulkan_presenter.cpp b/src/vulkan/vulkan_presenter.cpp index 21444decd46..94546a83a71 100644 --- a/src/vulkan/vulkan_presenter.cpp +++ b/src/vulkan/vulkan_presenter.cpp @@ -10,8 +10,8 @@ namespace dxvk::vk { const Rc& vkd, PresenterDevice device, const PresenterDesc& desc) - : m_vki(vki), m_vkd(vkd), m_device(device) { - if (createSurface(window) != VK_SUCCESS) + : m_vki(vki), m_vkd(vkd), m_device(device), m_window(window) { + if (createSurface() != VK_SUCCESS) throw DxvkError("Failed to create surface"); if (recreateSwapChain(desc) != VK_SUCCESS) @@ -105,8 +105,20 @@ namespace dxvk::vk { VkResult status; if ((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - m_device.adapter, m_surface, &caps)) != VK_SUCCESS) - return status; + m_device.adapter, m_surface, &caps)) != VK_SUCCESS) { + while (status == VK_ERROR_SURFACE_LOST_KHR) { + // Recreate the surface and try again. + if (m_surface) + destroySurface(); + if ((status = createSurface()) != VK_SUCCESS) + continue; + if ((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + m_device.adapter, m_surface, &caps)) != VK_SUCCESS) + continue; + } + if (status != VK_SUCCESS) + return status; + } if ((status = getSupportedFormats(formats)) != VK_SUCCESS) return status; @@ -355,16 +367,16 @@ namespace dxvk::vk { } - VkResult Presenter::createSurface(HWND window) { + VkResult Presenter::createSurface() { HINSTANCE instance = reinterpret_cast( - GetWindowLongPtr(window, GWLP_HINSTANCE)); + GetWindowLongPtr(m_window, GWLP_HINSTANCE)); VkWin32SurfaceCreateInfoKHR info; info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; info.pNext = nullptr; info.flags = 0; info.hinstance = instance; - info.hwnd = window; + info.hwnd = m_window; VkResult status = m_vki->vkCreateWin32SurfaceKHR( m_vki->instance(), &info, nullptr, &m_surface); @@ -412,4 +424,4 @@ namespace dxvk::vk { m_vki->vkDestroySurfaceKHR(m_vki->instance(), m_surface, nullptr); } -} \ No newline at end of file +} diff --git a/src/vulkan/vulkan_presenter.h b/src/vulkan/vulkan_presenter.h index 1435f7fe3a4..c78444d6085 100644 --- a/src/vulkan/vulkan_presenter.h +++ b/src/vulkan/vulkan_presenter.h @@ -174,6 +174,7 @@ namespace dxvk::vk { PresenterDevice m_device; PresenterInfo m_info; + HWND m_window = nullptr; VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkSwapchainKHR m_swapchain = VK_NULL_HANDLE; @@ -213,7 +214,7 @@ namespace dxvk::vk { VkPresentModeKHR presentMode, uint32_t desired); - VkResult createSurface(HWND window); + VkResult createSurface(); void destroySwapchain(); @@ -221,4 +222,4 @@ namespace dxvk::vk { }; -} \ No newline at end of file +} From 61cb6d9c62d6e0b87518bdcceb7ba94ec082225a Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Mon, 1 Apr 2019 13:25:29 -0500 Subject: [PATCH 2/3] [vulkan] Don't loop endlessly on a lost surface. If the surface is lost in a way that can't be recovered by recreating the surface from the window, the previous change would wind up looping forever. Just retry 5 times before giving up. --- src/vulkan/vulkan_presenter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vulkan/vulkan_presenter.cpp b/src/vulkan/vulkan_presenter.cpp index 94546a83a71..c760bb1b276 100644 --- a/src/vulkan/vulkan_presenter.cpp +++ b/src/vulkan/vulkan_presenter.cpp @@ -106,8 +106,8 @@ namespace dxvk::vk { if ((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( m_device.adapter, m_surface, &caps)) != VK_SUCCESS) { - while (status == VK_ERROR_SURFACE_LOST_KHR) { - // Recreate the surface and try again. + for (uint32_t i = 0; i < 5 && status == VK_ERROR_SURFACE_LOST_KHR; i++) { + // Recreate the surface and try again. Give up after 5 tries. if (m_surface) destroySurface(); if ((status = createSurface()) != VK_SUCCESS) From 190e6ca87e18b22865a6dfcf492b308df0291f3c Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Mon, 1 Apr 2019 13:46:38 -0500 Subject: [PATCH 3/3] Only try once to recreate surfaces on surface loss. --- src/vulkan/vulkan_presenter.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/vulkan/vulkan_presenter.cpp b/src/vulkan/vulkan_presenter.cpp index c760bb1b276..623db231c0c 100644 --- a/src/vulkan/vulkan_presenter.cpp +++ b/src/vulkan/vulkan_presenter.cpp @@ -106,15 +106,14 @@ namespace dxvk::vk { if ((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( m_device.adapter, m_surface, &caps)) != VK_SUCCESS) { - for (uint32_t i = 0; i < 5 && status == VK_ERROR_SURFACE_LOST_KHR; i++) { - // Recreate the surface and try again. Give up after 5 tries. + if (status == VK_ERROR_SURFACE_LOST_KHR) { + // Recreate the surface and try again. if (m_surface) destroySurface(); if ((status = createSurface()) != VK_SUCCESS) - continue; - if ((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - m_device.adapter, m_surface, &caps)) != VK_SUCCESS) - continue; + return status; + status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + m_device.adapter, m_surface, &caps); } if (status != VK_SUCCESS) return status;