diff --git a/Source/sys-clk/build.bat b/Source/sys-clk/build.bat deleted file mode 100644 index 0b273727..00000000 --- a/Source/sys-clk/build.bat +++ /dev/null @@ -1,61 +0,0 @@ -@echo off -setlocal enabledelayedexpansion - -REM --- Root directory --- -set ROOT_DIR=%~dp0 -set DIST_DIR=%ROOT_DIR%dist - -REM --- Number of CPU cores --- -set CORES=%NUMBER_OF_PROCESSORS% - -REM --- Optional first argument as DIST_DIR --- -if not "%~1"=="" set DIST_DIR=%~1 - -echo DIST_DIR: %DIST_DIR% -echo CORES: %CORES% - -REM ======================== -REM sysmodule -REM ======================== -echo *** sysmodule *** - -REM Extract TITLE_ID from perms.json using findstr (rough approximation) -for /f "tokens=2 delims=: " %%A in ('findstr /i "title_id" "%ROOT_DIR%sysmodule\perms.json"') do ( - set TITLE_ID=%%A -) - -REM Remove quotes and 0x prefix -set TITLE_ID=!TITLE_ID:"=! -set TITLE_ID=!TITLE_ID:0x=! - -REM Build sysmodule -pushd "%ROOT_DIR%sysmodule" -make -j %CORES% -popd - -REM Copy sysmodule files to dist -if not exist "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\flags" mkdir "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\flags" -copy /Y "%ROOT_DIR%sysmodule\out\horizon-oc.nsp" "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\exefs.nsp" -type nul > "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\flags\boot2.flag" -copy /Y "%ROOT_DIR%sysmodule\toolbox.json" "%DIST_DIR%\atmosphere\contents\%TITLE_ID%\toolbox.json" - -REM ======================== -REM overlay -REM ======================== -echo *** overlay *** -pushd "%ROOT_DIR%overlay" -make -j %CORES% -popd - -if not exist "%DIST_DIR%\switch\.overlays" mkdir "%DIST_DIR%\switch\.overlays" -copy /Y "%ROOT_DIR%overlay\out\horizon-oc-overlay.ovl" "%DIST_DIR%\switch\.overlays\horizon-oc-overlay.ovl" - -REM ======================== -REM assets -REM ======================== -echo *** assets *** -if not exist "%DIST_DIR%\config\horizon-oc" mkdir "%DIST_DIR%\config\horizon-oc" -copy /Y "%ROOT_DIR%config.ini.template" "%DIST_DIR%\config\horizon-oc\config.ini.template" -copy /Y "%ROOT_DIR%..\..\README.md" "%DIST_DIR%\README.md" - -endlocal diff --git a/Source/sys-clk/build.sh b/Source/sys-clk/build.sh index 05cc45c0..fbd37070 100644 --- a/Source/sys-clk/build.sh +++ b/Source/sys-clk/build.sh @@ -36,3 +36,7 @@ echo "*** assets ***" mkdir -p "$DIST_DIR/config/horizon-oc" cp -vf "$ROOT_DIR/config.ini.template" "$DIST_DIR/config/horizon-oc/config.ini.template" cp -vf "$ROOT_DIR/../../README.md" "$DIST_DIR/README.md" + +echo "*** lang ***" + +cp -r "$ROOT_DIR/overlay/lang/" "$DIST_DIR/config/horizon-oc/lang/" diff --git a/Source/sys-clk/common/include/sysclk/board.h b/Source/sys-clk/common/include/sysclk/board.h index 46bd9b1f..c4175041 100644 --- a/Source/sys-clk/common/include/sysclk/board.h +++ b/Source/sys-clk/common/include/sysclk/board.h @@ -123,7 +123,7 @@ typedef enum { } GPUUndervoltLevel; enum { - DVFSMode_Disabled, + DVFSMode_Disabled = 0, DVFSMode_Hijack, // DVFSMode_OfficialService, // DVFSMode_Hack, @@ -137,6 +137,15 @@ typedef enum { GpuSchedulingMode_EnumMax, } GpuSchedulingMode; +typedef enum { + GovernorState_DoNotOverride = 0, + GovernorState_Disabled, + GovernorState_Enabled_CpuGpu, + GovernorState_Enabled_Cpu, + GovernorState_Enabled_Gpu, + GovernorState_EnumMax, +} GovernorState; + #define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax) static inline const char* sysclkFormatModule(SysClkModule module, bool pretty) 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 92945126..6e0153c9 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 @@ -149,6 +149,36 @@ void AppProfileGui::addModuleListItemToggle(SysClkProfile profile, SysClkModule this->listElement->addItem(toggle); } +std::string AppProfileGui::formatValueDisplay( + std::uint32_t value, + const std::vector& namedValues, + const std::string& suffix, + std::uint32_t divisor, + int decimalPlaces +) +{ + if (value == 0) { + return FREQ_DEFAULT_TEXT; + } + + if (!namedValues.empty()) { + for (const auto& namedValue : namedValues) { + if (namedValue.value == value) { + return namedValue.name; + } + } + } + + char buf[32]; + if (decimalPlaces > 0) { + double displayValue = (double)value / divisor; + snprintf(buf, sizeof(buf), "%.*f%s", decimalPlaces, displayValue, suffix.c_str()); + } else { + snprintf(buf, sizeof(buf), "%u%s", value / divisor, suffix.c_str()); + } + return std::string(buf); +} + void AppProfileGui::addModuleListItemValue( SysClkProfile profile, SysClkModule module, @@ -160,24 +190,16 @@ void AppProfileGui::addModuleListItemValue( std::uint32_t divisor, int decimalPlaces, ValueThresholds thresholds, - std::vector namedValues + std::vector namedValues, + bool showDefaultValue ) { tsl::elm::ListItem* listItem = new tsl::elm::ListItem(sysclkFormatModule(module, true)); std::uint32_t storedValue = this->profileList->mhzMap[profile][module]; - if (storedValue == 0) { - listItem->setValue(FREQ_DEFAULT_TEXT); - } else { - char buf[32]; - if (decimalPlaces > 0) { - double displayValue = (double)storedValue / divisor; - snprintf(buf, sizeof(buf), "%.*f%s", decimalPlaces, displayValue, suffix.c_str()); - } else { - snprintf(buf, sizeof(buf), "%u%s", storedValue / divisor, suffix.c_str()); - } - listItem->setValue(buf); - } + + listItem->setValue(this->formatValueDisplay(storedValue, namedValues, suffix, divisor, decimalPlaces)); + listItem->setClickListener( [this, listItem, @@ -191,7 +213,8 @@ void AppProfileGui::addModuleListItemValue( divisor, decimalPlaces, thresholds, - namedValues](u64 keys) + namedValues, + showDefaultValue](u64 keys) { if ((keys & HidNpadButton_A) == HidNpadButton_A) { @@ -210,23 +233,11 @@ void AppProfileGui::addModuleListItemValue( currentValue, range, categoryName, - [this, listItem, profile, module, divisor, suffix, decimalPlaces, thresholds](std::uint32_t value) -> bool + [this, listItem, profile, module, divisor, suffix, decimalPlaces, thresholds, namedValues](std::uint32_t value) -> bool { this->profileList->mhzMap[profile][module] = value / divisor; - if (value == 0) { - listItem->setValue(FREQ_DEFAULT_TEXT); - } else { - char buf[32]; - if (decimalPlaces > 0) { - double displayValue = (double)value / divisor; - snprintf(buf, sizeof(buf), "%.*f%s", - decimalPlaces, displayValue, suffix.c_str()); - } else { - snprintf(buf, sizeof(buf), "%u%s", - value / divisor, suffix.c_str()); - } - listItem->setValue(buf); - } + listItem->setValue(this->formatValueDisplay(value / divisor, namedValues, suffix, divisor, decimalPlaces)); + Result rc = sysclkIpcSetProfiles(this->applicationId, this->profileList); @@ -242,7 +253,7 @@ void AppProfileGui::addModuleListItemValue( false, {}, namedValues, - true + showDefaultValue ); return true; } @@ -355,7 +366,15 @@ void AppProfileGui::addProfileUI(SysClkProfile profile) } } #endif - this->addModuleListItemToggle(profile, HorizonOCModule_Governor); + 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), + }; + + this->addModuleListItemValue(profile, HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), governorSettings, false); } void AppProfileGui::listUI() @@ -395,4 +414,4 @@ void AppProfileGui::update() "" ); } -} +} \ No newline at end of file diff --git a/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.h b/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.h index f6697b1a..4981cb72 100644 --- a/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.h +++ b/Source/sys-clk/overlay/src/ui/gui/app_profile_gui.h @@ -23,22 +23,17 @@ * stuff is worth it, you can buy us a beer in return. - The sys-clk authors * -------------------------------------------------------------------------- */ - - #pragma once - #include "../../ipc.h" #include "base_menu_gui.h" #include "freq_choice_gui.h" #include "value_choice_gui.h" #define SYSCLK_GLOBAL_PROFILE_TID 0xA111111111111111 - class AppProfileGui : public BaseMenuGui { protected: std::uint64_t applicationId; SysClkTitleProfileList* profileList; - void openFreqChoiceGui(tsl::elm::ListItem* listItem, SysClkProfile profile, SysClkModule module); void addModuleListItem(SysClkProfile profile, SysClkModule module); void addModuleListItemToggle(SysClkProfile profile, SysClkModule module); @@ -54,6 +49,13 @@ class AppProfileGui : public BaseMenuGui const std::vector& namedValues = {}, bool showDefaultValue = true ); + std::string formatValueDisplay( + std::uint32_t value, + const std::vector& namedValues, + const std::string& suffix, + std::uint32_t divisor, + int decimalPlaces + ); void addModuleListItemValue( SysClkProfile profile, SysClkModule module, @@ -65,14 +67,14 @@ class AppProfileGui : public BaseMenuGui std::uint32_t divisor, int decimalPlaces, ValueThresholds thresholds, - std::vector namedValues = {} + std::vector namedValues = {}, + bool showDefaultValue = true ); void addProfileUI(SysClkProfile profile); - public: AppProfileGui(std::uint64_t applicationId, SysClkTitleProfileList* profileList); ~AppProfileGui(); void listUI() override; static void changeTo(std::uint64_t applicationId); void update() override; -}; +}; \ No newline at end of file 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 c6aa6e3f..55450d0a 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 @@ -99,11 +99,16 @@ void GlobalOverrideGui::addModuleListItemValue( const std::string& suffix, std::uint32_t divisor, int decimalPlaces, - ValueThresholds thresholds + ValueThresholds thresholds, + const std::vector& namedValues, + bool showDefaultValue ) { + bool hasNamedValues = !namedValues.empty(); - this->customFormatModules[module] = std::make_tuple(suffix, divisor, decimalPlaces); + if (!hasNamedValues) { + this->customFormatModules[module] = std::make_tuple(suffix, divisor, decimalPlaces); + } tsl::elm::ListItem* listItem = new tsl::elm::ListItem(sysclkFormatModule(module, true)); @@ -121,7 +126,10 @@ void GlobalOverrideGui::addModuleListItemValue( suffix, divisor, decimalPlaces, - thresholds](u64 keys) + thresholds, + namedValues, + hasNamedValues, + showDefaultValue](u64 keys) { if ((keys & HidNpadButton_A) == HidNpadButton_A) { @@ -147,7 +155,7 @@ void GlobalOverrideGui::addModuleListItemValue( range, categoryName, - [this, listItem, module, divisor, suffix, decimalPlaces, thresholds](std::uint32_t value) -> bool + [this, listItem, module, divisor, suffix, decimalPlaces, thresholds, namedValues, hasNamedValues, showDefaultValue](std::uint32_t value) -> bool { if (!this->context) { return false; @@ -158,6 +166,13 @@ void GlobalOverrideGui::addModuleListItemValue( if (value == 0) { listItem->setValue(FREQ_DEFAULT_TEXT); + } else if (hasNamedValues) { + for (const auto& namedValue : namedValues) { + if (namedValue.value == value / divisor) { + listItem->setValue(namedValue.name); + break; + } + } } else { char buf[32]; if (decimalPlaces > 0) { @@ -188,8 +203,8 @@ void GlobalOverrideGui::addModuleListItemValue( thresholds, false, std::map(), - std::vector(), - true + namedValues, + showDefaultValue ); return true; @@ -294,7 +309,16 @@ void GlobalOverrideGui::listUI() if(!IsHoag() && 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 - this->addModuleToggleItem(HorizonOCModule_Governor); + + 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), + }; + + this->addModuleListItemValue(HorizonOCModule_Governor, "Governor", 0, 0, 1, "", 1, 0, ValueThresholds(), governorSettings, false); } void GlobalOverrideGui::refresh() @@ -306,17 +330,30 @@ void GlobalOverrideGui::refresh() for (std::uint16_t m = 0; m < SysClkModule_EnumMax; m++) { if (m == HorizonOCModule_Governor) { - auto *toggle = - static_cast(this->listItems[m]); - if (!toggle) - continue; - - bool newState = this->context->overrideFreqs[m] != 0; - - if (toggle->getState() != newState) { - toggle->setState(newState); + if (this->listItems[m] != nullptr && + this->listHz[m] != this->context->overrideFreqs[m]) { + + 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) { + if (setting.value == currentValue) { + displayText = setting.name; + break; + } + } + + this->listItems[m]->setValue(displayText); + this->listHz[m] = currentValue; } - continue; } diff --git a/Source/sys-clk/overlay/src/ui/gui/global_override_gui.h b/Source/sys-clk/overlay/src/ui/gui/global_override_gui.h index 9b86f39e..3c198851 100644 --- a/Source/sys-clk/overlay/src/ui/gui/global_override_gui.h +++ b/Source/sys-clk/overlay/src/ui/gui/global_override_gui.h @@ -1,4 +1,5 @@ /* + * * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors * * This program is free software; you can redistribute it and/or modify it @@ -23,10 +24,7 @@ * stuff is worth it, you can buy us a beer in return. - The sys-clk authors * -------------------------------------------------------------------------- */ - - #pragma once - #include "../../ipc.h" #include "base_menu_gui.h" #include "freq_choice_gui.h" @@ -63,7 +61,9 @@ class GlobalOverrideGui : public BaseMenuGui const std::string& suffix, std::uint32_t divisor, int decimalPlaces, - ValueThresholds thresholds = {} + ValueThresholds thresholds = {}, + const std::vector& namedValues = {}, + bool showDefaultValue = true ); public: GlobalOverrideGui(); @@ -71,4 +71,4 @@ class GlobalOverrideGui : public BaseMenuGui void listUI() override; void refresh() override; void setModuleCustomFormat(SysClkModule module, const std::string& suffix, std::uint32_t divisor, int decimalPlaces); -}; +}; \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/board.cpp b/Source/sys-clk/sysmodule/src/board.cpp index 4cc7fe45..650c4c39 100644 --- a/Source/sys-clk/sysmodule/src/board.cpp +++ b/Source/sys-clk/sysmodule/src/board.cpp @@ -471,7 +471,7 @@ void Board::SetHz(SysClkModule module, std::uint32_t hz) rc = clkrstSetClockRate(&session, hz); ASSERT_RESULT_OK(rc, "clkrstSetClockRate"); if (module == SysClkModule_CPU) { - svcSleepThread(300'000); + svcSleepThread(200'000); rc = clkrstSetClockRate(&session, hz); ASSERT_RESULT_OK(rc, "clkrstSetClockRate"); } @@ -482,7 +482,7 @@ void Board::SetHz(SysClkModule module, std::uint32_t hz) rc = pcvSetClockRate(Board::GetPcvModule(module), hz); ASSERT_RESULT_OK(rc, "pcvSetClockRate"); if (module == SysClkModule_CPU) { - svcSleepThread(300'000); + svcSleepThread(200'000); rc = pcvSetClockRate(Board::GetPcvModule(module), hz); ASSERT_RESULT_OK(rc, "pcvSetClockRate"); } diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp index f8f7df08..313499fa 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.cpp +++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp @@ -41,14 +41,18 @@ #include #define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0)) -bool isGovernorEnabled = false; // to avoid thread messes -bool lastGovernorState = false; +bool isGpuGovernorEnabled = false; +bool isCpuGovernorEnabled = false; +bool lastGpuGovernorState = false; +bool lastCpuGovernorState = false; bool hasChanged = true; ClockManager *ClockManager::instance = NULL; -Thread governorTHREAD; +Thread cpuGovernorTHREAD; +Thread gpuGovernorTHREAD; u32 initialConfigValues[SysClkConfigValue_EnumMax]; // initial config. used for safety checks u64 previousRamHz; bool kipAvailable = false; +bool isCpuGovernorInBoostMode = false; ClockManager *ClockManager::GetInstance() { @@ -92,8 +96,19 @@ ClockManager::ClockManager() this->sysDockIntegration = new SysDockIntegration; memset(&initialConfigValues, 0, sizeof(initialConfigValues)); this->GetKipData(); + threadCreate( - &governorTHREAD, + &cpuGovernorTHREAD, + ClockManager::CpuGovernorThread, + this, + NULL, + 0x2000, + 0x3F, + -2 + ); + + threadCreate( + &gpuGovernorTHREAD, ClockManager::GovernorThread, this, NULL, @@ -102,7 +117,8 @@ ClockManager::ClockManager() -2 ); - threadStart(&governorTHREAD); + threadStart(&cpuGovernorTHREAD); + threadStart(&gpuGovernorTHREAD); for(int i = 0; i < HorizonOCSpeedo_EnumMax; i++) { this->context->speedos[i] = Board::getSpeedo((HorizonOCSpeedo)i); @@ -119,7 +135,8 @@ ClockManager::ClockManager() ClockManager::~ClockManager() { - threadClose(&governorTHREAD); + threadClose(&cpuGovernorTHREAD); + threadClose(&gpuGovernorTHREAD); delete this->config; delete this->context; } @@ -311,6 +328,160 @@ u32 findIndexMHz(u32 arr[], u32 size, u32 value) { return 0; } +void ClockManager::CpuGovernorThread(void* arg) +{ + ClockManager* mgr = static_cast(arg); + + for (;;) + { + if (!mgr->running) + { + svcSleepThread(50'000'000); + continue; + } + + if (!isCpuGovernorEnabled) + { + svcSleepThread(50'000'000); + continue; + } + + std::uint32_t mode = 0; + Result rc = apmExtGetCurrentPerformanceConfiguration(&mode); + bool isInBoostMode = R_SUCCEEDED(rc) && apmExtIsBoostMode(mode); + + if (isInBoostMode) + { + isCpuGovernorInBoostMode = true; + svcSleepThread(50'000'000); + continue; + } + + isCpuGovernorInBoostMode = false; + + auto& table = mgr->freqTable[SysClkModule_CPU]; + if (table.count == 0) + { + svcSleepThread(50'000'000); + continue; + } + + std::scoped_lock lock{mgr->contextMutex}; + + u32 currentHz = Board::GetHz(SysClkModule_CPU); + + u32 index = table.count - 1; + for (u32 i = 0; i < table.count; i++) + { + if (table.list[i] == currentHz) + { + index = i; + break; + } + } + + if (table.list[index] != currentHz) + { + for (u32 i = 0; i < table.count; i++) + { + if (table.list[i] >= currentHz) + { + index = i; + break; + } + } + } + + u32 targetHz = mgr->context->overrideFreqs[SysClkModule_CPU]; + if (!targetHz) + { + targetHz = mgr->config->GetAutoClockHz( + mgr->context->applicationId, + SysClkModule_CPU, + mgr->context->profile, + false + ); + + if (!targetHz) + { + targetHz = mgr->config->GetAutoClockHz( + GLOBAL_PROFILE_ID, + SysClkModule_CPU, + mgr->context->profile, + false + ); + } + } + + int gpuLoad = Board::GetPartLoad(HocClkPartLoad_GPU); + int cpuLoad = Board::GetPartLoad(HocClkPartLoad_CPUMax); + + if (isGpuGovernorEnabled && gpuLoad < 800) + { + if (cpuLoad < 600 && index > 0) + { + index--; + } + else if (cpuLoad > 800 && index + 1 < table.count) + { + index++; + } + } + else + { + if (cpuLoad < 600 && index > 0) + { + index--; + } + else if (cpuLoad > 800 && index + 1 < table.count) + { + index++; + } + } + + u32 maxHz = mgr->GetMaxAllowedHz(SysClkModule_CPU, mgr->context->profile); + + if (targetHz) + { + u32 targetIndex = table.count - 1; + for (u32 i = 0; i < table.count; i++) + { + if (table.list[i] >= targetHz) + { + targetIndex = i; + break; + } + } + + if (index > targetIndex) + { + index = targetIndex; + } + } + + if (maxHz > 0 && table.list[index] > maxHz) + { + for (u32 i = table.count; i > 0; i--) + { + if (table.list[i - 1] <= maxHz) + { + index = i - 1; + break; + } + } + } + + u32 newHz = table.list[index]; + if (mgr->IsAssignableHz(SysClkModule_CPU, newHz)) + { + Board::SetHz(SysClkModule_CPU, newHz); + mgr->context->freqs[SysClkModule_CPU] = newHz; + } + + svcSleepThread(50'000'000); + } +} + void ClockManager::GovernorThread(void* arg) { ClockManager* mgr = static_cast(arg); @@ -323,8 +494,7 @@ void ClockManager::GovernorThread(void* arg) continue; } - - if (!isGovernorEnabled) + if (!isGpuGovernorEnabled) { svcSleepThread(50'000'000); continue; @@ -341,7 +511,7 @@ void ClockManager::GovernorThread(void* arg) u32 currentHz = Board::GetHz(SysClkModule_GPU); - u32 index = 0; + u32 index = table.count - 1; for (u32 i = 0; i < table.count; i++) { if (table.list[i] == currentHz) @@ -351,6 +521,18 @@ void ClockManager::GovernorThread(void* arg) } } + if (table.list[index] != currentHz) + { + for (u32 i = 0; i < table.count; i++) + { + if (table.list[i] >= currentHz) + { + index = i; + break; + } + } + } + u32 targetHz = mgr->context->overrideFreqs[SysClkModule_GPU]; if (!targetHz) { @@ -372,17 +554,34 @@ void ClockManager::GovernorThread(void* arg) } } - int load = Board::GetPartLoad(HocClkPartLoad_GPU); + int gpuLoad = Board::GetPartLoad(HocClkPartLoad_GPU); + int cpuLoad = Board::GetPartLoad(HocClkPartLoad_CPUMax); - if (load < 600 && index > 0) + if (isCpuGovernorEnabled && !isCpuGovernorInBoostMode && cpuLoad < 600) { - index--; + if (gpuLoad < 600 && index > 0) + { + index--; + } + else if (gpuLoad > 750 && index + 1 < table.count) + { + index++; + } } - else if (load > 800 && index + 1 < table.count) + else { - index++; + if (gpuLoad < 600 && index > 0) + { + index--; + } + else if (gpuLoad > 800 && index + 1 < table.count) + { + index++; + } } + u32 maxHz = mgr->GetMaxAllowedHz(SysClkModule_GPU, mgr->context->profile); + if (targetHz) { u32 targetIndex = table.count - 1; @@ -401,6 +600,17 @@ void ClockManager::GovernorThread(void* arg) } } + if (maxHz > 0 && table.list[index] > maxHz) + { + for (u32 i = table.count; i > 0; i--) + { + if (table.list[i - 1] <= maxHz) + { + index = i - 1; + break; + } + } + } u32 newHz = table.list[index]; if (mgr->IsAssignableHz(SysClkModule_GPU, newHz)) @@ -415,6 +625,19 @@ void ClockManager::GovernorThread(void* arg) bool prevBoostMode = true; +GovernorState ClockManager::GetEffectiveGovernorState(GovernorState appState, GovernorState tempState) +{ + if (tempState == GovernorState_Disabled) + { + return GovernorState_Disabled; + } + if (tempState != GovernorState_DoNotOverride) + { + return tempState; + } + return appState; +} + void ClockManager::Tick() { std::scoped_lock lock{this->contextMutex}; @@ -454,8 +677,6 @@ void ClockManager::Tick() // } prevBoostMode = isBoost; - bool noGPU = false; - if (this->RefreshContext() || this->config->Refresh()) { @@ -490,15 +711,32 @@ void ClockManager::Tick() } if(module == HorizonOCModule_Governor) { - bool newGovernorState = targetHz; - if(newGovernorState != lastGovernorState) { - FileUtils::LogLine("[mgr] Governor state changed: %s", newGovernorState ? "enabled" : "disabled"); - lastGovernorState = newGovernorState; + GovernorState appGovernorState = (GovernorState)targetHz; + + u32 tempTargetHz = this->context->overrideFreqs[HorizonOCModule_Governor]; + if (!tempTargetHz) + { + tempTargetHz = this->config->GetAutoClockHz(this->context->applicationId, HorizonOCModule_Governor, this->context->profile, returnRaw); + if(!tempTargetHz) + tempTargetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Governor, this->context->profile, returnRaw); + } + GovernorState tempGovernorState = (GovernorState)tempTargetHz; + + 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); + + if(newCpuGovernorState != lastCpuGovernorState || newGpuGovernorState != lastGpuGovernorState) { + FileUtils::LogLine("[mgr] Governor state changed: CPU %s, GPU %s", newCpuGovernorState ? "enabled" : "disabled", newGpuGovernorState ? "enabled" : "disabled"); + lastCpuGovernorState = newCpuGovernorState; + lastGpuGovernorState = newGpuGovernorState; hasChanged = true; Board::ResetToStock(); } - isGovernorEnabled = newGovernorState; + isCpuGovernorEnabled = newCpuGovernorState; + isGpuGovernorEnabled = newGpuGovernorState; } if(module == HorizonOCModule_Display && this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) { @@ -512,15 +750,16 @@ void ClockManager::Tick() if(targetHz && this->context->realFreqs[HorizonOCModule_Display] != targetHz && module == HorizonOCModule_Display) this->context->realFreqs[HorizonOCModule_Display] = targetHz; - // Skip GPU if governor handles it + // Skip GPU and CPU if governors handle them if(module > SysClkModule_MEM) { continue; } - if(isGovernorEnabled) { - noGPU = true; - } else { - noGPU = false; - } + + bool noCPU = isCpuGovernorEnabled; + bool noGPU = isGpuGovernorEnabled; + + if(noCPU && module == SysClkModule_CPU) + continue; if(noGPU && module == SysClkModule_GPU) continue; @@ -1065,4 +1304,4 @@ void ClockManager::GetKipData() { FileUtils::LogLine("[clock_manager] Config refresh error in GetKipData!"); writeNotification("Horizon OC\nConfig refresh failed"); } -} +} \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/clock_manager.h b/Source/sys-clk/sysmodule/src/clock_manager.h index 4c27ecad..45dfc745 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.h +++ b/Source/sys-clk/sysmodule/src/clock_manager.h @@ -23,33 +23,24 @@ * stuff is worth it, you can buy us a beer in return. - The sys-clk authors * -------------------------------------------------------------------------- */ - - #pragma once - #include #include #include - #include "config.h" #include "board.h" #include #include "integrations.h" -void governorThread(void*); class SysDockIntegration; - class ClockManager { public: static ClockManager* GetInstance(); static void Initialize(); static void Exit(); - - ClockManager(); virtual ~ClockManager(); - SysClkContext GetCurrentContext(); Config* GetConfig(); void SetRunning(bool running); @@ -60,7 +51,9 @@ class ClockManager void WaitForNextTick(); void SetKipData(); void GetKipData(); + static void CpuGovernorThread(void* arg); static void GovernorThread(void* arg); + GovernorState GetEffectiveGovernorState(GovernorState appState, GovernorState tempState); struct { std::uint32_t count; std::uint32_t list[SYSCLK_FREQ_LIST_MAX]; @@ -75,9 +68,7 @@ class ClockManager bool ConfigIntervalTimeout(SysClkConfigValue intervalMsConfigValue, std::uint64_t ns, std::uint64_t* lastLogNs); void RefreshFreqTableRow(SysClkModule module); bool RefreshContext(); - static ClockManager *instance; - std::atomic_bool running; LockableMutex contextMutex; Config* config; @@ -87,4 +78,4 @@ class ClockManager std::uint64_t lastPowerLogNs; std::uint64_t lastCsvWriteNs; SysDockIntegration *sysDockIntegration; -}; +}; \ No newline at end of file