diff --git a/Common/KeyMap.cpp b/Common/KeyMap.cpp index 805bd4b4d2..092ca95144 100644 --- a/Common/KeyMap.cpp +++ b/Common/KeyMap.cpp @@ -645,7 +645,8 @@ const KeyMap_IntStrPair psp_button_names[] = { {VIRTKEY_RAPID_FIRE, "RapidFire"}, {VIRTKEY_UNTHROTTLE, "Unthrottle"}, {VIRTKEY_SPEED_TOGGLE, "SpeedToggle"}, - {VIRTKEY_SPEED_PRESS, "Speed toggle hold"}, + {VIRTKEY_SPEED_CUSTOM1, "Alt speed 1"}, + {VIRTKEY_SPEED_CUSTOM2, "Alt speed 2"}, {VIRTKEY_PAUSE, "Pause"}, #ifndef MOBILE_DEVICE {VIRTKEY_FRAME_ADVANCE, "Frame Advance"}, diff --git a/Common/KeyMap.h b/Common/KeyMap.h index 810beec448..9f408ed7f6 100644 --- a/Common/KeyMap.h +++ b/Common/KeyMap.h @@ -52,7 +52,8 @@ enum { VIRTKEY_DEVMENU = 0x40000014, VIRTKEY_FRAME_ADVANCE = 0x40000015, VIRTKEY_RECORD = 0x40000016, - VIRTKEY_SPEED_PRESS = 0x40000017, + VIRTKEY_SPEED_CUSTOM1 = 0x40000017, + VIRTKEY_SPEED_CUSTOM2 = 0x40000018, VIRTKEY_LAST, VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST }; diff --git a/Core/Config.cpp b/Core/Config.cpp index cb4044d8d1..810b9102b7 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -525,7 +525,8 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("HighQualityDepth", &g_Config.bHighQualityDepth, true, true, true), ReportedConfigSetting("FrameSkip", &g_Config.iFrameSkip, 0, true, true), ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), - ConfigSetting("FrameRate", &g_Config.iFpsLimit, 0, true, true), + ConfigSetting("FrameRate", &g_Config.iFpsLimit1, 0, true, true), + ConfigSetting("FrameRate2", &g_Config.iFpsLimit2, -1, true, true), ConfigSetting("FrameSkipUnthrottle", &g_Config.bFrameSkipUnthrottle, &DefaultFrameskipUnthrottle, true, false), #if defined(USING_WIN_UI) ConfigSetting("RestartRequired", &g_Config.bRestartRequired, false, false), diff --git a/Core/Config.h b/Core/Config.h index 3898eba28e..da179fa8d3 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -160,7 +160,8 @@ public: int iTexScalingLevel; // 0 = auto, 1 = off, 2 = 2x, ..., 5 = 5x int iTexScalingType; // 0 = xBRZ, 1 = Hybrid bool bTexDeposterize; - int iFpsLimit; + int iFpsLimit1; + int iFpsLimit2; int iForceMaxEmulatedFPS; int iMaxRecent; int iCurrentStateSlot; diff --git a/Core/CoreParameter.h b/Core/CoreParameter.h index 9e6ec3ef18..ce14107ba1 100644 --- a/Core/CoreParameter.h +++ b/Core/CoreParameter.h @@ -31,6 +31,12 @@ enum GPUCore { GPUCORE_VULKAN, }; +enum class FPSLimit { + NORMAL = 0, + CUSTOM1 = 1, + CUSTOM2 = 2, +}; + class FileLoader; class GraphicsContext; @@ -42,13 +48,13 @@ enum class CPUCore; // PSP_CoreParameter() struct CoreParameter { - CoreParameter() : thin3d(nullptr), collectEmuLog(0), unthrottle(false), fpsLimit(0), updateRecent(true), freezeNext(false), frozen(false), mountIsoLoader(nullptr) {} + CoreParameter() {} CPUCore cpuCore; GPUCore gpuCore; - GraphicsContext *graphicsContext; // TODO: Find a better place. - Draw::DrawContext *thin3d; + GraphicsContext *graphicsContext = nullptr; // TODO: Find a better place. + Draw::DrawContext *thin3d = nullptr; bool enableSound; // there aren't multiple sound cores. std::string fileToStart; @@ -58,7 +64,7 @@ struct CoreParameter { bool startPaused; bool printfEmuLog; // writes "emulator:" logging to stdout - std::string *collectEmuLog; + std::string *collectEmuLog = nullptr; bool headLess; // Try to avoid messageboxes etc // Internal PSP resolution @@ -70,16 +76,16 @@ struct CoreParameter { int pixelHeight; // Can be modified at runtime. - bool unthrottle; - int fpsLimit; + bool unthrottle = false; + FPSLimit fpsLimit = FPSLimit::NORMAL; - bool updateRecent; + bool updateRecent = true; // Freeze-frame. For nvidia perfhud profiling. Developers only. - bool freezeNext; - bool frozen; + bool freezeNext = false; + bool frozen = false; - FileLoader *mountIsoLoader; + FileLoader *mountIsoLoader = nullptr; Compatibility compat; }; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 42c8bd6310..b86d467df8 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -476,17 +476,17 @@ void __DisplayGetDebugStats(char *stats, size_t bufsize) { statbuf); } -enum { - FPS_LIMIT_NORMAL = 0, - FPS_LIMIT_CUSTOM = 1, -}; + void __DisplaySetWasPaused() { wasPaused = true; } static bool FrameTimingThrottled() { - if (PSP_CoreParameter().fpsLimit == FPS_LIMIT_CUSTOM && g_Config.iFpsLimit == 0) { + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iFpsLimit1 == 0) { + return false; + } + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 == 0) { return false; } return !PSP_CoreParameter().unthrottle; @@ -505,7 +505,7 @@ static void DoFrameDropLogging(float scaledTimestep) { // Let's collect all the throttling and frameskipping logic here. static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { PROFILE_THIS_SCOPE("timing"); - int fpsLimiter = PSP_CoreParameter().fpsLimit; + FPSLimit fpsLimiter = PSP_CoreParameter().fpsLimit; throttle = FrameTimingThrottled(); skipFrame = false; @@ -528,8 +528,10 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { time_update(); float scaledTimestep = timestep; - if (fpsLimiter == FPS_LIMIT_CUSTOM && g_Config.iFpsLimit != 0) { - scaledTimestep *= 60.0f / g_Config.iFpsLimit; + if (fpsLimiter == FPSLimit::CUSTOM1 && g_Config.iFpsLimit1 > 0) { + scaledTimestep *= 60.0f / g_Config.iFpsLimit1; + } else if (fpsLimiter == FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 > 0) { + scaledTimestep *= 60.0f / g_Config.iFpsLimit2; } if (lastFrameTime == 0.0 || wasPaused) { @@ -549,7 +551,8 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { // Auto-frameskip automatically if speed limit is set differently than the default. bool useAutoFrameskip = g_Config.bAutoFrameSkip && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; - if (g_Config.bAutoFrameSkip || (g_Config.iFrameSkip == 0 && fpsLimiter == FPS_LIMIT_CUSTOM && g_Config.iFpsLimit > 60)) { + bool forceFrameskip = (fpsLimiter == FPSLimit::CUSTOM1 && g_Config.iFpsLimit1 > 60) || (fpsLimiter == FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 > 60); + if (g_Config.bAutoFrameSkip || forceFrameskip) { // autoframeskip // Argh, we are falling behind! Let's skip a frame and see if we catch up. if (curFrameTime > nextFrameTime && doFrameSkip) { @@ -601,9 +604,11 @@ static void DoFrameIdleTiming() { } float scaledVblank = timePerVblank; - if (PSP_CoreParameter().fpsLimit == FPS_LIMIT_CUSTOM) { + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iFpsLimit1 > 0) { // 0 is handled in FrameTimingThrottled(). - scaledVblank *= 60.0f / g_Config.iFpsLimit; + scaledVblank *= 60.0f / g_Config.iFpsLimit1; + } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 > 0) { + scaledVblank *= 60.0f / g_Config.iFpsLimit2; } // If we have over at least a vblank of spare time, maintain at least 30fps in delay. @@ -695,7 +700,7 @@ void __DisplayFlip(int cyclesLate) { // Let the user know if we're running slow, so they know to adjust settings. // Sometimes users just think the sound emulation is broken. static bool hasNotifiedSlow = false; - if (!g_Config.bHideSlowWarnings && !hasNotifiedSlow && PSP_CoreParameter().fpsLimit == FPS_LIMIT_NORMAL && IsRunningSlow()) { + if (!g_Config.bHideSlowWarnings && !hasNotifiedSlow && PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && IsRunningSlow()) { #ifndef _DEBUG I18NCategory *err = GetI18NCategory("Error"); if (g_Config.bSoftwareRendering) { @@ -787,9 +792,11 @@ void hleLagSync(u64 userdata, int cyclesLate) { } float scale = 1.0f; - if (PSP_CoreParameter().fpsLimit == FPS_LIMIT_CUSTOM) { + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iFpsLimit1 > 0) { // 0 is handled in FrameTimingThrottled(). - scale = 60.0f / g_Config.iFpsLimit; + scale = 60.0f / g_Config.iFpsLimit1; + } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 > 0) { + scale = 60.0f / g_Config.iFpsLimit2; } const double goal = lastLagSync + (scale / 1000.0f); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 24aa119525..afd5a86d10 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -211,7 +211,7 @@ void GPU_DX9::ReapplyGfxState() { void GPU_DX9::BeginFrame() { // Turn off vsync when unthrottled int desiredVSyncInterval = g_Config.bVSync ? 1 : 0; - if ((PSP_CoreParameter().unthrottle) || (PSP_CoreParameter().fpsLimit == 1)) + if (PSP_CoreParameter().unthrottle || PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) desiredVSyncInterval = 0; if (desiredVSyncInterval != lastVsync_) { dxstate.SetVSyncInterval(desiredVSyncInterval); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 4e409ccd60..5eca0e9296 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -392,9 +392,10 @@ inline void GPU_GLES::UpdateVsyncInterval(bool force) { if (PSP_CoreParameter().unthrottle) { desiredVSyncInterval = 0; } - if (PSP_CoreParameter().fpsLimit == 1) { + if (PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) { + int limit = PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 ? g_Config.iFpsLimit1 : g_Config.iFpsLimit2; // For an alternative speed that is a clean factor of 60, the user probably still wants vsync. - if (g_Config.iFpsLimit == 0 || (g_Config.iFpsLimit != 15 && g_Config.iFpsLimit != 30 && g_Config.iFpsLimit != 60)) { + if (limit == 0 || (limit >= 0 && limit != 15 && limit != 30 && limit != 60)) { desiredVSyncInterval = 0; } } diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 8d4baa4f81..2b68d2dce0 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -472,21 +472,31 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) { break; case VIRTKEY_SPEED_TOGGLE: - if (PSP_CoreParameter().fpsLimit == 0) { - PSP_CoreParameter().fpsLimit = 1; + // Cycle through enabled speeds. + if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iFpsLimit1 >= 0) { + PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; osm.Show(sc->T("fixed", "Speed: alternate"), 1.0); - } else if (PSP_CoreParameter().fpsLimit == 1) { - PSP_CoreParameter().fpsLimit = 0; + } else if (PSP_CoreParameter().fpsLimit != FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 >= 0) { + PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2; + osm.Show(sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0); + } else if (PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) { + PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; osm.Show(sc->T("standard", "Speed: standard"), 1.0); } break; - case VIRTKEY_SPEED_PRESS: - if (PSP_CoreParameter().fpsLimit == 0) { - PSP_CoreParameter().fpsLimit = 1; + case VIRTKEY_SPEED_CUSTOM1: + if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) { + PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; osm.Show(sc->T("fixed", "Speed: alternate"), 1.0); } break; + case VIRTKEY_SPEED_CUSTOM2: + if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) { + PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2; + osm.Show(sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0); + } + break; case VIRTKEY_PAUSE: pauseTrigger_ = true; @@ -594,9 +604,15 @@ void EmuScreen::onVKeyUp(int virtualKeyCode) { PSP_CoreParameter().unthrottle = false; break; - case VIRTKEY_SPEED_PRESS: - if (PSP_CoreParameter().fpsLimit == 1) { - PSP_CoreParameter().fpsLimit = 0; + case VIRTKEY_SPEED_CUSTOM1: + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) { + PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; + osm.Show(sc->T("standard", "Speed: standard"), 1.0); + } + break; + case VIRTKEY_SPEED_CUSTOM2: + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) { + PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; osm.Show(sc->T("standard", "Speed: standard"), 1.0); } break; @@ -1022,11 +1038,6 @@ void EmuScreen::update() { // Virtual keys. __CtrlSetRapidFire(virtKeys[VIRTKEY_RAPID_FIRE - VIRTKEY_FIRST]); - // Make sure fpsLimit starts at 0 - if (PSP_CoreParameter().fpsLimit != 0 && PSP_CoreParameter().fpsLimit != 1) { - PSP_CoreParameter().fpsLimit = 0; - } - // This is here to support the iOS on screen back button. if (pauseTrigger_) { pauseTrigger_ = false; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index f4e45b3012..6e76db39e7 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -127,7 +127,8 @@ void GameSettingsScreen::CreateViews() { cap60FPS_ = g_Config.iForceMaxEmulatedFPS == 60; - iAlternateSpeedPercent_ = (g_Config.iFpsLimit * 100) / 60; + iAlternateSpeedPercent1_ = g_Config.iFpsLimit1 < 0 ? -1 : (g_Config.iFpsLimit1 * 100) / 60; + iAlternateSpeedPercent2_ = g_Config.iFpsLimit2 < 0 ? -1 : (g_Config.iFpsLimit2 * 100) / 60; bool vertical = UseVerticalLayout(); @@ -271,9 +272,15 @@ void GameSettingsScreen::CreateViews() { frameSkipAuto_->OnClick.Handle(this, &GameSettingsScreen::OnAutoFrameskip); graphicsSettings->Add(new CheckBox(&cap60FPS_, gr->T("Force max 60 FPS (helps GoW)"))); - PopupSliderChoice *altSpeed = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercent_, 0, 1000, gr->T("Alternative Speed", "Alternative speed"), 5, screenManager(), gr->T("%, 0:unlimited"))); - altSpeed->SetFormat("%i%%"); - altSpeed->SetZeroLabel(gr->T("Unlimited")); + PopupSliderChoice *altSpeed1 = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercent1_, 0, 1000, 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")); + + PopupSliderChoice *altSpeed2 = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercent2_, 0, 1000, 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")); graphicsSettings->Add(new ItemHeader(gr->T("Features"))); // Hide postprocess option on unsupported backends to avoid confusion. @@ -1033,7 +1040,8 @@ void GameSettingsScreen::update() { UIScreen::update(); g_Config.iForceMaxEmulatedFPS = cap60FPS_ ? 60 : 0; - g_Config.iFpsLimit = (iAlternateSpeedPercent_ * 60) / 100; + g_Config.iFpsLimit1 = iAlternateSpeedPercent1_ < 0 ? -1 : (iAlternateSpeedPercent1_ * 60) / 100; + g_Config.iFpsLimit2 = iAlternateSpeedPercent2_ < 0 ? -1 : (iAlternateSpeedPercent2_ * 60) / 100; bool vertical = UseVerticalLayout(); if (vertical != lastVertical_) { diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index c68fb8939a..259c8cf58b 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -106,7 +106,8 @@ private: // Temporaries to convert bools to int settings bool cap60FPS_; - int iAlternateSpeedPercent_; + int iAlternateSpeedPercent1_; + int iAlternateSpeedPercent2_; bool enableReports_; //edit the game-specific settings and restore the global settings after exiting diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index cc00b5326d..56316c620a 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -515,10 +515,6 @@ namespace MainWindow { NativeMessageReceived("gpu_resized", ""); } - static void setFpsLimit(int fps) { - g_Config.iFpsLimit = fps; - } - static void setFrameSkipping(int framesToSkip = -1) { if (framesToSkip >= FRAMESKIP_OFF) g_Config.iFrameSkip = framesToSkip;