From a40ea357db119e61b80d8bc683f0f0f74b759a73 Mon Sep 17 00:00:00 2001 From: souldbminersmwc Date: Fri, 13 Mar 2026 18:35:38 -0400 Subject: [PATCH] sysclk: add per-game VRR setting --- Source/sys-clk/common/include/sysclk/board.h | 4 + .../common/src/display_refresh_rate.cpp | 23 +++-- .../overlay/src/ui/gui/app_profile_gui.cpp | 11 ++- .../src/ui/gui/global_override_gui.cpp | 35 ++++---- .../sys-clk/overlay/src/ui/gui/misc_gui.cpp | 22 +++-- Source/sys-clk/sysmodule/src/board.cpp | 35 +++----- .../sys-clk/sysmodule/src/clock_manager.cpp | 90 +++++++++++++------ 7 files changed, 131 insertions(+), 89 deletions(-) diff --git a/Source/sys-clk/common/include/sysclk/board.h b/Source/sys-clk/common/include/sysclk/board.h index 6dc7b1aa..7741ecfa 100644 --- a/Source/sys-clk/common/include/sysclk/board.h +++ b/Source/sys-clk/common/include/sysclk/board.h @@ -146,9 +146,13 @@ typedef enum { typedef enum { GovernorState_DoNotOverride = 0, GovernorState_Disabled, + GovernorState_Enabled_CpuGpuVrr, + GovernorState_Enabled_CpuVrr, + GovernorState_Enabled_GpuVrr, GovernorState_Enabled_CpuGpu, GovernorState_Enabled_Cpu, GovernorState_Enabled_Gpu, + GovernorState_Enabled_Vrr, GovernorState_EnumMax, } GovernorState; typedef enum { diff --git a/Source/sys-clk/common/src/display_refresh_rate.cpp b/Source/sys-clk/common/src/display_refresh_rate.cpp index 9c380d83..1042a195 100644 --- a/Source/sys-clk/common/src/display_refresh_rate.cpp +++ b/Source/sys-clk/common/src/display_refresh_rate.cpp @@ -554,9 +554,10 @@ bool DisplayRefresh_SetRate(uint32_t new_refreshRate) { if (g_config.isRetroSUPER && !g_config.isDocked) { return _setNvDispHandheldRefreshRate(new_refreshRate); } - else if ((!g_config.isRetroSUPER && g_config.isLite) || - nvOpen(&fd, "/dev/nvdisp-disp1")) { - return _setPLLDHandheldRefreshRate(new_refreshRate); + + else if ((!g_config.isRetroSUPER && g_config.isLite) || R_FAILED(nvOpen(&fd, "/dev/nvdisp-disp1"))) { + if (_setPLLDHandheldRefreshRate(new_refreshRate) == false) + return false; } else { struct dpaux_read { @@ -578,15 +579,19 @@ bool DisplayRefresh_SetRate(uint32_t new_refreshRate) { nvClose(fd); if (rc != 0) { - if (!g_config.isRetroSUPER) { - return _setPLLDHandheldRefreshRate(new_refreshRate); - } else { - return _setNvDispHandheldRefreshRate(new_refreshRate); - } + if (!g_config.isRetroSUPER) { + return _setPLLDHandheldRefreshRate(new_refreshRate); + } else { + return _setNvDispHandheldRefreshRate(new_refreshRate); + } } else { - return _setNvDispDockedRefreshRate(new_refreshRate); + if(g_config.isDocked) + return _setNvDispDockedRefreshRate(new_refreshRate); + else + return true; } } + return false; } bool DisplayRefresh_GetRate(uint32_t* out_refreshRate, bool internal) { diff --git a/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.cpp index 2810d3ab..feae30fe 100644 --- a/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.cpp @@ -292,7 +292,7 @@ void AppProfileGui::addProfileUI(SysClkProfile profile) this->addModuleListItem(profile, SysClkModule_MEM); #if IS_MINIMAL == 0 ValueThresholds lcdThresholds(60, 65); - if(!IsHoag() && configList.values[HorizonOCConfigValue_OverwriteRefreshRate]) { + if(configList.values[HorizonOCConfigValue_OverwriteRefreshRate]) { if(profile != SysClkProfile_Docked) { this->addModuleListItemValue(profile, HorizonOCModule_Display, "Display", IsAula() ? 45 : 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds); } else { @@ -369,17 +369,24 @@ void AppProfileGui::addProfileUI(SysClkProfile profile) std::vector governorSettingsE = { NamedValue("Do Not Override", GovernorState_DoNotOverride), NamedValue("Disabled", GovernorState_Disabled), + NamedValue("CPU + GPU + VRR", GovernorState_Enabled_CpuGpuVrr), + NamedValue("CPU + VRR", GovernorState_Enabled_CpuVrr), + NamedValue("GPU + VRR", GovernorState_Enabled_GpuVrr), NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu), NamedValue("CPU", GovernorState_Enabled_Cpu), NamedValue("GPU", GovernorState_Enabled_Gpu), + NamedValue("VRR", GovernorState_Enabled_Vrr), }; std::vector governorSettings = { NamedValue("Do Not Override", GovernorState_DoNotOverride), NamedValue("Disabled", GovernorState_Disabled), + NamedValue("GPU + VRR", GovernorState_Enabled_GpuVrr), NamedValue("GPU", GovernorState_Enabled_Gpu), + NamedValue("VRR", GovernorState_Enabled_Vrr), }; - this->addModuleListItemValue(profile, HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), configList.values[HorizonOCConfigValue_EnableExperimentalSettings] ?governorSettingsE : governorSettings, false); + + this->addModuleListItemValue(profile, HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), configList.values[HorizonOCConfigValue_EnableExperimentalSettings] ? governorSettingsE : governorSettings, false); } void AppProfileGui::listUI() diff --git a/Source/sys-clk/overlay/src/ui/gui/global_override_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/global_override_gui.cpp index c3af091f..d868b933 100644 --- a/Source/sys-clk/overlay/src/ui/gui/global_override_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/global_override_gui.cpp @@ -290,6 +290,17 @@ void GlobalOverrideGui::addModuleToggleItem(SysClkModule module) this->listItems[module] = toggle; } +std::vector governorSettingsE = { + NamedValue("Do Not Override", GovernorState_DoNotOverride), + NamedValue("Disabled", GovernorState_Disabled), + NamedValue("CPU + GPU + VRR", GovernorState_Enabled_CpuGpuVrr), + NamedValue("CPU + VRR", GovernorState_Enabled_CpuVrr), + NamedValue("GPU + VRR", GovernorState_Enabled_GpuVrr), + NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu), + NamedValue("CPU", GovernorState_Enabled_Cpu), + NamedValue("GPU", GovernorState_Enabled_Gpu), + NamedValue("VRR", GovernorState_Enabled_Vrr), +}; void GlobalOverrideGui::listUI() { @@ -306,23 +317,20 @@ void GlobalOverrideGui::listUI() this->addModuleListItem(SysClkModule_MEM); #if IS_MINIMAL == 0 ValueThresholds lcdThresholds(60, 65); - if(!IsHoag() && configList.values[HorizonOCConfigValue_OverwriteRefreshRate]) + if(configList.values[HorizonOCConfigValue_OverwriteRefreshRate]) this->addModuleListItemValue(HorizonOCModule_Display, "Display", IsAula() ? 45 : 40, configList.values[HorizonOCConfigValue_EnableUnsafeDisplayFreqs] ? IsAula() ? 65 : 72 : 60, 1, " Hz", 1, 0, lcdThresholds); #endif - std::vector governorSettingsE = { - NamedValue("Do Not Override", GovernorState_DoNotOverride), - NamedValue("Disabled", GovernorState_Disabled), - NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu), - NamedValue("CPU", GovernorState_Enabled_Cpu), - NamedValue("GPU", GovernorState_Enabled_Gpu), - }; + std::vector governorSettings = { NamedValue("Do Not Override", GovernorState_DoNotOverride), NamedValue("Disabled", GovernorState_Disabled), + NamedValue("GPU + VRR", GovernorState_Enabled_GpuVrr), NamedValue("GPU", GovernorState_Enabled_Gpu), + NamedValue("VRR", GovernorState_Enabled_Vrr), }; + this->addModuleListItemValue(HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), configList.values[HorizonOCConfigValue_EnableExperimentalSettings] ?governorSettingsE : governorSettings, false); } @@ -341,15 +349,8 @@ void GlobalOverrideGui::refresh() std::string displayText = FREQ_DEFAULT_TEXT; std::uint32_t currentValue = this->context->overrideFreqs[m]; - std::vector governorSettings = { - NamedValue("Do Not Override", GovernorState_DoNotOverride), - NamedValue("Disabled", GovernorState_Disabled), - NamedValue("CPU + GPU", GovernorState_Enabled_CpuGpu), - NamedValue("CPU", GovernorState_Enabled_Cpu), - NamedValue("GPU", GovernorState_Enabled_Gpu), - }; - - for (const auto& setting : governorSettings) { + + for (const auto& setting : governorSettingsE) { if (setting.value == currentValue) { displayText = setting.name; break; diff --git a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp index cfecd5dd..d9522a71 100644 --- a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp @@ -424,18 +424,16 @@ void MiscGui::listUI() return false; }); this->listElement->addItem(gpuSubmenu); - if(!IsHoag()) { - this->listElement->addItem(new tsl::elm::CategoryHeader("Display")); - tsl::elm::ListItem* displaySubMenu = new tsl::elm::ListItem("Display Settings"); - displaySubMenu->setClickListener([](u64 keys) { - if (keys & HidNpadButton_A) { - tsl::changeTo(); - return true; - } - return false; - }); - this->listElement->addItem(displaySubMenu); - } + this->listElement->addItem(new tsl::elm::CategoryHeader("Display")); + tsl::elm::ListItem* displaySubMenu = new tsl::elm::ListItem("Display Settings"); + displaySubMenu->setClickListener([](u64 keys) { + if (keys & HidNpadButton_A) { + tsl::changeTo(); + return true; + } + return false; + }); + this->listElement->addItem(displaySubMenu); #if IS_MINIMAL == 0 // std::vector chargerCurrents = { // NamedValue("Disabled", 0), diff --git a/Source/sys-clk/sysmodule/src/board.cpp b/Source/sys-clk/sysmodule/src/board.cpp index e8a67b40..5a751826 100644 --- a/Source/sys-clk/sysmodule/src/board.cpp +++ b/Source/sys-clk/sysmodule/src/board.cpp @@ -280,17 +280,15 @@ void Board::Initialize() if (hosversionAtLeast(6,0,0) && R_SUCCEEDED(pwmInitialize())) { pwmCheck = pwmOpenSession2(&g_ICon, 0x3D000001); } - if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) { - u64 clkVirtAddr, dsiVirtAddr, outsize; - rc = svcQueryMemoryMapping(&clkVirtAddr, &outsize, 0x60006000, 0x1000); - ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (clk)"); - rc = svcQueryMemoryMapping(&dsiVirtAddr, &outsize, 0x54300000, 0x40000); - ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (dsi)"); + u64 clkVirtAddr, dsiVirtAddr, outsize; + rc = svcQueryMemoryMapping(&clkVirtAddr, &outsize, 0x60006000, 0x1000); + ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (clk)"); + rc = svcQueryMemoryMapping(&dsiVirtAddr, &outsize, 0x54300000, 0x40000); + ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (dsi)"); - DisplayRefreshConfig cfg = {.clkVirtAddr = clkVirtAddr, .dsiVirtAddr = dsiVirtAddr}; + DisplayRefreshConfig cfg = {.clkVirtAddr = clkVirtAddr, .dsiVirtAddr = dsiVirtAddr}; - DisplayRefresh_Initialize(&cfg); - } + DisplayRefresh_Initialize(&cfg); FetchHardwareInfos(); rc = svcQueryMemoryMapping(&cldvfs, &cldvfs_temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE); @@ -422,8 +420,7 @@ void Board::Exit() batteryInfoExit(); pmdmntExit(); nvExit(); - if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) - DisplayRefresh_Shutdown(); + DisplayRefresh_Shutdown(); } SysClkProfile Board::GetProfile() @@ -457,7 +454,7 @@ SysClkProfile Board::GetProfile() void Board::SetHz(SysClkModule module, std::uint32_t hz) { Result rc = 0; - if(module == HorizonOCModule_Display && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) { + if(module == HorizonOCModule_Display) { DisplayRefresh_SetRate(hz); return; } @@ -496,10 +493,7 @@ std::uint32_t Board::GetHz(SysClkModule module) std::uint32_t hz = 0; if(module == HorizonOCModule_Display) { - if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) - DisplayRefresh_GetRate(&hz, false); - else - hz = 60; + DisplayRefresh_GetRate(&hz, false); return hz; } @@ -536,10 +530,7 @@ std::uint32_t Board::GetRealHz(SysClkModule module) case SysClkModule_MEM: return t210ClkMemFreq(); case HorizonOCModule_Display: - if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) - DisplayRefresh_GetRate(&hz, false); - else - hz = 60; + DisplayRefresh_GetRate(&hz, false); return hz; default: ASSERT_ENUM_VALID(SysClkModule, module); @@ -734,9 +725,7 @@ void Board::ResetToStockGpu() } void Board::ResetToStockDisplay() { - if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag) { - DisplayRefresh_SetRate(60); - } + DisplayRefresh_SetRate(60); } u8 Board::GetHighestDockedDisplayRate() { diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp index d7c4dc0d..06ee1f89 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.cpp +++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp @@ -51,6 +51,7 @@ bool isGpuGovernorEnabled = false; bool isCpuGovernorEnabled = false; bool lastGpuGovernorState = false; bool lastCpuGovernorState = false; +bool lastVrrGovernorState = false; bool hasChanged = true; ClockManager *ClockManager::instance = NULL; Thread cpuGovernorTHREAD; @@ -59,7 +60,7 @@ Thread vrrTHREAD; u32 initialConfigValues[SysClkConfigValue_EnumMax]; // initial config. used for safety checks bool kipAvailable = false; bool isCpuGovernorInBoostMode = false; - +bool isVRREnabled = false; ClockManager *ClockManager::GetInstance() { return instance; @@ -373,6 +374,7 @@ void ClockManager::CpuGovernorThread(void* arg) { if (!mgr->running || !isCpuGovernorEnabled) { downHoldRemaining = 0; lastHz = 0; + svcSleepThread(POLL_NS); continue; } @@ -441,6 +443,7 @@ void ClockManager::GovernorThread(void* arg) { if (!mgr->running || !isGpuGovernorEnabled) { downHoldRemaining = 0; lastHz = 0; + svcSleepThread(POLL_NS); continue; } @@ -487,12 +490,8 @@ void ClockManager::VRRThread(void* arg) { ClockManager* mgr = static_cast(arg); u8 tick = 0; for (;;) { - if (!mgr->running || !mgr->config->GetConfigValue(HorizonOCConfigValue_VRR) || mgr->context->profile == SysClkProfile_Docked) { - continue; - } - - if(Board::GetConsoleType() == HorizonOCConsoleType_Hoag) { - svcSleepThread(~0ULL); + if (!mgr->running || mgr->context->profile == SysClkProfile_Docked || !isVRREnabled) { + svcSleepThread(POLL_NS); continue; } @@ -507,20 +506,38 @@ void ClockManager::VRRThread(void* arg) { continue; } - if(fps == 254) + if(fps == 254) { + svcSleepThread(POLL_NS); continue; + } // if(appletGetFocusState() != AppletFocusState_InFocus) { // Board::ResetToStockDisplay(); // continue; // } - u8 maxDisplay; - if(Board::GetConsoleType() == HorizonOCConsoleType_Aula) { - maxDisplay = mgr->config->GetConfigValue(HorizonOCConfigValue_EnableUnsafeDisplayFreqs) ? 65 : 60; - } else { - maxDisplay = mgr->config->GetConfigValue(HorizonOCConfigValue_EnableUnsafeDisplayFreqs) ? 72 : 60; + + u32 targetHz = mgr->context->overrideFreqs[HorizonOCModule_Display]; + if (!targetHz) + { + targetHz = mgr->config->GetAutoClockHz(mgr->context->applicationId, HorizonOCModule_Display, mgr->context->profile, false); + if(!targetHz) + targetHz = mgr->config->GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Display, mgr->context->profile, false); } - u8 minDisplay = Board::GetConsoleType() == HorizonOCConsoleType_Aula ? 40 : 45; + u8 maxDisplay; + if(targetHz) { + maxDisplay = targetHz; + } else { + if(Board::GetConsoleType() == HorizonOCConsoleType_Aula) { + maxDisplay = mgr->config->GetConfigValue(HorizonOCConfigValue_EnableUnsafeDisplayFreqs) ? 65 : 60; + } else { + maxDisplay = mgr->config->GetConfigValue(HorizonOCConfigValue_EnableUnsafeDisplayFreqs) ? 72 : 60; + } + } + + u8 minDisplay = Board::GetConsoleType() == HorizonOCConsoleType_Aula ? 45 : 40; + if(maxDisplay == minDisplay) + continue; + if(fps >= minDisplay && fps <= maxDisplay) Board::SetHz(HorizonOCModule_Display, fps); else { @@ -532,10 +549,10 @@ void ClockManager::VRRThread(void* arg) { } } } - if(++tick > 10) { + if(++tick > 50) { Board::ResetToStockDisplay(); tick = 0; - svcSleepThread(10'000'000); + svcSleepThread(25'000'000); } svcSleepThread(POLL_NS); @@ -598,12 +615,24 @@ void ClockManager::HandleGovernor(uint32_t targetHz) { GovernorState effectiveState = this->GetEffectiveGovernorState(appGovernorState, tempGovernorState); - bool newCpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpu || effectiveState == GovernorState_Enabled_Cpu); - bool newGpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpu || effectiveState == GovernorState_Enabled_Gpu); + bool newCpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpuVrr || + effectiveState == GovernorState_Enabled_CpuVrr || + effectiveState == GovernorState_Enabled_CpuGpu || + effectiveState == GovernorState_Enabled_Cpu); + bool newGpuGovernorState = (effectiveState == GovernorState_Enabled_CpuGpuVrr || + effectiveState == GovernorState_Enabled_GpuVrr || + effectiveState == GovernorState_Enabled_CpuGpu || + effectiveState == GovernorState_Enabled_Gpu); + + bool newVrrGovernorState = (effectiveState == GovernorState_Enabled_CpuGpuVrr || + effectiveState == GovernorState_Enabled_CpuVrr || + effectiveState == GovernorState_Enabled_GpuVrr || + effectiveState == GovernorState_Enabled_Vrr); + isCpuGovernorEnabled = newCpuGovernorState; isGpuGovernorEnabled = newGpuGovernorState; - + isVRREnabled = newVrrGovernorState; if(newCpuGovernorState == false && lastCpuGovernorState == true) { svcSleepThread(50'000'000); // thread syncing. probably a cleaner way to do this but hey, it works! Board::ResetToStockCpu(); @@ -612,11 +641,15 @@ void ClockManager::HandleGovernor(uint32_t targetHz) { svcSleepThread(50'000'000); Board::ResetToStockGpu(); } - - if(newCpuGovernorState != lastCpuGovernorState || newGpuGovernorState != lastGpuGovernorState) { - FileUtils::LogLine("[mgr] Governor state changed: CPU %s, GPU %s", newCpuGovernorState ? "enabled" : "disabled", newGpuGovernorState ? "enabled" : "disabled"); + if (newVrrGovernorState == false && lastVrrGovernorState == true) { + svcSleepThread(50'000'000); + Board::ResetToStockDisplay(); + } + if(newCpuGovernorState != lastCpuGovernorState || newGpuGovernorState != lastGpuGovernorState || newVrrGovernorState != lastVrrGovernorState) { + FileUtils::LogLine("[mgr] Governor state changed: CPU %s, GPU %s, VRR %s", newCpuGovernorState ? "enabled" : "disabled", newGpuGovernorState ? "enabled" : "disabled", newVrrGovernorState ? "enabled" : "disabled"); lastCpuGovernorState = newCpuGovernorState; lastGpuGovernorState = newGpuGovernorState; + lastVrrGovernorState = newVrrGovernorState; } } @@ -712,7 +745,7 @@ void ClockManager::HandleFreqReset(SysClkModule module, bool isBoost) { DVFSReset(); break; case HorizonOCModule_Display: - if(this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) { + if(this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate)) { Board::ResetToStockDisplay(); } break; @@ -756,7 +789,14 @@ void ClockManager::SetClocks(bool isBoost) { HandleGovernor(targetHz); } - if(module == HorizonOCModule_Display && this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) { + bool noCPU = isCpuGovernorEnabled; + bool noGPU = isGpuGovernorEnabled; + bool noDisp = isVRREnabled; + + if(noDisp && module == HorizonOCModule_Display) + continue; + + if(module == HorizonOCModule_Display && this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate)) { if(targetHz) Board::SetHz(HorizonOCModule_Display, targetHz); else @@ -768,8 +808,6 @@ void ClockManager::SetClocks(bool isBoost) { continue; } - bool noCPU = isCpuGovernorEnabled; - bool noGPU = isGpuGovernorEnabled; if(noCPU && module == SysClkModule_CPU) continue;