CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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