From c66619f7c925a5ae2b5950296ed881f464c98232 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Feb 2022 21:25:33 -0800 Subject: [PATCH] GE Debugger: Add filter to skip prim calls. This allows you to cut prims from the scene as desired. --- GPU/Debugger/Debugger.cpp | 108 ++++++++++++++++++++++++++++-- GPU/Debugger/Debugger.h | 6 +- GPU/GPUCommon.cpp | 38 ++++++----- Windows/GEDebugger/GEDebugger.cpp | 9 +++ Windows/ppsspp.rc | 2 + Windows/resource.h | 3 +- 6 files changed, 138 insertions(+), 28 deletions(-) diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index 5c70f1066d..2e67bf01e1 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -15,7 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include "Common/Log.h" +#include "Common/StringUtils.h" #include "GPU/GPU.h" #include "GPU/Debugger/Breakpoints.h" #include "GPU/Debugger/Debugger.h" @@ -32,6 +34,9 @@ static int primsLastFrame = 0; static int primsThisFrame = 0; static int thisFlipNum = 0; +static std::vector> restrictPrimRanges; +static std::string restrictPrimRule; + static void Init() { if (!inited) { GPUBreakpoints::Init(); @@ -90,9 +95,9 @@ static bool IsBreakpoint(u32 pc, u32 op) { } } -void NotifyCommand(u32 pc) { +bool NotifyCommand(u32 pc) { if (!active) - return; + return true; u32 op = Memory::ReadUnchecked_U32(pc); u32 cmd = op >> 24; if (thisFlipNum != gpuStats.numFlips) { @@ -100,8 +105,20 @@ void NotifyCommand(u32 pc) { primsThisFrame = 0; thisFlipNum = gpuStats.numFlips; } + + bool process = true; if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE) { primsThisFrame++; + + if (!restrictPrimRanges.empty()) { + process = false; + for (const auto &range : restrictPrimRanges) { + if (primsThisFrame >= range.first && primsThisFrame <= range.second) { + process = true; + break; + } + } + } } if (IsBreakpoint(pc, op)) { @@ -111,6 +128,8 @@ void NotifyCommand(u32 pc) { NOTICE_LOG(G3D, "Waiting at %08x, %s", pc, info.desc.c_str()); GPUStepping::EnterStepping(); } + + return process; } void NotifyDraw() { @@ -131,11 +150,6 @@ void NotifyDisplay(u32 framebuf, u32 stride, int format) { } } -void NotifyTextureAttachment(u32 texaddr) { - if (!active) - return; -} - int PrimsThisFrame() { return primsThisFrame; } @@ -144,4 +158,84 @@ int PrimsLastFrame() { return primsLastFrame; } +static bool ParseRange(const std::string &s, std::pair &range) { + int c = sscanf(s.c_str(), "%d-%d", &range.first, &range.second); + if (c == 0) + return false; + if (c == 1) + range.second = range.first; + return true; +} + +bool SetRestrictPrims(const char *rule) { + SetActive(true); + if (rule == nullptr || rule[0] == 0 || (rule[0] == '*' && rule[1] == 0)) { + restrictPrimRanges.clear(); + restrictPrimRule.clear(); + return true; + } + + static constexpr int MAX_PRIMS = 0x7FFFFFFF; + std::vector parts; + SplitString(rule, ',', parts); + + // Parse expressions like: 0 or 0-1,4-5 or !2 or !2-3 or !2,!3 + std::vector> updated; + for (auto &part : parts) { + std::pair range; + if (part.size() > 1 && part[0] == '!') { + if (!ParseRange(part.substr(1), range)) + return false; + + // If there's nothing yet, add everything else. + if (updated.empty()) { + if (range.first > 0) + updated.push_back(std::make_pair(0, range.first - 1)); + if (range.second < MAX_PRIMS) + updated.push_back(std::make_pair(range.second + 1, MAX_PRIMS)); + continue; + } + + // Otherwise, remove this range from any existing. + for (size_t i = 0; i < updated.size(); ++i) { + auto &sub = updated[i]; + if (sub.second < range.first || sub.first > range.second) + continue; + if (sub.first >= range.first && sub.second <= range.second) { + // Entire subrange is inside the deleted entries, nuke. + sub.first = -1; + sub.second = -1; + continue; + } + if (sub.first < range.first && sub.second > range.second) { + // We're slicing a hole in this subrange. + int next = sub.second; + sub.second = range.first - 1; + updated.push_back(std::make_pair(range.second + 1, next)); + continue; + } + + // If we got here, we're simply clipping the subrange. + if (sub.first < range.first && sub.second >= range.first && sub.second <= range.second) + sub.second = range.first - 1; + if (sub.first >= range.first && sub.first <= range.second && sub.second < range.second) + sub.first = range.second + 1; + } + } else { + if (!ParseRange(part, range)) + return false; + + updated.push_back(range); + } + } + + restrictPrimRanges = updated; + restrictPrimRule = rule; + return true; +} + +const char *GetRestrictPrims() { + return restrictPrimRule.c_str(); +} + } diff --git a/GPU/Debugger/Debugger.h b/GPU/Debugger/Debugger.h index 15be467cda..43ec3174b9 100644 --- a/GPU/Debugger/Debugger.h +++ b/GPU/Debugger/Debugger.h @@ -40,12 +40,14 @@ void SetBreakNext(BreakNext next); void SetBreakCount(int c, bool relative = false); // While debugging is active, these may block. -void NotifyCommand(u32 pc); +bool NotifyCommand(u32 pc); void NotifyDraw(); void NotifyDisplay(u32 framebuf, u32 stride, int format); -void NotifyTextureAttachment(u32 texaddr); int PrimsThisFrame(); int PrimsLastFrame(); +bool SetRestrictPrims(const char *rule); +const char *GetRestrictPrims(); + } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 532b95786b..37ed289a2d 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1097,27 +1097,29 @@ void GPUCommon::SlowRunLoop(DisplayList &list) const bool dumpThisFrame = dumpThisFrame_; while (downcount > 0) { - GPUDebug::NotifyCommand(list.pc); - GPURecord::NotifyCommand(list.pc); - u32 op = Memory::ReadUnchecked_U32(list.pc); - u32 cmd = op >> 24; + bool process = GPUDebug::NotifyCommand(list.pc); + if (process) { + GPURecord::NotifyCommand(list.pc); + u32 op = Memory::ReadUnchecked_U32(list.pc); + u32 cmd = op >> 24; - u32 diff = op ^ gstate.cmdmem[cmd]; - PreExecuteOp(op, diff); - if (dumpThisFrame) { - char temp[256]; - u32 prev; - if (Memory::IsValidAddress(list.pc - 4)) { - prev = Memory::ReadUnchecked_U32(list.pc - 4); - } else { - prev = 0; + u32 diff = op ^ gstate.cmdmem[cmd]; + PreExecuteOp(op, diff); + if (dumpThisFrame) { + char temp[256]; + u32 prev; + if (Memory::IsValidAddress(list.pc - 4)) { + prev = Memory::ReadUnchecked_U32(list.pc - 4); + } else { + prev = 0; + } + GeDisassembleOp(list.pc, op, prev, temp, 256); + NOTICE_LOG(G3D, "%08x: %s", op, temp); } - GeDisassembleOp(list.pc, op, prev, temp, 256); - NOTICE_LOG(G3D, "%08x: %s", op, temp); - } - gstate.cmdmem[cmd] = op; + gstate.cmdmem[cmd] = op; - ExecuteOp(op, diff); + ExecuteOp(op, diff); + } list.pc += 4; --downcount; diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 31b8195bee..2a7c32713f 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -912,6 +912,15 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { UpdatePreviews(); } break; + + case IDC_GEDBG_SETPRIMFILTER: + { + std::string value = GPUDebug::GetRestrictPrims(); + if (InputBox_GetString(GetModuleHandle(NULL), m_hDlg, L"Prim counter ranges", value, value)) { + GPUDebug::SetRestrictPrims(value.c_str()); + } + break; + } } break; diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 7b1af26d1c..2dc840f852 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -665,6 +665,8 @@ BEGIN BEGIN MENUITEM "Rec&ord Next Frame", IDC_GEDBG_RECORD MENUITEM "F&lush Pending Draws", IDC_GEDBG_FLUSH + MENUITEM "", 0, MFT_SEPARATOR + MENUITEM "Fi<er Prims", IDC_GEDBG_SETPRIMFILTER END POPUP "&Step", ID_GEDBG_STEP_MENU diff --git a/Windows/resource.h b/Windows/resource.h index 98ecab1e1c..29879fdc57 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -325,6 +325,7 @@ #define IDC_GEDBG_FLUSH 40212 #define IDC_GEDBG_FLUSHAUTO 40213 #define IDI_BREAKPOINT_SMALL 40214 +#define IDC_GEDBG_SETPRIMFILTER 40215 // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 @@ -337,7 +338,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 256 -#define _APS_NEXT_COMMAND_VALUE 40215 +#define _APS_NEXT_COMMAND_VALUE 40216 #define _APS_NEXT_CONTROL_VALUE 1202 #define _APS_NEXT_SYMED_VALUE 101 #endif