From ea209e6dabdcd99f51dd2ae8b11adeb715b9668f Mon Sep 17 00:00:00 2001 From: MaranBr Date: Mon, 2 Mar 2026 02:53:01 +0100 Subject: [PATCH] [vulkan] Fine-tuning of frame pacing logic (#3628) It makes fine adjustments to the frame pacing, ensuring better stability and precision. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3628 Reviewed-by: crueter Reviewed-by: Lizzie Co-authored-by: MaranBr Co-committed-by: MaranBr --- src/video_core/renderer_vulkan/vk_scheduler.h | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 2913211480..667f136ee6 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -16,8 +16,8 @@ #include "common/alignment.h" #include "common/common_types.h" -#include "common/settings.h" #include "common/polyfill_thread.h" +#include "common/settings.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h" #include "video_core/vulkan_common/vulkan_wrapper.h" @@ -114,29 +114,36 @@ public: /// Waits for the given GPU tick, optionally pacing frames. void Wait(u64 tick, double target_fps = 0.0) { + if (tick > 0) { + if (tick >= master_semaphore->CurrentTick()) { + Flush(); + } + master_semaphore->Wait(tick); + } if (Settings::values.use_speed_limit.GetValue() && target_fps > 0.0) { - const auto now = std::chrono::steady_clock::now(); - if (start_time == std::chrono::steady_clock::time_point{} || current_target_fps != target_fps) { - start_time = now; + auto now = std::chrono::steady_clock::now(); + if (last_target_fps != target_fps) { + frame_interval = std::chrono::duration_cast(std::chrono::duration(1.0 / target_fps)); + max_frame_count = static_cast(0.1 * target_fps); + last_target_fps = target_fps; frame_counter = 0; - current_target_fps = target_fps; + start_time = now; } frame_counter++; - std::chrono::duration frame_interval(1.0 / current_target_fps); auto target_time = start_time + frame_interval * frame_counter; - if (target_time > now) { - std::this_thread::sleep_until(target_time); - } else { - start_time = now; + if (target_time >= now) { + auto sleep_time = target_time - now; + if (sleep_time > std::chrono::milliseconds(15)) { + std::this_thread::sleep_for(sleep_time - std::chrono::milliseconds(1)); + } + while (std::chrono::steady_clock::now() < target_time) { + std::this_thread::yield(); + } + } else if (frame_counter > max_frame_count) { frame_counter = 0; + start_time = now; } } - if (tick > 0) { - if (tick >= master_semaphore->CurrentTick()) { - Flush(); - } - master_semaphore->Wait(tick); - } } /// Returns the master timeline semaphore. @@ -281,9 +288,11 @@ private: std::condition_variable_any event_cv; std::jthread worker_thread; + std::chrono::steady_clock::duration frame_interval{}; std::chrono::steady_clock::time_point start_time{}; + double last_target_fps{}; + u64 max_frame_count{}; u64 frame_counter{}; - double current_target_fps{}; }; } // namespace Vulkan