mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 13:20:03 +00:00 
			
		
		
		
	vk_master_semaphore: Remove waitable atomic
* These are buggy on some platforms and regular condition_variables are faster most of the time
This commit is contained in:
		
							parent
							
								
									b9c9beeee5
								
							
						
					
					
						commit
						2bcbfeb861
					
				
					 2 changed files with 27 additions and 36 deletions
				
			
		|  | @ -5,7 +5,6 @@ | ||||||
| #include <mutex> | #include <mutex> | ||||||
| #include "video_core/renderer_vulkan/vk_instance.h" | #include "video_core/renderer_vulkan/vk_instance.h" | ||||||
| #include "video_core/renderer_vulkan/vk_master_semaphore.h" | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | ||||||
| #include "video_core/renderer_vulkan/vk_scheduler.h" |  | ||||||
| 
 | 
 | ||||||
| namespace Vulkan { | namespace Vulkan { | ||||||
| 
 | 
 | ||||||
|  | @ -109,23 +108,20 @@ constexpr u64 FENCE_RESERVE = 8; | ||||||
| MasterSemaphoreFence::MasterSemaphoreFence(const Instance& instance_) : instance{instance_} { | MasterSemaphoreFence::MasterSemaphoreFence(const Instance& instance_) : instance{instance_} { | ||||||
|     const vk::Device device{instance.GetDevice()}; |     const vk::Device device{instance.GetDevice()}; | ||||||
|     for (u64 i = 0; i < FENCE_RESERVE; i++) { |     for (u64 i = 0; i < FENCE_RESERVE; i++) { | ||||||
|         free_queue.push(device.createFenceUnique({})); |         free_queue.push_back(device.createFence({})); | ||||||
|     } |     } | ||||||
|     wait_thread = std::jthread([this](std::stop_token token) { WaitThread(token); }); |     wait_thread = std::jthread([this](std::stop_token token) { WaitThread(token); }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MasterSemaphoreFence::~MasterSemaphoreFence() = default; | MasterSemaphoreFence::~MasterSemaphoreFence() { | ||||||
|  |     std::ranges::for_each(free_queue, [this](auto fence) { instance.GetDevice().destroyFence(fence); }); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void MasterSemaphoreFence::Refresh() {} | void MasterSemaphoreFence::Refresh() {} | ||||||
| 
 | 
 | ||||||
| void MasterSemaphoreFence::Wait(u64 tick) { | void MasterSemaphoreFence::Wait(u64 tick) { | ||||||
|     while (true) { |     std::unique_lock lk{free_mutex}; | ||||||
|         u64 current_value = gpu_tick.load(std::memory_order_relaxed); |     free_cv.wait(lk, [&] { return gpu_tick.load(std::memory_order_relaxed) >= tick; }); | ||||||
|         if (current_value >= tick) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         gpu_tick.wait(current_value); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MasterSemaphoreFence::SubmitWork(vk::CommandBuffer cmdbuf, vk::Semaphore wait, | void MasterSemaphoreFence::SubmitWork(vk::CommandBuffer cmdbuf, vk::Semaphore wait, | ||||||
|  | @ -149,59 +145,58 @@ void MasterSemaphoreFence::SubmitWork(vk::CommandBuffer cmdbuf, vk::Semaphore wa | ||||||
|         .pSignalSemaphores = &signal, |         .pSignalSemaphores = &signal, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     vk::UniqueFence fence{GetFreeFence()}; |     const vk::Fence fence = GetFreeFence(); | ||||||
|  | 
 | ||||||
|     try { |     try { | ||||||
|         instance.GetGraphicsQueue().submit(submit_info, *fence); |         instance.GetGraphicsQueue().submit(submit_info, fence); | ||||||
|     } catch (vk::DeviceLostError& err) { |     } catch (vk::DeviceLostError& err) { | ||||||
|         LOG_CRITICAL(Render_Vulkan, "Device lost during submit: {}", err.what()); |         LOG_CRITICAL(Render_Vulkan, "Device lost during submit: {}", err.what()); | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::scoped_lock lock{wait_mutex}; |     std::scoped_lock lock{wait_mutex}; | ||||||
|     wait_queue.push({ |     wait_queue.emplace(fence, signal_value); | ||||||
|         .handle = std::move(fence), |  | ||||||
|         .signal_value = signal_value, |  | ||||||
|     }); |  | ||||||
|     wait_cv.notify_one(); |     wait_cv.notify_one(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MasterSemaphoreFence::WaitThread(std::stop_token token) { | void MasterSemaphoreFence::WaitThread(std::stop_token token) { | ||||||
|     const vk::Device device{instance.GetDevice()}; |     const vk::Device device{instance.GetDevice()}; | ||||||
|     while (!token.stop_requested()) { |     while (!token.stop_requested()) { | ||||||
|         Fence fence; |         vk::Fence fence; | ||||||
|  |         u64 signal_value; | ||||||
|         { |         { | ||||||
|             std::unique_lock lock{wait_mutex}; |             std::unique_lock lock{wait_mutex}; | ||||||
|             Common::CondvarWait(wait_cv, lock, token, [this] { return !wait_queue.empty(); }); |             Common::CondvarWait(wait_cv, lock, token, [this] { return !wait_queue.empty(); }); | ||||||
|             if (token.stop_requested()) { |             if (token.stop_requested()) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             fence = std::move(wait_queue.front()); |             std::tie(fence, signal_value) = wait_queue.front(); | ||||||
|             wait_queue.pop(); |             wait_queue.pop(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const vk::Result result = device.waitForFences(*fence.handle, true, WAIT_TIMEOUT); |         const vk::Result result = device.waitForFences(fence, true, WAIT_TIMEOUT); | ||||||
|         if (result != vk::Result::eSuccess) { |         if (result != vk::Result::eSuccess) { | ||||||
|             LOG_CRITICAL(Render_Vulkan, "Fence wait failed with error {}", vk::to_string(result)); |             LOG_CRITICAL(Render_Vulkan, "Fence wait failed with error {}", vk::to_string(result)); | ||||||
|             UNREACHABLE(); |             UNREACHABLE(); | ||||||
|         } |         } | ||||||
|         device.resetFences(*fence.handle); |  | ||||||
| 
 | 
 | ||||||
|         gpu_tick.store(fence.signal_value); |         device.resetFences(fence); | ||||||
|         gpu_tick.notify_all(); |         gpu_tick.store(signal_value); | ||||||
| 
 | 
 | ||||||
|         std::scoped_lock lock{free_mutex}; |         std::scoped_lock lock{free_mutex}; | ||||||
|         free_queue.push(std::move(fence.handle)); |         free_queue.push_back(fence); | ||||||
|  |         free_cv.notify_all(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| vk::UniqueFence MasterSemaphoreFence::GetFreeFence() { | vk::Fence MasterSemaphoreFence::GetFreeFence() { | ||||||
|     std::scoped_lock lock{free_mutex}; |     std::scoped_lock lock{free_mutex}; | ||||||
|     if (free_queue.empty()) { |     if (free_queue.empty()) { | ||||||
|         return instance.GetDevice().createFenceUnique({}); |         return instance.GetDevice().createFence({}); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     vk::UniqueFence fence{std::move(free_queue.front())}; |     const vk::Fence fence = free_queue.front(); | ||||||
|     free_queue.pop(); |     free_queue.pop_front(); | ||||||
|     return fence; |     return fence; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -72,6 +72,7 @@ private: | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class MasterSemaphoreFence : public MasterSemaphore { | class MasterSemaphoreFence : public MasterSemaphore { | ||||||
|  |     using Waitable = std::pair<vk::Fence, u64>; | ||||||
| public: | public: | ||||||
|     explicit MasterSemaphoreFence(const Instance& instance); |     explicit MasterSemaphoreFence(const Instance& instance); | ||||||
|     ~MasterSemaphoreFence() override; |     ~MasterSemaphoreFence() override; | ||||||
|  | @ -86,20 +87,15 @@ public: | ||||||
| private: | private: | ||||||
|     void WaitThread(std::stop_token token); |     void WaitThread(std::stop_token token); | ||||||
| 
 | 
 | ||||||
|     vk::UniqueFence GetFreeFence(); |     vk::Fence GetFreeFence(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     const Instance& instance; |     const Instance& instance; | ||||||
| 
 |     std::deque<vk::Fence> free_queue; | ||||||
|     struct Fence { |     std::queue<Waitable> wait_queue; | ||||||
|         vk::UniqueFence handle; |  | ||||||
|         u64 signal_value; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     std::queue<vk::UniqueFence> free_queue; |  | ||||||
|     std::queue<Fence> wait_queue; |  | ||||||
|     std::mutex free_mutex; |     std::mutex free_mutex; | ||||||
|     std::mutex wait_mutex; |     std::mutex wait_mutex; | ||||||
|  |     std::condition_variable free_cv; | ||||||
|     std::condition_variable_any wait_cv; |     std::condition_variable_any wait_cv; | ||||||
|     std::jthread wait_thread; |     std::jthread wait_thread; | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue