CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/UI/DebugOverlay.cpp
Views: 1401
#include "Common/Render/DrawBuffer.h"1#include "Common/GPU/thin3d.h"2#include "Common/System/System.h"3#include "Common/Data/Text/I18n.h"4#include "Common/CPUDetect.h"5#include "Core/MIPS/MIPS.h"6#include "Core/HW/Display.h"7#include "Core/FrameTiming.h"8#include "Core/HLE/sceSas.h"9#include "Core/HLE/sceKernel.h"10#include "Core/HLE/scePower.h"11#include "Core/HLE/Plugins.h"12#include "Core/ControlMapper.h"13#include "Core/Config.h"14#include "Core/MemFault.h"15#include "Core/Reporting.h"16#include "Core/CwCheat.h"17#include "Core/Core.h"18#include "Core/ELF/ParamSFO.h"19#include "Core/System.h"20#include "Core/Util/GameDB.h"21#include "GPU/GPU.h"22#include "GPU/GPUInterface.h"23// TODO: This should be moved here or to Common, doesn't belong in /GPU24#include "GPU/Vulkan/DebugVisVulkan.h"25#include "GPU/Common/FramebufferManagerCommon.h"2627#include "UI/DevScreens.h"28#include "UI/DebugOverlay.h"2930// For std::max31#include <algorithm>3233static void DrawDebugStats(UIContext *ctx, const Bounds &bounds) {34FontID ubuntu24("UBUNTU24");3536float left = std::max(bounds.w / 2 - 20.0f, 550.0f);37float right = bounds.w - left - 20.0f;3839char statbuf[4096];4041ctx->Flush();42ctx->BindFontTexture();43ctx->Draw()->SetFontScale(.7f, .7f);4445__DisplayGetDebugStats(statbuf, sizeof(statbuf));46ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 11, bounds.y + 31, left, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII);47ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 10, bounds.y + 30, left, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);4849ctx->Draw()->SetFontScale(1.0f, 1.0f);50ctx->Flush();51ctx->RebindTexture();52}5354static void DrawAudioDebugStats(UIContext *ctx, const Bounds &bounds) {55FontID ubuntu24("UBUNTU24");5657char statbuf[4096] = { 0 };58System_AudioGetDebugStats(statbuf, sizeof(statbuf));5960ctx->Flush();61ctx->BindFontTexture();62ctx->Draw()->SetFontScale(0.5f, 0.5f);63ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 11, bounds.y + 31, bounds.w - 20, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII);64ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 10, bounds.y + 30, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);6566float left = std::max(bounds.w / 2 - 20.0f, 500.0f);6768__SasGetDebugStats(statbuf, sizeof(statbuf));69ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + left + 21, bounds.y + 31, bounds.w - left, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII);70ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + left + 20, bounds.y + 30, bounds.w - left, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);7172ctx->Draw()->SetFontScale(1.0f, 1.0f);7374ctx->Flush();75ctx->RebindTexture();76}7778static void DrawControlDebug(UIContext *ctx, const ControlMapper &mapper, const Bounds &bounds) {79FontID ubuntu24("UBUNTU24");8081char statbuf[4096] = { 0 };82mapper.GetDebugString(statbuf, sizeof(statbuf));8384ctx->Flush();85ctx->BindFontTexture();86ctx->Draw()->SetFontScale(0.5f, 0.5f);87ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 11, bounds.y + 31, bounds.w - 20, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII);88ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 10, bounds.y + 30, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);89ctx->Draw()->SetFontScale(1.0f, 1.0f);90ctx->Flush();91ctx->RebindTexture();92}9394static void DrawFrameTimes(UIContext *ctx, const Bounds &bounds) {95FontID ubuntu24("UBUNTU24");96double *sleepHistory;97int valid, pos;98double *history = __DisplayGetFrameTimes(&valid, &pos, &sleepHistory);99int scale = 7000;100int width = 600;101102ctx->Flush();103ctx->BeginNoTex();104int bottom = bounds.y2();105for (int i = 0; i < valid; ++i) {106double activeTime = history[i] - sleepHistory[i];107ctx->Draw()->vLine(bounds.x + i, bottom, bottom - activeTime * scale, 0xFF3FFF3F);108ctx->Draw()->vLine(bounds.x + i, bottom - activeTime * scale, bottom - history[i] * scale, 0x7F3FFF3F);109}110ctx->Draw()->vLine(bounds.x + pos, bottom, bottom - 512, 0xFFff3F3f);111112ctx->Draw()->hLine(bounds.x, bottom - 0.0333 * scale, bounds.x + width, 0xFF3f3Fff);113ctx->Draw()->hLine(bounds.x, bottom - 0.0167 * scale, bounds.x + width, 0xFF3f3Fff);114115ctx->Flush();116ctx->Begin();117ctx->BindFontTexture();118ctx->Draw()->SetFontScale(0.5f, 0.5f);119ctx->Draw()->DrawText(ubuntu24, "33.3ms", bounds.x + width, bottom - 0.0333 * scale, 0xFF3f3Fff, ALIGN_BOTTOMLEFT | FLAG_DYNAMIC_ASCII);120ctx->Draw()->DrawText(ubuntu24, "16.7ms", bounds.x + width, bottom - 0.0167 * scale, 0xFF3f3Fff, ALIGN_BOTTOMLEFT | FLAG_DYNAMIC_ASCII);121ctx->Draw()->SetFontScale(1.0f, 1.0f);122ctx->Flush();123ctx->RebindTexture();124}125126static void DrawFrameTiming(UIContext *ctx, const Bounds &bounds) {127FontID ubuntu24("UBUNTU24");128129char statBuf[1024]{};130131ctx->Flush();132ctx->BindFontTexture();133ctx->Draw()->SetFontScale(0.5f, 0.5f);134135snprintf(statBuf, sizeof(statBuf),136"Mode (interval): %s (%d)",137Draw::PresentModeToString(g_frameTiming.presentMode),138g_frameTiming.presentInterval);139140ctx->Draw()->DrawTextRect(ubuntu24, statBuf, bounds.x + 10, bounds.y + 50, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);141142for (int i = 0; i < 5; i++) {143size_t curIndex = i + 6;144size_t prevIndex = i + 7;145146FrameTimeData data = ctx->GetDrawContext()->FrameTimeHistory().Back(curIndex);147FrameTimeData prevData = ctx->GetDrawContext()->FrameTimeHistory().Back(prevIndex);148if (data.frameBegin == 0.0) {149snprintf(statBuf, sizeof(statBuf), "(No frame time data)");150} else {151double stride = data.frameBegin - prevData.frameBegin;152double fenceLatency_s = data.afterFenceWait - data.frameBegin;153double submitLatency_s = data.firstSubmit - data.frameBegin;154double queuePresentLatency_s = data.queuePresent - data.frameBegin;155double actualPresentLatency_s = data.actualPresent - data.frameBegin;156double presentMargin = data.presentMargin;157double computedMargin = data.actualPresent - data.queuePresent;158159char presentStats[256] = "";160if (data.actualPresent != 0.0) {161snprintf(presentStats, sizeof(presentStats),162"* Present: %0.1f ms\n"163"* Margin: %0.1f ms\n"164"* Margin(c): %0.1f ms\n",165actualPresentLatency_s * 1000.0,166presentMargin * 1000.0,167computedMargin * 1000.0);168}169snprintf(statBuf, sizeof(statBuf),170"* Stride: %0.1f (waits: %d)\n"171"%llu: From start:\n"172"* Past fence: %0.1f ms\n"173"* Submit #1: %0.1f ms\n"174"* Queue-p: %0.1f ms\n"175"%s",176stride * 1000.0,177data.waitCount,178(long long)data.frameId,179fenceLatency_s * 1000.0,180submitLatency_s * 1000.0,181queuePresentLatency_s * 1000.0,182presentStats183);184}185ctx->Draw()->DrawTextRect(ubuntu24, statBuf, bounds.x + 10 + i * 150, bounds.y + 150, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);186}187ctx->Draw()->SetFontScale(1.0f, 1.0f);188ctx->Flush();189ctx->RebindTexture();190}191192void DrawFramebufferList(UIContext *ctx, GPUInterface *gpu, const Bounds &bounds) {193if (!gpu) {194return;195}196FontID ubuntu24("UBUNTU24");197auto list = gpu->GetFramebufferList();198ctx->Flush();199ctx->BindFontTexture();200ctx->Draw()->SetFontScale(0.7f, 0.7f);201202int i = 0;203for (const VirtualFramebuffer *vfb : list) {204char buf[512];205snprintf(buf, sizeof(buf), "%08x (Z %08x): %dx%d (stride %d, %d)",206vfb->fb_address, vfb->z_address, vfb->width, vfb->height, vfb->fb_stride, vfb->z_stride);207ctx->Draw()->DrawTextRect(ubuntu24, buf, bounds.x + 10, bounds.y + 20 + i * 50, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);208i++;209}210ctx->Flush();211}212213void DrawControlMapperOverlay(UIContext *ctx, const Bounds &bounds, const ControlMapper &controlMapper) {214DrawControlDebug(ctx, controlMapper, ctx->GetLayoutBounds());215}216217void DrawDebugOverlay(UIContext *ctx, const Bounds &bounds, DebugOverlay overlay) {218bool inGame = GetUIState() == UISTATE_INGAME;219220switch (overlay) {221case DebugOverlay::DEBUG_STATS:222if (inGame)223DrawDebugStats(ctx, ctx->GetLayoutBounds());224break;225case DebugOverlay::FRAME_GRAPH:226if (inGame)227DrawFrameTimes(ctx, ctx->GetLayoutBounds());228break;229case DebugOverlay::FRAME_TIMING:230DrawFrameTiming(ctx, ctx->GetLayoutBounds());231break;232case DebugOverlay::Audio:233DrawAudioDebugStats(ctx, ctx->GetLayoutBounds());234break;235#if !PPSSPP_PLATFORM(UWP) && !PPSSPP_PLATFORM(SWITCH)236case DebugOverlay::GPU_PROFILE:237if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {238DrawGPUProfilerVis(ctx, gpu);239}240break;241case DebugOverlay::GPU_ALLOCATOR:242if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {243DrawGPUMemoryVis(ctx, gpu);244}245break;246#endif247case DebugOverlay::FRAMEBUFFER_LIST:248if (inGame)249DrawFramebufferList(ctx, gpu, bounds);250break;251default:252break;253}254}255256257static const char *CPUCoreAsString(int core) {258switch (core) {259case 0: return "Interpreter";260case 1: return "JIT";261case 2: return "IR Interpreter";262case 3: return "JIT using IR";263default: return "N/A";264}265}266267void DrawCrashDump(UIContext *ctx, const Path &gamePath) {268const MIPSExceptionInfo &info = Core_GetExceptionInfo();269270auto sy = GetI18NCategory(I18NCat::SYSTEM);271FontID ubuntu24("UBUNTU24");272std::string discID = g_paramSFO.GetDiscID();273int x = 20 + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT);274int y = 20 + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP);275276ctx->Flush();277if (ctx->Draw()->GetFontAtlas()->getFont(ubuntu24))278ctx->BindFontTexture();279ctx->Draw()->SetFontScale(1.1f, 1.1f);280ctx->Draw()->DrawTextShadow(ubuntu24, sy->T_cstr("Game crashed"), x, y, 0xFFFFFFFF);281282char statbuf[4096];283char versionString[256];284snprintf(versionString, sizeof(versionString), "%s", PPSSPP_GIT_VERSION);285286bool checkingISO = false;287bool isoOK = false;288289char crcStr[50]{};290if (Reporting::HasCRC(gamePath)) {291u32 crc = Reporting::RetrieveCRC(gamePath);292std::vector<GameDBInfo> dbInfos;293if (g_gameDB.GetGameInfos(discID, &dbInfos)) {294for (auto &dbInfo : dbInfos) {295if (dbInfo.crc == crc) {296isoOK = true;297}298}299}300snprintf(crcStr, sizeof(crcStr), "CRC: %08x %s\n", crc, isoOK ? "(Known good!)" : "(not identified)");301} else {302// Queue it for calculation, we want it!303// It's OK to call this repeatedly until we have it, which is natural here.304Reporting::QueueCRC(gamePath);305checkingISO = true;306}307308// TODO: Draw a lot more information. Full register set, and so on.309310#ifdef _DEBUG311char build[] = "debug";312#else313char build[] = "release";314#endif315316std::string sysName = System_GetProperty(SYSPROP_NAME);317int sysVersion = System_GetPropertyInt(SYSPROP_SYSTEMVERSION);318319// First column320y += 65;321322int columnWidth = (ctx->GetBounds().w - x - 10) / 2;323int height = ctx->GetBounds().h;324325ctx->PushScissor(Bounds(x, y, columnWidth, height));326327// INFO_LOG(Log::System, "DrawCrashDump (%d %d %d %d)", x, y, columnWidth, height);328329snprintf(statbuf, sizeof(statbuf), R"(%s330%s (%s)331%s (%s)332%s v%d (%s)333%s334)",335ExceptionTypeAsString(info.type),336discID.c_str(), g_paramSFO.GetValueString("TITLE").c_str(),337versionString, build,338sysName.c_str(), sysVersion, GetCompilerABI(),339crcStr340);341342ctx->Draw()->SetFontScale(.7f, .7f);343ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);344y += 160;345346if (info.type == MIPSExceptionType::MEMORY) {347snprintf(statbuf, sizeof(statbuf), R"(348Access: %s at %08x (sz: %d)349PC: %08x350%s)",351MemoryExceptionTypeAsString(info.memory_type),352info.address,353info.accessSize,354info.pc,355info.info.c_str());356ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);357y += 180;358} else if (info.type == MIPSExceptionType::BAD_EXEC_ADDR) {359snprintf(statbuf, sizeof(statbuf), R"(360Destination: %s to %08x361PC: %08x362RA: %08x)",363ExecExceptionTypeAsString(info.exec_type),364info.address,365info.pc,366info.ra);367ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);368y += 180;369} else if (info.type == MIPSExceptionType::BREAK) {370snprintf(statbuf, sizeof(statbuf), R"(371BREAK372PC: %08x373)", info.pc);374ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);375y += 180;376} else {377snprintf(statbuf, sizeof(statbuf), R"(378Invalid / Unknown (%d)379)", (int)info.type);380ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);381y += 180;382}383384std::string kernelState = __KernelStateSummary();385386ctx->Draw()->DrawTextShadow(ubuntu24, kernelState.c_str(), x, y, 0xFFFFFFFF);387388y += 40;389390ctx->Draw()->SetFontScale(.5f, .5f);391392ctx->Draw()->DrawTextShadow(ubuntu24, info.stackTrace.c_str(), x, y, 0xFFFFFFFF);393394ctx->Draw()->SetFontScale(.7f, .7f);395396ctx->PopScissor();397398// Draw some additional stuff to the right.399400std::string tips;401if (CheatsInEffect()) {402tips += "* Turn off cheats.\n";403}404if (GetLockedCPUSpeedMhz()) {405tips += "* Set CPU clock to default (0)\n";406}407if (checkingISO) {408tips += "* (waiting for CRC...)\n";409} else if (!isoOK) { // TODO: Should check that it actually is an ISO and not a homebrew410tips += "* Verify and possibly re-dump your ISO\n (CRC not recognized)\n";411}412if (!tips.empty()) {413tips = "Things to try:\n" + tips;414}415416x += columnWidth + 10;417y = 85;418snprintf(statbuf, sizeof(statbuf),419"CPU Core: %s (flags: %08x)\n"420"Locked CPU freq: %d MHz\n"421"Cheats: %s, Plugins: %s\n\n%s",422CPUCoreAsString(g_Config.iCpuCore), g_Config.uJitDisableFlags,423GetLockedCPUSpeedMhz(),424CheatsInEffect() ? "Y" : "N", HLEPlugins::HasEnabled() ? "Y" : "N", tips.c_str());425426ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);427ctx->Flush();428ctx->Draw()->SetFontScale(1.0f, 1.0f);429ctx->RebindTexture();430}431432void DrawFPS(UIContext *ctx, const Bounds &bounds) {433FontID ubuntu24("UBUNTU24");434float vps, fps, actual_fps;435__DisplayGetFPS(&vps, &fps, &actual_fps);436437char fpsbuf[256];438fpsbuf[0] = '\0';439if ((g_Config.iShowStatusFlags & ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) == ((int)ShowStatusFlags::FPS_COUNTER | (int)ShowStatusFlags::SPEED_COUNTER)) {440snprintf(fpsbuf, sizeof(fpsbuf), "%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / ((g_Config.iDisplayRefreshRate / 60.0f * 59.94f) / 100.0f));441} else {442if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER) {443snprintf(fpsbuf, sizeof(fpsbuf), "FPS: %0.1f", actual_fps);444} else if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER) {445snprintf(fpsbuf, sizeof(fpsbuf), "Speed: %0.1f%%", vps / (59.94f / 100.0f));446}447}448449#ifdef CAN_DISPLAY_CURRENT_BATTERY_CAPACITY450if (g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT) {451char temp[256];452snprintf(temp, sizeof(temp), "%s Battery: %d%%", fpsbuf, getCurrentBatteryCapacity());453snprintf(fpsbuf, sizeof(fpsbuf), "%s", temp);454}455#endif456457ctx->Flush();458ctx->BindFontTexture();459ctx->Draw()->SetFontScale(0.7f, 0.7f);460ctx->Draw()->DrawText(ubuntu24, fpsbuf, bounds.x2() - 8, 20, 0xc0000000, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);461ctx->Draw()->DrawText(ubuntu24, fpsbuf, bounds.x2() - 10, 19, 0xFF3fFF3f, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);462ctx->Draw()->SetFontScale(1.0f, 1.0f);463ctx->Flush();464ctx->RebindTexture();465}466467468