Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/UI/DebugOverlay.cpp
3185 views
1
#include "Common/Render/DrawBuffer.h"
2
#include "Common/GPU/thin3d.h"
3
#include "Common/System/System.h"
4
#include "Common/Data/Text/I18n.h"
5
#include "Common/CPUDetect.h"
6
#include "Common/StringUtils.h"
7
#include "Common/Data/Text/Parsers.h"
8
9
#include "Core/MIPS/MIPS.h"
10
#include "Core/HW/Display.h"
11
#include "Core/FrameTiming.h"
12
#include "Core/HLE/sceSas.h"
13
#include "Core/HLE/sceKernel.h"
14
#include "Core/HLE/scePower.h"
15
#include "Core/HLE/Plugins.h"
16
#include "Core/ControlMapper.h"
17
#include "Core/Config.h"
18
#include "Core/MemFault.h"
19
#include "Core/Reporting.h"
20
#include "Core/CwCheat.h"
21
#include "Core/Core.h"
22
#include "Core/ELF/ParamSFO.h"
23
#include "Core/System.h"
24
#include "Core/Util/GameDB.h"
25
#include "GPU/GPU.h"
26
#include "GPU/GPUCommon.h"
27
// TODO: This should be moved here or to Common, doesn't belong in /GPU
28
#include "GPU/Vulkan/DebugVisVulkan.h"
29
#include "GPU/Common/FramebufferManagerCommon.h"
30
31
#include "UI/DevScreens.h"
32
#include "UI/DebugOverlay.h"
33
34
// For std::max
35
#include <algorithm>
36
37
static void DrawDebugStats(UIContext *ctx, const Bounds &bounds) {
38
FontID ubuntu24("UBUNTU24");
39
40
float left = std::max(bounds.w / 2 - 20.0f, 550.0f);
41
float right = bounds.w - left - 20.0f;
42
43
char statbuf[4096];
44
45
ctx->Flush();
46
ctx->BindFontTexture();
47
ctx->Draw()->SetFontScale(.7f, .7f);
48
49
__DisplayGetDebugStats(statbuf, sizeof(statbuf));
50
ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 11, bounds.y + 31, left, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII);
51
ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 10, bounds.y + 30, left, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
52
53
ctx->Draw()->SetFontScale(1.0f, 1.0f);
54
ctx->Flush();
55
ctx->RebindTexture();
56
}
57
58
static void DrawAudioDebugStats(UIContext *ctx, const Bounds &bounds) {
59
FontID ubuntu24("UBUNTU24");
60
61
char statbuf[4096] = { 0 };
62
System_AudioGetDebugStats(statbuf, sizeof(statbuf));
63
64
ctx->Flush();
65
ctx->BindFontTexture();
66
ctx->Draw()->SetFontScale(0.5f, 0.5f);
67
ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 11, bounds.y + 31, bounds.w - 20, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII);
68
ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 10, bounds.y + 30, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
69
70
float left = std::max(bounds.w / 2 - 20.0f, 500.0f);
71
72
__SasGetDebugStats(statbuf, sizeof(statbuf));
73
ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + left + 21, bounds.y + 31, bounds.w - left, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII);
74
ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + left + 20, bounds.y + 30, bounds.w - left, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
75
76
ctx->Draw()->SetFontScale(1.0f, 1.0f);
77
78
ctx->Flush();
79
ctx->RebindTexture();
80
}
81
82
static void DrawControlDebug(UIContext *ctx, const ControlMapper &mapper, const Bounds &bounds) {
83
FontID ubuntu24("UBUNTU24");
84
85
char statbuf[4096] = { 0 };
86
mapper.GetDebugString(statbuf, sizeof(statbuf));
87
88
ctx->Flush();
89
ctx->BindFontTexture();
90
ctx->Draw()->SetFontScale(0.5f, 0.5f);
91
ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 11, bounds.y + 31, bounds.w - 20, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII);
92
ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 10, bounds.y + 30, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
93
ctx->Draw()->SetFontScale(1.0f, 1.0f);
94
ctx->Flush();
95
ctx->RebindTexture();
96
}
97
98
static void DrawFrameTimes(UIContext *ctx, const Bounds &bounds) {
99
FontID ubuntu24("UBUNTU24");
100
float *sleepHistory;
101
int valid, pos;
102
float *history = __DisplayGetFrameTimes(&valid, &pos, &sleepHistory);
103
int scale = 7000;
104
int width = 600;
105
106
ctx->Flush();
107
ctx->BeginNoTex();
108
int bottom = bounds.y2();
109
for (int i = 0; i < valid; ++i) {
110
double activeTime = history[i] - sleepHistory[i];
111
ctx->Draw()->vLine(bounds.x + i, bottom, bottom - activeTime * scale, 0xFF3FFF3F);
112
ctx->Draw()->vLine(bounds.x + i, bottom - activeTime * scale, bottom - history[i] * scale, 0x7F3FFF3F);
113
}
114
ctx->Draw()->vLine(bounds.x + pos, bottom, bottom - 512, 0xFFff3F3f);
115
116
ctx->Draw()->hLine(bounds.x, bottom - 0.0333 * scale, bounds.x + width, 0xFF3f3Fff);
117
ctx->Draw()->hLine(bounds.x, bottom - 0.0167 * scale, bounds.x + width, 0xFF3f3Fff);
118
119
ctx->Flush();
120
ctx->Begin();
121
ctx->BindFontTexture();
122
ctx->Draw()->SetFontScale(0.5f, 0.5f);
123
ctx->Draw()->DrawText(ubuntu24, "33.3ms", bounds.x + width, bottom - 0.0333 * scale, 0xFF3f3Fff, ALIGN_BOTTOMLEFT | FLAG_DYNAMIC_ASCII);
124
ctx->Draw()->DrawText(ubuntu24, "16.7ms", bounds.x + width, bottom - 0.0167 * scale, 0xFF3f3Fff, ALIGN_BOTTOMLEFT | FLAG_DYNAMIC_ASCII);
125
ctx->Draw()->SetFontScale(1.0f, 1.0f);
126
ctx->Flush();
127
ctx->RebindTexture();
128
}
129
130
static void DrawFrameTiming(UIContext *ctx, const Bounds &bounds) {
131
FontID ubuntu24("UBUNTU24");
132
133
char statBuf[1024]{};
134
135
ctx->Flush();
136
ctx->BindFontTexture();
137
ctx->Draw()->SetFontScale(0.5f, 0.5f);
138
139
snprintf(statBuf, sizeof(statBuf),
140
"Mode (interval): %s (%d)",
141
Draw::PresentModeToString(g_frameTiming.presentMode),
142
g_frameTiming.presentInterval);
143
144
ctx->Draw()->DrawTextRect(ubuntu24, statBuf, bounds.x + 10, bounds.y + 50, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
145
146
for (int i = 0; i < 5; i++) {
147
size_t curIndex = i + 6;
148
size_t prevIndex = i + 7;
149
150
FrameTimeData data = ctx->GetDrawContext()->FrameTimeHistory().Back(curIndex);
151
FrameTimeData prevData = ctx->GetDrawContext()->FrameTimeHistory().Back(prevIndex);
152
if (data.frameBegin == 0.0) {
153
snprintf(statBuf, sizeof(statBuf), "(No frame time data)");
154
} else {
155
double stride = data.frameBegin - prevData.frameBegin;
156
double fenceLatency_s = data.afterFenceWait - data.frameBegin;
157
double submitLatency_s = data.firstSubmit - data.frameBegin;
158
double queuePresentLatency_s = data.queuePresent - data.frameBegin;
159
double actualPresentLatency_s = data.actualPresent - data.frameBegin;
160
double presentMargin = data.presentMargin;
161
double computedMargin = data.actualPresent - data.queuePresent;
162
163
char presentStats[256] = "";
164
if (data.actualPresent != 0.0) {
165
snprintf(presentStats, sizeof(presentStats),
166
"* Present: %0.1f ms\n"
167
"* Margin: %0.1f ms\n"
168
"* Margin(c): %0.1f ms\n",
169
actualPresentLatency_s * 1000.0,
170
presentMargin * 1000.0,
171
computedMargin * 1000.0);
172
}
173
snprintf(statBuf, sizeof(statBuf),
174
"* Stride: %0.1f (waits: %d)\n"
175
"%llu: From start:\n"
176
"* Past fence: %0.1f ms\n"
177
"* Submit #1: %0.1f ms\n"
178
"* Queue-p: %0.1f ms\n"
179
"%s",
180
stride * 1000.0,
181
data.waitCount,
182
(long long)data.frameId,
183
fenceLatency_s * 1000.0,
184
submitLatency_s * 1000.0,
185
queuePresentLatency_s * 1000.0,
186
presentStats
187
);
188
}
189
ctx->Draw()->DrawTextRect(ubuntu24, statBuf, bounds.x + 10 + i * 150, bounds.y + 150, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
190
}
191
ctx->Draw()->SetFontScale(1.0f, 1.0f);
192
ctx->Flush();
193
ctx->RebindTexture();
194
}
195
196
void DrawFramebufferList(UIContext *ctx, GPUDebugInterface *gpu, const Bounds &bounds) {
197
if (!gpu) {
198
return;
199
}
200
FontID ubuntu24("UBUNTU24");
201
auto list = gpu->GetFramebufferList();
202
ctx->Flush();
203
ctx->BindFontTexture();
204
ctx->Draw()->SetFontScale(0.7f, 0.7f);
205
206
int i = 0;
207
for (const VirtualFramebuffer *vfb : list) {
208
char buf[512];
209
snprintf(buf, sizeof(buf), "%08x (Z %08x): %dx%d (stride %d, %d)",
210
vfb->fb_address, vfb->z_address, vfb->width, vfb->height, vfb->fb_stride, vfb->z_stride);
211
ctx->Draw()->DrawTextRect(ubuntu24, buf, bounds.x + 10, bounds.y + 20 + i * 50, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
212
i++;
213
}
214
ctx->Flush();
215
}
216
217
void DrawControlMapperOverlay(UIContext *ctx, const Bounds &bounds, const ControlMapper &controlMapper) {
218
DrawControlDebug(ctx, controlMapper, ctx->GetLayoutBounds());
219
}
220
221
void DrawDebugOverlay(UIContext *ctx, const Bounds &bounds, DebugOverlay overlay) {
222
bool inGame = GetUIState() == UISTATE_INGAME;
223
224
switch (overlay) {
225
case DebugOverlay::DEBUG_STATS:
226
if (inGame)
227
DrawDebugStats(ctx, ctx->GetLayoutBounds());
228
break;
229
case DebugOverlay::FRAME_GRAPH:
230
if (inGame)
231
DrawFrameTimes(ctx, ctx->GetLayoutBounds());
232
break;
233
case DebugOverlay::FRAME_TIMING:
234
DrawFrameTiming(ctx, ctx->GetLayoutBounds());
235
break;
236
case DebugOverlay::Audio:
237
DrawAudioDebugStats(ctx, ctx->GetLayoutBounds());
238
break;
239
#if !PPSSPP_PLATFORM(UWP) && !PPSSPP_PLATFORM(SWITCH)
240
case DebugOverlay::GPU_PROFILE:
241
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
242
DrawGPUProfilerVis(ctx, gpu);
243
}
244
break;
245
case DebugOverlay::GPU_ALLOCATOR:
246
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
247
DrawGPUMemoryVis(ctx, gpu);
248
}
249
break;
250
#endif
251
case DebugOverlay::FRAMEBUFFER_LIST:
252
if (inGame)
253
DrawFramebufferList(ctx, gpu, bounds);
254
break;
255
default:
256
break;
257
}
258
}
259
260
261
static const char *CPUCoreAsString(int core) {
262
switch (core) {
263
case 0: return "Interpreter";
264
case 1: return "JIT";
265
case 2: return "IR Interpreter";
266
case 3: return "JIT using IR";
267
default: return "N/A";
268
}
269
}
270
271
void DrawCrashDump(UIContext *ctx, const Path &gamePath) {
272
const MIPSExceptionInfo &info = Core_GetExceptionInfo();
273
274
auto sy = GetI18NCategory(I18NCat::SYSTEM);
275
FontID ubuntu24("UBUNTU24");
276
std::string discID = g_paramSFO.GetDiscID();
277
278
std::string activeFlags = PSP_CoreParameter().compat.GetActiveFlagsString();
279
if (activeFlags.empty()) {
280
activeFlags = "(no compat flags active)";
281
}
282
283
int x = 20 + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT);
284
int y = 20 + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP);
285
286
ctx->Flush();
287
if (ctx->Draw()->GetFontAtlas()->getFont(ubuntu24))
288
ctx->BindFontTexture();
289
ctx->Draw()->SetFontScale(1.1f, 1.1f);
290
ctx->Draw()->DrawTextShadow(ubuntu24, sy->T_cstr("Game crashed"), x, y, 0xFFFFFFFF);
291
292
char statbuf[4096];
293
char versionString[256];
294
snprintf(versionString, sizeof(versionString), "%s", PPSSPP_GIT_VERSION);
295
296
bool checkingISO = false;
297
bool isoOK = false;
298
char crcStr[50]{};
299
300
switch (PSP_CoreParameter().fileType) {
301
case IdentifiedFileType::PSP_ISO:
302
case IdentifiedFileType::PSP_ISO_NP:
303
{
304
if (Reporting::HasCRC(gamePath)) {
305
u32 crc = Reporting::RetrieveCRC(gamePath);
306
std::vector<GameDBInfo> dbInfos;
307
if (discID.size() >= 9 && g_gameDB.GetGameInfos(discID, &dbInfos)) {
308
for (auto &dbInfo : dbInfos) {
309
if (dbInfo.crc == crc) {
310
isoOK = true;
311
}
312
}
313
}
314
snprintf(crcStr, sizeof(crcStr), "CRC: %08x %s\n", crc, isoOK ? "(Known good!)" : "(not identified)");
315
} else {
316
// Queue it for calculation, we want it!
317
// It's OK to call this repeatedly until we have it, which is natural here.
318
Reporting::QueueCRC(gamePath);
319
checkingISO = true;
320
}
321
break;
322
}
323
default:
324
// Don't show ISO warning for other file types.
325
isoOK = true;
326
break;
327
};
328
329
// TODO: Draw a lot more information. Full register set, and so on.
330
331
#ifdef _DEBUG
332
const char * const build = "debug";
333
#else
334
const char * const build = "release";
335
#endif
336
337
std::string sysName = System_GetProperty(SYSPROP_NAME);
338
int sysVersion = System_GetPropertyInt(SYSPROP_SYSTEMVERSION);
339
340
// First column
341
y += 65;
342
343
int columnWidth = (ctx->GetBounds().w - x - 10) / 2;
344
int height = ctx->GetBounds().h;
345
346
ctx->PushScissor(Bounds(x, y, columnWidth, height));
347
348
// INFO_LOG(Log::System, "DrawCrashDump (%d %d %d %d)", x, y, columnWidth, height);
349
350
snprintf(statbuf, sizeof(statbuf), R"(%s
351
%s (%s)
352
%s (%s)
353
%s v%d (%s)
354
%s
355
)",
356
ExceptionTypeAsString(info.type),
357
discID.c_str(), g_paramSFO.GetValueString("TITLE").c_str(),
358
versionString, build,
359
sysName.c_str(), sysVersion, GetCompilerABI(),
360
crcStr
361
);
362
363
ctx->Draw()->SetFontScale(.7f, .7f);
364
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
365
y += 160;
366
367
if (info.type == MIPSExceptionType::MEMORY) {
368
snprintf(statbuf, sizeof(statbuf), R"(
369
Access: %s at %08x (sz: %d)
370
PC: %08x
371
%s)",
372
MemoryExceptionTypeAsString(info.memory_type),
373
info.address,
374
info.accessSize,
375
info.pc,
376
info.info.c_str());
377
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
378
y += 180;
379
} else if (info.type == MIPSExceptionType::BAD_EXEC_ADDR) {
380
snprintf(statbuf, sizeof(statbuf), R"(
381
Destination: %s to %08x
382
PC: %08x
383
RA: %08x)",
384
ExecExceptionTypeAsString(info.exec_type),
385
info.address,
386
info.pc,
387
info.ra);
388
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
389
y += 180;
390
} else if (info.type == MIPSExceptionType::BREAK) {
391
snprintf(statbuf, sizeof(statbuf), R"(
392
BREAK
393
PC: %08x
394
)", info.pc);
395
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
396
y += 180;
397
} else {
398
snprintf(statbuf, sizeof(statbuf), R"(
399
Invalid / Unknown (%d)
400
)", (int)info.type);
401
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
402
y += 180;
403
}
404
405
std::string kernelState = __KernelStateSummary();
406
407
ctx->Draw()->DrawTextShadow(ubuntu24, kernelState.c_str(), x, y, 0xFFFFFFFF);
408
409
y += 40;
410
411
ctx->Draw()->SetFontScale(.5f, .5f);
412
413
ctx->Draw()->DrawTextShadow(ubuntu24, info.stackTrace.c_str(), x, y, 0xFFFFFFFF);
414
415
ctx->Draw()->SetFontScale(.7f, .7f);
416
417
ctx->PopScissor();
418
419
// Draw some additional stuff to the right, explaining why the background is purple, if it is.
420
// Should try to be in sync with Reporting::IsSupported().
421
422
std::string tips;
423
if (CheatsInEffect()) {
424
tips += "* Turn off cheats.\n";
425
}
426
if (HLEPlugins::HasEnabled()) {
427
tips += "* Turn off plugins.\n";
428
}
429
if (g_Config.uJitDisableFlags) {
430
tips += StringFromFormat("* Don't use JitDisableFlags: %08x\n", g_Config.uJitDisableFlags);
431
}
432
if (GetLockedCPUSpeedMhz()) {
433
tips += "* Set CPU clock to default (0)\n";
434
}
435
if (checkingISO) {
436
tips += "* (waiting for CRC...)\n";
437
} else if (!isoOK) {
438
tips += "* Verify and possibly re-dump your ISO\n (CRC not recognized)\n";
439
}
440
if (g_paramSFO.GetValueString("DISC_VERSION").empty()) {
441
tips += "\n(DISC_VERSION is empty)\n";
442
}
443
if (!tips.empty()) {
444
tips = "Things to try:\n" + tips;
445
}
446
447
x += columnWidth + 10;
448
y = 85;
449
snprintf(statbuf, sizeof(statbuf),
450
"CPU Core: %s (flags: %08x)\n"
451
"Locked CPU freq: %d MHz\n"
452
"Cheats: %s, Plugins: %s\n%s\n\n%s",
453
CPUCoreAsString(g_Config.iCpuCore), g_Config.uJitDisableFlags,
454
GetLockedCPUSpeedMhz(),
455
CheatsInEffect() ? "Y" : "N", HLEPlugins::HasEnabled() ? "Y" : "N", activeFlags.c_str(), tips.c_str());
456
457
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
458
ctx->Flush();
459
ctx->Draw()->SetFontScale(1.0f, 1.0f);
460
ctx->RebindTexture();
461
}
462
463
void DrawFPS(UIContext *ctx, const Bounds &bounds) {
464
FontID ubuntu24("UBUNTU24");
465
float vps, fps, actual_fps;
466
__DisplayGetFPS(&vps, &fps, &actual_fps);
467
468
char temp[256];
469
StringWriter w(temp);
470
471
if ((g_Config.iShowStatusFlags & ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) == ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) {
472
// Both at the same time gets a shorter formulation.
473
w.F("%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / ((g_Config.iDisplayRefreshRate / 60.0f * 59.94f) / 100.0f));
474
} else {
475
if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER) {
476
w.F("FPS: %0.1f", actual_fps);
477
} else if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER) {
478
w.F("Speed: %0.1f%%", vps / (59.94f / 100.0f));
479
}
480
}
481
if (System_GetPropertyBool(SYSPROP_CAN_READ_BATTERY_PERCENTAGE)) {
482
if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT) {
483
const int percentage = System_GetPropertyInt(SYSPROP_BATTERY_PERCENTAGE);
484
// Just plain append battery. Add linebreak?
485
w.F(" Battery: %d%%", percentage);
486
}
487
}
488
489
ctx->Flush();
490
491
ctx->BindFontTexture();
492
ctx->Draw()->SetFontScale(0.7f, 0.7f);
493
ctx->Draw()->DrawText(ubuntu24, w.as_view(), bounds.x2() - 8, 20, 0xc0000000, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
494
ctx->Draw()->DrawText(ubuntu24, w.as_view(), bounds.x2() - 10, 19, 0xFF3fFF3f, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
495
ctx->Draw()->SetFontScale(1.0f, 1.0f);
496
ctx->Flush();
497
ctx->RebindTexture();
498
}
499
500