diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index 6e8c19268f..5879ac9ef1 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -104,26 +104,38 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor, vsync_worker_running_ = true; vsync_worker_thread_ = kernel::object_ref( new kernel::XHostThread(kernel_state_, 128 * 1024, 0, [this]() { - double vsync_duration_d = + const double vsync_duration_d = cvars::vsync ? std::max( 5.0, 1000.0 / static_cast(cvars::vsync_fps)) : 1.0; uint64_t last_frame_time = Clock::QueryGuestTickCount(); - while (vsync_worker_running_) { - uint64_t current_time = Clock::QueryGuestTickCount(); + // Sleep for 90% of the vblank duration, spin for 10% + const double duration_scalar = 0.90; - uint64_t tick_freq = Clock::guest_tick_frequency(); - uint64_t time_delta = current_time - last_frame_time; - double elapsed_d = static_cast(time_delta) / - (static_cast(tick_freq) / 1000.0); + while (vsync_worker_running_) { + 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) { - MarkVblank(); last_frame_time = current_time; + + // 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) { xe::threading::Sleep(std::chrono::milliseconds(1)); - } + } } return 0; })); @@ -131,7 +143,8 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor, vsync_worker_thread_->set_can_debugger_suspend(true); vsync_worker_thread_->set_name("GPU VSync"); vsync_worker_thread_->Create(); - vsync_worker_thread_->thread()->set_priority(threading::ThreadPriority::kLowest); + vsync_worker_thread_->thread()->set_priority( + threading::ThreadPriority::kLowest); if (cvars::trace_gpu_stream) { BeginTracing(); }