diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp index 350757194e..51706fc33f 100644 --- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp @@ -353,8 +353,13 @@ void CommandBufferManager::SubmitCommandBuffer(size_t index, VkSemaphore wait_se nullptr}; res = vkQueuePresentKHR(g_vulkan_context->GetPresentQueue(), &present_info); - if (res != VK_SUCCESS && res != VK_ERROR_OUT_OF_DATE_KHR && res != VK_SUBOPTIMAL_KHR) - LOG_VULKAN_ERROR(res, "vkQueuePresentKHR failed: "); + if (res != VK_SUCCESS) + { + // VK_ERROR_OUT_OF_DATE_KHR is not fatal, just means we need to recreate our swap chain. + if (res != VK_ERROR_OUT_OF_DATE_KHR && res != VK_SUBOPTIMAL_KHR) + LOG_VULKAN_ERROR(res, "vkQueuePresentKHR failed: "); + m_present_failed_flag.Set(); + } } // Command buffer has been queued, so permit the next one. diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h index 67266b69b9..908abe97d1 100644 --- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h @@ -16,6 +16,7 @@ #include #include "Common/BlockingLoop.h" +#include "Common/Flag.h" #include "Common/Semaphore.h" #include "VideoCommon/VideoCommon.h" @@ -78,6 +79,8 @@ public: void ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completion); + // Was the last present submitted to the queue a failure? If so, we must recreate our swapchain. + bool DidLastPresentFail() { return m_present_failed_flag.TestAndClear(); } // Schedule a vulkan resource for destruction later on. This will occur when the command buffer // is next re-used, and the GPU has finished working with the specified resource. void DeferBufferDestruction(VkBuffer object); @@ -144,6 +147,7 @@ private: }; std::deque m_pending_submits; std::mutex m_pending_submit_lock; + Common::Flag m_present_failed_flag; bool m_use_threaded_submission = false; }; diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 6342c43817..018df1dbf0 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -718,8 +718,18 @@ void Renderer::DrawScreen(const TargetRectangle& scaled_efb_rect, u32 xfb_addr, const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, u32 fb_stride, u32 fb_height) { - // Grab the next image from the swap chain in preparation for drawing the window. - VkResult res = m_swap_chain->AcquireNextImage(m_image_available_semaphore); + VkResult res; + if (!g_command_buffer_mgr->DidLastPresentFail()) + { + // Grab the next image from the swap chain in preparation for drawing the window. + res = m_swap_chain->AcquireNextImage(m_image_available_semaphore); + } + else + { + // If the last present failed, we need to recreate the swap chain. + res = VK_ERROR_OUT_OF_DATE_KHR; + } + if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) { // There's an issue here. We can't resize the swap chain while the GPU is still busy with it,