2929#include " VideoCommon/PerformanceMetrics.h"
3030#include " VideoCommon/VideoBackendBase.h"
3131#include " VideoCommon/VideoConfig.h"
32+ #include " VideoCommon/VideoEvents.h"
3233
3334namespace CoreTiming
3435{
@@ -105,6 +106,14 @@ void CoreTimingManager::Init()
105106
106107 m_last_oc_factor = m_config_oc_factor;
107108 m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
109+
110+ m_throttled_since_presentation = false ;
111+ m_frame_hook = AfterPresentEvent::Register (
112+ [this ](const PresentInfo&) {
113+ m_throttled_since_presentation.store (false , std::memory_order_relaxed);
114+ },
115+ " CoreTiming AfterPresentEvent"
116+ );
108117}
109118
110119void CoreTimingManager::Shutdown ()
@@ -406,6 +415,22 @@ void CoreTimingManager::SleepUntil(TimePoint time_point)
406415
407416void CoreTimingManager::Throttle (const s64 target_cycle)
408417{
418+ const TimePoint time = Clock::now ();
419+
420+ const bool already_throttled =
421+ m_throttled_since_presentation.exchange (true , std::memory_order_relaxed);
422+
423+ // When Immediate XFB is enabled, try to Throttle just once since each presentation.
424+ // This lowers latency by speeding through to the next presentation after grabbing input.
425+ // Make sure we don't get too far ahead of proper timing though,
426+ // otherwise the emulator unreasonably speeds through loading screens that don't have XFB copies.
427+
428+ const bool skip_throttle = already_throttled && g_ActiveConfig.bImmediateXFB &&
429+ ((GetTargetHostTime (target_cycle) - time) < (m_max_fallback / 2 ));
430+
431+ if (skip_throttle)
432+ return ;
433+
409434 if (IsSpeedUnlimited ())
410435 {
411436 ResetThrottle (target_cycle);
@@ -425,8 +450,6 @@ void CoreTimingManager::Throttle(const s64 target_cycle)
425450
426451 TimePoint target_time = CalculateTargetHostTimeInternal (target_cycle);
427452
428- const TimePoint time = Clock::now ();
429-
430453 const TimePoint min_target = time - m_max_fallback;
431454 if (target_time < min_target)
432455 {
0 commit comments