From 71b38e58e688ba39701b62041883ea957cedbd2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 22 Oct 2026 15:28:18 +0200 Subject: [PATCH] Config: Store the alternative speeds in percent The settings screen showed them in percent but they were stored as frame rates out of 60, so the screen kept converted copies and wrote them back. Now they're stored in percent under new ini keys (AltSpeedPercent, AltSpeedPercent2, AnalogAltSpeedPercent), migrated from the old frame rate keys like the audio volumes were, and converted to a frame rate where the timing needs one. Low percentages no longer round to a 0 fps limit, which meant unlimited. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/Config.cpp | 27 ++++++++++++++++++++++++--- Core/Config.h | 20 +++++++++++++++++--- Core/HLE/sceDisplay.cpp | 4 ++-- UI/EmuScreen.cpp | 16 ++++++++-------- UI/GameSettingsScreen.cpp | 18 +++--------------- UI/GameSettingsScreen.h | 3 --- 6 files changed, 54 insertions(+), 34 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index ab7a631017..799f77c726 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -715,6 +715,23 @@ static const ConfigSetting gestureControlSettings[] = { ConfigSetting("AnalogGestureSensibility", SETTING(g_Config.gestureControls[0], fAnalogGestureSensitivity), 1.0f, CfgFlag::PER_GAME), }; +// The alternative speeds used to be stored as frame rates, out of 60. +static int LegacyFpsLimitToPercent(int fps) { + return fps < 0 ? -1 : (fps * 100 + 30) / 60; +} + +static int DefaultAltSpeedPercent1() { + return LegacyFpsLimitToPercent(g_Config.iLegacyFpsLimit1); +} + +static int DefaultAltSpeedPercent2() { + return LegacyFpsLimitToPercent(g_Config.iLegacyFpsLimit2); +} + +static int DefaultAnalogAltSpeedPercent() { + return LegacyFpsLimitToPercent(g_Config.iLegacyAnalogFpsLimit); +} + static const ConfigSetting graphicsSettings[] = { ConfigSetting("iShowStatusFlags", SETTING(g_Config, iShowStatusFlags), 0, CfgFlag::PER_GAME), ConfigSetting("GraphicsBackend", SETTING(g_Config, iGPUBackend), &DefaultGPUBackend, &GPUBackendTranslator::To, &GPUBackendTranslator::From, CfgFlag::DEFAULT | CfgFlag::REPORT), @@ -744,9 +761,13 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("AutoFrameSkip", SETTING(g_Config, bAutoFrameSkip), IsVREnabled(), CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("StereoRendering", SETTING(g_Config, bStereoRendering), false, CfgFlag::PER_GAME), ConfigSetting("StereoToMonoShader", SETTING(g_Config, sStereoToMonoShader), "RedBlue", CfgFlag::PER_GAME), - ConfigSetting("FrameRate", SETTING(g_Config, iFpsLimit1), 0, CfgFlag::PER_GAME), - ConfigSetting("FrameRate2", SETTING(g_Config, iFpsLimit2), -1, CfgFlag::PER_GAME), - ConfigSetting("AnalogFrameRate", SETTING(g_Config, iAnalogFpsLimit), 240, CfgFlag::PER_GAME), + // Read before the new settings, which use them as defaults. + ConfigSetting("FrameRate", SETTING(g_Config, iLegacyFpsLimit1), 0, CfgFlag::PER_GAME | CfgFlag::DONT_SAVE), + ConfigSetting("FrameRate2", SETTING(g_Config, iLegacyFpsLimit2), -1, CfgFlag::PER_GAME | CfgFlag::DONT_SAVE), + ConfigSetting("AnalogFrameRate", SETTING(g_Config, iLegacyAnalogFpsLimit), 240, CfgFlag::PER_GAME | CfgFlag::DONT_SAVE), + ConfigSetting("AltSpeedPercent", SETTING(g_Config, iAltSpeedPercent1), &DefaultAltSpeedPercent1, CfgFlag::PER_GAME), + ConfigSetting("AltSpeedPercent2", SETTING(g_Config, iAltSpeedPercent2), &DefaultAltSpeedPercent2, CfgFlag::PER_GAME), + ConfigSetting("AnalogAltSpeedPercent", SETTING(g_Config, iAnalogAltSpeedPercent), &DefaultAnalogAltSpeedPercent, CfgFlag::PER_GAME), #if PPSSPP_PLATFORM(WINDOWS) ConfigSetting("RestartRequired", SETTING(g_Config, bRestartRequired), false, CfgFlag::DONT_SAVE), #endif diff --git a/Core/Config.h b/Core/Config.h index fcc38aef28..86bcd5322c 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -360,9 +360,14 @@ public: int iTexScalingType; // 0 = xBRZ, 1 = Hybrid bool bTexDeposterize; bool bTexHardwareScaling; - int iFpsLimit1; - int iFpsLimit2; - int iAnalogFpsLimit; + // In percent of normal speed. 0 means unlimited, and negative (not for analog) disabled. + int iAltSpeedPercent1; + int iAltSpeedPercent2; + int iAnalogAltSpeedPercent; + // The old frame rate based settings. Only read, to migrate them. + int iLegacyFpsLimit1; + int iLegacyFpsLimit2; + int iLegacyAnalogFpsLimit; int iMaxRecent; int iCurrentStateSlot; int iRewindSnapshotInterval; @@ -836,6 +841,15 @@ private: std::string CreateRandMAC(); std::string DefaultProAdhocServer(); +// The frame rate limit for an alternative speed. Unlimited (0) and disabled (negative) stay as they are. +inline int AltSpeedPercentToFps(int percent) { + if (percent <= 0) { + return percent; + } + int fps = (percent * 60 + 50) / 100; + return fps < 1 ? 1 : fps; +} + // TODO: Find a better place for this. extern http::RequestManager g_DownloadManager; extern Config g_Config; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index d4ea955bf7..05f245e257 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -424,9 +424,9 @@ static int FrameTimingLimit() { return 0; // Can't slow down in hardcore mode. if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) - return fixRate(g_Config.iFpsLimit1); + return fixRate(AltSpeedPercentToFps(g_Config.iAltSpeedPercent1)); if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) - return fixRate(g_Config.iFpsLimit2); + return fixRate(AltSpeedPercentToFps(g_Config.iAltSpeedPercent2)); if (PSP_CoreParameter().fpsLimit == FPSLimit::ANALOG) return fixRate(PSP_CoreParameter().analogFpsLimit); if (PSP_CoreParameter().fpsLimit == FPSLimit::DEBUGGER) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index e401c974f1..8b47928e1e 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -697,14 +697,14 @@ void EmuScreen::sendMessage(UIMessage message, const char *value) { // TODO: We should replace the "fpsLimit" system with a speed factor. static void ShowFpsLimitNotice() { - int fpsLimit = 60; + int percent = 100; switch (PSP_CoreParameter().fpsLimit) { case FPSLimit::CUSTOM1: - fpsLimit = g_Config.iFpsLimit1; + percent = g_Config.iAltSpeedPercent1; break; case FPSLimit::CUSTOM2: - fpsLimit = g_Config.iFpsLimit2; + percent = g_Config.iAltSpeedPercent2; break; default: break; @@ -713,7 +713,7 @@ static void ShowFpsLimitNotice() { // Now display it. char temp[51]; - snprintf(temp, sizeof(temp), "%d%%", (int)((float)fpsLimit / 60.0f * 100.0f)); + snprintf(temp, sizeof(temp), "%d%%", percent); g_OSD.Show(OSDType::STATUS_ICON, temp, "", "I_FAST_FORWARD", 1.5f, "altspeed"); g_OSD.SetFlags("altspeed", OSDMessageFlags::Transparent); } @@ -994,9 +994,9 @@ void EmuScreen::ProcessVKey(VirtKey virtKey, bool down) { if (down) { if (!NetworkWarnUserIfOnlineAndCantSpeed()) { // Cycle through enabled speeds. - if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iFpsLimit1 >= 0) { + if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iAltSpeedPercent1 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; - } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iFpsLimit2 >= 0) { + } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iAltSpeedPercent2 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2; } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 || PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) { PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; @@ -1145,7 +1145,7 @@ void EmuScreen::OnVKeyAnalog(VirtKey virtualKeyCode, float value) { if (limitMode != FPSLimit::NORMAL && limitMode != FPSLimit::ANALOG) return; // Don't even try if the limit is invalid. - if (g_Config.iAnalogFpsLimit <= 0) + if (g_Config.iAnalogAltSpeedPercent <= 0) return; // Apply a small deadzone (against the resting position.) @@ -1153,7 +1153,7 @@ void EmuScreen::OnVKeyAnalog(VirtKey virtualKeyCode, float value) { // If target is above 60, value is how much to speed up over 60. Otherwise, it's how much slower. // So normalize the target. - int target = g_Config.iAnalogFpsLimit - 60; + int target = AltSpeedPercentToFps(g_Config.iAnalogAltSpeedPercent) - 60; PSP_CoreParameter().analogFpsLimit = 60 + (int)(target * value); // If we've reset back to normal, turn it off. diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 87baaed7fa..e74a0c7707 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -131,9 +131,6 @@ GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID, void GameSettingsScreen::ReadConfigTemporaries() { // Written back on exit, so it must be read even if the System tab is never opened. enableReports_ = Reporting::IsEnabled(); - iAlternateSpeedPercent1_ = g_Config.iFpsLimit1 < 0 ? -1 : (g_Config.iFpsLimit1 * 100) / 60; - iAlternateSpeedPercent2_ = g_Config.iFpsLimit2 < 0 ? -1 : (g_Config.iFpsLimit2 * 100) / 60; - iAlternateSpeedPercentAnalog_ = (g_Config.iAnalogFpsLimit * 100) / 60; } GameSettingsScreen::~GameSettingsScreen() { @@ -467,28 +464,19 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control"))); - PopupSliderChoice *altSpeed1 = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercent1_, 0, 1000, UI::NO_DEFAULT_INT, gr->T("Alternative Speed", "Alternative speed"), 5, screenManager(), gr->T("%, 0:unlimited"))); + PopupSliderChoice *altSpeed1 = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iAltSpeedPercent1, 0, 1000, UI::NO_DEFAULT_INT, gr->T("Alternative Speed", "Alternative speed"), 5, screenManager(), gr->T("%, 0:unlimited"))); altSpeed1->SetFormat("%i%%"); altSpeed1->SetZeroLabel(gr->T("Unlimited")); altSpeed1->SetNegativeDisable(gr->T("Disabled")); - altSpeed1->OnChange.Add([this](UI::EventParams &) { - g_Config.iFpsLimit1 = iAlternateSpeedPercent1_ < 0 ? -1 : (iAlternateSpeedPercent1_ * 60) / 100; - }); - PopupSliderChoice *altSpeed2 = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercent2_, 0, 1000, UI::NO_DEFAULT_INT, gr->T("Alternative Speed 2", "Alternative speed 2 (in %, 0 = unlimited)"), 5, screenManager(), gr->T("%, 0:unlimited"))); + PopupSliderChoice *altSpeed2 = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iAltSpeedPercent2, 0, 1000, UI::NO_DEFAULT_INT, gr->T("Alternative Speed 2", "Alternative speed 2 (in %, 0 = unlimited)"), 5, screenManager(), gr->T("%, 0:unlimited"))); altSpeed2->SetFormat("%i%%"); altSpeed2->SetZeroLabel(gr->T("Unlimited")); altSpeed2->SetNegativeDisable(gr->T("Disabled")); - altSpeed2->OnChange.Add([this](UI::EventParams &) { - g_Config.iFpsLimit2 = iAlternateSpeedPercent2_ < 0 ? -1 : (iAlternateSpeedPercent2_ * 60) / 100; - }); if (analogSpeedMapped_) { - PopupSliderChoice *analogSpeed = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercentAnalog_, 1, 1000, UI::NO_DEFAULT_INT, gr->T("Analog alternative speed", "Analog alternative speed (in %)"), 5, screenManager(), "%")); + PopupSliderChoice *analogSpeed = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iAnalogAltSpeedPercent, 1, 1000, UI::NO_DEFAULT_INT, gr->T("Analog alternative speed", "Analog alternative speed (in %)"), 5, screenManager(), "%")); analogSpeed->SetFormat("%i%%"); - analogSpeed->OnChange.Add([this](UI::EventParams &) { - g_Config.iAnalogFpsLimit = (iAlternateSpeedPercentAnalog_ * 60) / 100; - }); } graphicsSettings->Add(new ItemHeader(gr->T("Speed Hacks", "Speed Hacks (can cause rendering errors!)"))); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 7c15ca0a44..2d04e0d1f8 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -89,9 +89,6 @@ private: void ReadConfigTemporaries(); // Temporaries to convert setting types, cache enabled, etc. - int iAlternateSpeedPercent1_ = 0; - int iAlternateSpeedPercent2_ = 0; - int iAlternateSpeedPercentAnalog_ = 0; int prevInflightFrames_ = -1; bool enableReports_ = false; bool analogSpeedMapped_ = false;