From db13c09c411946aff75f20231f3e90b1f7798284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 17 Dec 2024 11:12:46 +0100 Subject: [PATCH] Add break-on-count (with rudimentary UI), break on block transfer --- GPU/Common/GPUDebugInterface.h | 5 +++-- GPU/Debugger/Debugger.cpp | 1 + GPU/Debugger/Debugger.h | 1 + GPU/GPUCommon.cpp | 36 ++++++++++++++----------------- GPU/GPUCommon.h | 17 ++++++++++----- UI/ImDebugger/ImDebugger.h | 2 ++ UI/ImDebugger/ImGe.cpp | 29 ++++++++++++++++++++++++- Windows/GEDebugger/GEDebugger.cpp | 4 ++-- Windows/InputBox.cpp | 2 +- Windows/InputBox.h | 2 +- 10 files changed, 67 insertions(+), 32 deletions(-) diff --git a/GPU/Common/GPUDebugInterface.h b/GPU/Common/GPUDebugInterface.h index 5ec2774bff..3a118985dd 100644 --- a/GPU/Common/GPUDebugInterface.h +++ b/GPU/Common/GPUDebugInterface.h @@ -248,9 +248,10 @@ public: virtual void ClearBreakNext() = 0; virtual void SetBreakNext(GPUDebug::BreakNext next) = 0 ; virtual void SetBreakCount(int c, bool relative = false) = 0 ; - virtual GPUDebug::BreakNext GetBreakNext() = 0 ; + virtual GPUDebug::BreakNext GetBreakNext() const = 0; + virtual int GetBreakCount() const = 0; virtual bool SetRestrictPrims(std::string_view rule) = 0 ; - virtual const char *GetRestrictPrims() = 0 ; + virtual std::string_view GetRestrictPrims() = 0; virtual GPURecord::Recorder *GetRecorder() = 0; virtual GPUBreakpoints *GetBreakpoints() = 0; diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index 376b947310..7745a9d93a 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -36,6 +36,7 @@ const char *BreakNextToString(BreakNext next) { case BreakNext::VSYNC: return "VSYNC"; case BreakNext::PRIM: return "PRIM"; case BreakNext::CURVE: return "CURVE"; + case BreakNext::BLOCK_TRANSFER: return "BLOCK_TRANSFER"; case BreakNext::COUNT: return "COUNT"; default: return "N/A"; } diff --git a/GPU/Debugger/Debugger.h b/GPU/Debugger/Debugger.h index 48e08fbb32..4fa0c61ddb 100644 --- a/GPU/Debugger/Debugger.h +++ b/GPU/Debugger/Debugger.h @@ -34,6 +34,7 @@ enum class BreakNext { VSYNC, PRIM, CURVE, + BLOCK_TRANSFER, COUNT, }; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index ccb9420d87..0cc1caca0d 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2017,10 +2017,6 @@ void GPUCommon::ClearBreakNext() { GPUStepping::ResumeFromStepping(); } -GPUDebug::BreakNext GPUCommon::GetBreakNext() { - return breakNext_; -} - void GPUCommon::SetBreakNext(GPUDebug::BreakNext next) { breakNext_ = next; breakAtCount_ = -1; @@ -2034,6 +2030,7 @@ void GPUCommon::SetBreakNext(GPUDebug::BreakNext next) { breakpoints_.AddCmdBreakpoint(GE_CMD_BEZIER, true); breakpoints_.AddCmdBreakpoint(GE_CMD_SPLINE, true); breakpoints_.AddCmdBreakpoint(GE_CMD_VAP, true); + breakpoints_.AddCmdBreakpoint(GE_CMD_TRANSFERSTART, true); // We count block transfers as prims, too. break; case GPUDebug::BreakNext::CURVE: breakpoints_.AddCmdBreakpoint(GE_CMD_BEZIER, true); @@ -2044,6 +2041,9 @@ void GPUCommon::SetBreakNext(GPUDebug::BreakNext next) { // This will take us to the following actual draw. primAfterDraw_ = true; break; + case GPUDebug::BreakNext::BLOCK_TRANSFER: + breakpoints_.AddCmdBreakpoint(GE_CMD_TRANSFERSTART, true); + break; default: break; } @@ -2075,14 +2075,14 @@ GPUDebug::NotifyResult GPUCommon::NotifyCommand(u32 pc, GPUBreakpoints *breakpoi bool isPrim = false; bool process = true; - if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE || cmd == GE_CMD_VAP) { // VAP is immediate mode prims. + if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE || cmd == GE_CMD_VAP || cmd == GE_CMD_TRANSFERSTART) { // VAP is immediate mode prims. isPrim = true; // TODO: Should restricted prim ranges also avoid breakpoints? - if (!restrictPrimRanges.empty()) { + if (!restrictPrimRanges_.empty()) { process = false; - for (const auto &range : restrictPrimRanges) { + for (const auto &range : restrictPrimRanges_) { if ((primsThisFrame_ + 1) >= range.first && (primsThisFrame_ + 1) <= range.second) { process = true; break; @@ -2100,12 +2100,12 @@ GPUDebug::NotifyResult GPUCommon::NotifyCommand(u32 pc, GPUBreakpoints *breakpoi debugBreak = breakpoints->IsBreakpoint(pc, op); } - if (debugBreak && pc == g_skipPcOnce) { - INFO_LOG(Log::GeDebugger, "Skipping GE break at %08x (last break was here)", g_skipPcOnce); - g_skipPcOnce = 0; + if (debugBreak && pc == skipPcOnce_) { + INFO_LOG(Log::GeDebugger, "Skipping GE break at %08x (last break was here)", skipPcOnce_); + skipPcOnce_ = 0; goto bail; } - g_skipPcOnce = 0; + skipPcOnce_ = 0; if (debugBreak) { breakpoints->ClearTempBreakpoints(); @@ -2119,7 +2119,7 @@ GPUDebug::NotifyResult GPUCommon::NotifyCommand(u32 pc, GPUBreakpoints *breakpoi auto info = DisassembleOp(pc, op); NOTICE_LOG(Log::GeDebugger, "Waiting at %08x, %s", pc, info.desc.c_str()); - g_skipPcOnce = pc; + skipPcOnce_ = pc; breakNext_ = BreakNext::NONE; // Not incrementing the prim counter! return NotifyResult::Break; // caller will call GPUStepping::EnterStepping(). @@ -2159,19 +2159,15 @@ void GPUCommon::NotifyDisplay(u32 framebuf, u32 stride, int format) { bool GPUCommon::SetRestrictPrims(std::string_view rule) { if (rule.empty() || rule == "*") { - restrictPrimRanges.clear(); - restrictPrimRule.clear(); + restrictPrimRanges_.clear(); + restrictPrimRule_.clear(); return true; } - if (GPUDebug::ParsePrimRanges(rule, &restrictPrimRanges)) { - restrictPrimRule = rule; + if (GPUDebug::ParsePrimRanges(rule, &restrictPrimRanges_)) { + restrictPrimRule_ = rule; return true; } else { return false; } } - -const char *GPUCommon::GetRestrictPrims() { - return restrictPrimRule.c_str(); -} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 8e8d9337b2..ae1c629651 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -388,9 +388,16 @@ public: void ClearBreakNext() override; void SetBreakNext(GPUDebug::BreakNext next) override; void SetBreakCount(int c, bool relative = false) override; - GPUDebug::BreakNext GetBreakNext() override; + GPUDebug::BreakNext GetBreakNext() const override { + return breakNext_; + } + int GetBreakCount() const override { + return breakAtCount_; + } bool SetRestrictPrims(std::string_view rule) override; - const char *GetRestrictPrims() override; + std::string_view GetRestrictPrims() override { + return restrictPrimRule_; + } int PrimsThisFrame() const override { return primsThisFrame_; @@ -545,10 +552,10 @@ protected: bool primAfterDraw_ = false; - uint32_t g_skipPcOnce = 0; + uint32_t skipPcOnce_ = 0; - std::vector> restrictPrimRanges; - std::string restrictPrimRule; + std::vector> restrictPrimRanges_; + std::string restrictPrimRule_; private: void DoExecuteCall(u32 target); diff --git a/UI/ImDebugger/ImDebugger.h b/UI/ImDebugger/ImDebugger.h index 616be9a725..01901fb931 100644 --- a/UI/ImDebugger/ImDebugger.h +++ b/UI/ImDebugger/ImDebugger.h @@ -151,6 +151,8 @@ struct ImConfig { int selectedMemCheck = -1; uint64_t selectedTexAddr = 0; + int breakCount = 0; + bool displayLatched = false; // We use a separate ini file from the main PPSSPP config. diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index 9cd627ce68..aee9829fac 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -784,6 +784,10 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterfa gpuDebug->SetBreakNext(GPUDebug::BreakNext::DRAW); } ImGui::SameLine(); + if (ImGui::Button("Block xfer")) { + gpuDebug->SetBreakNext(GPUDebug::BreakNext::BLOCK_TRANSFER); + } + ImGui::SameLine(); if (ImGui::Button("Curve")) { gpuDebug->SetBreakNext(GPUDebug::BreakNext::CURVE); } @@ -798,7 +802,26 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterfa ImGui::SameLine(); ImGui::Text("%d/%d", gpuDebug->PrimsThisFrame(), gpuDebug->PrimsLastFrame()); - // TODO: Break on count! + if (disableStepButtons) { + ImGui::BeginDisabled(); + } + ImGui::SameLine(); + ImGui::SetNextItemWidth(160.0f); + ImGui::InputInt("Number", &cfg.breakCount); + + ImGui::SameLine(); + if (ImGui::Button("Break on #")) { + gpuDebug->SetBreakNext(GPUDebug::BreakNext::COUNT); + gpuDebug->SetBreakCount(cfg.breakCount); + } + ImGui::SameLine(); + if (ImGui::Button("Step by")) { + gpuDebug->SetBreakNext(GPUDebug::BreakNext::COUNT); + gpuDebug->SetBreakCount(cfg.breakCount, true); // relative + } + if (disableStepButtons) { + ImGui::EndDisabled(); + } // Line break if (ImGui::Button("Goto PC")) { @@ -821,6 +844,10 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterfa if (showBannerInFrames_ == 0) { ImGui::Text("Step pending (waiting for CPU): %s", GPUDebug::BreakNextToString(gpuDebug->GetBreakNext())); ImGui::SameLine(); + if (gpuDebug->GetBreakNext() == GPUDebug::BreakNext::COUNT) { + ImGui::Text("(%d)", gpuDebug->GetBreakCount()); + ImGui::SameLine(); + } if (ImGui::Button("Cancel step")) { gpuDebug->ClearBreakNext(); } diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 975d25100c..c9f1462dd9 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -1116,8 +1116,8 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case IDC_GEDBG_SETPRIMFILTER: { - std::string value = gpuDebug->GetRestrictPrims(); - if (InputBox_GetString(GetModuleHandle(NULL), m_hDlg, L"Prim counter ranges", value, value)) { + std::string value; + if (InputBox_GetString(GetModuleHandle(NULL), m_hDlg, L"Prim counter ranges", gpuDebug->GetRestrictPrims(), value)) { gpuDebug->SetRestrictPrims(value.c_str()); } break; diff --git a/Windows/InputBox.cpp b/Windows/InputBox.cpp index 4c760585da..d539798774 100644 --- a/Windows/InputBox.cpp +++ b/Windows/InputBox.cpp @@ -59,7 +59,7 @@ static INT_PTR CALLBACK InputBoxFunc(HWND hDlg, UINT message, WPARAM wParam, LPA } } -bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::string &defaultValue, std::string &outvalue, InputBoxFlags flags) { +bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, std::string_view defaultValue, std::string &outvalue, InputBoxFlags flags) { const wchar_t *defaultTitle = L"Input value"; g_params.defaultSelected = flags & InputBoxFlags::Selected; diff --git a/Windows/InputBox.h b/Windows/InputBox.h index 9f5a805a98..79d790b9bb 100644 --- a/Windows/InputBox.h +++ b/Windows/InputBox.h @@ -12,7 +12,7 @@ enum class InputBoxFlags { ENUM_CLASS_BITOPS(InputBoxFlags); // All I/O is in UTF-8 -bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::string &defaultvalue, std::string &outvalue, InputBoxFlags flags = InputBoxFlags::Default); +bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, std::string_view defaultvalue, std::string &outvalue, InputBoxFlags flags = InputBoxFlags::Default); bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, const wchar_t *title, u32 defaultvalue, u32 &outvalue); bool UserPasswordBox_GetStrings(HINSTANCE hInst, HWND hParent, const wchar_t *title, std::string *username, std::string *password);