sysclk: add per-game VRR setting

This commit is contained in:
souldbminersmwc
2026-03-13 18:35:38 -04:00
parent 7434c22772
commit a40ea357db
7 changed files with 131 additions and 89 deletions

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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<NamedValue> 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<NamedValue> 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()

View File

@@ -290,6 +290,17 @@ void GlobalOverrideGui::addModuleToggleItem(SysClkModule module)
this->listItems[module] = toggle;
}
std::vector<NamedValue> 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<NamedValue> 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<NamedValue> 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<NamedValue> 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;

View File

@@ -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<DisplaySubMenuGui>();
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<DisplaySubMenuGui>();
return true;
}
return false;
});
this->listElement->addItem(displaySubMenu);
#if IS_MINIMAL == 0
// std::vector<NamedValue> chargerCurrents = {
// NamedValue("Disabled", 0),

View File

@@ -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() {

View File

@@ -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<ClockManager*>(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;