From 7af15c73bc8aa2f1e1089ced996ef83d3584c259 Mon Sep 17 00:00:00 2001 From: Nabile Rahmani Date: Sat, 13 Jul 2024 15:04:20 +0200 Subject: [PATCH] [Feature] Option to override the display refresh rate This adds a per-game graphics option, `DisplayRefreshRate`, to override the display refresh rate. It defaults to 60 Hz, and is located in Dev tools. Games using variable timesteps benefit from higher refresh rates. Closes #19319 --- Common/VR/PPSSPPVR.cpp | 2 +- Core/Config.cpp | 2 ++ Core/Config.h | 1 + Core/HLE/sceDisplay.cpp | 8 ++++++-- Core/HLE/sceDisplay.h | 2 -- Core/HW/Display.cpp | 2 +- UI/DebugOverlay.cpp | 2 +- UI/GameSettingsScreen.cpp | 3 +++ 8 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 173243fda9..9741d197ac 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -684,7 +684,7 @@ bool StartVRRender() { vrCompat[VR_COMPAT_SKYPLANE] = PSP_CoreParameter().compat.vrCompat().Skyplane; // Set customizations - __DisplaySetFramerate(g_Config.bForce72Hz ? 72 : 60); + g_Config.iDisplayRefreshRate = g_Config.bForce72Hz ? 72 : 60; VR_SetConfigFloat(VR_CONFIG_CANVAS_DISTANCE, vrScene && (appMode == VR_GAME_MODE) ? g_Config.fCanvas3DDistance : g_Config.fCanvasDistance); VR_SetConfig(VR_CONFIG_PASSTHROUGH, g_Config.bPassthrough); return true; diff --git a/Core/Config.cpp b/Core/Config.cpp index fe82d69655..f7cee90453 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -693,6 +693,8 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("UberShaderVertex", &g_Config.bUberShaderVertex, true, CfgFlag::DEFAULT), ConfigSetting("UberShaderFragment", &g_Config.bUberShaderFragment, true, CfgFlag::DEFAULT), + + ConfigSetting("DisplayRefreshRate", &g_Config.iDisplayRefreshRate, 60, CfgFlag::PER_GAME), }; static const ConfigSetting soundSettings[] = { diff --git a/Core/Config.h b/Core/Config.h index fdacd88fc5..21da06a770 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -160,6 +160,7 @@ public: std::string sMicDevice; bool bCameraMirrorHorizontal; int iDisplayFramerateMode; // enum DisplayFramerateMode. Android-only. + int iDisplayRefreshRate; bool bSoftwareRendering; bool bSoftwareRenderingJit; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 55c3a62d1a..62f5390989 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -106,7 +106,7 @@ static int height; static bool wasPaused; static bool flippedThisFrame; -static int framerate = 60; +static int framerate = g_Config.iDisplayRefreshRate; // 1.001f to compensate for the classic 59.94 NTSC framerate that the PSP seems to have. static double timePerVblank = 1.001 / framerate; @@ -152,6 +152,7 @@ void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId); void __DisplayVblankEndCallback(SceUID threadID, SceUID prevCallbackId); void __DisplayFlip(int cyclesLate); +static void __DisplaySetFramerate(int value); static bool UseLagSync() { return g_Config.bForceLagSync && !g_Config.bAutoFrameSkip; @@ -562,6 +563,9 @@ static void NotifyUserIfSlow() { } void __DisplayFlip(int cyclesLate) { + if (g_Config.iDisplayRefreshRate != framerate) + __DisplaySetFramerate(g_Config.iDisplayRefreshRate); + flippedThisFrame = true; // We flip only if the framebuffer was dirty. This eliminates flicker when using // non-buffered rendering. The interaction with frame skipping seems to need @@ -1126,7 +1130,7 @@ void Register_sceDisplay_driver() { RegisterModule("sceDisplay_driver", ARRAY_SIZE(sceDisplay), sceDisplay); } -void __DisplaySetFramerate(int value) { +static void __DisplaySetFramerate(int value) { framerate = value; timePerVblank = 1.001 / (double)framerate; frameMs = 1001.0 / (double)framerate; diff --git a/Core/HLE/sceDisplay.h b/Core/HLE/sceDisplay.h index b68133e8a2..bb134af815 100644 --- a/Core/HLE/sceDisplay.h +++ b/Core/HLE/sceDisplay.h @@ -34,5 +34,3 @@ void __DisplaySetWasPaused(); void Register_sceDisplay_driver(); void __DisplayWaitForVblanks(const char* reason, int vblanks, bool callbacks = false); - -void __DisplaySetFramerate(int value); diff --git a/Core/HW/Display.cpp b/Core/HW/Display.cpp index 0759d8a9ee..146aaf8cf2 100644 --- a/Core/HW/Display.cpp +++ b/Core/HW/Display.cpp @@ -78,7 +78,7 @@ static void CalculateFPS() { actualFps = (float)(actualFlips - lastActualFlips); fps = frames / (now - lastFpsTime); - flips = (float)(60.0 * (double)(gpuStats.numFlips - lastNumFlips) / frames); + flips = (float)(g_Config.iDisplayRefreshRate * (double)(gpuStats.numFlips - lastNumFlips) / frames); lastFpsFrame = numVBlanks; lastNumFlips = gpuStats.numFlips; diff --git a/UI/DebugOverlay.cpp b/UI/DebugOverlay.cpp index 9e402144ac..fea1b03a04 100644 --- a/UI/DebugOverlay.cpp +++ b/UI/DebugOverlay.cpp @@ -437,7 +437,7 @@ void DrawFPS(UIContext *ctx, const Bounds &bounds) { char fpsbuf[256]{}; if (g_Config.iShowStatusFlags == ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) { - snprintf(fpsbuf, sizeof(fpsbuf), "%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / (59.94f / 100.0f)); + snprintf(fpsbuf, sizeof(fpsbuf), "%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / (g_Config.iDisplayRefreshRate / 100.0f)); } else { if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER) { snprintf(fpsbuf, sizeof(fpsbuf), "FPS: %0.1f", actual_fps); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 4c1d301e61..8460d948c4 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1888,6 +1888,9 @@ void DeveloperToolsScreen::CreateViews() { ffMode->SetEnabledFunc([]() { return !g_Config.bVSync; }); ffMode->HideChoice(1); // not used + auto displayRefreshRate = list->Add(new PopupSliderChoice(&g_Config.iDisplayRefreshRate, 60, 1000, 60, dev->T("Display refresh rate"), 1, screenManager())); + displayRefreshRate->SetFormat(dev->T("%d Hz")); + Draw::DrawContext *draw = screenManager()->getDrawContext(); list->Add(new ItemHeader(dev->T("Ubershaders")));