From 11ee3fa58735e4c21cbb133ad959e3caa0dbe2f0 Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Sat, 27 Sep 2025 18:09:50 +0900 Subject: [PATCH] Simplify vsync handling and ensure it works correctly on Linux. Linux scheduler quantum is 4-10ms so requesting 15ms sleep ends up sleeping 16-19ms and overshoots our target causing games to run at 57fps The new behavior essentially makes it behave as if vsync isn't set and fps limit is 60 (as advertized). --- src/xenia/gpu/graphics_system.cc | 48 ++++++-------------------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index 30588aca9..3c03c0364 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -163,52 +163,22 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor, 1000.0 / static_cast( normalized_framerate_limit)) : 1.0; - uint64_t last_frame_time = Clock::QueryGuestTickCount(); - // Sleep for 90% of the vblank duration, spin for 10% - constexpr double duration_scalar = 0.90; while (frame_limiter_worker_running_) { register_file()->values[XE_GPU_REG_D1MODE_V_COUNTER] += GetInternalDisplayResolution().second; - if (cvars::vsync) { - const uint64_t current_time = Clock::QueryGuestTickCount(); - const uint64_t tick_freq = Clock::guest_tick_frequency(); - const uint64_t time_delta = current_time - last_frame_time; - const double elapsed_d = - static_cast(time_delta) / - (static_cast(tick_freq) / 1000.0); - if (elapsed_d >= vsync_duration_d) { - last_frame_time = current_time; + MarkVblank(); - // TODO(disjtqz): should recalculate the remaining time to a - // vblank after MarkVblank, no idea how long the guest code - // normally takes - MarkVblank(); - if (cvars::vsync) { - const uint64_t estimated_nanoseconds = - static_cast( - (vsync_duration_d * 1000000.0) * - duration_scalar); // 1000 microseconds = 1 ms - - threading::NanoSleep(estimated_nanoseconds); - } - } - } - - if (!cvars::vsync) { - MarkVblank(); - if (normalized_framerate_limit > 0) { - // framerate_limit is over 0, vsync disabled - // - No VSYNC + limited frames defined by user - uint64_t framerate_limited_sleep_time = - 1000000000 / normalized_framerate_limit; - xe::threading::NanoSleep(framerate_limited_sleep_time); - } else { - // framerate_limit is 0, vsync disabled - // - No VSYNC + unlimited frames - xe::threading::Sleep(std::chrono::milliseconds(1)); + if (cvars::vsync || normalized_framerate_limit > 0) { + uint64_t sleep_duration_ns = + static_cast(vsync_duration_d * 1000000.0); + if (!cvars::vsync && normalized_framerate_limit > 0) { + sleep_duration_ns = 1000000000 / normalized_framerate_limit; } + threading::NanoSleep(sleep_duration_ns); + } else { + xe::threading::Sleep(std::chrono::milliseconds(1)); } } return 0;