diff --git a/Common/GPU/Vulkan/VulkanFrameData.cpp b/Common/GPU/Vulkan/VulkanFrameData.cpp index e8d6f67784..d5bc6f47aa 100644 --- a/Common/GPU/Vulkan/VulkanFrameData.cpp +++ b/Common/GPU/Vulkan/VulkanFrameData.cpp @@ -1,3 +1,5 @@ +#include + #include "VulkanFrameData.h" #include "Common/Log.h" @@ -26,6 +28,7 @@ void FrameData::Init(VulkanContext *vulkan, int index) { // Creating the frame fence with true so they can be instantly waited on the first frame fence = vulkan->CreateFence(true); + readyForFence = true; // This fence one is used for synchronizing readbacks. Does not need preinitialization. readbackFence = vulkan->CreateFence(false); @@ -169,7 +172,18 @@ void FrameData::SubmitPending(VulkanContext *vulkan, FrameSubmitType type, Frame submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = &sharedData.renderingCompleteSemaphore; } - VkResult res = vkQueueSubmit(vulkan->GetGraphicsQueue(), 1, &submit_info, fenceToTrigger); + + VkResult res; + if (fenceToTrigger == fence) { + // The fence is waited on by the main thread, they are not allowed to access it simultaneously. + std::lock_guard lock(fenceMutex); + res = vkQueueSubmit(vulkan->GetGraphicsQueue(), 1, &submit_info, fenceToTrigger); + readyForFence = true; + fenceCondVar.notify_one(); + } else { + res = vkQueueSubmit(vulkan->GetGraphicsQueue(), 1, &submit_info, fenceToTrigger); + } + if (res == VK_ERROR_DEVICE_LOST) { _assert_msg_(false, "Lost the Vulkan device in vkQueueSubmit! If this happens again, switch Graphics Backend away from Vulkan"); } else { diff --git a/Common/GPU/Vulkan/VulkanFrameData.h b/Common/GPU/Vulkan/VulkanFrameData.h index a80210e81c..9fdd865ebf 100644 --- a/Common/GPU/Vulkan/VulkanFrameData.h +++ b/Common/GPU/Vulkan/VulkanFrameData.h @@ -44,6 +44,10 @@ enum class FrameSubmitType { struct FrameData { bool skipSwap = false; + std::mutex fenceMutex; + std::condition_variable fenceCondVar; + bool readyForFence = true; + VkFence fence; VkFence readbackFence; // Strictly speaking we might only need one global of these. diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 4229ed5d86..c307314233 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -504,6 +504,16 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling, bool enableLogProfile VLOG("PUSH: Fencing %d", curFrame); + // Makes sure the submission from the previous time around has happened. Otherwise + // we are not allowed to wait from another thread here.. + { + std::unique_lock lock(frameData.fenceMutex); + while (!frameData.readyForFence) { + frameData.fenceCondVar.wait(lock); + } + frameData.readyForFence = false; + } + // This must be the very first Vulkan call we do in a new frame. // Makes sure the very last command buffer from the frame before the previous has been fully executed. if (vkWaitForFences(device, 1, &frameData.fence, true, UINT64_MAX) == VK_ERROR_DEVICE_LOST) {