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).
This commit is contained in:
Herman S.
2025-09-27 18:36:11 +09:00
parent d157c9c8fe
commit 11ee3fa587
+9 -39
View File
@@ -163,52 +163,22 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
1000.0 / static_cast<double>( 1000.0 / static_cast<double>(
normalized_framerate_limit)) normalized_framerate_limit))
: 1.0; : 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_) { while (frame_limiter_worker_running_) {
register_file()->values[XE_GPU_REG_D1MODE_V_COUNTER] += register_file()->values[XE_GPU_REG_D1MODE_V_COUNTER] +=
GetInternalDisplayResolution().second; GetInternalDisplayResolution().second;
if (cvars::vsync) { MarkVblank();
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<double>(time_delta) /
(static_cast<double>(tick_freq) / 1000.0);
if (elapsed_d >= vsync_duration_d) {
last_frame_time = current_time;
// TODO(disjtqz): should recalculate the remaining time to a if (cvars::vsync || normalized_framerate_limit > 0) {
// vblank after MarkVblank, no idea how long the guest code uint64_t sleep_duration_ns =
// normally takes static_cast<uint64_t>(vsync_duration_d * 1000000.0);
MarkVblank(); if (!cvars::vsync && normalized_framerate_limit > 0) {
if (cvars::vsync) { sleep_duration_ns = 1000000000 / normalized_framerate_limit;
const uint64_t estimated_nanoseconds =
static_cast<uint64_t>(
(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));
} }
threading::NanoSleep(sleep_duration_ns);
} else {
xe::threading::Sleep(std::chrono::milliseconds(1));
} }
} }
return 0; return 0;