From 5802747e60fa31c9d24a0e075d2578bf5e1d85b6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 5 Nov 2017 08:40:11 -0800 Subject: [PATCH] Vulkan: Resignal unexecuted fences on thread stop. When resizing or similar, we may end up with frames we never ran. This also happens on startup. We need them signaled at start so we can wait on them, or we may deadlock. --- ext/native/thin3d/VulkanRenderManager.cpp | 38 ++++++++++++++--------- ext/native/thin3d/VulkanRenderManager.h | 2 ++ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 0b6c7e015b99..1afab1219390 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -189,12 +189,6 @@ void VulkanRenderManager::CreateBackbuffers() { // Start the thread. if (useThread) { - for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { - // Reset all the frameData. Might be dirty from previous thread stop. - frameData_[i].readyForRun = false; - frameData_[i].readyForFence = true; - } - run_ = true; // Won't necessarily be 0. threadInitFrame_ = vulkan_->GetCurFrame(); @@ -202,22 +196,37 @@ void VulkanRenderManager::CreateBackbuffers() { } } -void VulkanRenderManager::DestroyBackbuffers() { - if (useThread) { +void VulkanRenderManager::StopThread(bool shutdown) { + if (useThread && run_) { run_ = false; // Stop the thread. for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { + auto &frameData = frameData_[i]; { - std::unique_lock lock(frameData_[i].push_mutex); - frameData_[i].push_condVar.notify_all(); + std::unique_lock lock(frameData.push_mutex); + frameData.push_condVar.notify_all(); } { - std::unique_lock lock(frameData_[i].pull_mutex); - frameData_[i].pull_condVar.notify_all(); + std::unique_lock lock(frameData.pull_mutex); + frameData.pull_condVar.notify_all(); } } thread_.join(); + + // Reset fences for next time around - must be done after join. + for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { + auto &frameData = frameData_[i]; + frameData.readyForRun = false; + if (!shutdown && !frameData.readyForFence) { + vkDestroyFence(vulkan_->GetDevice(), frameData.fence, nullptr); + frameData.fence = vulkan_->CreateFence(true); + } + } } +} + +void VulkanRenderManager::DestroyBackbuffers() { + StopThread(false); vulkan_->WaitUntilQueueIdle(); VkDevice device = vulkan_->GetDevice(); @@ -237,9 +246,10 @@ void VulkanRenderManager::DestroyBackbuffers() { } VulkanRenderManager::~VulkanRenderManager() { - run_ = false; - VkDevice device = vulkan_->GetDevice(); + StopThread(true); vulkan_->WaitUntilQueueIdle(); + + VkDevice device = vulkan_->GetDevice(); vkDestroySemaphore(device, acquireSemaphore_, nullptr); vkDestroySemaphore(device, renderingCompleteSemaphore_, nullptr); for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index 9b9ae5f6792c..f567163fa5ac 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -221,6 +221,8 @@ class VulkanRenderManager { void FlushSync(); void EndSyncFrame(int frame); + void StopThread(bool shutdown); + // Permanent objects VkSemaphore acquireSemaphore_; VkSemaphore renderingCompleteSemaphore_;