CoreTiming: Throttle only once after presentation for potentially better input latency.
This commit is contained in:
parent
f5d7b1fb4c
commit
c1c192a3d3
|
@ -29,6 +29,7 @@
|
|||
#include "VideoCommon/PerformanceMetrics.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
namespace CoreTiming
|
||||
{
|
||||
|
@ -105,6 +106,13 @@ void CoreTimingManager::Init()
|
|||
|
||||
m_last_oc_factor = m_config_oc_factor;
|
||||
m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
|
||||
|
||||
m_throttled_since_presentation = false;
|
||||
m_frame_hook = AfterPresentEvent::Register(
|
||||
[this](const PresentInfo&) {
|
||||
m_throttled_since_presentation.store(false, std::memory_order_relaxed);
|
||||
},
|
||||
"CoreTiming AfterPresentEvent");
|
||||
}
|
||||
|
||||
void CoreTimingManager::Shutdown()
|
||||
|
@ -114,6 +122,7 @@ void CoreTimingManager::Shutdown()
|
|||
ClearPendingEvents();
|
||||
UnregisterAllEvents();
|
||||
CPUThreadConfigCallback::RemoveConfigChangedCallback(m_registered_config_callback_id);
|
||||
m_frame_hook.reset();
|
||||
}
|
||||
|
||||
void CoreTimingManager::RefreshConfig()
|
||||
|
@ -406,6 +415,24 @@ void CoreTimingManager::SleepUntil(TimePoint time_point)
|
|||
|
||||
void CoreTimingManager::Throttle(const s64 target_cycle)
|
||||
{
|
||||
const TimePoint time = Clock::now();
|
||||
|
||||
const bool already_throttled =
|
||||
m_throttled_since_presentation.exchange(true, std::memory_order_relaxed);
|
||||
|
||||
// Try to Throttle just once after each presentation.
|
||||
// This lowers latency by speeding through to the next presentation after grabbing input.
|
||||
// Make sure we don't get too far ahead of proper timing though,
|
||||
// otherwise the emulator unreasonably speeds through loading screens that don't have XFB copies,
|
||||
// and makes the audio sound terrible.
|
||||
|
||||
// TODO: base this on the audio buffer size
|
||||
const bool skip_throttle =
|
||||
already_throttled && ((GetTargetHostTime(target_cycle) - time) < (m_max_fallback / 2));
|
||||
|
||||
if (skip_throttle)
|
||||
return;
|
||||
|
||||
if (IsSpeedUnlimited())
|
||||
{
|
||||
ResetThrottle(target_cycle);
|
||||
|
@ -425,8 +452,6 @@ void CoreTimingManager::Throttle(const s64 target_cycle)
|
|||
|
||||
TimePoint target_time = CalculateTargetHostTimeInternal(target_cycle);
|
||||
|
||||
const TimePoint time = Clock::now();
|
||||
|
||||
const TimePoint min_target = time - m_max_fallback;
|
||||
if (target_time < min_target)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/HookableEvent.h"
|
||||
#include "Common/SPSCQueue.h"
|
||||
#include "Common/Timer.h"
|
||||
#include "Core/CPUThreadConfigCallback.h"
|
||||
|
@ -225,6 +226,9 @@ private:
|
|||
std::atomic_bool m_use_precision_timer = false;
|
||||
Common::PrecisionTimer m_precision_cpu_timer;
|
||||
Common::PrecisionTimer m_precision_gpu_timer;
|
||||
|
||||
Common::EventHook m_frame_hook;
|
||||
std::atomic<bool> m_throttled_since_presentation = false;
|
||||
};
|
||||
|
||||
} // namespace CoreTiming
|
||||
|
|
|
@ -97,7 +97,9 @@ void VideoBackendBase::Video_OutputXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride
|
|||
auto& system = Core::System::GetInstance();
|
||||
system.GetFifo().SyncGPU(Fifo::SyncGPUReason::Swap);
|
||||
|
||||
const TimePoint presentation_time = system.GetCoreTiming().GetTargetHostTime(ticks);
|
||||
// HAX: Present immediately.
|
||||
const TimePoint presentation_time = Clock::now();
|
||||
|
||||
AsyncRequests::GetInstance()->PushEvent([=] {
|
||||
g_presenter->ViSwap(xfb_addr, fb_width, fb_stride, fb_height, ticks, presentation_time);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue