sysclk: add VRR
This commit is contained in:
@@ -45,6 +45,7 @@ typedef struct
|
||||
u16 iddq[HorizonOCSpeedo_EnumMax];
|
||||
GpuSchedulingMode gpuSchedulingMode;
|
||||
bool isSysDockInstalled;
|
||||
bool isSaltyNXInstalled;
|
||||
u8 maxDisplayFreq;
|
||||
u8 dramID;
|
||||
bool isDram8GB;
|
||||
|
||||
@@ -66,6 +66,8 @@ typedef enum {
|
||||
|
||||
HorizonOCConfigValue_RAMVoltUsageDisplayMode,
|
||||
|
||||
HorizonOCConfigValue_VRR,
|
||||
|
||||
KipConfigValue_custRev,
|
||||
// KipConfigValue_mtcConf,
|
||||
KipConfigValue_hpMode,
|
||||
@@ -250,6 +252,9 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
|
||||
case HorizonOCConfigValue_RAMVoltUsageDisplayMode:
|
||||
return pretty ? "RAM Voltage / Usage Display Mode" : "ram_volt_usage_display_mode";
|
||||
|
||||
case HorizonOCConfigValue_VRR:
|
||||
return pretty ? "Variable Refresh Rate (VRR)" : "vrr";
|
||||
|
||||
// KIP config values
|
||||
case KipConfigValue_custRev:
|
||||
return pretty ? "Custom Revision" : "kip_cust_rev";
|
||||
@@ -430,6 +435,7 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
|
||||
case HorizonOCConfigValue_GPUScheduling:
|
||||
case HorizonOCConfigValue_LiveCpuUv:
|
||||
case HorizonOCConfigValue_GPUSchedulingMethod:
|
||||
case HorizonOCConfigValue_VRR:
|
||||
return 0ULL;
|
||||
case HocClkConfigValue_EristaMaxCpuClock:
|
||||
return 1785ULL;
|
||||
@@ -479,6 +485,7 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
|
||||
case HorizonOCConfigValue_EnableExperimentalSettings:
|
||||
case HorizonOCConfigValue_LiveCpuUv:
|
||||
case HorizonOCConfigValue_GPUSchedulingMethod:
|
||||
case HorizonOCConfigValue_VRR:
|
||||
return (input & 0x1) == input;
|
||||
|
||||
case KipConfigValue_custRev:
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
tsl::elm::ListItem* SpeedoItem = NULL;
|
||||
tsl::elm::ListItem* IddqItem = NULL;
|
||||
tsl::elm::ListItem* sysdockStatusItem = NULL;
|
||||
tsl::elm::ListItem* saltyNXStatusItem = NULL;
|
||||
|
||||
ImageElement* CatImage = NULL;
|
||||
HideableCategoryHeader* CatHeader = NULL;
|
||||
HideableCustomDrawer* CatSpacer = NULL;
|
||||
@@ -57,6 +59,10 @@ void AboutGui::listUI()
|
||||
new tsl::elm::ListItem("sys-dock status:");
|
||||
this->listElement->addItem(sysdockStatusItem);
|
||||
|
||||
saltyNXStatusItem =
|
||||
new tsl::elm::ListItem("SaltyNX status:");
|
||||
this->listElement->addItem(saltyNXStatusItem);
|
||||
|
||||
this->listElement->addItem(
|
||||
new tsl::elm::CategoryHeader("Credits")
|
||||
);
|
||||
@@ -227,4 +233,5 @@ void AboutGui::refresh()
|
||||
SpeedoItem->setValue(strings[0]);
|
||||
IddqItem->setValue(strings[1]);
|
||||
sysdockStatusItem->setValue(this->context->isSysDockInstalled ? "Installed" : "Not Installed");
|
||||
saltyNXStatusItem->setValue(this->context->isSaltyNXInstalled ? "Installed" : "Not Installed");
|
||||
}
|
||||
@@ -168,8 +168,10 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
renderer->drawString(displayStrings[21], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Bat voltage
|
||||
renderer->drawString(displayStrings[23], false, positions[2] - 2, y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Bat Age
|
||||
|
||||
renderer->drawString(labels[14], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // FPS label
|
||||
renderer->drawString(displayStrings[26], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // FPS
|
||||
if(this->context->isSaltyNXInstalled) {
|
||||
renderer->drawString(labels[14], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // FPS label
|
||||
renderer->drawString(displayStrings[26], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // FPS
|
||||
}
|
||||
|
||||
y+=20;
|
||||
}
|
||||
@@ -285,12 +287,13 @@ void BaseMenuGui::refresh()
|
||||
sprintf(displayStrings[24], "%u%%", context->partLoad[HocClkPartLoad_FAN]);
|
||||
|
||||
sprintf(displayStrings[25], "%u Hz", context->realFreqs[HorizonOCModule_Display]);
|
||||
|
||||
if(context->fps == 254) {
|
||||
strcpy(displayStrings[26], "N/A");
|
||||
} else {
|
||||
memset(displayStrings[26], 0, sizeof(displayStrings[26]));
|
||||
sprintf(displayStrings[26], "%u", context->fps);
|
||||
if(this->context->isSaltyNXInstalled) {
|
||||
if(context->fps == 254) {
|
||||
strcpy(displayStrings[26], "N/A");
|
||||
} else {
|
||||
memset(displayStrings[26], 0, sizeof(displayStrings[26]));
|
||||
sprintf(displayStrings[26], "%u", context->fps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -366,6 +366,13 @@ void MiscGui::listUI()
|
||||
|
||||
addConfigButton(HorizonOCConfigValue_RAMVoltUsageDisplayMode, "RAM Voltage Display Mode", ValueRange(0, 12, 1, "", 0), "RAM Voltage Display Mode", &thresholdsDisabled, {}, ramVoltDispModes, false);
|
||||
|
||||
addConfigButton(
|
||||
HocClkConfigValue_LiteTDPLimit,
|
||||
"Polling Interval",
|
||||
ValueRange(50, 1000, 50, "ms", 1),
|
||||
"Polling Interval",
|
||||
&thresholdsDisabled
|
||||
);
|
||||
tsl::elm::ListItem* safetySubmenu = new tsl::elm::ListItem("Safety Settings");
|
||||
safetySubmenu->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
@@ -536,6 +543,7 @@ public:
|
||||
protected:
|
||||
void listUI() override {
|
||||
addConfigToggle(HorizonOCConfigValue_OverwriteRefreshRate, nullptr);
|
||||
addConfigToggle(HorizonOCConfigValue_VRR, nullptr);
|
||||
tsl::elm::CustomDrawer* warningText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
|
||||
renderer->drawString("\uE150 Enabling unsafe display", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
|
||||
renderer->drawString("refresh rates may cause stress", false, x + 20, y + 50, 18, tsl::style::color::ColorText);
|
||||
|
||||
@@ -55,11 +55,11 @@ bool hasChanged = true;
|
||||
ClockManager *ClockManager::instance = NULL;
|
||||
Thread cpuGovernorTHREAD;
|
||||
Thread gpuGovernorTHREAD;
|
||||
Thread vrrTHREAD;
|
||||
u32 initialConfigValues[SysClkConfigValue_EnumMax]; // initial config. used for safety checks
|
||||
bool kipAvailable = false;
|
||||
bool isCpuGovernorInBoostMode = false;
|
||||
|
||||
|
||||
ClockManager *ClockManager::GetInstance()
|
||||
{
|
||||
return instance;
|
||||
@@ -125,8 +125,15 @@ ClockManager::ClockManager()
|
||||
-2
|
||||
);
|
||||
|
||||
threadStart(&cpuGovernorTHREAD);
|
||||
threadStart(&gpuGovernorTHREAD);
|
||||
threadCreate(
|
||||
&vrrTHREAD,
|
||||
ClockManager::VRRThread,
|
||||
this,
|
||||
NULL,
|
||||
0x2000,
|
||||
0x3F,
|
||||
-2
|
||||
);
|
||||
|
||||
for(int i = 0; i < HorizonOCSpeedo_EnumMax; i++) {
|
||||
this->context->speedos[i] = Board::getSpeedo((HorizonOCSpeedo)i);
|
||||
@@ -137,13 +144,27 @@ ClockManager::ClockManager()
|
||||
this->context->isDram8GB = Board::IsDram8GB();
|
||||
Board::SetGpuSchedulingMode((GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling), (GpuSchedulingOverrideMethod)this->config->GetConfigValue(HorizonOCConfigValue_GPUSchedulingMethod));
|
||||
this->context->gpuSchedulingMode = (GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling);
|
||||
|
||||
this->context->isSysDockInstalled = this->sysDockIntegration->getCurrentSysDockState();
|
||||
this->context->isSaltyNXInstalled = this->saltyNXIntegration->getCurrentSaltyNXState();
|
||||
if(this->context->isSaltyNXInstalled) {
|
||||
this->saltyNXIntegration->LoadSaltyNX();
|
||||
}
|
||||
|
||||
|
||||
threadStart(&cpuGovernorTHREAD);
|
||||
threadStart(&gpuGovernorTHREAD);
|
||||
threadStart(&vrrTHREAD);
|
||||
}
|
||||
|
||||
ClockManager::~ClockManager()
|
||||
{
|
||||
threadClose(&cpuGovernorTHREAD);
|
||||
threadClose(&gpuGovernorTHREAD);
|
||||
threadClose(&vrrTHREAD);
|
||||
|
||||
delete this->sysDockIntegration;
|
||||
delete this->saltyNXIntegration;
|
||||
delete this->config;
|
||||
delete this->context;
|
||||
}
|
||||
@@ -461,6 +482,67 @@ void ClockManager::GovernorThread(void* arg) {
|
||||
svcSleepThread(POLL_NS);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{mgr->contextMutex};
|
||||
|
||||
u8 fps;
|
||||
|
||||
if(mgr->context->isSaltyNXInstalled) {
|
||||
fps = mgr->saltyNXIntegration->GetFPS();
|
||||
} else {
|
||||
svcSleepThread(~0ULL); // effectively disable the thread if SaltyNX isn't installed, as there's no point in it running
|
||||
continue;
|
||||
}
|
||||
|
||||
if(fps == 254)
|
||||
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;
|
||||
}
|
||||
|
||||
u8 minDisplay = Board::GetConsoleType() == HorizonOCConsoleType_Aula ? 40 : 45;
|
||||
if(fps >= minDisplay && fps <= maxDisplay)
|
||||
Board::SetHz(HorizonOCModule_Display, fps);
|
||||
else {
|
||||
for(u32 i = 0; i < 10; i++) {
|
||||
u32 compareHz = fps * i;
|
||||
if(compareHz >= minDisplay && compareHz <= maxDisplay) {
|
||||
Board::SetHz(HorizonOCModule_Display, compareHz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(++tick > 10) {
|
||||
Board::ResetToStockDisplay();
|
||||
tick = 0;
|
||||
svcSleepThread(10'000'000);
|
||||
}
|
||||
|
||||
svcSleepThread(POLL_NS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GovernorState ClockManager::GetEffectiveGovernorState(GovernorState appState, GovernorState tempState)
|
||||
{
|
||||
if (tempState == GovernorState_Disabled)
|
||||
@@ -625,6 +707,12 @@ void ClockManager::HandleFreqReset(SysClkModule module, bool isBoost) {
|
||||
case SysClkModule_MEM:
|
||||
Board::ResetToStockMem();
|
||||
DVFSReset();
|
||||
break;
|
||||
case HorizonOCModule_Display:
|
||||
if(this->config->GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && Board::GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
Board::ResetToStockDisplay();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -890,8 +978,10 @@ bool ClockManager::RefreshContext()
|
||||
|
||||
if(Board::GetConsoleType() != HorizonOCConsoleType_Hoag)
|
||||
Board::SetDisplayRefreshDockedState(this->context->profile == SysClkProfile_Docked);
|
||||
|
||||
this->context->fps = saltyNXIntegration->GetFPS();
|
||||
if(this->context->isSaltyNXInstalled)
|
||||
this->context->fps = saltyNXIntegration->GetFPS();
|
||||
else
|
||||
this->context->fps = 254; // N/A
|
||||
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
@@ -185,6 +185,13 @@ class ClockManager
|
||||
*/
|
||||
static void GovernorThread(void* arg);
|
||||
|
||||
/**
|
||||
* Runs the VRR Algorithm
|
||||
*
|
||||
* @param arg Cast to ClockManager* for context
|
||||
*/
|
||||
static void VRRThread(void* arg);
|
||||
|
||||
/**
|
||||
* Gets the effective governor state from application/temporary override
|
||||
*
|
||||
|
||||
@@ -26,18 +26,22 @@ SysDockIntegration::SysDockIntegration() {
|
||||
|
||||
bool SysDockIntegration::getCurrentSysDockState() {
|
||||
struct stat st = {0};
|
||||
if (stat("sdmc:/atmosphere/contents/42000000000000A0", &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return stat("sdmc:/atmosphere/contents/42000000000000A0/flags/boot2.flag", &st) == 0;
|
||||
}
|
||||
|
||||
SaltyNXIntegration::SaltyNXIntegration() {
|
||||
}
|
||||
|
||||
void SaltyNXIntegration::LoadSaltyNX() {
|
||||
if (!CheckPort())
|
||||
return;
|
||||
LoadSharedMemory();
|
||||
}
|
||||
|
||||
bool SaltyNXIntegration::getCurrentSaltyNXState() {
|
||||
struct stat st = {0};
|
||||
return stat("sdmc:/atmosphere/contents/0000000000534C56/flags/boot2.flag", &st) == 0;
|
||||
}
|
||||
|
||||
bool SaltyNXIntegration::CheckPort() {
|
||||
Handle saltysd;
|
||||
@@ -103,5 +107,4 @@ u8 SaltyNXIntegration::GetFPS() {
|
||||
}
|
||||
|
||||
return NxFps ? NxFps->FPS : 254;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -83,6 +83,8 @@ public:
|
||||
bool SharedMemoryUsed = false;
|
||||
Handle remoteSharedMemory = 1;
|
||||
SaltyNXIntegration();
|
||||
void LoadSaltyNX();
|
||||
bool getCurrentSaltyNXState();
|
||||
|
||||
bool CheckPort();
|
||||
void LoadSharedMemory();
|
||||
|
||||
Reference in New Issue
Block a user