diff options
Diffstat (limited to '')
-rw-r--r-- | src/video_core/renderer_vulkan/vk_master_semaphore.h | 62 |
1 files changed, 30 insertions, 32 deletions
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 689f02ea5..3f599d7bd 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h @@ -4,7 +4,11 @@ #pragma once #include <atomic> +#include <condition_variable> +#include <deque> +#include <mutex> #include <thread> +#include <queue> #include "common/common_types.h" #include "common/polyfill_thread.h" @@ -15,6 +19,8 @@ namespace Vulkan { class Device; class MasterSemaphore { + using Waitable = std::pair<u64, vk::Fence>; + public: explicit MasterSemaphore(const Device& device); ~MasterSemaphore(); @@ -29,11 +35,6 @@ public: return gpu_tick.load(std::memory_order_acquire); } - /// Returns the timeline semaphore handle. - [[nodiscard]] VkSemaphore Handle() const noexcept { - return *semaphore; - } - /// Returns true when a tick has been hit by the GPU. [[nodiscard]] bool IsFree(u64 tick) const noexcept { return KnownGpuTick() >= tick; @@ -45,41 +46,38 @@ public: } /// Refresh the known GPU tick - void Refresh() { - u64 this_tick{}; - u64 counter{}; - do { - this_tick = gpu_tick.load(std::memory_order_acquire); - counter = semaphore.GetCounter(); - if (counter < this_tick) { - return; - } - } while (!gpu_tick.compare_exchange_weak(this_tick, counter, std::memory_order_release, - std::memory_order_relaxed)); - } + void Refresh(); /// Waits for a tick to be hit on the GPU - void Wait(u64 tick) { - // No need to wait if the GPU is ahead of the tick - if (IsFree(tick)) { - return; - } - // Update the GPU tick and try again - Refresh(); - if (IsFree(tick)) { - return; - } - // If none of the above is hit, fallback to a regular wait - while (!semaphore.Wait(tick)) { - } - Refresh(); - } + void Wait(u64 tick); + + /// Submits the device graphics queue, updating the tick as necessary + VkResult SubmitQueue(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, + VkSemaphore wait_semaphore, u64 host_tick); + +private: + VkResult SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, + VkSemaphore wait_semaphore, u64 host_tick); + VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, + VkSemaphore wait_semaphore, u64 host_tick); + + void WaitThread(std::stop_token token); + + vk::Fence GetFreeFence(); private: + const Device& device; ///< Device. vk::Semaphore semaphore; ///< Timeline semaphore. std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. std::atomic<u64> current_tick{1}; ///< Current logical tick. + std::mutex wait_mutex; + std::mutex free_mutex; + std::condition_variable free_cv; + std::condition_variable_any wait_cv; + std::queue<Waitable> wait_queue; ///< Queue for the fences to be waited on by the wait thread. + std::deque<vk::Fence> free_queue; ///< Holds available fences for submission. std::jthread debug_thread; ///< Debug thread to workaround validation layer bugs. + std::jthread wait_thread; ///< Helper thread that waits for submitted fences. }; } // namespace Vulkan |