mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-12-16 04:09:39 +00:00
CoreTiming: Add "Rush Frame Presentation" setting to throttle only once after each presentation for lower input latency.
This commit is contained in:
parent
8495e01668
commit
16260040e0
@ -47,6 +47,8 @@ const Info<bool> MAIN_DSP_HLE{{System::Main, "Core", "DSPHLE"}, true};
|
|||||||
const Info<int> MAIN_MAX_FALLBACK{{System::Main, "Core", "MaxFallback"}, 100};
|
const Info<int> MAIN_MAX_FALLBACK{{System::Main, "Core", "MaxFallback"}, 100};
|
||||||
const Info<int> MAIN_TIMING_VARIANCE{{System::Main, "Core", "TimingVariance"}, 40};
|
const Info<int> MAIN_TIMING_VARIANCE{{System::Main, "Core", "TimingVariance"}, 40};
|
||||||
const Info<bool> MAIN_CORRECT_TIME_DRIFT{{System::Main, "Core", "CorrectTimeDrift"}, false};
|
const Info<bool> MAIN_CORRECT_TIME_DRIFT{{System::Main, "Core", "CorrectTimeDrift"}, false};
|
||||||
|
const Info<bool> MAIN_RUSH_FRAME_PRESENTATION{{System::Main, "Core", "RushFramePresentation"},
|
||||||
|
false};
|
||||||
#if defined(ANDROID)
|
#if defined(ANDROID)
|
||||||
// Currently enabled by default on Android because the performance boost is really needed.
|
// Currently enabled by default on Android because the performance boost is really needed.
|
||||||
constexpr bool DEFAULT_CPU_THREAD = true;
|
constexpr bool DEFAULT_CPU_THREAD = true;
|
||||||
|
|||||||
@ -65,6 +65,7 @@ extern const Info<bool> MAIN_DSP_HLE;
|
|||||||
extern const Info<int> MAIN_MAX_FALLBACK;
|
extern const Info<int> MAIN_MAX_FALLBACK;
|
||||||
extern const Info<int> MAIN_TIMING_VARIANCE;
|
extern const Info<int> MAIN_TIMING_VARIANCE;
|
||||||
extern const Info<bool> MAIN_CORRECT_TIME_DRIFT;
|
extern const Info<bool> MAIN_CORRECT_TIME_DRIFT;
|
||||||
|
extern const Info<bool> MAIN_RUSH_FRAME_PRESENTATION;
|
||||||
extern const Info<bool> MAIN_CPU_THREAD;
|
extern const Info<bool> MAIN_CPU_THREAD;
|
||||||
extern const Info<bool> MAIN_SYNC_ON_SKIP_IDLE;
|
extern const Info<bool> MAIN_SYNC_ON_SKIP_IDLE;
|
||||||
extern const Info<std::string> MAIN_DEFAULT_ISO;
|
extern const Info<std::string> MAIN_DEFAULT_ISO;
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
#include "VideoCommon/PerformanceMetrics.h"
|
#include "VideoCommon/PerformanceMetrics.h"
|
||||||
#include "VideoCommon/VideoBackendBase.h"
|
#include "VideoCommon/VideoBackendBase.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
namespace CoreTiming
|
namespace CoreTiming
|
||||||
{
|
{
|
||||||
@ -113,6 +114,11 @@ void CoreTimingManager::Init()
|
|||||||
ResetThrottle(GetTicks());
|
ResetThrottle(GetTicks());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_throttled_after_presentation = false;
|
||||||
|
m_frame_hook = m_system.GetVideoEvents().after_present_event.Register([this](const PresentInfo&) {
|
||||||
|
m_throttled_after_presentation.store(false, std::memory_order_relaxed);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTimingManager::Shutdown()
|
void CoreTimingManager::Shutdown()
|
||||||
@ -124,6 +130,7 @@ void CoreTimingManager::Shutdown()
|
|||||||
ClearPendingEvents();
|
ClearPendingEvents();
|
||||||
UnregisterAllEvents();
|
UnregisterAllEvents();
|
||||||
CPUThreadConfigCallback::RemoveConfigChangedCallback(m_registered_config_callback_id);
|
CPUThreadConfigCallback::RemoveConfigChangedCallback(m_registered_config_callback_id);
|
||||||
|
m_frame_hook.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTimingManager::RefreshConfig()
|
void CoreTimingManager::RefreshConfig()
|
||||||
@ -134,6 +141,11 @@ void CoreTimingManager::RefreshConfig()
|
|||||||
1.0f);
|
1.0f);
|
||||||
m_config_oc_inv_factor = 1.0f / m_config_oc_factor;
|
m_config_oc_inv_factor = 1.0f / m_config_oc_factor;
|
||||||
m_config_sync_on_skip_idle = Config::Get(Config::MAIN_SYNC_ON_SKIP_IDLE);
|
m_config_sync_on_skip_idle = Config::Get(Config::MAIN_SYNC_ON_SKIP_IDLE);
|
||||||
|
m_config_rush_frame_presentation = Config::Get(Config::MAIN_RUSH_FRAME_PRESENTATION);
|
||||||
|
|
||||||
|
// We don't want to skip so much throttling that the audio buffer overfills.
|
||||||
|
m_max_throttle_skip_time =
|
||||||
|
std::chrono::milliseconds{Config::Get(Config::MAIN_AUDIO_BUFFER_SIZE)} / 2;
|
||||||
|
|
||||||
// A maximum fallback is used to prevent the system from sleeping for
|
// A maximum fallback is used to prevent the system from sleeping for
|
||||||
// too long or going full speed in an attempt to catch up to timings.
|
// too long or going full speed in an attempt to catch up to timings.
|
||||||
@ -422,6 +434,21 @@ void CoreTimingManager::SleepUntil(TimePoint time_point)
|
|||||||
|
|
||||||
void CoreTimingManager::Throttle(const s64 target_cycle)
|
void CoreTimingManager::Throttle(const s64 target_cycle)
|
||||||
{
|
{
|
||||||
|
const TimePoint time = Clock::now();
|
||||||
|
|
||||||
|
const bool already_throttled =
|
||||||
|
m_throttled_after_presentation.exchange(true, std::memory_order_relaxed);
|
||||||
|
|
||||||
|
// If RushFramePresentation is enabled, try to Throttle just once after each presentation.
|
||||||
|
// This lowers input latency by speeding through to 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,
|
||||||
|
// making audio sound terrible.
|
||||||
|
const bool skip_throttle = already_throttled && m_config_rush_frame_presentation &&
|
||||||
|
((GetTargetHostTime(target_cycle) - time) < m_max_throttle_skip_time);
|
||||||
|
if (skip_throttle)
|
||||||
|
return;
|
||||||
|
|
||||||
if (IsSpeedUnlimited())
|
if (IsSpeedUnlimited())
|
||||||
{
|
{
|
||||||
ResetThrottle(target_cycle);
|
ResetThrottle(target_cycle);
|
||||||
@ -441,8 +468,6 @@ void CoreTimingManager::Throttle(const s64 target_cycle)
|
|||||||
|
|
||||||
TimePoint target_time = CalculateTargetHostTimeInternal(target_cycle);
|
TimePoint target_time = CalculateTargetHostTimeInternal(target_cycle);
|
||||||
|
|
||||||
const TimePoint time = Clock::now();
|
|
||||||
|
|
||||||
const TimePoint min_target = time - m_max_fallback;
|
const TimePoint min_target = time - m_max_fallback;
|
||||||
|
|
||||||
// "Correct Time Drift" setting prevents timing relaxing.
|
// "Correct Time Drift" setting prevents timing relaxing.
|
||||||
|
|||||||
@ -207,6 +207,7 @@ private:
|
|||||||
float m_config_oc_factor = 1.0f;
|
float m_config_oc_factor = 1.0f;
|
||||||
float m_config_oc_inv_factor = 1.0f;
|
float m_config_oc_inv_factor = 1.0f;
|
||||||
bool m_config_sync_on_skip_idle = false;
|
bool m_config_sync_on_skip_idle = false;
|
||||||
|
bool m_config_rush_frame_presentation = false;
|
||||||
|
|
||||||
s64 m_throttle_reference_cycle = 0;
|
s64 m_throttle_reference_cycle = 0;
|
||||||
TimePoint m_throttle_reference_time = Clock::now();
|
TimePoint m_throttle_reference_time = Clock::now();
|
||||||
@ -232,6 +233,11 @@ private:
|
|||||||
Common::PrecisionTimer m_precision_gpu_timer;
|
Common::PrecisionTimer m_precision_gpu_timer;
|
||||||
|
|
||||||
Common::EventHook m_core_state_changed_hook;
|
Common::EventHook m_core_state_changed_hook;
|
||||||
|
Common::EventHook m_frame_hook;
|
||||||
|
|
||||||
|
// Used to optionally minimize throttling for improving input latency.
|
||||||
|
std::atomic_bool m_throttled_after_presentation = false;
|
||||||
|
DT m_max_throttle_skip_time{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CoreTiming
|
} // namespace CoreTiming
|
||||||
|
|||||||
@ -114,6 +114,19 @@ void AdvancedPane::CreateLayout()
|
|||||||
"<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
|
"<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
|
||||||
timing_group_layout->addWidget(correct_time_drift);
|
timing_group_layout->addWidget(correct_time_drift);
|
||||||
|
|
||||||
|
auto* const rush_frame_presentation =
|
||||||
|
// i18n: "Rush" is a verb
|
||||||
|
new ConfigBool{tr("Rush Frame Presentation"), Config::MAIN_RUSH_FRAME_PRESENTATION};
|
||||||
|
rush_frame_presentation->SetDescription(
|
||||||
|
tr("Limits throttling between input and frame output,"
|
||||||
|
" speeding through emulation to reach presentation,"
|
||||||
|
" displaying sooner, and thus reducing input latency."
|
||||||
|
"<br><br>This will generally make frame pacing worse."
|
||||||
|
"<br>This setting can work either with or without Immediately Present XFB."
|
||||||
|
"<br>An Audio Buffer Size of at least 80 ms is recommended to ensure full effect."
|
||||||
|
"<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>"));
|
||||||
|
timing_group_layout->addWidget(rush_frame_presentation);
|
||||||
|
|
||||||
// Make all labels the same width, so that the sliders are aligned.
|
// Make all labels the same width, so that the sliders are aligned.
|
||||||
const QFontMetrics font_metrics{font()};
|
const QFontMetrics font_metrics{font()};
|
||||||
const int label_width = font_metrics.boundingRect(QStringLiteral(" 500% (000.00 VPS)")).width();
|
const int label_width = font_metrics.boundingRect(QStringLiteral(" 500% (000.00 VPS)")).width();
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Core/Config/GraphicsSettings.h"
|
#include "Core/Config/GraphicsSettings.h"
|
||||||
|
#include "Core/Config/MainSettings.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
#include "Core/HW/VideoInterface.h"
|
#include "Core/HW/VideoInterface.h"
|
||||||
#include "Core/Host.h"
|
#include "Core/Host.h"
|
||||||
@ -201,7 +202,13 @@ void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height,
|
|||||||
|
|
||||||
if (!is_duplicate || !g_ActiveConfig.bSkipPresentingDuplicateXFBs)
|
if (!is_duplicate || !g_ActiveConfig.bSkipPresentingDuplicateXFBs)
|
||||||
{
|
{
|
||||||
Present(presentation_time);
|
// If RushFramePresentation is enabled, ignore the proper time to present as soon as possible.
|
||||||
|
// The goal is to achieve the lowest possible input latency.
|
||||||
|
if (Config::Get(Config::MAIN_RUSH_FRAME_PRESENTATION))
|
||||||
|
Present();
|
||||||
|
else
|
||||||
|
Present(presentation_time);
|
||||||
|
|
||||||
ProcessFrameDumping(ticks);
|
ProcessFrameDumping(ticks);
|
||||||
|
|
||||||
video_events.after_present_event.Trigger(present_info);
|
video_events.after_present_event.Trigger(present_info);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user