diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index 3c03c0364..6be717f52 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -163,11 +163,57 @@ 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 on Windows, spin for 10% + // Linux uses full sleep duration due to scheduler quantum issues +#if XE_PLATFORM_WIN32 + constexpr double duration_scalar = 0.90; +#endif +#if XE_PLATFORM_LINUX + constexpr double duration_scalar = 1.0; +#endif while (frame_limiter_worker_running_) { register_file()->values[XE_GPU_REG_D1MODE_V_COUNTER] += GetInternalDisplayResolution().second; +#if XE_PLATFORM_WIN32 + 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(); + 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)); + } + } +#endif +#if XE_PLATFORM_LINUX + // Linux: Use simplified timing logic to avoid oversleeping MarkVblank(); if (cvars::vsync || normalized_framerate_limit > 0) { @@ -180,6 +226,7 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor, } else { xe::threading::Sleep(std::chrono::milliseconds(1)); } +#endif } return 0; },