mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50: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 "video_core/renderer_vulkan/vk_instance.h" | ||||
| #include "video_core/renderer_vulkan/vk_master_semaphore.h" | ||||
| #include "video_core/renderer_vulkan/vk_scheduler.h" | ||||
| 
 | ||||
| namespace Vulkan { | ||||
| 
 | ||||
|  | @ -109,23 +108,20 @@ constexpr u64 FENCE_RESERVE = 8; | |||
| MasterSemaphoreFence::MasterSemaphoreFence(const Instance& instance_) : instance{instance_} { | ||||
|     const vk::Device device{instance.GetDevice()}; | ||||
|     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); }); | ||||
| } | ||||
| 
 | ||||
| MasterSemaphoreFence::~MasterSemaphoreFence() = default; | ||||
| MasterSemaphoreFence::~MasterSemaphoreFence() { | ||||
|     std::ranges::for_each(free_queue, [this](auto fence) { instance.GetDevice().destroyFence(fence); }); | ||||
| } | ||||
| 
 | ||||
| void MasterSemaphoreFence::Refresh() {} | ||||
| 
 | ||||
| void MasterSemaphoreFence::Wait(u64 tick) { | ||||
|     while (true) { | ||||
|         u64 current_value = gpu_tick.load(std::memory_order_relaxed); | ||||
|         if (current_value >= tick) { | ||||
|             return; | ||||
|         } | ||||
|         gpu_tick.wait(current_value); | ||||
|     } | ||||
|     std::unique_lock lk{free_mutex}; | ||||
|     free_cv.wait(lk, [&] { return gpu_tick.load(std::memory_order_relaxed) >= tick; }); | ||||
| } | ||||
| 
 | ||||
| void MasterSemaphoreFence::SubmitWork(vk::CommandBuffer cmdbuf, vk::Semaphore wait, | ||||
|  | @ -149,59 +145,58 @@ void MasterSemaphoreFence::SubmitWork(vk::CommandBuffer cmdbuf, vk::Semaphore wa | |||
|         .pSignalSemaphores = &signal, | ||||
|     }; | ||||
| 
 | ||||
|     vk::UniqueFence fence{GetFreeFence()}; | ||||
|     const vk::Fence fence = GetFreeFence(); | ||||
| 
 | ||||
|     try { | ||||
|         instance.GetGraphicsQueue().submit(submit_info, *fence); | ||||
|         instance.GetGraphicsQueue().submit(submit_info, fence); | ||||
|     } catch (vk::DeviceLostError& err) { | ||||
|         LOG_CRITICAL(Render_Vulkan, "Device lost during submit: {}", err.what()); | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
| 
 | ||||
|     std::scoped_lock lock{wait_mutex}; | ||||
|     wait_queue.push({ | ||||
|         .handle = std::move(fence), | ||||
|         .signal_value = signal_value, | ||||
|     }); | ||||
|     wait_queue.emplace(fence, signal_value); | ||||
|     wait_cv.notify_one(); | ||||
| } | ||||
| 
 | ||||
| void MasterSemaphoreFence::WaitThread(std::stop_token token) { | ||||
|     const vk::Device device{instance.GetDevice()}; | ||||
|     while (!token.stop_requested()) { | ||||
|         Fence fence; | ||||
|         vk::Fence fence; | ||||
|         u64 signal_value; | ||||
|         { | ||||
|             std::unique_lock lock{wait_mutex}; | ||||
|             Common::CondvarWait(wait_cv, lock, token, [this] { return !wait_queue.empty(); }); | ||||
|             if (token.stop_requested()) { | ||||
|                 return; | ||||
|             } | ||||
|             fence = std::move(wait_queue.front()); | ||||
|             std::tie(fence, signal_value) = wait_queue.front(); | ||||
|             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) { | ||||
|             LOG_CRITICAL(Render_Vulkan, "Fence wait failed with error {}", vk::to_string(result)); | ||||
|             UNREACHABLE(); | ||||
|         } | ||||
|         device.resetFences(*fence.handle); | ||||
| 
 | ||||
|         gpu_tick.store(fence.signal_value); | ||||
|         gpu_tick.notify_all(); | ||||
|         device.resetFences(fence); | ||||
|         gpu_tick.store(signal_value); | ||||
| 
 | ||||
|         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}; | ||||
|     if (free_queue.empty()) { | ||||
|         return instance.GetDevice().createFenceUnique({}); | ||||
|         return instance.GetDevice().createFence({}); | ||||
|     } | ||||
| 
 | ||||
|     vk::UniqueFence fence{std::move(free_queue.front())}; | ||||
|     free_queue.pop(); | ||||
|     const vk::Fence fence = free_queue.front(); | ||||
|     free_queue.pop_front(); | ||||
|     return fence; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -72,6 +72,7 @@ private: | |||
| }; | ||||
| 
 | ||||
| class MasterSemaphoreFence : public MasterSemaphore { | ||||
|     using Waitable = std::pair<vk::Fence, u64>; | ||||
| public: | ||||
|     explicit MasterSemaphoreFence(const Instance& instance); | ||||
|     ~MasterSemaphoreFence() override; | ||||
|  | @ -86,20 +87,15 @@ public: | |||
| private: | ||||
|     void WaitThread(std::stop_token token); | ||||
| 
 | ||||
|     vk::UniqueFence GetFreeFence(); | ||||
|     vk::Fence GetFreeFence(); | ||||
| 
 | ||||
| private: | ||||
|     const Instance& instance; | ||||
| 
 | ||||
|     struct Fence { | ||||
|         vk::UniqueFence handle; | ||||
|         u64 signal_value; | ||||
|     }; | ||||
| 
 | ||||
|     std::queue<vk::UniqueFence> free_queue; | ||||
|     std::queue<Fence> wait_queue; | ||||
|     std::deque<vk::Fence> free_queue; | ||||
|     std::queue<Waitable> wait_queue; | ||||
|     std::mutex free_mutex; | ||||
|     std::mutex wait_mutex; | ||||
|     std::condition_variable free_cv; | ||||
|     std::condition_variable_any wait_cv; | ||||
|     std::jthread wait_thread; | ||||
| }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue