Skip to content

Commit c132a16

Browse files
committed
Merge remote-tracking branch 'Meha/master'
2 parents e02a0f9 + ca46d3d commit c132a16

File tree

8 files changed

+111
-76
lines changed

8 files changed

+111
-76
lines changed

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ include $(DEVKITPRO)/libnx/switch_rules
3838
# NACP building is skipped as well.
3939
#---------------------------------------------------------------------------------
4040
APP_TITLE := Status Monitor
41-
APP_VERSION := 1.1.4U+
41+
APP_VERSION := 1.1.6U
4242
TARGET := $(notdir $(CURDIR))
4343
BUILD := build
4444
SOURCES := source
@@ -51,7 +51,7 @@ NO_ICON := 1
5151
#---------------------------------------------------------------------------------
5252
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
5353

54-
CFLAGS := -g -Wall -O2 -ffunction-sections \
54+
CFLAGS := -g -Wall -Wno-address-of-packed-member -O2 -ffunction-sections \
5555
$(ARCH) $(DEFINES)
5656

5757
CFLAGS += $(INCLUDE) -D__SWITCH__ -DAPP_VERSION="\"$(APP_VERSION)\""

config/status-monitor/config.ini.template

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
[status-monitor]
2-
ultra=Ultra+
2+
ultra=Ultra
33
battery_avg_iir_filter=false
44
battery_time_left_refreshrate=60
5+
average_gpu_load=true
56

67
[full]
78
refresh_rate=1

docs/config.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Colors are provided in RGBA4444 format, which means that each character represen
1414
| `key_combo` | Buttons combination that allows exiting Full, Mini, Micro, FPS Graph and FPS Counter modes; max 4 buttons, otherwise next buttons will be ignored. Combine different buttons with `+` | `A`, `B`, `X`, `Y`, `L`, `R`, `ZL`, `ZR`, `PLUS`, `MINUS`, `DUP`, `DDOWN`, `DLEFT`, `DRIGHT`, `SL`, `SR`, `LSTICK`, `RSTICK`, `UP`, `DOWN`, `LEFT`, `RIGHT` | `L+DDOWN+RSTICK` |
1515
| `battery_avg_iir_filter` | Read voltage + current averages directly from fuel gauge, that uses infinite impulse response filter | `true`, `false` | `false` |
1616
| `battery_time_left_refreshrate` | How many seconds must pass to refresh Battery Remaining Time | from `1` to `60` | `60` |
17+
| `average_gpu_load` | Average 5 last GPU load readings. Because GPU load by design shows only load for last 1/60s, this option allows for more accurate gpu load readings at the cost of slight bump in CPU Core #3 usage (from 2 to 4 percentage points depending on CPU clock). | `true`, `false` | `false` |
1718

1819

1920
> [full]

source/Utils.hpp

+69-39
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Thread t3;
3636
Thread t4;
3737
Thread t6;
3838
Thread t7;
39+
Thread t5;
3940
const uint64_t systemtickfrequency = 19200000;
4041
bool threadexit = false;
4142
bool threadexit2 = false;
@@ -130,8 +131,38 @@ double Rotation_Duty = 0;
130131
//GPU Usage
131132
FieldDescriptor fd = 0;
132133
uint32_t GPU_Load_u = 0;
134+
bool GPULoadPerFrame = true;
133135

134136
//NX-FPS
137+
138+
struct resolutionCalls {
139+
uint16_t width;
140+
uint16_t height;
141+
uint16_t calls;
142+
};
143+
144+
struct NxFpsSharedBlock {
145+
uint32_t MAGIC;
146+
uint8_t FPS;
147+
float FPSavg;
148+
bool pluginActive;
149+
uint8_t FPSlocked;
150+
uint8_t FPSmode;
151+
uint8_t ZeroSync;
152+
uint8_t patchApplied;
153+
uint8_t API;
154+
uint32_t FPSticks[10];
155+
uint8_t Buffers;
156+
uint8_t SetBuffers;
157+
uint8_t ActiveBuffers;
158+
uint8_t SetActiveBuffers;
159+
uint8_t displaySync;
160+
resolutionCalls renderCalls[8];
161+
resolutionCalls viewportCalls[8];
162+
bool forceOriginalRefreshRate;
163+
} NX_PACKED;
164+
165+
NxFpsSharedBlock* NxFps = 0;
135166
bool GameRunning = false;
136167
bool check = true;
137168
bool SaltySD = false;
@@ -144,22 +175,8 @@ float FPSmin = 254;
144175
float FPSmax = 0;
145176
SharedMemory _sharedmemory = {};
146177
bool SharedMemoryUsed = false;
147-
uint32_t* MAGIC_shared = 0;
148-
uint8_t* FPS_shared = 0;
149-
uint8_t* API_shared = 0;
150-
float* FPSavg_shared = 0;
151-
bool* pluginActive = 0;
152-
uint32_t* FPSticks_shared = 0;
153178
Handle remoteSharedMemory = 1;
154179

