Skip to content

Commit

Permalink
Add "Game Resolutions" menu (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
masagrator authored Aug 4, 2024
1 parent d221717 commit 334036d
Show file tree
Hide file tree
Showing 7 changed files with 342 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ include $(DEVKITPRO)/libnx/switch_rules
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
APP_TITLE := Status Monitor
APP_VERSION := 1.0.4
APP_VERSION := 1.1.0
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
Expand Down
7 changes: 7 additions & 0 deletions config/status-monitor/config.ini.template
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,10 @@ dashed_line_color=#8888
main_line_color=#FFFF
rounded_line_color=#F0FF
perfect_line_color=#0C0F
[game_resolutions]
refresh_rate=10
layer_width_align=left
layer_height_align=top
background_color=#1117
cat_color=#FFFF
text_color=#FFFF
11 changes: 11 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,14 @@ Colors are provided in RGBA4444 format, which means that each character represen
| `main_line_color` | Color of line representing FPS value on graph in RGBA4444 format | From `#0000` to `#FFFF` | `#FFFF` |
| `rounded_line_color` | Color of line representing FPS value on graph if it's divisble by 10 in RGBA4444 format | From `#0000` to `#FFFF` | `#F0FF` |
| `perfect_line_color` | Color of line representing FPS value on graph if it's divisble by 30 in RGBA4444 format | From `#0000` to `#FFFF` | `#0C0F` |

> [game_resolutions]
| Key | Explanation | Possible values | Default Value |
|-----|-------------|-----------------|---------------|
| `refresh_rate` | How often per second this mode should be refreshed. Higher value means higher CPU Core #3 usage, that's why it is recommended to stay at 1. | From `1` to `60` | `10` |
| `layer_width_align` | On which side of the screen X axis you want this mode | `left`, `center`, `right` | `left` |
| `layer_height_align` | On which side of the screen Y axis you want this mode | `top`, `center`, `bottom` | `top` |
| `background_color` | Background color in RGBA4444 format | From `#0000` to `#FFFF` | `#1117` |
| `cat_color` | Category text color (left side) in RGBA4444 format | From `#0000` to `#FFFF` | `#FFFF` |
| `text_color` | Stats text color (right side) in RGBA4444 format | From `#0000` to `#FFFF` | `#FFFF` |
30 changes: 25 additions & 5 deletions docs/modes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Modes

Status Monitor Overlay from 0.8 release contains six modes to choose from Main Menu.<br>
Status Monitor Overlay from 1.0.0 release contains five modes to choose from Main Menu.<br>
For additional functions you need to install:
- [SaltyNX](https://github.com/masagrator/SaltyNX/releases)
- [sys-clk 2.0.0_rc4+](https://github.com/retronx-team/sys-clk/releases) (using closed source forks of sys-clk can result in retrieving wrong real clockrates and ram load)
Expand Down Expand Up @@ -90,16 +90,16 @@ Contains most of supported informations with lower precision in one line.
| FPS | %.1f | Frames Per Second |


# FPS Counter
# FPS

> Counter
It shows only FPS value in 31Hz + vsync signal. <br>
If game is not launched, it will show always 254.0 value.<br>

Mode available only with SaltyNX installed.

# Graphs

> FPS
> Graph
It shows average FPS graph in 31Hz + vsync signal. In background of graph you can see rendered actual average FPS.<br>
If game is not launched, it will show always 254.0 value and graph will be empty.<br>
Expand Down Expand Up @@ -145,6 +145,26 @@ Shows only if charger is connected:

If Network Type is "Wi-Fi", you can press Y to show password. Since max password length is 64 characters, it may show in up to 3 lines.

> Game Resolutions
For this mode to show and work properly you must have SaltyNX 0.9.0+ installed.

When game runs, this menu shows what resolutions and how many times they were passed to GPU via two functions:
- __Depth__ shows info from depth texture passed to `nvnCommandBufferSetRenderTargets`
- __Viewport__ shows info from arguments passed to `nvnCommandBufferSetViewport` and `nvnCommandBufferSetViewports`

This menu shows first 8 resolutions passed to those functions in last frame rendering loop, sorted in descending order of calls number.<br>
Its main purpose is to catch game rendering resolution, but user must deduce which ones are correct.<br>
I have limited catched resolutions only to ones that have ratio higher than 1.70 and lower than 1.90.<br>

Remember that resolutions you can see in this mode may be used in different ways - for example Tokyo Xanadu Ex+ max dynamic resolution in handheld will show 1280x736, but it's not that game will squeeze this into 720p screen, it's just removing those additional 16 pixels from showing on screen.

Those commands are used by all 3D games using NVN API (that's why it won't work with other APIs and may not work with games using 2D engines).<br>
This mode is not 100% fullproof, so it can show that nothing is catched or it won't catch what is used for 3D rendering (if this happens for some 3D game, please report an issue).

By default refresh rate of this menu is 10 FPS. You can change that in config.ini, more in config.md<br>
Exiting is done by using the same combo buttons used in other main modes.

# Additional info

> How Battery Remaining Time is calculated
Expand Down
103 changes: 103 additions & 0 deletions source/Utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,32 @@ SharedMemory _sharedmemory = {};
bool SharedMemoryUsed = false;
uint32_t* MAGIC_shared = 0;
uint8_t* FPS_shared = 0;
uint8_t* API_shared = 0;
float* FPSavg_shared = 0;
bool* pluginActive = 0;
uint32_t* FPSticks_shared = 0;
Handle remoteSharedMemory = 1;

struct resolutionCalls {
uint16_t width;
uint16_t height;
uint16_t calls;
};
resolutionCalls* renderCalls_shared = 0;
resolutionCalls* viewportCalls_shared = 0;

//Read real freqs from sys-clk sysmodule
uint32_t realCPU_Hz = 0;
uint32_t realGPU_Hz = 0;
uint32_t realRAM_Hz = 0;
uint32_t ramLoad[SysClkRamLoad_EnumMax];
uint8_t refreshRate = 0;

int compare (const void* elem1, const void* elem2) {
if ((((resolutionCalls*)(elem1)) -> calls) > (((resolutionCalls*)(elem2)) -> calls)) return -1;
else return 1;
}

void LoadSharedMemoryAndRefreshRate() {
if (SaltySD_Connect())
return;
Expand Down Expand Up @@ -237,7 +251,10 @@ void CheckIfGameRunning(void*) {
FPS_shared = (uint8_t*)(base + rel_offset + 4);
FPSavg_shared = (float*)(base + rel_offset + 5);
pluginActive = (bool*)(base + rel_offset + 9);
API_shared = (uint8_t*)(base + rel_offset + 14);
FPSticks_shared = (uint32_t*)(base + rel_offset + 15);
renderCalls_shared = (resolutionCalls*)(base + rel_offset + 60);
viewportCalls_shared = (resolutionCalls*)(base + rel_offset + 60 + (sizeof(resolutionCalls) * 8));
*pluginActive = false;
svcSleepThread(100'000'000);
if (*pluginActive) {
Expand Down Expand Up @@ -941,6 +958,14 @@ struct FpsGraphSettings {
int setPos;
};

struct ResolutionSettings {
uint8_t refreshRate;
uint16_t backgroundColor;
uint16_t catColor;
uint16_t textColor;
int setPos;
};

void GetConfigSettings(MiniSettings* settings) {
settings -> realFrequencies = false;
settings -> handheldFontSize = 15;
Expand All @@ -951,6 +976,7 @@ void GetConfigSettings(MiniSettings* settings) {
settings -> show = "CPU+GPU+RAM+TEMP+DRAW+FAN+FPS";
settings -> showRAMLoad = true;
settings -> refreshRate = 1;
settings -> setPos = 0;

FILE* configFileIn = fopen("sdmc:/config/status-monitor/config.ini", "r");
if (!configFileIn)
Expand Down Expand Up @@ -1412,3 +1438,80 @@ void GetConfigSettings(FullSettings* settings) {
settings -> showTargetFreqs = key.compare("FALSE");
}
}

void GetConfigSettings(ResolutionSettings* settings) {
convertStrToRGBA4444("#1117", &(settings -> backgroundColor));
convertStrToRGBA4444("#FFFF", &(settings -> catColor));
convertStrToRGBA4444("#FFFF", &(settings -> textColor));
settings -> refreshRate = 10;
settings -> setPos = 0;

FILE* configFileIn = fopen("sdmc:/config/status-monitor/config.ini", "r");
if (!configFileIn)
return;
fseek(configFileIn, 0, SEEK_END);
long fileSize = ftell(configFileIn);
rewind(configFileIn);

std::string fileDataString(fileSize, '\0');
fread(&fileDataString[0], sizeof(char), fileSize, configFileIn);
fclose(configFileIn);

auto parsedData = tsl::hlp::ini::parseIni(fileDataString);

std::string key;
if (parsedData.find("game_resolutions") == parsedData.end())
return;
if (parsedData["game_resolutions"].find("refresh_rate") != parsedData["game_resolutions"].end()) {
long maxFPS = 60;
long minFPS = 1;

key = parsedData["game_resolutions"]["refresh_rate"];
long rate = atol(key.c_str());
if (rate < minFPS) {
settings -> refreshRate = minFPS;
}
else if (rate > maxFPS)
settings -> refreshRate = maxFPS;
else settings -> refreshRate = rate;
}

if (parsedData["game_resolutions"].find("background_color") != parsedData["game_resolutions"].end()) {
key = parsedData["game_resolutions"]["background_color"];
uint16_t temp = 0;
if (convertStrToRGBA4444(key, &temp))
settings -> backgroundColor = temp;
}
if (parsedData["game_resolutions"].find("cat_color") != parsedData["game_resolutions"].end()) {
key = parsedData["game_resolutions"]["cat_color"];
uint16_t temp = 0;
if (convertStrToRGBA4444(key, &temp))
settings -> catColor = temp;
}
if (parsedData["game_resolutions"].find("text_color") != parsedData["game_resolutions"].end()) {
key = parsedData["game_resolutions"]["text_color"];
uint16_t temp = 0;
if (convertStrToRGBA4444(key, &temp))
settings -> textColor = temp;
}
if (parsedData["game_resolutions"].find("layer_width_align") != parsedData["game_resolutions"].end()) {
key = parsedData["game_resolutions"]["layer_width_align"];
convertToUpper(key);
if (!key.compare("CENTER")) {
settings -> setPos = 1;
}
if (!key.compare("RIGHT")) {
settings -> setPos = 2;
}
}
if (parsedData["game_resolutions"].find("layer_height_align") != parsedData["game_resolutions"].end()) {
key = parsedData["game_resolutions"]["layer_height_align"];
convertToUpper(key);
if (!key.compare("CENTER")) {
settings -> setPos += 3;
}
if (!key.compare("BOTTOM")) {
settings -> setPos += 6;
}
}
}
13 changes: 13 additions & 0 deletions source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ static bool skipMain = false;
#include "modes/Micro.hpp"
#include "modes/Battery.hpp"
#include "modes/Misc.hpp"
#include "modes/Resolutions.hpp"

//Graphs
class GraphsMenu : public tsl::Gui {
Expand Down Expand Up @@ -88,6 +89,18 @@ class OtherMenu : public tsl::Gui {
});
list->addItem(Misc);

if (SaltySD) {
auto Res = new tsl::elm::ListItem("Game Resolutions");
Res->setClickListener([](uint64_t keys) {
if (keys & KEY_A) {
tsl::changeTo<ResolutionsOverlay>();
return true;
}
return false;
});
list->addItem(Res);
}

rootFrame->setContent(list);

return rootFrame;
Expand Down
Loading

0 comments on commit 334036d

Please sign in to comment.