diff --git a/Common/GPU/Vulkan/VulkanPresentation.h b/Common/GPU/Vulkan/VulkanPresentation.h index 141d1e2211..4d6891896f 100644 --- a/Common/GPU/Vulkan/VulkanPresentation.h +++ b/Common/GPU/Vulkan/VulkanPresentation.h @@ -31,6 +31,11 @@ public: // Mirrors vkQueuePresentKHR: hands the finished image back, waiting on waitSemaphore first. virtual VkResult QueuePresent(VulkanContext *vulkan, VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore) = 0; + // Called around a queued presentation. Hosts that hand an image to another thread can use this + // to keep the caller from invoking its video callback until QueuePresent has completed. + virtual void BeginPresent() {} + virtual void EndPresent() {} + virtual uint32_t GetImageCount() const = 0; virtual VkImage GetImage(uint32_t index) const = 0; virtual VkExtent2D GetExtent() const = 0; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index b34b269b94..c60771c059 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -1620,6 +1620,9 @@ void VulkanRenderManager::Finish() { void VulkanRenderManager::Present() { int curFrame = vulkan_->GetCurFrame(); + if (VulkanPresentation *presentation = vulkan_->GetPresentation()) { + presentation->BeginPresent(); + } VKRRenderThreadTask *task = new VKRRenderThreadTask(VKRRunType::PRESENT); task->frame = curFrame; @@ -1671,6 +1674,9 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) { } frameData.skipSwap = false; } + if (VulkanPresentation *presentation = vulkan_->GetPresentation()) { + presentation->EndPresent(); + } return; } diff --git a/libretro/LibretroVulkanPresentation.cpp b/libretro/LibretroVulkanPresentation.cpp index 0400633e62..d841d4db00 100644 --- a/libretro/LibretroVulkanPresentation.cpp +++ b/libretro/LibretroVulkanPresentation.cpp @@ -106,8 +106,8 @@ void LibretroVulkanPresentation::Destroy(VulkanContext *context) { images_.clear(); syncIndexMask_ = 0; std::lock_guard lock(mutex_); - currentIndex_ = -1; - everPresented_ = false; + presentPending_ = false; + condVar_.notify_all(); } bool LibretroVulkanPresentation::NeedsRecreate() const { @@ -138,13 +138,21 @@ VkResult LibretroVulkanPresentation::QueuePresent(VulkanContext *vulkan, VkQueue return VK_ERROR_OUT_OF_DATE_KHR; } std::unique_lock lock(mutex_); - currentIndex_ = (int)imageIndex; vulkan_->set_image(vulkan_->handle, &images_[imageIndex].retroImage, 0, nullptr, vulkan_->queue_index); - everPresented_ = true; - condVar_.notify_all(); return VK_SUCCESS; } +void LibretroVulkanPresentation::BeginPresent() { + std::lock_guard lock(mutex_); + presentPending_ = true; +} + +void LibretroVulkanPresentation::EndPresent() { + std::lock_guard lock(mutex_); + presentPending_ = false; + condVar_.notify_all(); +} + void LibretroVulkanPresentation::LockQueue() { vulkan_->lock_queue(vulkan_->handle); } @@ -162,7 +170,5 @@ void LibretroVulkanPresentation::PrepareSubmit(VkSubmitInfo &submitInfo) { void LibretroVulkanPresentation::WaitForPresentation() { std::unique_lock lock(mutex_); - if (everPresented_ && currentIndex_ < 0) { - condVar_.wait(lock); - } + condVar_.wait(lock, [this] { return !presentPending_; }); } diff --git a/libretro/LibretroVulkanPresentation.h b/libretro/LibretroVulkanPresentation.h index 0bb581aa4e..8c160d8593 100644 --- a/libretro/LibretroVulkanPresentation.h +++ b/libretro/LibretroVulkanPresentation.h @@ -30,6 +30,8 @@ public: VkResult AcquireNextImage(VulkanContext *vulkan, VkSemaphore signalSemaphore, uint32_t *imageIndex) override; VkResult QueuePresent(VulkanContext *vulkan, VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore) override; + void BeginPresent() override; + void EndPresent() override; uint32_t GetImageCount() const override { return (uint32_t)images_.size(); } VkImage GetImage(uint32_t index) const override { return images_[index].image; } @@ -65,8 +67,7 @@ private: std::mutex mutex_; std::condition_variable condVar_; - int currentIndex_ = -1; - bool everPresented_ = false; + bool presentPending_ = false; static uint32_t ImageCountFromMask(uint32_t mask); bool IsValidImageIndex(uint32_t imageIndex) const;