diff --git a/Core/Config.cpp b/Core/Config.cpp index 84e8bcf01e..94a52cf781 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -529,11 +529,11 @@ static int DefaultInternalResolution() { #endif } -static bool DefaultFrameskipUnthrottle() { +static int DefaultUnthrottleMode() { #if PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS) - return true; + return (int)UnthrottleMode::SKIP_DRAW; #else - return false; + return (int)UnthrottleMode::CONTINUOUS; #endif } @@ -705,6 +705,28 @@ struct ConfigTranslator { typedef ConfigTranslator GPUBackendTranslator; +static int UnthrottleModeFromString(const std::string &s) { + if (!strcasecmp(s.c_str(), "CONTINUOUS")) + return (int)UnthrottleMode::CONTINUOUS; + if (!strcasecmp(s.c_str(), "SKIP_DRAW")) + return (int)UnthrottleMode::SKIP_DRAW; + if (!strcasecmp(s.c_str(), "SKIP_FLIP")) + return (int)UnthrottleMode::SKIP_FLIP; + return DefaultUnthrottleMode(); +} + +std::string UnthrottleModeToString(int v) { + switch (UnthrottleMode(v)) { + case UnthrottleMode::CONTINUOUS: + return "CONTINUOUS"; + case UnthrottleMode::SKIP_DRAW: + return "SKIP_DRAW"; + case UnthrottleMode::SKIP_FLIP: + return "SKIP_FLIP"; + } + return "CONTINUOUS"; +} + static ConfigSetting graphicsSettings[] = { ConfigSetting("EnableCardboardVR", &g_Config.bEnableCardboardVR, false, true, true), ConfigSetting("CardboardScreenSize", &g_Config.iCardboardScreenSize, 50, true, true), @@ -734,7 +756,7 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, 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), + ConfigSetting("UnthrottleMode", &g_Config.iUnthrottleMode, &DefaultUnthrottleMode, &UnthrottleModeToString, &UnthrottleModeFromString, true, true), #if defined(USING_WIN_UI) ConfigSetting("RestartRequired", &g_Config.bRestartRequired, false, false), #endif diff --git a/Core/Config.h b/Core/Config.h index 1843823047..d858b85804 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -161,8 +161,8 @@ public: bool bVSync; int iFrameSkip; int iFrameSkipType; + int iUnthrottleMode; // See UnthrottleMode in ConfigValues.h. bool bAutoFrameSkip; - bool bFrameSkipUnthrottle; bool bEnableCardboardVR; // Cardboard Master Switch int iCardboardScreenSize; // Screen Size (in %) diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index 89c8598112..8936f63809 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -110,3 +110,9 @@ enum class AutoLoadSaveState { OLDEST = 1, NEWEST = 2, }; + +enum class UnthrottleMode { + CONTINUOUS = 0, + SKIP_DRAW = 1, + SKIP_FLIP = 2, +}; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 176cfdd5f8..12c069ab0e 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -561,7 +561,7 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { // we have nothing to do here. bool doFrameSkip = g_Config.iFrameSkip != 0; - bool unthrottleNeedsSkip = g_Config.bFrameSkipUnthrottle; + bool unthrottleNeedsSkip = g_Config.iUnthrottleMode == (int)UnthrottleMode::SKIP_DRAW; if (g_Config.bVSync && GetGPUBackend() == GPUBackend::VULKAN) { // Vulkan doesn't support the interval setting, so we force frameskip. unthrottleNeedsSkip = true; @@ -758,7 +758,7 @@ void __DisplayFlip(int cyclesLate) { bool duplicateFrames = g_Config.bRenderDuplicateFrames && g_Config.iFrameSkip == 0; - bool unthrottleNeedsSkip = g_Config.bFrameSkipUnthrottle; + bool unthrottleNeedsSkip = g_Config.iUnthrottleMode != (int)UnthrottleMode::CONTINUOUS; if (g_Config.bVSync && GetGPUBackend() == GPUBackend::VULKAN) { // Vulkan doesn't support the interval setting, so we force frameskip. unthrottleNeedsSkip = true; @@ -794,11 +794,24 @@ void __DisplayFlip(int cyclesLate) { hasNotifiedSlow = true; } + bool forceNoFlip = false; + // Alternative to frameskip unthrottle, where we draw everything. + // Useful if skipping a frame breaks graphics or for checking drawing speed. + if (g_Config.iUnthrottleMode == (int)UnthrottleMode::SKIP_FLIP && !FrameTimingThrottled()) { + static double lastFlip = 0; + double now = time_now_d(); + if ((now - lastFlip) < 1.0f / System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE)) { + forceNoFlip = true; + } else { + lastFlip = now; + } + } + // Setting CORE_NEXTFRAME causes a swap. const bool fbReallyDirty = gpu->FramebufferReallyDirty(); if (fbReallyDirty || noRecentFlip || postEffectRequiresFlip) { // Check first though, might've just quit / been paused. - if (Core_NextFrame()) { + if (!forceNoFlip && Core_NextFrame()) { gpu->CopyDisplayToOutput(fbReallyDirty); if (fbReallyDirty) { actualFlips++; diff --git a/headless/Headless.cpp b/headless/Headless.cpp index ef43d5ba85..8246a7df43 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -382,7 +382,7 @@ int main(int argc, const char* argv[]) g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CROSS; g_Config.iLockParentalLevel = 9; g_Config.iInternalResolution = 1; - g_Config.bFrameSkipUnthrottle = false; + g_Config.iUnthrottleMode = (int)UnthrottleMode::CONTINUOUS; g_Config.bEnableLogging = fullLog; g_Config.iNumWorkerThreads = 1; g_Config.bSoftwareSkinning = true; diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index e5566a7e99..4e2a6bf07d 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -342,7 +342,7 @@ void retro_init(void) #endif g_Config.bEnableLogging = true; - g_Config.bFrameSkipUnthrottle = false; + g_Config.iUnthrottleMode = (int)UnthrottleMode::CONTINUOUS; g_Config.bMemStickInserted = PSP_MEMORYSTICK_STATE_INSERTED; g_Config.iGlobalVolume = VOLUME_MAX - 1; g_Config.iAltSpeedVolume = -1;