diff options
| author | 2023-05-20 14:08:05 +0300 | |
|---|---|---|
| committer | 2023-05-20 19:23:53 +0300 | |
| commit | 4e491ab59ba8b9c08253ca9cce5bb9fe909ac2ff (patch) | |
| tree | 1a371195bf04722d77c01ec624224adc517ce7a3 | |
| parent | Merge pull request #10344 from german77/pro-amiibo (diff) | |
| download | yuzu-4e491ab59ba8b9c08253ca9cce5bb9fe909ac2ff.tar.gz yuzu-4e491ab59ba8b9c08253ca9cce5bb9fe909ac2ff.tar.xz yuzu-4e491ab59ba8b9c08253ca9cce5bb9fe909ac2ff.zip | |
vk_master_semaphore: Move fence wait on separate thread
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_master_semaphore.cpp | 46 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_master_semaphore.h | 15 |
2 files changed, 58 insertions, 3 deletions
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index 47c74e4d8..8b65aeaeb 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp | |||
| @@ -10,11 +10,16 @@ | |||
| 10 | 10 | ||
| 11 | namespace Vulkan { | 11 | namespace Vulkan { |
| 12 | 12 | ||
| 13 | constexpr u64 FENCE_RESERVE_SIZE = 8; | ||
| 14 | |||
| 13 | MasterSemaphore::MasterSemaphore(const Device& device_) : device(device_) { | 15 | MasterSemaphore::MasterSemaphore(const Device& device_) : device(device_) { |
| 14 | if (!device.HasTimelineSemaphore()) { | 16 | if (!device.HasTimelineSemaphore()) { |
| 15 | static constexpr VkFenceCreateInfo fence_ci{ | 17 | static constexpr VkFenceCreateInfo fence_ci{ |
| 16 | .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0}; | 18 | .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0}; |
| 17 | fence = device.GetLogical().CreateFence(fence_ci); | 19 | free_queue.resize(FENCE_RESERVE_SIZE); |
| 20 | std::ranges::generate(free_queue, | ||
| 21 | [&] { return device.GetLogical().CreateFence(fence_ci); }); | ||
| 22 | wait_thread = std::jthread([this](std::stop_token token) { WaitThread(token); }); | ||
| 18 | return; | 23 | return; |
| 19 | } | 24 | } |
| 20 | 25 | ||
| @@ -167,16 +172,53 @@ VkResult MasterSemaphore::SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphor | |||
| 167 | .pSignalSemaphores = &signal_semaphore, | 172 | .pSignalSemaphores = &signal_semaphore, |
| 168 | }; | 173 | }; |
| 169 | 174 | ||
| 175 | auto fence = GetFreeFence(); | ||
| 170 | auto result = device.GetGraphicsQueue().Submit(submit_info, *fence); | 176 | auto result = device.GetGraphicsQueue().Submit(submit_info, *fence); |
| 171 | 177 | ||
| 172 | if (result == VK_SUCCESS) { | 178 | if (result == VK_SUCCESS) { |
| 179 | std::scoped_lock lock{wait_mutex}; | ||
| 180 | wait_queue.emplace(host_tick, std::move(fence)); | ||
| 181 | wait_cv.notify_one(); | ||
| 182 | } | ||
| 183 | |||
| 184 | return result; | ||
| 185 | } | ||
| 186 | |||
| 187 | void MasterSemaphore::WaitThread(std::stop_token token) { | ||
| 188 | while (!token.stop_requested()) { | ||
| 189 | u64 host_tick; | ||
| 190 | vk::Fence fence; | ||
| 191 | { | ||
| 192 | std::unique_lock lock{wait_mutex}; | ||
| 193 | Common::CondvarWait(wait_cv, lock, token, [this] { return !wait_queue.empty(); }); | ||
| 194 | if (token.stop_requested()) { | ||
| 195 | return; | ||
| 196 | } | ||
| 197 | std::tie(host_tick, fence) = std::move(wait_queue.front()); | ||
| 198 | wait_queue.pop(); | ||
| 199 | } | ||
| 200 | |||
| 173 | fence.Wait(); | 201 | fence.Wait(); |
| 174 | fence.Reset(); | 202 | fence.Reset(); |
| 175 | gpu_tick.store(host_tick); | 203 | gpu_tick.store(host_tick); |
| 176 | gpu_tick.notify_all(); | 204 | gpu_tick.notify_all(); |
| 205 | |||
| 206 | std::scoped_lock lock{free_mutex}; | ||
| 207 | free_queue.push_front(std::move(fence)); | ||
| 177 | } | 208 | } |
| 209 | } | ||
| 178 | 210 | ||
| 179 | return result; | 211 | vk::Fence MasterSemaphore::GetFreeFence() { |
| 212 | std::scoped_lock lock{free_mutex}; | ||
| 213 | if (free_queue.empty()) { | ||
| 214 | static constexpr VkFenceCreateInfo fence_ci{ | ||
| 215 | .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0}; | ||
| 216 | return device.GetLogical().CreateFence(fence_ci); | ||
| 217 | } | ||
| 218 | |||
| 219 | auto fence = std::move(free_queue.back()); | ||
| 220 | free_queue.pop_back(); | ||
| 221 | return fence; | ||
| 180 | } | 222 | } |
| 181 | 223 | ||
| 182 | } // namespace Vulkan | 224 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index f2f61f781..1e7c90215 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h | |||
| @@ -5,8 +5,10 @@ | |||
| 5 | 5 | ||
| 6 | #include <atomic> | 6 | #include <atomic> |
| 7 | #include <condition_variable> | 7 | #include <condition_variable> |
| 8 | #include <deque> | ||
| 8 | #include <mutex> | 9 | #include <mutex> |
| 9 | #include <thread> | 10 | #include <thread> |
| 11 | #include <queue> | ||
| 10 | 12 | ||
| 11 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 12 | #include "common/polyfill_thread.h" | 14 | #include "common/polyfill_thread.h" |
| @@ -17,6 +19,8 @@ namespace Vulkan { | |||
| 17 | class Device; | 19 | class Device; |
| 18 | 20 | ||
| 19 | class MasterSemaphore { | 21 | class MasterSemaphore { |
| 22 | using Waitable = std::pair<u64, vk::Fence>; | ||
| 23 | |||
| 20 | public: | 24 | public: |
| 21 | explicit MasterSemaphore(const Device& device); | 25 | explicit MasterSemaphore(const Device& device); |
| 22 | ~MasterSemaphore(); | 26 | ~MasterSemaphore(); |
| @@ -57,13 +61,22 @@ private: | |||
| 57 | VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, | 61 | VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, |
| 58 | VkSemaphore wait_semaphore, u64 host_tick); | 62 | VkSemaphore wait_semaphore, u64 host_tick); |
| 59 | 63 | ||
| 64 | void WaitThread(std::stop_token token); | ||
| 65 | |||
| 66 | vk::Fence GetFreeFence(); | ||
| 67 | |||
| 60 | private: | 68 | private: |
| 61 | const Device& device; ///< Device. | 69 | const Device& device; ///< Device. |
| 62 | vk::Fence fence; ///< Fence. | ||
| 63 | vk::Semaphore semaphore; ///< Timeline semaphore. | 70 | vk::Semaphore semaphore; ///< Timeline semaphore. |
| 64 | std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. | 71 | std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. |
| 65 | std::atomic<u64> current_tick{1}; ///< Current logical tick. | 72 | std::atomic<u64> current_tick{1}; ///< Current logical tick. |
| 73 | std::mutex wait_mutex; | ||
| 74 | std::mutex free_mutex; | ||
| 75 | std::condition_variable_any wait_cv; | ||
| 76 | std::queue<Waitable> wait_queue; ///< Queue for the fences to be waited on by the wait thread. | ||
| 77 | std::deque<vk::Fence> free_queue; ///< Holds available fences for submission. | ||
| 66 | std::jthread debug_thread; ///< Debug thread to workaround validation layer bugs. | 78 | std::jthread debug_thread; ///< Debug thread to workaround validation layer bugs. |
| 79 | std::jthread wait_thread; ///< Helper thread that waits for submitted fences. | ||
| 67 | }; | 80 | }; |
| 68 | 81 | ||
| 69 | } // namespace Vulkan | 82 | } // namespace Vulkan |