mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 07:35:41 +00:00
System: Implement variable emulation speed
This commit is contained in:
parent
a81a0c0f21
commit
70fe43a3ec
|
@ -503,6 +503,7 @@ void HostInterface::SetDefaultSettings()
|
||||||
m_settings.region = ConsoleRegion::Auto;
|
m_settings.region = ConsoleRegion::Auto;
|
||||||
m_settings.cpu_execution_mode = CPUExecutionMode::Interpreter;
|
m_settings.cpu_execution_mode = CPUExecutionMode::Interpreter;
|
||||||
|
|
||||||
|
m_settings.emulation_speed = 1.0f;
|
||||||
m_settings.speed_limiter_enabled = true;
|
m_settings.speed_limiter_enabled = true;
|
||||||
m_settings.start_paused = false;
|
m_settings.start_paused = false;
|
||||||
|
|
||||||
|
@ -532,6 +533,7 @@ void HostInterface::SetDefaultSettings()
|
||||||
|
|
||||||
void HostInterface::UpdateSettings(const std::function<void()>& apply_callback)
|
void HostInterface::UpdateSettings(const std::function<void()>& apply_callback)
|
||||||
{
|
{
|
||||||
|
const float old_emulation_speed = m_settings.emulation_speed;
|
||||||
const CPUExecutionMode old_cpu_execution_mode = m_settings.cpu_execution_mode;
|
const CPUExecutionMode old_cpu_execution_mode = m_settings.cpu_execution_mode;
|
||||||
const GPURenderer old_gpu_renderer = m_settings.gpu_renderer;
|
const GPURenderer old_gpu_renderer = m_settings.gpu_renderer;
|
||||||
const u32 old_gpu_resolution_scale = m_settings.gpu_resolution_scale;
|
const u32 old_gpu_resolution_scale = m_settings.gpu_resolution_scale;
|
||||||
|
@ -556,6 +558,9 @@ void HostInterface::UpdateSettings(const std::function<void()>& apply_callback)
|
||||||
|
|
||||||
if (m_system)
|
if (m_system)
|
||||||
{
|
{
|
||||||
|
if (m_settings.emulation_speed != old_emulation_speed)
|
||||||
|
m_system->UpdateThrottlePeriod();
|
||||||
|
|
||||||
if (m_settings.cpu_execution_mode != old_cpu_execution_mode)
|
if (m_settings.cpu_execution_mode != old_cpu_execution_mode)
|
||||||
m_system->SetCPUExecutionMode(m_settings.cpu_execution_mode);
|
m_system->SetCPUExecutionMode(m_settings.cpu_execution_mode);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ void Settings::Load(SettingsInterface& si)
|
||||||
region =
|
region =
|
||||||
ParseConsoleRegionName(si.GetStringValue("Console", "Region", "NTSC-U").c_str()).value_or(ConsoleRegion::NTSC_U);
|
ParseConsoleRegionName(si.GetStringValue("Console", "Region", "NTSC-U").c_str()).value_or(ConsoleRegion::NTSC_U);
|
||||||
|
|
||||||
|
emulation_speed = si.GetFloatValue("General", "EmulationSpeed", 1.0f);
|
||||||
speed_limiter_enabled = si.GetBoolValue("General", "SpeedLimiterEnabled", true);
|
speed_limiter_enabled = si.GetBoolValue("General", "SpeedLimiterEnabled", true);
|
||||||
start_paused = si.GetBoolValue("General", "StartPaused", false);
|
start_paused = si.GetBoolValue("General", "StartPaused", false);
|
||||||
|
|
||||||
|
@ -57,6 +58,7 @@ void Settings::Save(SettingsInterface& si) const
|
||||||
{
|
{
|
||||||
si.SetStringValue("Console", "Region", GetConsoleRegionName(region));
|
si.SetStringValue("Console", "Region", GetConsoleRegionName(region));
|
||||||
|
|
||||||
|
si.SetFloatValue("General", "EmulationSpeed", emulation_speed);
|
||||||
si.SetBoolValue("General", "SpeedLimiterEnabled", speed_limiter_enabled);
|
si.SetBoolValue("General", "SpeedLimiterEnabled", speed_limiter_enabled);
|
||||||
si.SetBoolValue("General", "StartPaused", start_paused);
|
si.SetBoolValue("General", "StartPaused", start_paused);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ struct Settings
|
||||||
|
|
||||||
CPUExecutionMode cpu_execution_mode = CPUExecutionMode::Interpreter;
|
CPUExecutionMode cpu_execution_mode = CPUExecutionMode::Interpreter;
|
||||||
|
|
||||||
|
float emulation_speed = 1.0f;
|
||||||
bool start_paused = false;
|
bool start_paused = false;
|
||||||
bool speed_limiter_enabled = true;
|
bool speed_limiter_enabled = true;
|
||||||
|
|
||||||
|
|
|
@ -209,6 +209,8 @@ void System::InitializeComponents()
|
||||||
m_timers->Initialize(this, m_interrupt_controller.get(), m_gpu.get());
|
m_timers->Initialize(this, m_interrupt_controller.get(), m_gpu.get());
|
||||||
m_spu->Initialize(this, m_dma.get(), m_interrupt_controller.get());
|
m_spu->Initialize(this, m_dma.get(), m_interrupt_controller.get());
|
||||||
m_mdec->Initialize(this, m_dma.get());
|
m_mdec->Initialize(this, m_dma.get());
|
||||||
|
|
||||||
|
UpdateThrottlePeriod();
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::DestroyComponents()
|
void System::DestroyComponents()
|
||||||
|
@ -402,6 +404,20 @@ void System::RunFrame()
|
||||||
UpdatePerformanceCounters();
|
UpdatePerformanceCounters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::SetThrottleFrequency(float frequency)
|
||||||
|
{
|
||||||
|
m_throttle_frequency = frequency;
|
||||||
|
UpdateThrottlePeriod();
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::UpdateThrottlePeriod()
|
||||||
|
{
|
||||||
|
m_throttle_period = static_cast<s32>(1000000000.0 / static_cast<double>(m_throttle_frequency) /
|
||||||
|
static_cast<double>(GetSettings().emulation_speed));
|
||||||
|
m_last_throttle_time = 0;
|
||||||
|
m_throttle_timer.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
void System::Throttle()
|
void System::Throttle()
|
||||||
{
|
{
|
||||||
// Allow variance of up to 40ms either way.
|
// Allow variance of up to 40ms either way.
|
||||||
|
@ -413,15 +429,15 @@ void System::Throttle()
|
||||||
// Use unsigned for defined overflow/wrap-around.
|
// Use unsigned for defined overflow/wrap-around.
|
||||||
const u64 time = static_cast<u64>(m_throttle_timer.GetTimeNanoseconds());
|
const u64 time = static_cast<u64>(m_throttle_timer.GetTimeNanoseconds());
|
||||||
const s64 sleep_time = static_cast<s64>(m_last_throttle_time - time);
|
const s64 sleep_time = static_cast<s64>(m_last_throttle_time - time);
|
||||||
if (std::abs(sleep_time) >= MAX_VARIANCE_TIME)
|
if (sleep_time < -MAX_VARIANCE_TIME)
|
||||||
{
|
{
|
||||||
#ifndef _DEBUG
|
#ifndef _DEBUG
|
||||||
// Don't display the slow messages in debug, it'll always be slow...
|
// Don't display the slow messages in debug, it'll always be slow...
|
||||||
// Limit how often the messages are displayed.
|
// Limit how often the messages are displayed.
|
||||||
if (m_speed_lost_time_timestamp.GetTimeSeconds() >= 1.0f)
|
if (m_speed_lost_time_timestamp.GetTimeSeconds() >= 1.0f)
|
||||||
{
|
{
|
||||||
Log_WarningPrintf("System too %s, lost %.2f ms", sleep_time < 0 ? "slow" : "fast",
|
Log_WarningPrintf("System too slow, lost %.2f ms",
|
||||||
static_cast<double>(std::abs(sleep_time) - MAX_VARIANCE_TIME) / 1000000.0);
|
static_cast<double>(-sleep_time - MAX_VARIANCE_TIME) / 1000000.0);
|
||||||
m_speed_lost_time_timestamp.Reset();
|
m_speed_lost_time_timestamp.Reset();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -93,7 +93,10 @@ public:
|
||||||
void RunFrame();
|
void RunFrame();
|
||||||
|
|
||||||
/// Adjusts the throttle frequency, i.e. how many times we should sleep per second.
|
/// Adjusts the throttle frequency, i.e. how many times we should sleep per second.
|
||||||
void SetThrottleFrequency(double frequency) { m_throttle_period = static_cast<s64>(1000000000.0 / frequency); }
|
void SetThrottleFrequency(float frequency);
|
||||||
|
|
||||||
|
/// Updates the throttle period, call when target emulation speed changes.
|
||||||
|
void UpdateThrottlePeriod();
|
||||||
|
|
||||||
/// Throttles the system, i.e. sleeps until it's time to execute the next frame.
|
/// Throttles the system, i.e. sleeps until it's time to execute the next frame.
|
||||||
void Throttle();
|
void Throttle();
|
||||||
|
@ -186,8 +189,9 @@ private:
|
||||||
std::string m_running_game_code;
|
std::string m_running_game_code;
|
||||||
std::string m_running_game_title;
|
std::string m_running_game_title;
|
||||||
|
|
||||||
|
float m_throttle_frequency = 60.0f;
|
||||||
|
s32 m_throttle_period = 0;
|
||||||
u64 m_last_throttle_time = 0;
|
u64 m_last_throttle_time = 0;
|
||||||
s64 m_throttle_period = INT64_C(1000000000) / 60;
|
|
||||||
Common::Timer m_throttle_timer;
|
Common::Timer m_throttle_timer;
|
||||||
Common::Timer m_speed_lost_time_timestamp;
|
Common::Timer m_speed_lost_time_timestamp;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,8 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.fastBoot, "BIOS/PatchFastBoot");
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.fastBoot, "BIOS/PatchFastBoot");
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.enableSpeedLimiter,
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.enableSpeedLimiter,
|
||||||
"General/SpeedLimiterEnabled");
|
"General/SpeedLimiterEnabled");
|
||||||
SettingWidgetBinder::BindWidgetToIntSetting(m_host_interface, m_ui.emulationSpeed, "General/EmulationSpeed");
|
SettingWidgetBinder::BindWidgetToNormalizedSetting(m_host_interface, m_ui.emulationSpeed, "General/EmulationSpeed",
|
||||||
|
100.0f);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.pauseOnStart, "General/StartPaused");
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.pauseOnStart, "General/StartPaused");
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.cpuExecutionMode, "CPU/ExecutionMode",
|
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.cpuExecutionMode, "CPU/ExecutionMode",
|
||||||
&Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName);
|
&Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName);
|
||||||
|
|
Loading…
Reference in a new issue