155-
struct resolutionCalls {
156-
uint16_t width;
157-
uint16_t height;
158-
uint16_t calls;
159-
};
160-
resolutionCalls* renderCalls_shared = 0;
161-
resolutionCalls* viewportCalls_shared = 0;
162-
163180
//Read real freqs from sys-clk sysmodule
164181
uint32_t realCPU_Hz = 0;
165182
uint32_t realGPU_Hz = 0;
@@ -212,16 +229,17 @@ void LoadSharedMemory() {
212229
else FPS = 1234;
213230
}
214231

215-
ptrdiff_t searchSharedMemoryBlock(uintptr_t base) {
232+
void searchSharedMemoryBlock(uintptr_t base) {
216233
ptrdiff_t search_offset = 0;
217234
while(search_offset < 0x1000) {
218-
MAGIC_shared = (uint32_t*)(base + search_offset);
219-
if (*MAGIC_shared == 0x465053) {
220-
return search_offset;
235+
NxFps = (NxFpsSharedBlock*)(base + search_offset);
236+
if (NxFps -> MAGIC == 0x465053) {
237+
return;
221238
}
222239
else search_offset += 4;
223240
}
224-
return -1;
241+
NxFps = 0;
242+
return;
225243
}
226244

227245
//Check if SaltyNX is working
@@ -252,29 +270,22 @@ void CheckIfGameRunning(void*) {
252270
if (!check && R_FAILED(pmdmntGetApplicationProcessId(&PID))) {
253271
GameRunning = false;
254272
if (SharedMemoryUsed) {
255-
*MAGIC_shared = 0;
256-
*pluginActive = false;
257-
*FPS_shared = 0;
258-
*FPSavg_shared = 0.0;
273+
(NxFps -> MAGIC) = 0;
274+
(NxFps -> pluginActive) = false;
275+
(NxFps -> FPS) = 0;
276+
(NxFps -> FPSavg) = 0.0;
259277
FPS = 254;
260278
FPSavg = 254.0;
261279
}
262280
check = true;
263281
}
264282
else if (!GameRunning && SharedMemoryUsed) {
265283
uintptr_t base = (uintptr_t)shmemGetAddr(&_sharedmemory);
266-
ptrdiff_t rel_offset = searchSharedMemoryBlock(base);
267-
if (rel_offset > -1) {
268-
FPS_shared = (uint8_t*)(base + rel_offset + 4);
269-
FPSavg_shared = (float*)(base + rel_offset + 5);
270-
pluginActive = (bool*)(base + rel_offset + 9);
271-
API_shared = (uint8_t*)(base + rel_offset + 14);
272-
FPSticks_shared = (uint32_t*)(base + rel_offset + 15);
273-
renderCalls_shared = (resolutionCalls*)(base + rel_offset + 60);
274-
viewportCalls_shared = (resolutionCalls*)(base + rel_offset + 60 + (sizeof(resolutionCalls) * 8));
275-
*pluginActive = false;
284+
searchSharedMemoryBlock(base);
285+
if (NxFps) {
286+
(NxFps -> pluginActive) = false;
276287
svcSleepThread(100'000'000);
277-
if (*pluginActive) {
288+
if ((NxFps -> pluginActive)) {
278289
GameRunning = true;
279290
check = false;
280291
}
@@ -411,6 +422,16 @@ void StartBatteryThread() {
411422

412423
Mutex mutex_Misc = {0};
413424

425+
void gpuLoadThread(void*) {
426+
if (!GPULoadPerFrame && R_SUCCEEDED(nvCheck)) while(!threadexit) {
427+
u8 average = 5;
428+
u32 temp = 0;
429+
nvIoctl(fd, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &temp);
430+
GPU_Load_u = ((GPU_Load_u * (average-1)) + temp) / average;
431+
svcSleepThread(16'666'000);
432+
}
433+
}
434+
414435
//Stuff that doesn't need multithreading
415436
void Misc(void*) {
416437
while (!threadexit) {
@@ -482,13 +503,13 @@ void Misc(void*) {
482503
}
483504

484505
//GPU Load
485-
if (R_SUCCEEDED(nvCheck)) nvIoctl(fd, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &GPU_Load_u);
506+
if (R_SUCCEEDED(nvCheck) && GPULoadPerFrame) nvIoctl(fd, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &GPU_Load_u);
486507

487508
//FPS
488509
if (GameRunning) {
489510
if (SharedMemoryUsed) {
490-
FPS = *FPS_shared;
491-
FPSavg = 19'200'000.f / (std::accumulate<uint32_t*, float>(FPSticks_shared, FPSticks_shared+10, 0) / 10);
511+
FPS = (NxFps -> FPS);
512+
FPSavg = 19'200'000.f / (std::accumulate<uint32_t*, float>(&(NxFps -> FPSticks[0]), &(NxFps -> FPSticks[10]), 0) / 10);
492513
if (FPSavg > FPSmax) FPSmax = FPSavg;
493514
if (FPSavg < FPSmin) FPSmin = FPSavg;
494515
}
@@ -619,6 +640,7 @@ void StartThreads() {
619640
threadCreate(&t2, CheckCore2, NULL, NULL, 0x1000, 0x10, 2);
620641
threadCreate(&t3, CheckCore3, NULL, NULL, 0x1000, 0x10, 3);
621642
threadCreate(&t4, Misc, NULL, NULL, 0x1000, 0x3F, -2);
643+
threadCreate(&t5, gpuLoadThread, NULL, NULL, 0x1000, 0x3F, -2);
622644
if (SaltySD) {
623645
//Assign NX-FPS to default core
624646
threadCreate(&t6, CheckIfGameRunning, NULL, NULL, 0x1000, 0x38, -2);
@@ -629,6 +651,7 @@ void StartThreads() {
629651
threadStart(&t2);
630652
threadStart(&t3);
631653
threadStart(&t4);
654+
threadStart(&t5);
632655
if (SaltySD) {
633656
//Start NX-FPS detection
634657
threadStart(&t6);
@@ -645,13 +668,15 @@ void CloseThreads() {
645668
threadWaitForExit(&t2);
646669
threadWaitForExit(&t3);
647670
threadWaitForExit(&t4);
671+
threadWaitForExit(&t5);
648672
threadWaitForExit(&t6);
649673
threadWaitForExit(&t7);
650674
threadClose(&t0);
651675
threadClose(&t1);
652676
threadClose(&t2);
653677
threadClose(&t3);
654678
threadClose(&t4);
679+
threadClose(&t5);
655680
threadClose(&t6);
656681
threadClose(&t7);
657682
threadexit = false;
@@ -663,8 +688,8 @@ void FPSCounter(void*) {
663688
while (!threadexit) {
664689
if (GameRunning) {
665690
if (SharedMemoryUsed) {
666-
FPS = *FPS_shared;
667-
FPSavg = 19'200'000.f / (std::accumulate<uint32_t*, float>(FPSticks_shared, FPSticks_shared+10, 0) / 10);
691+
FPS = (NxFps -> FPS);
692+
FPSavg = 19'200'000.f / (std::accumulate<uint32_t*, float>(&(NxFps -> FPSticks[0]), &(NxFps -> FPSticks[10]), 0) / 10);
668693
}
669694
}
670695
else FPSavg = 254;
@@ -916,6 +941,11 @@ void ParseIniFile() {
916941
}
917942
batteryTimeLeftRefreshRate = rate;
918943
}
944+
if (parsedData["status-monitor"].find("average_gpu_load") != parsedData["status-monitor"].end()) {
945+
auto key = parsedData["status-monitor"]["average_gpu_load"];
946+
convertToUpper(key);
947+
GPULoadPerFrame = key.compare("TRUE");
948+
}
919949
}
920950

921951
} else {

source/modes/FPS_Graph.hpp

+13-9
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,20 @@ class com_FPSGraph : public tsl::Gui {
211211
else if (performanceMode == ApmPerformanceMode_Normal) {
212212
isDocked = false;
213213
}
214-
215-
if (!isDocked && isStarted && FPSavg_old != 0 && FPSavg_old == FPSavg) {
216-
if (R_SUCCEEDED(SaltySD_Connect())) {
217-
if (R_FAILED(SaltySD_GetDisplayRefreshRate(&refreshRate)))
218-
refreshRate = 0;
219-
svcSleepThread(100'000'000);
220-
SaltySD_Term();
221-
}
214+
215+
if (!isDocked && isStarted && FPSavg_old != 0) {
216+
uint8_t SaltySharedDisplayRefreshRate = *(uint8_t*)((uintptr_t)shmemGetAddr(&_sharedmemory) + 1);
217+
if (SaltySharedDisplayRefreshRate) refreshRate = SaltySharedDisplayRefreshRate;
218+
else if (FPSavg_old == FPSavg) {
219+
if (R_SUCCEEDED(SaltySD_Connect())) {
220+
if (R_FAILED(SaltySD_GetDisplayRefreshRate(&refreshRate)))
221+
refreshRate = 0;
222+
svcSleepThread(100'000'000);
223+
SaltySD_Term();
224+
}
225+
}
222226
}
227+
223228
if (FPSavg_old == FPSavg)
224229
//return;
225230
goto read_value;
@@ -230,7 +235,6 @@ class com_FPSGraph : public tsl::Gui {
230235
if (!isDocked && R_SUCCEEDED(SaltySD_Connect())) {
231236
if (R_FAILED(SaltySD_GetDisplayRefreshRate(&refreshRate)))
232237
refreshRate = 0;
233-
svcSleepThread(100'000);
234238
SaltySD_Term();
235239
isStarted = true;
236240
}

source/modes/Full.hpp

+10-11
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class FullOverlay : public tsl::Gui {
2525
uint8_t COMMON_MARGIN = 20;
2626
FullSettings settings;
2727
uint64_t systemtickfrequency_impl = systemtickfrequency;
28+
std::string formattedKeyCombo = keyCombo;
29+
std::string message = "Hold to Exit";
2830
public:
2931
FullOverlay() {
3032
GetConfigSettings(&settings);
@@ -37,6 +39,8 @@ class FullOverlay : public tsl::Gui {
3739
tsl::gfx::Renderer::getRenderer().setLayerPos(1248, 0);
3840
}
3941
deactivateOriginalFooter = true;
42+
formatButtonCombination(formattedKeyCombo);
43+
message = "Hold " + formattedKeyCombo + " to Exit";
4044
StartThreads();
4145
}
4246
~FullOverlay() {
@@ -178,18 +182,13 @@ class FullOverlay : public tsl::Gui {
178182
uint32_t offset = COMMON_MARGIN + width_offset + dimensions.first;
179183
renderer->drawString(FPS_var_compressed_c, false, offset, 120, 20, renderer->a(0xFFFF));
180184
}
181-
if ((settings.showRES == true) && *API_shared == 1) {
185+
if ((settings.showRES == true) && (NxFps -> API) == 1) {
182186
width_offset = 170;
183187
renderer->drawString("Resolution:", false, COMMON_MARGIN + width_offset, 185, 20, renderer->a(0xFFFF));
184188
renderer->drawString(Resolutions_c, false, COMMON_MARGIN + width_offset, 205, 20, renderer->a(0xFFFF));
185189
}
186190
}
187191

188-
std::string formattedKeyCombo = keyCombo;
189-
formatButtonCombination(formattedKeyCombo);
190-
191-
std::string message = "Hold " + formattedKeyCombo + " to Exit";
192-
193192
renderer->drawString(message.c_str(), false, COMMON_MARGIN, 693, 23, renderer->a(0xFFFF));
194193

195194
});
@@ -269,17 +268,17 @@ class FullOverlay : public tsl::Gui {
269268
snprintf(FPS_var_compressed_c, sizeof FPS_var_compressed_c, "%u\n%2.1f", FPS, FPSavg);
270269

271270
//Resolutions
272-
if ((settings.showRES == true) && GameRunning && renderCalls_shared) {
271+
if ((settings.showRES == true) && GameRunning && NxFps) {
273272
if (!resolutionLookup) {
274-
renderCalls_shared[0].calls = 0xFFFF;
273+
(NxFps -> renderCalls[0].calls) = 0xFFFF;
275274
resolutionLookup = 1;
276275
}
277276
else if (resolutionLookup == 1) {
278-
if (renderCalls_shared[0].calls != 0xFFFF) resolutionLookup = 2;
277+
if ((NxFps -> renderCalls[0].calls) != 0xFFFF) resolutionLookup = 2;
279278
}
280279
else {
281-
memcpy(&m_resolutionRenderCalls, renderCalls_shared, sizeof(m_resolutionRenderCalls));
282-
memcpy(&m_resolutionViewportCalls, viewportCalls_shared, sizeof(m_resolutionViewportCalls));
280+
memcpy(&m_resolutionRenderCalls, &(NxFps -> renderCalls), sizeof(m_resolutionRenderCalls));
281+
memcpy(&m_resolutionViewportCalls, &(NxFps -> viewportCalls), sizeof(m_resolutionViewportCalls));
283282
qsort(m_resolutionRenderCalls, 8, sizeof(resolutionCalls), compare);
284283
qsort(m_resolutionViewportCalls, 8, sizeof(resolutionCalls), compare);
285284
memset(&m_resolutionOutput, 0, sizeof(m_resolutionOutput));

source/modes/Mini.hpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -370,17 +370,17 @@ class MiniOverlay : public tsl::Gui {
370370
snprintf(MINI_SOC_volt_c, sizeof(MINI_SOC_volt_c), "| %u.%u mV |", realSOC_mV/1000, (realSOC_mV/100)%10);
371371
}
372372

373-
if (GameRunning && renderCalls_shared && resolutionShow) {
373+
if (GameRunning && NxFps && resolutionShow) {
374374
if (!resolutionLookup) {
375-
renderCalls_shared[0].calls = 0xFFFF;
375+
(NxFps -> renderCalls[0].calls) = 0xFFFF;
376376
resolutionLookup = 1;
377377
}
378378
else if (resolutionLookup == 1) {
379-
if (renderCalls_shared[0].calls != 0xFFFF) resolutionLookup = 2;
379+
if ((NxFps -> renderCalls[0].calls) != 0xFFFF) resolutionLookup = 2;
380380
}
381381
else {
382-
memcpy(&m_resolutionRenderCalls, renderCalls_shared, sizeof(m_resolutionRenderCalls));
383-
memcpy(&m_resolutionViewportCalls, viewportCalls_shared, sizeof(m_resolutionViewportCalls));
382+
memcpy(&m_resolutionRenderCalls, &(NxFps -> renderCalls), sizeof(m_resolutionRenderCalls));
383+
memcpy(&m_resolutionViewportCalls, &(NxFps -> viewportCalls), sizeof(m_resolutionViewportCalls));
384384
qsort(m_resolutionRenderCalls, 8, sizeof(resolutionCalls), compare);
385385
qsort(m_resolutionViewportCalls, 8, sizeof(resolutionCalls), compare);
386386
memset(&m_resolutionOutput, 0, sizeof(m_resolutionOutput));
@@ -508,10 +508,10 @@ class MiniOverlay : public tsl::Gui {
508508
strcat(Temp, "\n");
509509
}
510510
char Temp_s[32] = "";
511-
if (*API_shared == 2) {
511+
if (NxFps -> API == 2) {
512512
snprintf(Temp_s, sizeof(Temp_s), "EGL");
513513
}
514-
else if (*API_shared == 3) {
514+
else if (NxFps -> API == 3) {
515515
snprintf(Temp_s, sizeof(Temp_s), "Vulkan");
516516
}
517517
else snprintf(Temp_s, sizeof(Temp_s), "%dx%d || %dx%d", m_resolutionOutput[0].width, m_resolutionOutput[0].height, m_resolutionOutput[1].width, m_resolutionOutput[1].height);

0 commit comments

Comments
 (0)