From 70fe43a3ecea1f149120bb4f6424535cad3fbcd8 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 11 Feb 2020 12:02:42 +0900 Subject: [PATCH] System: Implement variable emulation speed --- src/core/host_interface.cpp | 5 +++++ src/core/settings.cpp | 2 ++ src/core/settings.h | 1 + src/core/system.cpp | 22 +++++++++++++++++--- src/core/system.h | 8 +++++-- src/duckstation-qt/consolesettingswidget.cpp | 3 ++- 6 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index c8283fa75..b08e553b2 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -503,6 +503,7 @@ void HostInterface::SetDefaultSettings() m_settings.region = ConsoleRegion::Auto; m_settings.cpu_execution_mode = CPUExecutionMode::Interpreter; + m_settings.emulation_speed = 1.0f; m_settings.speed_limiter_enabled = true; m_settings.start_paused = false; @@ -532,6 +533,7 @@ void HostInterface::SetDefaultSettings() void HostInterface::UpdateSettings(const std::function& apply_callback) { + const float old_emulation_speed = m_settings.emulation_speed; const CPUExecutionMode old_cpu_execution_mode = m_settings.cpu_execution_mode; const GPURenderer old_gpu_renderer = m_settings.gpu_renderer; const u32 old_gpu_resolution_scale = m_settings.gpu_resolution_scale; @@ -556,6 +558,9 @@ void HostInterface::UpdateSettings(const std::function& apply_callback) if (m_system) { + if (m_settings.emulation_speed != old_emulation_speed) + m_system->UpdateThrottlePeriod(); + if (m_settings.cpu_execution_mode != old_cpu_execution_mode) m_system->SetCPUExecutionMode(m_settings.cpu_execution_mode); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 5bf755daa..b65747e05 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -9,6 +9,7 @@ void Settings::Load(SettingsInterface& si) region = 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); start_paused = si.GetBoolValue("General", "StartPaused", false); @@ -57,6 +58,7 @@ void Settings::Save(SettingsInterface& si) const { si.SetStringValue("Console", "Region", GetConsoleRegionName(region)); + si.SetFloatValue("General", "EmulationSpeed", emulation_speed); si.SetBoolValue("General", "SpeedLimiterEnabled", speed_limiter_enabled); si.SetBoolValue("General", "StartPaused", start_paused); diff --git a/src/core/settings.h b/src/core/settings.h index 2b9bec3b3..5c1b75b90 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -35,6 +35,7 @@ struct Settings CPUExecutionMode cpu_execution_mode = CPUExecutionMode::Interpreter; + float emulation_speed = 1.0f; bool start_paused = false; bool speed_limiter_enabled = true; diff --git a/src/core/system.cpp b/src/core/system.cpp index d7962302a..be7ce9574 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -209,6 +209,8 @@ void System::InitializeComponents() m_timers->Initialize(this, m_interrupt_controller.get(), m_gpu.get()); m_spu->Initialize(this, m_dma.get(), m_interrupt_controller.get()); m_mdec->Initialize(this, m_dma.get()); + + UpdateThrottlePeriod(); } void System::DestroyComponents() @@ -402,6 +404,20 @@ void System::RunFrame() UpdatePerformanceCounters(); } +void System::SetThrottleFrequency(float frequency) +{ + m_throttle_frequency = frequency; + UpdateThrottlePeriod(); +} + +void System::UpdateThrottlePeriod() +{ + m_throttle_period = static_cast(1000000000.0 / static_cast(m_throttle_frequency) / + static_cast(GetSettings().emulation_speed)); + m_last_throttle_time = 0; + m_throttle_timer.Reset(); +} + void System::Throttle() { // Allow variance of up to 40ms either way. @@ -413,15 +429,15 @@ void System::Throttle() // Use unsigned for defined overflow/wrap-around. const u64 time = static_cast(m_throttle_timer.GetTimeNanoseconds()); const s64 sleep_time = static_cast(m_last_throttle_time - time); - if (std::abs(sleep_time) >= MAX_VARIANCE_TIME) + if (sleep_time < -MAX_VARIANCE_TIME) { #ifndef _DEBUG // Don't display the slow messages in debug, it'll always be slow... // Limit how often the messages are displayed. if (m_speed_lost_time_timestamp.GetTimeSeconds() >= 1.0f) { - Log_WarningPrintf("System too %s, lost %.2f ms", sleep_time < 0 ? "slow" : "fast", - static_cast(std::abs(sleep_time) - MAX_VARIANCE_TIME) / 1000000.0); + Log_WarningPrintf("System too slow, lost %.2f ms", + static_cast(-sleep_time - MAX_VARIANCE_TIME) / 1000000.0); m_speed_lost_time_timestamp.Reset(); } #endif diff --git a/src/core/system.h b/src/core/system.h index bde11d87b..7d5ad2dd7 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -93,7 +93,10 @@ public: void RunFrame(); /// Adjusts the throttle frequency, i.e. how many times we should sleep per second. - void SetThrottleFrequency(double frequency) { m_throttle_period = static_cast(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. void Throttle(); @@ -186,8 +189,9 @@ private: std::string m_running_game_code; std::string m_running_game_title; + float m_throttle_frequency = 60.0f; + s32 m_throttle_period = 0; u64 m_last_throttle_time = 0; - s64 m_throttle_period = INT64_C(1000000000) / 60; Common::Timer m_throttle_timer; Common::Timer m_speed_lost_time_timestamp; diff --git a/src/duckstation-qt/consolesettingswidget.cpp b/src/duckstation-qt/consolesettingswidget.cpp index 3d68eaa1f..eb7a2b98b 100644 --- a/src/duckstation-qt/consolesettingswidget.cpp +++ b/src/duckstation-qt/consolesettingswidget.cpp @@ -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.enableSpeedLimiter, "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::BindWidgetToEnumSetting(m_host_interface, m_ui.cpuExecutionMode, "CPU/ExecutionMode", &Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName);