diff --git a/Common/GraphicsContext.h b/Common/GraphicsContext.h index 5dfec7f6d9..d17d77d726 100644 --- a/Common/GraphicsContext.h +++ b/Common/GraphicsContext.h @@ -34,6 +34,10 @@ public: virtual void ThreadEnd() {} virtual void StopThread() {} + // Useful for checks that need to be performed every frame. + // Should strive to get rid of these. + virtual void Poll() {} + virtual Draw::DrawContext *GetDrawContext() = 0; }; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 9e3ea05102..e6fca738f3 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1095,6 +1095,8 @@ void NativeRender(GraphicsContext *graphicsContext) { NativeMessageReceived("gpu_resized", ""); } #endif + } else { + graphicsContext->Poll(); } ui_draw2d.PopDrawMatrix(); diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index abdc03e603..8f7249dbc5 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -143,9 +143,9 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m _assert_msg_(G3D, success, "Failed to compile preset shaders"); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); - renderManager->SetInflightFrames(g_Config.iInflightFrames); - if (!renderManager->HasBackbuffers()) { + renderManager_ = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + renderManager_->SetInflightFrames(g_Config.iInflightFrames); + if (!renderManager_->HasBackbuffers()) { Shutdown(); return false; } @@ -166,6 +166,7 @@ void WindowsVulkanContext::Shutdown() { delete g_Vulkan; g_Vulkan = nullptr; + renderManager_ = nullptr; finalize_glslang(); } @@ -181,6 +182,13 @@ void WindowsVulkanContext::Resize() { draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); } +void WindowsVulkanContext::Poll() { + // Check for existing swapchain to avoid issues during shutdown. + if (g_Vulkan->GetSwapchain() && renderManager_->NeedsSwapchainRecreate()) { + Resize(); + } +} + void *WindowsVulkanContext::GetAPIContext() { return g_Vulkan; } diff --git a/Windows/GPU/WindowsVulkanContext.h b/Windows/GPU/WindowsVulkanContext.h index 0a00dfeab8..a006c52ed1 100644 --- a/Windows/GPU/WindowsVulkanContext.h +++ b/Windows/GPU/WindowsVulkanContext.h @@ -21,6 +21,8 @@ #include "Windows/GPU/WindowsGraphicsContext.h" #include "thin3d/thin3d.h" +class VulkanRenderManager; + class WindowsVulkanContext : public WindowsGraphicsContext { public: WindowsVulkanContext() : draw_(nullptr) {} @@ -29,11 +31,13 @@ public: void SwapInterval(int interval) override {} void SwapBuffers() override {} void Resize() override; + void Poll() override; void *GetAPIContext(); Draw::DrawContext *GetDrawContext() override { return draw_; } private: Draw::DrawContext *draw_; + VulkanRenderManager *renderManager_ = nullptr; }; diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 9e047d00be..573f0ce6c5 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -209,6 +209,8 @@ void VulkanRenderManager::CreateBackbuffers() { newInflightFrames_ = -1; } + outOfDateFrames_ = 0; + // Start the thread. if (useThread_ && HasBackbuffers()) { run_ = true; @@ -1029,11 +1031,14 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) { if (res == VK_SUBOPTIMAL_KHR) { // Hopefully the resize will happen shortly. Ignore - one frame might look bad or something. WLOG("VK_SUBOPTIMAL_KHR returned - ignoring"); + outOfDateFrames_++; } else if (res == VK_ERROR_OUT_OF_DATE_KHR) { WLOG("VK_ERROR_OUT_OF_DATE_KHR returned - not presenting"); frameData.skipSwap = true; + outOfDateFrames_++; } else { _assert_msg_(G3D, res == VK_SUCCESS, "vkAcquireNextImageKHR failed! result=%s", VulkanResultToString(res)); + outOfDateFrames_ = 0; } VkCommandBufferBeginInfo begin{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index 391d559f61..baf2990ab4 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -285,6 +285,11 @@ public: return frameData_[vulkan_->GetCurFrame()].profile.profileSummary; } + bool NeedsSwapchainRecreate() const { + // Accepting a few of these makes shutdown simpler. + return outOfDateFrames_ > VulkanContext::MAX_INFLIGHT_FRAMES; + } + private: bool InitBackbufferFramebuffers(int width, int height); bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering. @@ -337,6 +342,8 @@ private: int newInflightFrames_ = -1; int inflightFramesAtStart_ = 0; + int outOfDateFrames_ = 0; + // Submission time state int curWidth_ = -1; int curHeight_ = -1;