From afdbe90992bf4d4388b2560e309dd44c22b8ca8a Mon Sep 17 00:00:00 2001 From: PavelBARABANOV Date: Sun, 22 Feb 2026 01:56:16 +0300 Subject: [PATCH] [vk] Fix lost wakeup in fence mode using atomic wait --- .../renderer_vulkan/vk_master_semaphore.cpp | 40 +++++++------------ .../renderer_vulkan/vk_master_semaphore.h | 1 + 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index a82e2c73fa..0e92902669 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project @@ -78,11 +78,17 @@ void MasterSemaphore::Refresh() { void MasterSemaphore::Wait(u64 tick) { if (!semaphore) { - // If we don't support timeline semaphores, wait for the value normally - std::unique_lock lk{free_mutex}; - free_cv.wait(lk, [&] { - return gpu_tick.load(std::memory_order_acquire) >= tick; - }); + // Fast check: already reached the requested tick? + if (gpu_tick.load(std::memory_order_acquire) >= tick) { + return; + } + + // Wait for fence completions using atomic wait + u64 last_notify = notify_counter.load(std::memory_order_relaxed); + while (gpu_tick.load(std::memory_order_acquire) < tick) { + notify_counter.wait(last_notify, std::memory_order_acquire); + last_notify = notify_counter.load(std::memory_order_relaxed); + } return; } @@ -217,33 +223,15 @@ void MasterSemaphore::WaitThread(std::stop_token token) { std::tie(host_tick, fence) = std::move(wait_queue.front()); wait_queue.pop(); } - -#ifdef ANDROID - VkResult status; - do { - status = fence.GetStatus(); - if (status == VK_NOT_READY) { - std::this_thread::sleep_for(std::chrono::microseconds(100)); - } - } while (status == VK_NOT_READY); - - if (status == VK_SUCCESS) { - fence.Reset(); - } else { - vk::Check(status); - continue; - } -#else fence.Wait(); fence.Reset(); -#endif - { std::scoped_lock lock{free_mutex}; free_queue.push_front(std::move(fence)); gpu_tick.store(host_tick, std::memory_order_release); + notify_counter.fetch_add(1, std::memory_order_release); } - free_cv.notify_all(); + notify_counter.notify_one(); } } diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 7dfb93ffbf..997c2a180c 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h @@ -72,6 +72,7 @@ private: vk::Semaphore semaphore; ///< Timeline semaphore. std::atomic gpu_tick{0}; ///< Current known GPU tick. std::atomic current_tick{1}; ///< Current logical tick. + std::atomic notify_counter{0}; ///< Fence completion counter for atomic wait. std::mutex wait_mutex; std::mutex free_mutex; std::condition_variable free_cv;