Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/UI/DebugOverlay.cpp
5664 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
Draw::DrawContext *draw = ctx->GetDrawContext();
136
137
ctx->Flush();
138
ctx->BindFontTexture();
139
ctx->Draw()->SetFontScale(0.5f, 0.5f);
140
141
// NOTE: This is not necessarily the same as the actual present mode.
142
snprintf(statBuf, sizeof(statBuf),
143
"Presentation mode: %s Needs skip: %s\n"
144
"Actual presentation mode: %s",
145
Draw::PresentModeToString(g_frameTiming.PresentMode()),
146
g_frameTiming.FastForwardNeedsSkipFlip() ? "true" : "false",
147
Draw::PresentModeToString(draw->GetCurrentPresentMode()));
148
149
ctx->Draw()->DrawTextRect(ubuntu24, statBuf, bounds.x + 10, bounds.y + 50, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
150
151
for (int i = 0; i < 5; i++) {
152
size_t curIndex = i + 6;
153
size_t prevIndex = i + 7;
154
155
FrameTimeData data = ctx->GetDrawContext()->FrameTimeHistory().Back(curIndex);
156
FrameTimeData prevData = ctx->GetDrawContext()->FrameTimeHistory().Back(prevIndex);
157
if (data.frameBegin == 0.0) {
158
snprintf(statBuf, sizeof(statBuf), "(No frame time data)");
159
} else {
160
double stride = data.frameBegin - prevData.frameBegin;
161
double fenceLatency_s = data.afterFenceWait - data.frameBegin;
162
double submitLatency_s = data.firstSubmit - data.frameBegin;
163
double queuePresentLatency_s = data.queuePresent - data.frameBegin;
164
double actualPresentLatency_s = data.actualPresent - data.frameBegin;
165
double presentMargin = data.presentMargin;
166
double computedMargin = data.actualPresent - data.queuePresent;
167
168
char presentStats[256] = "";
169
if (data.actualPresent != 0.0) {
170
snprintf(presentStats, sizeof(presentStats),
171
"* Present: %0.1f ms\n"
172
"* Margin: %0.1f ms\n"
173
"* Margin(c): %0.1f ms\n",
174
actualPresentLatency_s * 1000.0,
175
presentMargin * 1000.0,
176
computedMargin * 1000.0);
177
}
178
snprintf(statBuf, sizeof(statBuf),
179
"* Stride: %0.1f (waits: %d)\n"
180
"%llu: From start:\n"
181
"* Past fence: %0.1f ms\n"
182
"* Submit #1: %0.1f ms\n"
183
"* Queue-p: %0.1f ms\n"
184
"%s",
185
stride * 1000.0,
186
data.waitCount,
187
(long long)data.frameId,
188
fenceLatency_s * 1000.0,
189
submitLatency_s * 1000.0,
190
queuePresentLatency_s * 1000.0,
191
presentStats
192
);
193
}
194
ctx->Draw()->DrawTextRect(ubuntu24, statBuf, bounds.x + 10 + i * 150, bounds.y + 150, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
195
}
196
ctx->Draw()->SetFontScale(1.0f, 1.0f);
197
ctx->Flush();
198
ctx->RebindTexture();
199
}
200
201
void DrawFramebufferList(UIContext *ctx, GPUDebugInterface *gpu, const Bounds &bounds) {
202
if (!gpu) {
203
return;
204
}
205
FontID ubuntu24("UBUNTU24");
206
auto list = gpu->GetFramebufferList();
207
ctx->Flush();
208
ctx->BindFontTexture();
209
ctx->Draw()->SetFontScale(0.7f, 0.7f);
210
211
int i = 0;
212
for (const VirtualFramebuffer *vfb : list) {
213
char buf[512];
214
snprintf(buf, sizeof(buf), "%08x (Z %08x): %dx%d (stride %d, %d)",
215
vfb->fb_address, vfb->z_address, vfb->width, vfb->height, vfb->fb_stride, vfb->z_stride);
216
ctx->Draw()->DrawTextRect(ubuntu24, buf, bounds.x + 10, bounds.y + 20 + i * 50, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
217
i++;
218
}
219
ctx->Flush();
220
}
221
222
void DrawControlMapperOverlay(UIContext *ctx, const Bounds &bounds, const ControlMapper &controlMapper) {
223
DrawControlDebug(ctx, controlMapper, ctx->GetLayoutBounds());
224
}
225
226
void DrawDebugOverlay(UIContext *ctx, const Bounds &bounds, DebugOverlay overlay) {
227
bool inGame = GetUIState() == UISTATE_INGAME;
228
229
switch (overlay) {
230
case DebugOverlay::DEBUG_STATS:
231
if (inGame)
232
DrawDebugStats(ctx, ctx->GetLayoutBounds());
233
break;
234
case DebugOverlay::FRAME_GRAPH:
235
if (inGame)
236
DrawFrameTimes(ctx, ctx->GetLayoutBounds());
237
break;
238
case DebugOverlay::FRAME_TIMING:
239
DrawFrameTiming(ctx, ctx->GetLayoutBounds());
240
break;
241
case DebugOverlay::Audio:
242
DrawAudioDebugStats(ctx, ctx->GetLayoutBounds());
243
break;
244
#if !PPSSPP_PLATFORM(UWP) && !PPSSPP_PLATFORM(SWITCH)
245
case DebugOverlay::GPU_PROFILE:
246
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
247
DrawGPUProfilerVis(ctx, gpu);
248
}
249
break;
250
case DebugOverlay::GPU_ALLOCATOR:
251
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
252
DrawGPUMemoryVis(ctx, gpu);
253
}
254
break;
255
#endif
256
case DebugOverlay::FRAMEBUFFER_LIST:
257
if (inGame)
258
DrawFramebufferList(ctx, gpu, bounds);
259
break;
260
default:
261
break;
262
}
263
}
264
265
266
static const char *CPUCoreAsString(int core) {
267
switch (core) {
268
case 0: return "Interpreter";
269
case 1: return "JIT";
270
case 2: return "IR Interpreter";
271
case 3: return "JIT using IR";
272
default: return "N/A";
273
}
274
}
275
276
void DrawCrashDump(UIContext *ctx, const Path &gamePath) {
277
const MIPSExceptionInfo &info = Core_GetExceptionInfo();
278
279
auto sy = GetI18NCategory(I18NCat::SYSTEM);
280
FontID ubuntu24("UBUNTU24");
281
std::string discID = g_paramSFO.GetDiscID();
282
283
std::string activeFlags = PSP_CoreParameter().compat.GetActiveFlagsString();
284
if (activeFlags.empty()) {
285
activeFlags = "(no compat flags active)";
286
}
287
288
int x = 20 + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT);
289
int y = 20 + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP);
290
291
ctx->Flush();
292
if (ctx->Draw()->GetFontAtlas()->getFont(ubuntu24))
293
ctx->BindFontTexture();
294
ctx->Draw()->SetFontScale(1.1f, 1.1f);
295
ctx->Draw()->DrawTextShadow(ubuntu24, sy->T_cstr("Game crashed"), x, y, 0xFFFFFFFF);
296
297
char statbuf[4096];
298
char versionString[256];
299
snprintf(versionString, sizeof(versionString), "%s", PPSSPP_GIT_VERSION);
300
301
bool checkingISO = false;
302
bool isoOK = false;
303
char crcStr[50]{};
304
305
switch (PSP_CoreParameter().fileType) {
306
case IdentifiedFileType::PSP_ISO:
307
case IdentifiedFileType::PSP_ISO_NP:
308
{
309
if (Reporting::HasCRC(gamePath)) {
310
u32 crc = Reporting::RetrieveCRC(gamePath);
311
std::vector<GameDBInfo> dbInfos;
312
if (discID.size() >= 9 && g_gameDB.GetGameInfos(discID, &dbInfos)) {
313
for (auto &dbInfo : dbInfos) {
314
if (dbInfo.crc == crc) {
315
isoOK = true;
316
}
317
}
318
}
319
snprintf(crcStr, sizeof(crcStr), "CRC: %08x %s\n", crc, isoOK ? "(Known good!)" : "(not identified)");
320
} else {
321
// Queue it for calculation, we want it!
322
// It's OK to call this repeatedly until we have it, which is natural here.
323
Reporting::QueueCRC(gamePath);
324
checkingISO = true;
325
}
326
break;
327
}
328
default:
329
// Don't show ISO warning for other file types.
330
isoOK = true;
331
break;
332
};
333
334
// TODO: Draw a lot more information. Full register set, and so on.
335
336
#ifdef _DEBUG
337
const char * const build = "debug";
338
#else
339
const char * const build = "release";
340
#endif
341
342
std::string sysName = System_GetProperty(SYSPROP_NAME);
343
int sysVersion = System_GetPropertyInt(SYSPROP_SYSTEMVERSION);
344
345
// First column
346
y += 65;
347
348
int columnWidth = (ctx->GetBounds().w - x - 10) / 2;
349
int height = ctx->GetBounds().h;
350
351
ctx->PushScissor(Bounds(x, y, columnWidth, height));
352
353
// INFO_LOG(Log::System, "DrawCrashDump (%d %d %d %d)", x, y, columnWidth, height);
354
355
snprintf(statbuf, sizeof(statbuf), R"(%s
356
%s (%s)
357
%s (%s)
358
%s v%d (%s)
359
%s
360
)",
361
ExceptionTypeAsString(info.type),
362
discID.c_str(), g_paramSFO.GetValueString("TITLE").c_str(),
363
versionString, build,
364
sysName.c_str(), sysVersion, GetCompilerABI(),
365
crcStr
366
);
367
368
ctx->Draw()->SetFontScale(.7f, .7f);
369
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
370
y += 160;
371
372
if (info.type == MIPSExceptionType::MEMORY) {
373
snprintf(statbuf, sizeof(statbuf), R"(
374
Access: %s at %08x (sz: %d)
375
PC: %08x
376
%s)",
377
MemoryExceptionTypeAsString(info.memory_type),
378
info.address,
379
info.accessSize,
380
info.pc,
381
info.info.c_str());
382
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
383
y += 180;
384
} else if (info.type == MIPSExceptionType::BAD_EXEC_ADDR) {
385
snprintf(statbuf, sizeof(statbuf), R"(
386
Destination: %s to %08x
387
PC: %08x
388
RA: %08x)",
389
ExecExceptionTypeAsString(info.exec_type),
390
info.address,
391
info.pc,
392
info.ra);
393
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
394
y += 180;
395
} else if (info.type == MIPSExceptionType::BREAK) {
396
snprintf(statbuf, sizeof(statbuf), R"(
397
BREAK
398
PC: %08x
399
)", info.pc);
400
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
401
y += 180;
402
} else {
403
snprintf(statbuf, sizeof(statbuf), R"(
404
Invalid / Unknown (%d)
405
)", (int)info.type);
406
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
407
y += 180;
408
}
409
410
std::string kernelState = __KernelStateSummary();
411
412
ctx->Draw()->DrawTextShadow(ubuntu24, kernelState.c_str(), x, y, 0xFFFFFFFF);
413
414
y += 40;
415
416
ctx->Draw()->SetFontScale(.5f, .5f);
417
418
ctx->Draw()->DrawTextShadow(ubuntu24, info.stackTrace.c_str(), x, y, 0xFFFFFFFF);
419
420
ctx->Draw()->SetFontScale(.7f, .7f);
421
422
ctx->PopScissor();
423
424
// Draw some additional stuff to the right, explaining why the background is purple, if it is.
425
// Should try to be in sync with Reporting::IsSupported().
426
427
std::string tips;
428
if (CheatsInEffect()) {
429
tips += "* Turn off cheats.\n";
430
}
431
if (HLEPlugins::HasEnabled()) {
432
tips += "* Turn off plugins.\n";
433
}
434
if (g_Config.uJitDisableFlags) {
435
tips += StringFromFormat("* Don't use JitDisableFlags: %08x\n", g_Config.uJitDisableFlags);
436
}
437
if (GetLockedCPUSpeedMhz()) {
438
tips += "* Set CPU clock to default (0)\n";
439
}
440
if (checkingISO) {
441
tips += "* (waiting for CRC...)\n";
442
} else if (!isoOK) {
443
tips += "* Verify and possibly re-dump your ISO\n (CRC not recognized)\n";
444
}
445
if (g_paramSFO.GetValueString("DISC_VERSION").empty()) {
446
tips += "\n(DISC_VERSION is empty)\n";
447
}
448
if (!tips.empty()) {
449
tips = "Things to try:\n" + tips;
450
}
451
452
x += columnWidth + 10;
453
y = 85;
454
snprintf(statbuf, sizeof(statbuf),
455
"CPU Core: %s (flags: %08x)\n"
456
"Locked CPU freq: %d MHz\n"
457
"Cheats: %s, Plugins: %s\n%s\n\n%s",
458
CPUCoreAsString(g_Config.iCpuCore), g_Config.uJitDisableFlags,
459
GetLockedCPUSpeedMhz(),
460
CheatsInEffect() ? "Y" : "N", HLEPlugins::HasEnabled() ? "Y" : "N", activeFlags.c_str(), tips.c_str());
461
462
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
463
ctx->Flush();
464
ctx->Draw()->SetFontScale(1.0f, 1.0f);
465
ctx->RebindTexture();
466
}
467
468
void DrawFPS(UIContext *ctx, const Bounds &bounds) {
469
FontID ubuntu24("UBUNTU24");
470
float vps, fps, actual_fps;
471
__DisplayGetFPS(&vps, &fps, &actual_fps);
472
473
char temp[256];
474
StringWriter w(temp);
475
476
if ((g_Config.iShowStatusFlags & ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) == ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) {
477
// Both at the same time gets a shorter formulation.
478
w.F("%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / ((g_Config.iDisplayRefreshRate / 60.0f * 59.94f) / 100.0f));
479
} else {
480
if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER) {
481
w.F("FPS: %0.1f", actual_fps);
482
} else if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER) {
483
w.F("Speed: %0.1f%%", vps / (59.94f / 100.0f));
484
}
485
}
486
if (System_GetPropertyBool(SYSPROP_CAN_READ_BATTERY_PERCENTAGE)) {
487
if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT) {
488
const int percentage = System_GetPropertyInt(SYSPROP_BATTERY_PERCENTAGE);
489
// Just plain append battery. Add linebreak?
490
w.F(" Battery: %d%%", percentage);
491
}
492
}
493
494
ctx->Flush();
495
496
ctx->BindFontTexture();
497
ctx->Draw()->SetFontScale(0.7f, 0.7f);
498
ctx->Draw()->DrawText(ubuntu24, w.as_view(), bounds.x2() - 8, bounds.y + 10, 0xc0000000, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
499
ctx->Draw()->DrawText(ubuntu24, w.as_view(), bounds.x2() - 10, bounds.y + 8, 0xFF3fFF3f, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
500
ctx->Draw()->SetFontScale(1.0f, 1.0f);
501
ctx->Flush();
502
ctx->RebindTexture();
503
}
504
505