From 663131d5f8268944f1a394e1efa313f37c39afc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Dec 2024 13:13:31 +0100 Subject: [PATCH 1/8] GPUDebug: Remove lastStepTime --- GPU/Debugger/Debugger.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index f2d8d616b3..34b3a41c0b 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -35,7 +35,6 @@ static int thisFlipNum = 0; bool g_primAfterDraw = false; -static double lastStepTime = -1.0; static uint32_t g_skipPcOnce = 0; static std::vector> restrictPrimRanges; @@ -65,7 +64,6 @@ void ClearBreak() { breakNext = BreakNext::NONE; breakAtCount = -1; GPUStepping::ResumeFromStepping(); - lastStepTime = -1.0; } BreakNext GetBreakNext() { @@ -94,7 +92,6 @@ void SetBreakNext(BreakNext next, GPUBreakpoints *breakpoints) { if (GPUStepping::IsStepping()) { GPUStepping::ResumeFromStepping(); } - lastStepTime = next == BreakNext::NONE ? -1.0 : time_now_d(); } void SetBreakCount(int c, bool relative) { @@ -154,12 +151,7 @@ NotifyResult NotifyCommand(u32 pc, GPUBreakpoints *breakpoints) { } auto info = gpuDebug->DisassembleOp(pc); - if (lastStepTime >= 0.0) { - NOTICE_LOG(Log::GeDebugger, "Waiting at %08x, %s (%fms)", pc, info.desc.c_str(), (time_now_d() - lastStepTime) * 1000.0); - lastStepTime = -1.0; - } else { - NOTICE_LOG(Log::GeDebugger, "Waiting at %08x, %s", pc, info.desc.c_str()); - } + NOTICE_LOG(Log::GeDebugger, "Waiting at %08x, %s", pc, info.desc.c_str()); g_skipPcOnce = pc; breakNext = BreakNext::NONE; From f1e3399916f4a647c178aef871267064d5911fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Dec 2024 13:18:23 +0100 Subject: [PATCH 2/8] Break out the parser from RestrictPrimRanges --- GPU/Debugger/Debugger.cpp | 28 ++++++++++++++++++---------- GPU/Debugger/Debugger.h | 3 ++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index 34b3a41c0b..c3132c818d 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -204,14 +204,9 @@ static bool ParseRange(const std::string &s, std::pair &range) { return true; } -bool SetRestrictPrims(const char *rule) { - if (rule == nullptr || rule[0] == 0 || (rule[0] == '*' && rule[1] == 0)) { - restrictPrimRanges.clear(); - restrictPrimRule.clear(); - return true; - } +bool ParsePrimRanges(std::string_view rule, std::vector> *output) { + constexpr int MAX_PRIMS = 0x7FFFFFFF; - static constexpr int MAX_PRIMS = 0x7FFFFFFF; std::vector parts; SplitString(rule, ',', parts); @@ -264,12 +259,25 @@ bool SetRestrictPrims(const char *rule) { updated.push_back(range); } } - - restrictPrimRanges = updated; - restrictPrimRule = rule; + *output = updated; return true; } +bool SetRestrictPrims(std::string_view rule) { + if (rule.empty() || rule == "*") { + restrictPrimRanges.clear(); + restrictPrimRule.clear(); + return true; + } + + if (ParsePrimRanges(rule, &restrictPrimRanges)) { + restrictPrimRule = rule; + return true; + } else { + return false; + } +} + const char *GetRestrictPrims() { return restrictPrimRule.c_str(); } diff --git a/GPU/Debugger/Debugger.h b/GPU/Debugger/Debugger.h index fa99d039d6..2767cc37bd 100644 --- a/GPU/Debugger/Debugger.h +++ b/GPU/Debugger/Debugger.h @@ -17,6 +17,7 @@ #pragma once +#include #include "Common/CommonTypes.h" namespace GPUDebug { @@ -56,7 +57,7 @@ void NotifyBeginFrame(); int PrimsThisFrame(); int PrimsLastFrame(); -bool SetRestrictPrims(const char *rule); +bool SetRestrictPrims(std::string_view rule); const char *GetRestrictPrims(); } // namespace From 794fa280356028cb56d3d4e9c22f81c5733d1569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Dec 2024 13:23:34 +0100 Subject: [PATCH 3/8] Small simplification --- GPU/Common/FramebufferManagerCommon.cpp | 4 +--- GPU/Common/FramebufferManagerCommon.h | 6 +----- GPU/Debugger/Debugger.cpp | 1 - GPU/Debugger/Debugger.h | 5 +++++ GPU/GPUCommonHW.cpp | 5 ++++- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 84f034f9ee..446225b136 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -140,14 +140,12 @@ bool FramebufferManagerCommon::PresentedThisFrame() const { return presentation_->PresentedThisFrame(); } -void FramebufferManagerCommon::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format, GPURecord::Recorder *recorder) { +void FramebufferManagerCommon::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) { displayFramebufPtr_ = framebuf & 0x3FFFFFFF; if (Memory::IsVRAMAddress(displayFramebufPtr_)) displayFramebufPtr_ = framebuf & 0x041FFFFF; displayStride_ = stride; displayFormat_ = format; - GPUDebug::NotifyDisplay(framebuf, stride, format); - recorder->NotifyDisplay(framebuf, stride, format); } VirtualFramebuffer *FramebufferManagerCommon::GetVFBAt(u32 addr) const { diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index cbd13773dd..37a71d751b 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -273,10 +273,6 @@ namespace Draw { class DrawContext; } -namespace GPURecord { -class Recorder; -} - struct DrawPixelsEntry { Draw::Texture *tex; uint64_t contentsHash; @@ -306,7 +302,7 @@ public: void Init(int msaaLevel); virtual void BeginFrame(); - void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format, GPURecord::Recorder *recorder); + void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format); void DestroyFramebuf(VirtualFramebuffer *v); VirtualFramebuffer *DoSetRenderFrameBuffer(FramebufferHeuristicParams ¶ms, u32 skipDrawReason); diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index c3132c818d..0610965dcd 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -18,7 +18,6 @@ #include #include "Common/Log.h" #include "Common/StringUtils.h" -#include "Common/TimeUtil.h" #include "GPU/GPU.h" #include "GPU/Debugger/Breakpoints.h" #include "GPU/Debugger/Debugger.h" diff --git a/GPU/Debugger/Debugger.h b/GPU/Debugger/Debugger.h index 2767cc37bd..f2d5e3b727 100644 --- a/GPU/Debugger/Debugger.h +++ b/GPU/Debugger/Debugger.h @@ -18,6 +18,8 @@ #pragma once #include +#include +#include #include "Common/CommonTypes.h" namespace GPUDebug { @@ -35,6 +37,9 @@ enum class BreakNext { COUNT, }; +const char *BreakNextToString(BreakNext next); +bool ParsePrimRanges(std::string_view rule, std::vector> *output); + bool NeedsSlowInterpreter(); void SetBreakNext(BreakNext next, GPUBreakpoints *breakpoints); diff --git a/GPU/GPUCommonHW.cpp b/GPU/GPUCommonHW.cpp index 951c78c373..34b77b1fc3 100644 --- a/GPU/GPUCommonHW.cpp +++ b/GPU/GPUCommonHW.cpp @@ -13,6 +13,7 @@ #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/TextureCacheCommon.h" #include "GPU/Common/FramebufferManagerCommon.h" +#include "GPU/Debugger/Debugger.h" struct CommonCommandTableEntry { uint8_t cmd; @@ -512,7 +513,9 @@ void GPUCommonHW::BeginHostFrame() { } void GPUCommonHW::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) { - framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format, &recorder_); + framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format); + GPUDebug::NotifyDisplay(framebuf, stride, format); + recorder_.NotifyDisplay(framebuf, stride, format); } void GPUCommonHW::CheckFlushOp(int cmd, u32 diff) { From 11dbae3457c82f3ff2fabd640629bb3dd183ad2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Dec 2024 13:42:05 +0100 Subject: [PATCH 4/8] Remove the "DispatchFlush" mechanism, not convinced it's a win --- GPU/Common/DrawEngineCommon.cpp | 8 ++++---- GPU/Common/DrawEngineCommon.h | 5 ++--- GPU/Common/FramebufferManagerCommon.cpp | 2 +- GPU/Common/GPUDebugInterface.h | 2 +- GPU/Common/SplineCommon.cpp | 2 +- GPU/D3D11/DrawEngineD3D11.cpp | 6 ++++-- GPU/D3D11/DrawEngineD3D11.h | 17 +---------------- GPU/Debugger/Stepping.cpp | 2 +- GPU/Directx9/DrawEngineDX9.cpp | 6 ++++-- GPU/Directx9/DrawEngineDX9.h | 15 +-------------- GPU/GLES/DrawEngineGLES.cpp | 5 ++++- GPU/GLES/DrawEngineGLES.h | 15 +-------------- GPU/GPUCommon.cpp | 10 +++------- GPU/GPUCommon.h | 2 -- GPU/GPUCommonHW.cpp | 12 ++++++------ GPU/Software/TransformUnit.cpp | 2 +- GPU/Software/TransformUnit.h | 2 +- GPU/Vulkan/DrawEngineVulkan.cpp | 6 +++++- GPU/Vulkan/DrawEngineVulkan.h | 18 ++---------------- 19 files changed, 43 insertions(+), 94 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 7ef2a88041..8724325f17 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -189,7 +189,7 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex bool clockwise = !gstate.isCullEnabled() || gstate.getCullMode() == cullMode; SubmitPrim(&temp[0], nullptr, prim, vertexCount, vertTypeID, clockwise, &bytesRead); - DispatchFlush(); + Flush(); if (!prevThrough) { gstate.vertType &= ~GE_VTYPE_THROUGH; @@ -924,7 +924,7 @@ int DrawEngineCommon::ExtendNonIndexedPrim(const uint32_t *cmd, const uint32_t * void DrawEngineCommon::SkipPrim(GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int *bytesRead) { if (!indexGen.PrimCompatible(prevPrim_, prim)) { - DispatchFlush(); + Flush(); } // This isn't exactly right, if we flushed, since prims can straddle previous calls. @@ -950,7 +950,7 @@ void DrawEngineCommon::SkipPrim(GEPrimitiveType prim, int vertexCount, u32 vertT // vertTypeID is the vertex type but with the UVGen mode smashed into the top bits. bool DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, bool clockwise, int *bytesRead) { if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawVerts_ >= MAX_DEFERRED_DRAW_VERTS || numDrawInds_ >= MAX_DEFERRED_DRAW_INDS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX) { - DispatchFlush(); + Flush(); } _dbg_assert_(numDrawVerts_ < MAX_DEFERRED_DRAW_VERTS); _dbg_assert_(numDrawInds_ < MAX_DEFERRED_DRAW_INDS); @@ -1033,7 +1033,7 @@ bool DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimiti if (prim == GE_PRIM_RECTANGLES && (gstate.getTextureAddress(0) & 0x3FFFFFFF) == (gstate.getFrameBufAddress() & 0x3FFFFFFF)) { // This prevents issues with consecutive self-renders in Ridge Racer. gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); - DispatchFlush(); + Flush(); } return true; } diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 7ec1a92a78..ea8b74d8e3 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -89,9 +89,8 @@ public: static u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, VertexDecoder *dec, int lowerBound, int upperBound, u32 vertType); - // Flush is normally non-virtual but here's a virtual way to call it, used by the shared spline code, which is expensive anyway. - // Not really sure if these wrappers are worth it... - virtual void DispatchFlush() = 0; + // Dispatches the queued-up draws. + virtual void Flush() = 0; // This would seem to be unnecessary now, but is still required for splines/beziers to work in the software backend since SubmitPrim // is different. Should probably refactor that. diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 446225b136..1e8784bee0 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -3256,7 +3256,7 @@ void FramebufferManagerCommon::FlushBeforeCopy() { // all the irrelevant state checking it'll use to decide what to do. Should // do something more focused here. SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); - drawEngine_->DispatchFlush(); + drawEngine_->Flush(); } } diff --git a/GPU/Common/GPUDebugInterface.h b/GPU/Common/GPUDebugInterface.h index 079798d5ca..5d1c47279c 100644 --- a/GPU/Common/GPUDebugInterface.h +++ b/GPU/Common/GPUDebugInterface.h @@ -225,7 +225,7 @@ public: // Needs to be called from the GPU thread. // Calling from a separate thread (e.g. UI) may fail. virtual void SetCmdValue(u32 op) = 0; - virtual void DispatchFlush() = 0; + virtual void Flush() = 0; virtual void GetStats(char *buffer, size_t bufsize) = 0; diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index de22c14fcf..9100e0b21e 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -580,7 +580,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, true, &generatedBytesRead); if (flushOnParams_) - DispatchFlush(); + Flush(); if (origVertType & GE_VTYPE_TC_MASK) { gstate_c.uv = prevUVScale; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index e1cfacdc90..60a3e72456 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -252,8 +252,10 @@ void DrawEngineD3D11::Invalidate(InvalidationCallbackFlags flags) { } } -// The inline wrapper in the header checks for numDrawCalls_ == 0 -void DrawEngineD3D11::DoFlush() { +void DrawEngineD3D11::Flush() { + if (!numDrawVerts_) { + return; + } bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 9f365ab247..d870ae1850 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -77,25 +77,12 @@ public: void BeginFrame(); - // So that this can be inlined - void Flush() { - if (!numDrawVerts_) - return; - DoFlush(); - } + void Flush() override; void FinishDeferred() { - if (!numDrawVerts_) - return; DecodeVerts(decoded_); } - void DispatchFlush() override { - if (!numDrawVerts_) - return; - Flush(); - } - void NotifyConfigChanged() override; void ClearInputLayoutMap(); @@ -103,8 +90,6 @@ public: private: void Invalidate(InvalidationCallbackFlags flags); - void DoFlush(); - void ApplyDrawState(int prim); void ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef); diff --git a/GPU/Debugger/Stepping.cpp b/GPU/Debugger/Stepping.cpp index ff15a566a6..0860c1a292 100644 --- a/GPU/Debugger/Stepping.cpp +++ b/GPU/Debugger/Stepping.cpp @@ -143,7 +143,7 @@ static void RunPauseAction() { break; case PAUSE_FLUSHDRAW: - gpuDebug->DispatchFlush(); + gpuDebug->Flush(); break; default: diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 50f830b385..e973d0370c 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -229,8 +229,10 @@ void DrawEngineDX9::Invalidate(InvalidationCallbackFlags flags) { } } -// The inline wrapper in the header checks for numDrawCalls_ == 0 -void DrawEngineDX9::DoFlush() { +void DrawEngineDX9::Flush() { + if (!numDrawVerts_) { + return; + } bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 2a21c85eec..6bbf6ffcab 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -68,31 +68,18 @@ public: void BeginFrame(); // So that this can be inlined - void Flush() { - if (!numDrawVerts_) - return; - DoFlush(); - } + void Flush() override; void FinishDeferred() { - if (!numDrawVerts_) - return; DecodeVerts(decoded_); } - void DispatchFlush() override { - if (!numDrawVerts_) - return; - Flush(); - } - protected: // Not currently supported. bool UpdateUseHWTessellation(bool enable) const override { return false; } private: void Invalidate(InvalidationCallbackFlags flags); - void DoFlush(); void ApplyDrawState(int prim); void ApplyDrawStateLate(); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 08df5d630b..13adfc2ea9 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -230,7 +230,10 @@ void DrawEngineGLES::Invalidate(InvalidationCallbackFlags flags) { } } -void DrawEngineGLES::DoFlush() { +void DrawEngineGLES::Flush() { + if (!numDrawVerts_) { + return; + } PROFILE_THIS_SCOPE("flush"); FrameData &frameData = frameData_[render_->GetCurFrame()]; VShaderID vsid; diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 06264637f7..167635af5a 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -85,21 +85,8 @@ public: void EndFrame(); // So that this can be inlined - void Flush() { - if (!numDrawVerts_) - return; - DoFlush(); - } - + void Flush() override; void FinishDeferred() { - if (!numDrawVerts_) - return; - DoFlush(); - } - - void DispatchFlush() override { - if (!numDrawVerts_) - return; Flush(); } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 304173f064..0ba269e5a2 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -47,11 +47,7 @@ #include "GPU/Debugger/Stepping.h" void GPUCommon::Flush() { - drawEngineCommon_->DispatchFlush(); -} - -void GPUCommon::DispatchFlush() { - drawEngineCommon_->DispatchFlush(); + drawEngineCommon_->Flush(); } GPUCommon::GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : @@ -1348,7 +1344,7 @@ void GPUCommon::FlushImm() { bool changed = texturing != prevTexturing || cullEnable != prevCullEnable || dither != prevDither; changed = changed || prevShading != shading || prevFog != fog; if (changed) { - DispatchFlush(); + Flush(); gstate.antiAliasEnable = (GE_CMD_ANTIALIASENABLE << 24) | (int)antialias; gstate.shademodel = (GE_CMD_SHADEMODE << 24) | (int)shading; gstate.cullfaceEnable = (GE_CMD_CULLFACEENABLE << 24) | (int)cullEnable; @@ -1363,7 +1359,7 @@ void GPUCommon::FlushImm() { immFirstSent_ = true; if (changed) { - DispatchFlush(); + Flush(); gstate.antiAliasEnable = (GE_CMD_ANTIALIASENABLE << 24) | (int)prevAntialias; gstate.shademodel = (GE_CMD_SHADEMODE << 24) | (int)prevShading; gstate.cullfaceEnable = (GE_CMD_CULLFACEENABLE << 24) | (int)prevCullEnable; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index f929db8feb..3e91671b70 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -305,9 +305,7 @@ public: static int EstimatePerVertexCost(); - // Note: Not virtual! void Flush(); - void DispatchFlush() override; #ifdef USE_CRT_DBG #undef new diff --git a/GPU/GPUCommonHW.cpp b/GPU/GPUCommonHW.cpp index 34b77b1fc3..08937ee9ba 100644 --- a/GPU/GPUCommonHW.cpp +++ b/GPU/GPUCommonHW.cpp @@ -524,7 +524,7 @@ void GPUCommonHW::CheckFlushOp(int cmd, u32 diff) { if (dumpThisFrame_) { NOTICE_LOG(Log::G3D, "================ FLUSH ================"); } - drawEngineCommon_->DispatchFlush(); + drawEngineCommon_->Flush(); } } @@ -534,7 +534,7 @@ void GPUCommonHW::PreExecuteOp(u32 op, u32 diff) { void GPUCommonHW::CopyDisplayToOutput(bool reallyDirty) { // Flush anything left over. - drawEngineCommon_->DispatchFlush(); + drawEngineCommon_->Flush(); shaderManager_->DirtyLastShader(); @@ -850,7 +850,7 @@ void GPUCommonHW::FastRunLoop(DisplayList &list) { } else { uint64_t flags = info.flags; if (flags & FLAG_FLUSHBEFOREONCHANGE) { - drawEngineCommon_->DispatchFlush(); + drawEngineCommon_->Flush(); } gstate.cmdmem[cmd] = op; if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) { @@ -1256,7 +1256,7 @@ bail: // flush back cull mode if (cullMode != gstate.getCullMode()) { // We rewrote everything to the old cull mode, so flush first. - drawEngineCommon_->DispatchFlush(); + drawEngineCommon_->Flush(); // Now update things for next time. gstate.cmdmem[GE_CMD_CULL] ^= 1; @@ -1303,7 +1303,7 @@ void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) { // Can't flush after setting gstate_c.submitType below since it'll be a mess - it must be done already. if (flushOnParams_) - drawEngineCommon_->DispatchFlush(); + drawEngineCommon_->Flush(); Spline::BezierSurface surface; surface.tess_u = gstate.getPatchDivisionU(); @@ -1375,7 +1375,7 @@ void GPUCommonHW::Execute_Spline(u32 op, u32 diff) { // Can't flush after setting gstate_c.submitType below since it'll be a mess - it must be done already. if (flushOnParams_) - drawEngineCommon_->DispatchFlush(); + drawEngineCommon_->Flush(); Spline::SplineSurface surface; surface.tess_u = gstate.getPatchDivisionU(); diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 2a8e4c72ed..be2e4ea71a 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -66,7 +66,7 @@ void SoftwareDrawEngine::NotifyConfigChanged() { decOptions_.applySkinInDecode = true; } -void SoftwareDrawEngine::DispatchFlush() { +void SoftwareDrawEngine::Flush() { transformUnit.Flush("debug"); } diff --git a/GPU/Software/TransformUnit.h b/GPU/Software/TransformUnit.h index 488a31980f..6945448ec2 100644 --- a/GPU/Software/TransformUnit.h +++ b/GPU/Software/TransformUnit.h @@ -177,7 +177,7 @@ public: void DeviceRestore(Draw::DrawContext *draw) override {} void NotifyConfigChanged() override; - void DispatchFlush() override; + void Flush() override; void DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, bool clockwise, int *bytesRead) override; void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) override; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 47b466fc11..5e7ba14a10 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -216,7 +216,11 @@ void DrawEngineVulkan::Invalidate(InvalidationCallbackFlags flags) { } // The inline wrapper in the header checks for numDrawCalls_ == 0 -void DrawEngineVulkan::DoFlush() { +void DrawEngineVulkan::Flush() { + if (!numDrawVerts_) { + return; + } + VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); renderManager->AssertInRenderPass(); diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index d191fe0f8a..185f66f9a2 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -123,26 +123,13 @@ public: void DeviceLost() override; void DeviceRestore(Draw::DrawContext *draw) override; - // So that this can be inlined - void Flush() { - if (!numDrawInds_) - return; - DoFlush(); - } + void Flush() override; void FinishDeferred() { - if (!numDrawInds_) - return; // Decode any pending vertices. And also flush while we're at it, for simplicity. // It might be possible to only decode like in the other backends, but meh, it can't matter. // Issue #10095 has a nice example of where this is required. - DoFlush(); - } - - void DispatchFlush() override { - if (!numDrawInds_) - return; - DoFlush(); + Flush(); } VKRPipelineLayout *GetPipelineLayout() const { @@ -183,7 +170,6 @@ private: void DestroyDeviceObjects(); - void DoFlush(); void UpdateUBOs(); NO_INLINE void ResetAfterDraw(); From b47c9b6dd2f92e3d3a989c9138e902cd0d4e89a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Dec 2024 13:44:35 +0100 Subject: [PATCH 5/8] Remove redundant call to SetColorUpdated --- GPU/D3D11/DrawEngineD3D11.cpp | 4 ---- GPU/Directx9/DrawEngineDX9.cpp | 4 ---- GPU/GLES/DrawEngineGLES.cpp | 1 - GPU/Vulkan/DrawEngineVulkan.cpp | 3 --- 4 files changed, 12 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 60a3e72456..172cbc0476 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -467,10 +467,6 @@ void DrawEngineD3D11::Flush() { if (gstate.isClearModeAlphaMask()) clearFlag |= Draw::FBChannel::FB_STENCIL_BIT; if (gstate.isClearModeDepthMask()) clearFlag |= Draw::FBChannel::FB_DEPTH_BIT; - if (clearFlag & Draw::FBChannel::FB_COLOR_BIT) { - framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - } - uint8_t clearStencil = clearColor >> 24; draw_->Clear(clearFlag, clearColor, clearDepth, clearStencil); diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index e973d0370c..f6c41fa273 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -404,10 +404,6 @@ void DrawEngineDX9::Flush() { if (gstate.isClearModeAlphaMask()) mask |= D3DCLEAR_STENCIL; if (gstate.isClearModeDepthMask()) mask |= D3DCLEAR_ZBUFFER; - if (mask & D3DCLEAR_TARGET) { - framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - } - device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24); if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) { diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 13adfc2ea9..a45d77ae62 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -437,7 +437,6 @@ void DrawEngineGLES::Flush() { if (depthMask) target |= GL_DEPTH_BUFFER_BIT; render_->Clear(clearColor, clearDepth, clearColor >> 24, target, rgbaMask, vpAndScissor_.scissorX, vpAndScissor_.scissorY, vpAndScissor_.scissorW, vpAndScissor_.scissorH); - framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate_c.framebufFormat == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 5e7ba14a10..a3baffbbf1 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -555,9 +555,6 @@ void DrawEngineVulkan::Flush() { // Note that since the alpha channel and the stencil channel are shared on the PSP, // when we clear alpha, we also clear stencil to the same value. draw_->Clear(mask, result.color, result.depth, result.color >> 24); - if (clearColor || clearAlpha) { - framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - } if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { int scissorX1 = gstate.getScissorX1(); int scissorY1 = gstate.getScissorY1(); From 190af89d9f7932d582fb38ca2438062129afc6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Dec 2024 13:49:07 +0100 Subject: [PATCH 6/8] Plumb in a GPUCommon pointer in the draw engines. (Hopefully can get rid of this later) --- GPU/Common/DrawEngineCommon.h | 7 +++++++ GPU/D3D11/GPU_D3D11.cpp | 1 + GPU/Directx9/GPU_DX9.cpp | 1 + GPU/GLES/GPU_GLES.cpp | 1 + GPU/Software/SoftGpu.cpp | 1 + GPU/Vulkan/GPU_Vulkan.cpp | 1 + 6 files changed, 12 insertions(+) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index ea8b74d8e3..7b236da599 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -82,6 +82,11 @@ public: virtual ~DrawEngineCommon(); void Init(); + + void SetGPUCommon(GPUCommon *gpuCommon) { + gpuCommon_ = gpuCommon; + } + virtual void DeviceLost() = 0; virtual void DeviceRestore(Draw::DrawContext *draw) = 0; @@ -330,4 +335,6 @@ protected: Vec2f minOffset_; Vec2f maxOffset_; bool offsetOutsideEdge_; + + GPUCommon *gpuCommon_; }; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 2e425b1f44..1c41a5a58b 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -58,6 +58,7 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) textureCache_ = textureCacheD3D11_; drawEngineCommon_ = &drawEngine_; shaderManager_ = shaderManagerD3D11_; + drawEngine_.SetGPUCommon(this); drawEngine_.SetShaderManager(shaderManagerD3D11_); drawEngine_.SetTextureCache(textureCacheD3D11_); drawEngine_.SetFramebufferManager(framebufferManagerD3D11_); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index cf49fa1c0a..61f94384d3 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -56,6 +56,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) drawEngineCommon_ = &drawEngine_; shaderManager_ = shaderManagerDX9_; + drawEngine_.SetGPUCommon(this); drawEngine_.SetShaderManager(shaderManagerDX9_); drawEngine_.SetTextureCache(textureCacheDX9_); drawEngine_.SetFramebufferManager(framebufferManagerDX9_); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index aa2cc82f76..ff2909f868 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -58,6 +58,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) drawEngineCommon_ = &drawEngine_; shaderManager_ = shaderManagerGL_; + drawEngine_.SetGPUCommon(this); drawEngine_.SetShaderManager(shaderManagerGL_); drawEngine_.SetTextureCache(textureCacheGL_); drawEngine_.SetFramebufferManager(framebufferManagerGL_); diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index e58d9adc12..5a96c947f2 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -436,6 +436,7 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw) if (!drawEngine_) return; + drawEngine_->SetGPUCommon(this); drawEngine_->Init(); drawEngineCommon_ = drawEngine_; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 73acc0fe58..460e28387c 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -64,6 +64,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) drawEngineCommon_ = &drawEngine_; shaderManager_ = shaderManagerVulkan_; + drawEngine_.SetGPUCommon(this); drawEngine_.SetTextureCache(textureCacheVulkan_); drawEngine_.SetFramebufferManager(framebufferManagerVulkan_); drawEngine_.SetShaderManager(shaderManagerVulkan_); From 54d18bb343c6c62901a50ea3a08f707f4d86034b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Dec 2024 14:03:05 +0100 Subject: [PATCH 7/8] Lift some more debugging functionality into GPUCommon --- GPU/Common/GPUDebugInterface.cpp | 4 +- GPU/Common/GPUDebugInterface.h | 11 ++ GPU/D3D11/DrawEngineD3D11.cpp | 2 +- GPU/Debugger/Debugger.cpp | 172 ----------------------------- GPU/Debugger/Debugger.h | 23 +--- GPU/Directx9/DrawEngineDX9.cpp | 2 +- GPU/GLES/DrawEngineGLES.cpp | 2 +- GPU/GPUCommon.cpp | 173 +++++++++++++++++++++++++++++- GPU/GPUCommon.h | 38 ++++++- GPU/GPUCommonHW.cpp | 3 +- GPU/Software/SoftGpu.cpp | 26 ++--- GPU/Software/TransformUnit.cpp | 12 +-- GPU/Software/TransformUnit.h | 4 +- GPU/Vulkan/DrawEngineVulkan.cpp | 2 +- UI/ImDebugger/ImGe.cpp | 20 ++-- Windows/GEDebugger/GEDebugger.cpp | 28 ++--- 16 files changed, 270 insertions(+), 252 deletions(-) diff --git a/GPU/Common/GPUDebugInterface.cpp b/GPU/Common/GPUDebugInterface.cpp index 7b6cd223e1..979445ceaa 100644 --- a/GPU/Common/GPUDebugInterface.cpp +++ b/GPU/Common/GPUDebugInterface.cpp @@ -703,10 +703,10 @@ uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) { return state.getTransferDstAddress(); case GEReferenceIndex::PRIMCOUNT: - return GPUDebug::PrimsThisFrame(); + return gpu_->PrimsThisFrame(); case GEReferenceIndex::LASTPRIMCOUNT: - return GPUDebug::PrimsLastFrame(); + return gpu_->PrimsLastFrame(); case GEReferenceIndex::TEXADDR0: case GEReferenceIndex::TEXADDR1: diff --git a/GPU/Common/GPUDebugInterface.h b/GPU/Common/GPUDebugInterface.h index 5d1c47279c..adf158f01f 100644 --- a/GPU/Common/GPUDebugInterface.h +++ b/GPU/Common/GPUDebugInterface.h @@ -27,6 +27,7 @@ #include "GPU/GPUDefinitions.h" #include "GPU/GPUState.h" #include "GPU/ge_constants.h" +#include "GPU/Debugger/Debugger.h" class FramebufferManagerCommon; class TextureCacheCommon; @@ -244,6 +245,16 @@ public: virtual const std::list &GetDisplayListQueue() = 0; virtual const DisplayList &GetDisplayList(int index) = 0; + virtual int PrimsThisFrame() = 0; + virtual int PrimsLastFrame() = 0; + + 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 bool SetRestrictPrims(std::string_view rule) = 0 ; + virtual const char *GetRestrictPrims() = 0 ; + virtual GPURecord::Recorder *GetRecorder() = 0; virtual GPUBreakpoints *GetBreakpoints() = 0; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 172cbc0476..315ec61b0a 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -483,7 +483,7 @@ void DrawEngineD3D11::Flush() { ResetAfterDrawInline(); framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - GPUDebug::NotifyFlush(); + gpuCommon_->NotifyFlush(); } TessellationDataTransferD3D11::TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device) diff --git a/GPU/Debugger/Debugger.cpp b/GPU/Debugger/Debugger.cpp index 0610965dcd..376b947310 100644 --- a/GPU/Debugger/Debugger.cpp +++ b/GPU/Debugger/Debugger.cpp @@ -25,20 +25,6 @@ namespace GPUDebug { -static BreakNext breakNext = BreakNext::NONE; -static int breakAtCount = -1; - -static int primsLastFrame = 0; -static int primsThisFrame = 0; -static int thisFlipNum = 0; - -bool g_primAfterDraw = false; - -static uint32_t g_skipPcOnce = 0; - -static std::vector> restrictPrimRanges; -static std::string restrictPrimRule; - const char *BreakNextToString(BreakNext next) { switch (next) { case BreakNext::NONE: return "NONE,"; @@ -55,145 +41,6 @@ const char *BreakNextToString(BreakNext next) { } } -bool NeedsSlowInterpreter() { - return breakNext != BreakNext::NONE; -} - -void ClearBreak() { - breakNext = BreakNext::NONE; - breakAtCount = -1; - GPUStepping::ResumeFromStepping(); -} - -BreakNext GetBreakNext() { - return breakNext; -} - -void SetBreakNext(BreakNext next, GPUBreakpoints *breakpoints) { - breakNext = next; - breakAtCount = -1; - if (next == BreakNext::TEX) { - breakpoints->AddTextureChangeTempBreakpoint(); - } else if (next == BreakNext::PRIM || next == BreakNext::COUNT) { - breakpoints->AddCmdBreakpoint(GE_CMD_PRIM, true); - breakpoints->AddCmdBreakpoint(GE_CMD_BEZIER, true); - breakpoints->AddCmdBreakpoint(GE_CMD_SPLINE, true); - breakpoints->AddCmdBreakpoint(GE_CMD_VAP, true); - } else if (next == BreakNext::CURVE) { - breakpoints->AddCmdBreakpoint(GE_CMD_BEZIER, true); - breakpoints->AddCmdBreakpoint(GE_CMD_SPLINE, true); - } else if (next == BreakNext::DRAW) { - // This is now handled by switching to BreakNext::PRIM when we encounter a flush. - // This will take us to the following actual draw. - g_primAfterDraw = true; - } - - if (GPUStepping::IsStepping()) { - GPUStepping::ResumeFromStepping(); - } -} - -void SetBreakCount(int c, bool relative) { - if (relative) { - breakAtCount = primsThisFrame + c; - } else { - breakAtCount = c; - } -} - -NotifyResult NotifyCommand(u32 pc, GPUBreakpoints *breakpoints) { - u32 op = Memory::ReadUnchecked_U32(pc); - u32 cmd = op >> 24; - if (thisFlipNum != gpuStats.numFlips) { - primsLastFrame = primsThisFrame; - primsThisFrame = 0; - thisFlipNum = gpuStats.numFlips; - } - - bool process = true; - if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE || cmd == GE_CMD_VAP) { - primsThisFrame++; - - if (!restrictPrimRanges.empty()) { - process = false; - for (const auto &range : restrictPrimRanges) { - if (primsThisFrame >= range.first && primsThisFrame <= range.second) { - process = true; - break; - } - } - } - } - - bool isBreakpoint = false; - if (breakNext == BreakNext::OP) { - isBreakpoint = true; - } else if (breakNext == BreakNext::COUNT) { - isBreakpoint = primsThisFrame == breakAtCount; - } else if (breakpoints->HasBreakpoints()) { - isBreakpoint = breakpoints->IsBreakpoint(pc, op); - } - - if (isBreakpoint && pc == g_skipPcOnce) { - INFO_LOG(Log::GeDebugger, "Skipping GE break at %08x (last break was here)", g_skipPcOnce); - g_skipPcOnce = 0; - return process ? NotifyResult::Execute : NotifyResult::Skip; - } - g_skipPcOnce = 0; - - if (isBreakpoint) { - breakpoints->ClearTempBreakpoints(); - - if (coreState == CORE_POWERDOWN || !gpuDebug) { - breakNext = BreakNext::NONE; - return process ? NotifyResult::Execute : NotifyResult::Skip; - } - - auto info = gpuDebug->DisassembleOp(pc); - NOTICE_LOG(Log::GeDebugger, "Waiting at %08x, %s", pc, info.desc.c_str()); - - g_skipPcOnce = pc; - breakNext = BreakNext::NONE; - return NotifyResult::Break; // new. caller will call GPUStepping::EnterStepping(). - } - - return process ? NotifyResult::Execute : NotifyResult::Skip; -} - -void NotifyFlush() { - if (breakNext == BreakNext::DRAW && !GPUStepping::IsStepping()) { - // Break on the first PRIM after a flush. - if (g_primAfterDraw) { - NOTICE_LOG(Log::GeDebugger, "Flush detected, breaking at next PRIM"); - g_primAfterDraw = false; - // Switch to PRIM mode. - SetBreakNext(BreakNext::PRIM, gpuDebug->GetBreakpoints()); - } - } -} - -void NotifyDisplay(u32 framebuf, u32 stride, int format) { - if (breakNext == BreakNext::FRAME) { - // Start stepping at the first op of the new frame. - breakNext = BreakNext::OP; - } -} - -void NotifyBeginFrame() { - if (breakNext == BreakNext::VSYNC) { - // Just start stepping as soon as we can once the vblank finishes. - breakNext = BreakNext::OP; - } -} - -int PrimsThisFrame() { - return primsThisFrame; -} - -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) @@ -262,23 +109,4 @@ bool ParsePrimRanges(std::string_view rule, std::vector> *ou return true; } -bool SetRestrictPrims(std::string_view rule) { - if (rule.empty() || rule == "*") { - restrictPrimRanges.clear(); - restrictPrimRule.clear(); - return true; - } - - if (ParsePrimRanges(rule, &restrictPrimRanges)) { - restrictPrimRule = rule; - return true; - } else { - return false; - } -} - -const char *GetRestrictPrims() { - return restrictPrimRule.c_str(); -} - } diff --git a/GPU/Debugger/Debugger.h b/GPU/Debugger/Debugger.h index f2d5e3b727..48e08fbb32 100644 --- a/GPU/Debugger/Debugger.h +++ b/GPU/Debugger/Debugger.h @@ -37,32 +37,13 @@ enum class BreakNext { COUNT, }; -const char *BreakNextToString(BreakNext next); -bool ParsePrimRanges(std::string_view rule, std::vector> *output); - -bool NeedsSlowInterpreter(); - -void SetBreakNext(BreakNext next, GPUBreakpoints *breakpoints); -void SetBreakCount(int c, bool relative = false); -BreakNext GetBreakNext(); -const char *BreakNextToString(BreakNext next); - enum class NotifyResult { Execute, Skip, Break }; -// While debugging is active, these may block. -NotifyResult NotifyCommand(u32 pc, GPUBreakpoints *breakpoints); -void NotifyFlush(); -void NotifyDisplay(u32 framebuf, u32 stride, int format); -void NotifyBeginFrame(); - -int PrimsThisFrame(); -int PrimsLastFrame(); - -bool SetRestrictPrims(std::string_view rule); -const char *GetRestrictPrims(); +const char *BreakNextToString(GPUDebug::BreakNext next); +bool ParsePrimRanges(std::string_view rule, std::vector> *output); } // namespace diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index f6c41fa273..6cc0618a24 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -419,7 +419,7 @@ void DrawEngineDX9::Flush() { ResetAfterDrawInline(); framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - GPUDebug::NotifyFlush(); + gpuCommon_->NotifyFlush(); } void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) { diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index a45d77ae62..7d2e7cce0e 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -453,7 +453,7 @@ void DrawEngineGLES::Flush() { bail: ResetAfterDrawInline(); framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - GPUDebug::NotifyFlush(); + gpuCommon_->NotifyFlush(); } // TODO: Refactor this to a single USE flag. diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 0ba269e5a2..1ecd09757b 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -620,15 +620,14 @@ void GPUCommon::PSPFrame() { } else if (dumpThisFrame_) { dumpThisFrame_ = false; } - GPUDebug::NotifyBeginFrame(); - recorder_.NotifyBeginFrame(); + NotifyBeginFrame(); } // Returns false on breakpoint. bool GPUCommon::SlowRunLoop(DisplayList &list) { const bool dumpThisFrame = dumpThisFrame_; while (downcount > 0) { - GPUDebug::NotifyResult result = GPUDebug::NotifyCommand(list.pc, &breakpoints_); + GPUDebug::NotifyResult result = NotifyCommand(list.pc, &breakpoints_); if (result == GPUDebug::NotifyResult::Execute) { recorder_.NotifyCommand(list.pc); @@ -787,7 +786,7 @@ DLResult GPUCommon::ProcessDLQueue() { // To enable breakpoints, we don't do fast matrix loads while debugger active. debugRecording_ = recorder_.IsActive(); - useFastRunLoop_ = !(dumpThisFrame_ || debugRecording_ || GPUDebug::NeedsSlowInterpreter() || breakpoints_.HasBreakpoints()); + useFastRunLoop_ = !(dumpThisFrame_ || debugRecording_ || NeedsSlowInterpreter() || breakpoints_.HasBreakpoints()); } else { resumingFromDebugBreak_ = false; // The bottom part of the gpuState loop below, that wasn't executed @@ -878,7 +877,7 @@ DLResult GPUCommon::ProcessDLQueue() { bool GPUCommon::ShouldSplitOverGe() const { // Check for debugger active. // We only need to do this if we want to be able to step through Ge display lists using the Ge debuggers. - return GPUDebug::NeedsSlowInterpreter() || breakpoints_.HasBreakpoints(); + return NeedsSlowInterpreter() || breakpoints_.HasBreakpoints(); } void GPUCommon::Execute_OffsetAddr(u32 op, u32 diff) { @@ -2003,3 +2002,167 @@ bool GPUCommon::DescribeCodePtr(const u8 *ptr, std::string &name) { return drawEngineCommon_->DescribeCodePtr(ptr, name); } +bool GPUCommon::NeedsSlowInterpreter() const { + return breakNext != GPUDebug::BreakNext::NONE; +} + +void GPUCommon::ClearBreakNext() { + breakNext = GPUDebug::BreakNext::NONE; + breakAtCount = -1; + GPUStepping::ResumeFromStepping(); +} + +GPUDebug::BreakNext GPUCommon::GetBreakNext() { + return breakNext; +} + +void GPUCommon::SetBreakNext(GPUDebug::BreakNext next) { + breakNext = next; + breakAtCount = -1; + if (next == GPUDebug::BreakNext::TEX) { + breakpoints_.AddTextureChangeTempBreakpoint(); + } else if (next == GPUDebug::BreakNext::PRIM || next == GPUDebug::BreakNext::COUNT) { + breakpoints_.AddCmdBreakpoint(GE_CMD_PRIM, true); + breakpoints_.AddCmdBreakpoint(GE_CMD_BEZIER, true); + breakpoints_.AddCmdBreakpoint(GE_CMD_SPLINE, true); + breakpoints_.AddCmdBreakpoint(GE_CMD_VAP, true); + } else if (next == GPUDebug::BreakNext::CURVE) { + breakpoints_.AddCmdBreakpoint(GE_CMD_BEZIER, true); + breakpoints_.AddCmdBreakpoint(GE_CMD_SPLINE, true); + } else if (next == GPUDebug::BreakNext::DRAW) { + // This is now handled by switching to BreakNext::PRIM when we encounter a flush. + // This will take us to the following actual draw. + primAfterDraw_ = true; + } + + if (GPUStepping::IsStepping()) { + GPUStepping::ResumeFromStepping(); + } +} + +void GPUCommon::SetBreakCount(int c, bool relative) { + if (relative) { + breakAtCount = primsThisFrame + c; + } else { + breakAtCount = c; + } +} + +GPUDebug::NotifyResult GPUCommon::NotifyCommand(u32 pc, GPUBreakpoints *breakpoints) { + using namespace GPUDebug; + + u32 op = Memory::ReadUnchecked_U32(pc); + u32 cmd = op >> 24; + if (thisFlipNum != gpuStats.numFlips) { + primsLastFrame = primsThisFrame; + primsThisFrame = 0; + thisFlipNum = gpuStats.numFlips; + } + + bool process = true; + if (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE || cmd == GE_CMD_VAP) { + primsThisFrame++; + + if (!restrictPrimRanges.empty()) { + process = false; + for (const auto &range : restrictPrimRanges) { + if (primsThisFrame >= range.first && primsThisFrame <= range.second) { + process = true; + break; + } + } + } + } + + bool isBreakpoint = false; + if (breakNext == BreakNext::OP) { + isBreakpoint = true; + } else if (breakNext == BreakNext::COUNT) { + isBreakpoint = primsThisFrame == breakAtCount; + } else if (breakpoints->HasBreakpoints()) { + isBreakpoint = breakpoints->IsBreakpoint(pc, op); + } + + if (isBreakpoint && pc == g_skipPcOnce) { + INFO_LOG(Log::GeDebugger, "Skipping GE break at %08x (last break was here)", g_skipPcOnce); + g_skipPcOnce = 0; + return process ? NotifyResult::Execute : NotifyResult::Skip; + } + g_skipPcOnce = 0; + + if (isBreakpoint) { + breakpoints->ClearTempBreakpoints(); + + if (coreState == CORE_POWERDOWN || !gpuDebug) { + breakNext = BreakNext::NONE; + return process ? NotifyResult::Execute : NotifyResult::Skip; + } + + auto info = gpuDebug->DisassembleOp(pc); + NOTICE_LOG(Log::GeDebugger, "Waiting at %08x, %s", pc, info.desc.c_str()); + + g_skipPcOnce = pc; + breakNext = BreakNext::NONE; + return NotifyResult::Break; // new. caller will call GPUStepping::EnterStepping(). + } + + return process ? NotifyResult::Execute : NotifyResult::Skip; +} + +void GPUCommon::NotifyFlush() { + using namespace GPUDebug; + if (breakNext == BreakNext::DRAW && !GPUStepping::IsStepping()) { + // Break on the first PRIM after a flush. + if (primAfterDraw_) { + NOTICE_LOG(Log::GeDebugger, "Flush detected, breaking at next PRIM"); + primAfterDraw_ = false; + // Switch to PRIM mode. + SetBreakNext(BreakNext::PRIM); + } + } +} + +void GPUCommon::NotifyDisplay(u32 framebuf, u32 stride, int format) { + using namespace GPUDebug; + if (breakNext == BreakNext::FRAME) { + // Start stepping at the first op of the new frame. + breakNext = BreakNext::OP; + } + recorder_.NotifyDisplay(framebuf, stride, format); +} + +void GPUCommon::NotifyBeginFrame() { + using namespace GPUDebug; + if (breakNext == BreakNext::VSYNC) { + // Just start stepping as soon as we can once the vblank finishes. + breakNext = BreakNext::OP; + } + recorder_.NotifyBeginFrame(); +} + +int GPUCommon::PrimsThisFrame() { + return primsThisFrame; +} + +int GPUCommon::PrimsLastFrame() { + return primsLastFrame; +} + +bool GPUCommon::SetRestrictPrims(std::string_view rule) { + if (rule.empty() || rule == "*") { + restrictPrimRanges.clear(); + restrictPrimRule.clear(); + return true; + } + + 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 3e91671b70..bbac458561 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -14,6 +14,7 @@ #include "GPU/GPUState.h" #include "GPU/Debugger/Record.h" #include "GPU/Debugger/Breakpoints.h" +#include "GPU/Debugger/Debugger.h" #include "GPU/Common/ShaderCommon.h" #include "GPU/Common/GPUDebugInterface.h" #include "GPU/GPUDefinitions.h" @@ -384,7 +385,26 @@ public: return &breakpoints_; } + void ClearBreakNext() override; + void SetBreakNext(GPUDebug::BreakNext next) override; + void SetBreakCount(int c, bool relative = false) override; + GPUDebug::BreakNext GetBreakNext() override; + bool SetRestrictPrims(std::string_view rule) override; + const char *GetRestrictPrims() override; + + int PrimsThisFrame() override; + int PrimsLastFrame() override; + + void NotifyFlush(); + protected: + // While debugging is active, these may block. + void NotifyDisplay(u32 framebuf, u32 stride, int format); + void NotifyBeginFrame(); + + bool NeedsSlowInterpreter() const; + GPUDebug::NotifyResult NotifyCommand(u32 pc, GPUBreakpoints *breakpoints); + virtual void ClearCacheNextFrame() {} virtual void CheckRenderResized() {} @@ -467,7 +487,6 @@ protected: bool dumpNextFrame_ = false; bool dumpThisFrame_ = false; bool useFastRunLoop_ = false; - bool debugRecording_ = false; bool interruptsEnabled_ = false; bool displayResized_ = false; bool renderResized_ = false; @@ -508,9 +527,26 @@ protected: std::string reportingPrimaryInfo_; std::string reportingFullInfo_; + // Debugging state + bool debugRecording_ = false; + GPURecord::Recorder recorder_; GPUBreakpoints breakpoints_; + GPUDebug::BreakNext breakNext = GPUDebug::BreakNext::NONE; + int breakAtCount = -1; + + int primsLastFrame = 0; + int primsThisFrame = 0; + int thisFlipNum = 0; + + bool primAfterDraw_ = false; + + uint32_t g_skipPcOnce = 0; + + std::vector> restrictPrimRanges; + std::string restrictPrimRule; + private: void DoExecuteCall(u32 target); void PopDLQueue(); diff --git a/GPU/GPUCommonHW.cpp b/GPU/GPUCommonHW.cpp index 08937ee9ba..40a465276c 100644 --- a/GPU/GPUCommonHW.cpp +++ b/GPU/GPUCommonHW.cpp @@ -514,8 +514,7 @@ void GPUCommonHW::BeginHostFrame() { void GPUCommonHW::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) { framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format); - GPUDebug::NotifyDisplay(framebuf, stride, format); - recorder_.NotifyDisplay(framebuf, stride, format); + NotifyDisplay(framebuf, stride, format); } void GPUCommonHW::CheckFlushOp(int cmd, u32 diff) { diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 5a96c947f2..5611accb1d 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -494,8 +494,8 @@ void SoftGPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat for displayFramebuf_ = (framebuf & 0xFF000000) == 0 ? 0x44000000 | framebuf : framebuf; displayStride_ = stride; displayFormat_ = format; - GPUDebug::NotifyDisplay(framebuf, stride, format); - recorder_.NotifyDisplay(framebuf, stride, format); + + NotifyDisplay(framebuf, stride, format); } DSStretch g_DarkStalkerStretch; @@ -652,7 +652,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { } void SoftGPU::CopyDisplayToOutput(bool reallyDirty) { - drawEngine_->transformUnit.Flush("output"); + drawEngine_->transformUnit.Flush(this, "output"); // The display always shows 480x272. CopyToCurrentFboFromDisplayRam(FB_WIDTH, FB_HEIGHT); MarkDirty(displayFramebuf_, displayStride_, 272, displayFormat_, SoftGPUVRAMDirty::CLEAR); @@ -840,10 +840,10 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { // Need to flush both source and target, so we overwrite properly. if (Memory::IsValidRange(src, srcSize) && Memory::IsValidRange(dst, dstSize)) { - drawEngine_->transformUnit.FlushIfOverlap("blockxfer", false, src, srcStride, width * bpp, height); - drawEngine_->transformUnit.FlushIfOverlap("blockxfer", true, dst, dstStride, width * bpp, height); + drawEngine_->transformUnit.FlushIfOverlap(this, "blockxfer", false, src, srcStride, width * bpp, height); + drawEngine_->transformUnit.FlushIfOverlap(this, "blockxfer", true, dst, dstStride, width * bpp, height); } else { - drawEngine_->transformUnit.Flush("blockxfer_wrap"); + drawEngine_->transformUnit.Flush(this, "blockxfer_wrap"); } DoBlockTransfer(gstate_c.skipDrawReason); @@ -1005,7 +1005,7 @@ void SoftGPU::Execute_LoadClut(u32 op, u32 diff) { clutTotalBytes = 1024; // Might be copying drawing into the CLUT, so flush. - drawEngine_->transformUnit.FlushIfOverlap("loadclut", false, clutAddr, clutTotalBytes, clutTotalBytes, 1); + drawEngine_->transformUnit.FlushIfOverlap(this, "loadclut", false, clutAddr, clutTotalBytes, clutTotalBytes, 1); bool changed = false; if (Memory::IsValidAddress(clutAddr)) { @@ -1033,7 +1033,7 @@ void SoftGPU::Execute_LoadClut(u32 op, u32 diff) { void SoftGPU::Execute_FramebufPtr(u32 op, u32 diff) { // We assume fb.data won't change while we're drawing. if (diff) { - drawEngine_->transformUnit.Flush("framebuf"); + drawEngine_->transformUnit.Flush(this, "framebuf"); fb.data = Memory::GetPointerWrite(gstate.getFrameBufAddress()); } } @@ -1041,7 +1041,7 @@ void SoftGPU::Execute_FramebufPtr(u32 op, u32 diff) { void SoftGPU::Execute_FramebufFormat(u32 op, u32 diff) { // We should flush, because ranges within bins may change. if (diff) - drawEngine_->transformUnit.Flush("framebuf"); + drawEngine_->transformUnit.Flush(this, "framebuf"); } void SoftGPU::Execute_BoundingBox(u32 op, u32 diff) { @@ -1052,7 +1052,7 @@ void SoftGPU::Execute_BoundingBox(u32 op, u32 diff) { void SoftGPU::Execute_ZbufPtr(u32 op, u32 diff) { // We assume depthbuf.data won't change while we're drawing. if (diff) { - drawEngine_->transformUnit.Flush("depthbuf"); + drawEngine_->transformUnit.Flush(this, "depthbuf"); // For the pointer, ignore memory mirrors. This also gives some buffer for draws that go outside. // TODO: Confirm how wrapping is handled in drawing. Adjust if we ever handle VRAM mirrors more accurately. depthbuf.data = Memory::GetPointerWrite(gstate.getDepthBufAddress() & 0x041FFFF0); @@ -1273,18 +1273,18 @@ void SoftGPU::Execute_Call(u32 op, u32 diff) { void SoftGPU::FinishDeferred() { // Need to flush before going back to CPU, so drawing is appropriately visible. - drawEngine_->transformUnit.Flush("finish"); + drawEngine_->transformUnit.Flush(this, "finish"); } int SoftGPU::ListSync(int listid, int mode) { // Take this as a cue that we need to finish drawing. - drawEngine_->transformUnit.Flush("listsync"); + drawEngine_->transformUnit.Flush(this, "listsync"); return GPUCommon::ListSync(listid, mode); } u32 SoftGPU::DrawSync(int mode) { // Take this as a cue that we need to finish drawing. - drawEngine_->transformUnit.Flush("drawsync"); + drawEngine_->transformUnit.Flush(this, "drawsync"); return GPUCommon::DrawSync(mode); } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index be2e4ea71a..12a520b30f 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -67,7 +67,7 @@ void SoftwareDrawEngine::NotifyConfigChanged() { } void SoftwareDrawEngine::Flush() { - transformUnit.Flush("debug"); + transformUnit.Flush(gpuCommon_, "debug"); } void SoftwareDrawEngine::DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, bool clockwise, int *bytesRead) { @@ -891,12 +891,12 @@ void TransformUnit::SendTriangle(CullType cullType, const ClipVertexData *verts, } } -void TransformUnit::Flush(const char *reason) { +void TransformUnit::Flush(GPUCommon *common, const char *reason) { if (!hasDraws_) return; binner_->Flush(reason); - GPUDebug::NotifyFlush(); + common->NotifyFlush(); hasDraws_ = false; } @@ -905,14 +905,14 @@ void TransformUnit::GetStats(char *buffer, size_t bufsize) { binner_->GetStats(buffer, bufsize); } -void TransformUnit::FlushIfOverlap(const char *reason, bool modifying, uint32_t addr, uint32_t stride, uint32_t w, uint32_t h) { +void TransformUnit::FlushIfOverlap(GPUCommon *common, const char *reason, bool modifying, uint32_t addr, uint32_t stride, uint32_t w, uint32_t h) { if (!hasDraws_) return; if (binner_->HasPendingWrite(addr, stride, w, h)) - Flush(reason); + Flush(common, reason); if (modifying && binner_->HasPendingRead(addr, stride, w, h)) - Flush(reason); + Flush(common, reason); } void TransformUnit::NotifyClutUpdate(const void *src) { diff --git a/GPU/Software/TransformUnit.h b/GPU/Software/TransformUnit.h index 6945448ec2..46b7b47f55 100644 --- a/GPU/Software/TransformUnit.h +++ b/GPU/Software/TransformUnit.h @@ -141,8 +141,8 @@ public: static bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices); - void Flush(const char *reason); - void FlushIfOverlap(const char *reason, bool modifying, uint32_t addr, uint32_t stride, uint32_t w, uint32_t h); + void Flush(GPUCommon *common, const char *reason); + void FlushIfOverlap(GPUCommon *common, const char *reason, bool modifying, uint32_t addr, uint32_t stride, uint32_t w, uint32_t h); void NotifyClutUpdate(const void *src); void GetStats(char *buffer, size_t bufsize); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index a3baffbbf1..9e3270d4db 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -570,7 +570,7 @@ void DrawEngineVulkan::Flush() { framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - GPUDebug::NotifyFlush(); + gpuCommon_->NotifyFlush(); } void DrawEngineVulkan::ResetAfterDraw() { diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index 05cf4a376e..bd3bca15f5 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -359,34 +359,34 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterfa // GPUDebug::SetBreakNext(GPUDebug::BreakNext::FRAME); //} - bool disableStepButtons = GPUDebug::GetBreakNext() != GPUDebug::BreakNext::NONE; + bool disableStepButtons = gpuDebug->GetBreakNext() != GPUDebug::BreakNext::NONE; if (disableStepButtons) { ImGui::BeginDisabled(); } ImGui::SameLine(); if (ImGui::Button("Tex")) { - GPUDebug::SetBreakNext(GPUDebug::BreakNext::TEX, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::TEX); } ImGui::SameLine(); if (ImGui::Button("NonTex")) { - GPUDebug::SetBreakNext(GPUDebug::BreakNext::NONTEX, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::NONTEX); } ImGui::SameLine(); if (ImGui::Button("Prim")) { - GPUDebug::SetBreakNext(GPUDebug::BreakNext::PRIM, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::PRIM); } ImGui::SameLine(); if (ImGui::Button("Draw")) { - GPUDebug::SetBreakNext(GPUDebug::BreakNext::DRAW, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::DRAW); } ImGui::SameLine(); if (ImGui::Button("Curve")) { - GPUDebug::SetBreakNext(GPUDebug::BreakNext::CURVE, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::CURVE); } ImGui::SameLine(); if (ImGui::Button("Single step")) { - GPUDebug::SetBreakNext(GPUDebug::BreakNext::OP, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::OP); } if (disableStepButtons) { ImGui::EndDisabled(); @@ -406,15 +406,15 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterfa } // Display any pending step event. - if (GPUDebug::GetBreakNext() != GPUDebug::BreakNext::NONE) { + if (gpuDebug->GetBreakNext() != GPUDebug::BreakNext::NONE) { if (showBannerInFrames_ > 0) { showBannerInFrames_--; } if (showBannerInFrames_ == 0) { - ImGui::Text("Step pending (waiting for CPU): %s", GPUDebug::BreakNextToString(GPUDebug::GetBreakNext())); + ImGui::Text("Step pending (waiting for CPU): %s", GPUDebug::BreakNextToString(gpuDebug->GetBreakNext())); ImGui::SameLine(); if (ImGui::Button("Cancel step")) { - GPUDebug::SetBreakNext(GPUDebug::BreakNext::NONE, gpuDebug->GetBreakpoints()); + gpuDebug->ClearBreakNext(); } } } else { diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 9167530b04..975d25100c 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -135,8 +135,8 @@ StepCountDlg::~StepCountDlg() { void StepCountDlg::Jump(int count, bool relative) { if (relative && count == 0) return; - GPUDebug::SetBreakNext(GPUDebug::BreakNext::COUNT, gpuDebug->GetBreakpoints()); - GPUDebug::SetBreakCount(count, relative); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::COUNT); + gpuDebug->SetBreakCount(count, relative); }; BOOL StepCountDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { @@ -577,7 +577,7 @@ void CGEDebugger::UpdatePreviews() { } wchar_t primCounter[1024]{}; - swprintf(primCounter, ARRAY_SIZE(primCounter), L"%d/%d", GPUDebug::PrimsThisFrame(), GPUDebug::PrimsLastFrame()); + swprintf(primCounter, ARRAY_SIZE(primCounter), L"%d/%d", gpuDebug->PrimsThisFrame(), gpuDebug->PrimsLastFrame()); SetDlgItemText(m_hDlg, IDC_GEDBG_PRIMCOUNTER, primCounter); for (GEDebuggerTab &tabState : tabStates_) { @@ -989,31 +989,31 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_GEDBG_STEPDRAW: - GPUDebug::SetBreakNext(GPUDebug::BreakNext::DRAW, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::DRAW); break; case IDC_GEDBG_STEP: - GPUDebug::SetBreakNext(GPUDebug::BreakNext::OP, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::OP); break; case IDC_GEDBG_STEPTEX: - GPUDebug::SetBreakNext(GPUDebug::BreakNext::TEX, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::TEX); break; case IDC_GEDBG_STEPFRAME: - GPUDebug::SetBreakNext(GPUDebug::BreakNext::FRAME, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::FRAME); break; case IDC_GEDBG_STEPVSYNC: - GPUDebug::SetBreakNext(GPUDebug::BreakNext::VSYNC, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::VSYNC); break; case IDC_GEDBG_STEPPRIM: - GPUDebug::SetBreakNext(GPUDebug::BreakNext::PRIM, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::PRIM); break; case IDC_GEDBG_STEPCURVE: - GPUDebug::SetBreakNext(GPUDebug::BreakNext::CURVE, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::CURVE); break; case IDC_GEDBG_STEPCOUNT: @@ -1078,7 +1078,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, L""); SetDlgItemText(m_hDlg, IDC_GEDBG_PRIMCOUNTER, L""); - GPUDebug::SetBreakNext(GPUDebug::BreakNext::NONE, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::NONE); break; case IDC_GEDBG_RECORD: @@ -1116,9 +1116,9 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case IDC_GEDBG_SETPRIMFILTER: { - std::string value = GPUDebug::GetRestrictPrims(); + std::string value = gpuDebug->GetRestrictPrims(); if (InputBox_GetString(GetModuleHandle(NULL), m_hDlg, L"Prim counter ranges", value, value)) { - GPUDebug::SetRestrictPrims(value.c_str()); + gpuDebug->SetRestrictPrims(value.c_str()); } break; } @@ -1126,7 +1126,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { break; case WM_GEDBG_STEPDISPLAYLIST: - GPUDebug::SetBreakNext(GPUDebug::BreakNext::OP, gpuDebug->GetBreakpoints()); + gpuDebug->SetBreakNext(GPUDebug::BreakNext::OP); break; case WM_GEDBG_TOGGLEPCBREAKPOINT: From dda3ddf6b0e34104afc183fd1418128dca3c1b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 15 Dec 2024 14:14:33 +0100 Subject: [PATCH 8/8] Simplifications --- GPU/Common/GPUDebugInterface.h | 9 ++--- GPU/Debugger/Stepping.cpp | 4 -- GPU/GPUCommon.cpp | 45 ++++++++++------------ GPU/GPUCommon.h | 9 +++-- UI/ImDebugger/ImGe.cpp | 6 ++- Windows/GEDebugger/CtrlDisplayListView.cpp | 3 +- 6 files changed, 36 insertions(+), 40 deletions(-) diff --git a/GPU/Common/GPUDebugInterface.h b/GPU/Common/GPUDebugInterface.h index adf158f01f..5ec2774bff 100644 --- a/GPU/Common/GPUDebugInterface.h +++ b/GPU/Common/GPUDebugInterface.h @@ -213,9 +213,6 @@ public: virtual void ResetListStall(int listID, u32 stall) = 0; virtual void ResetListState(int listID, DisplayListState state) = 0; - GPUDebugOp DisassembleOp(u32 pc) { - return DisassembleOp(pc, Memory::Read_U32(pc)); - } virtual GPUDebugOp DisassembleOp(u32 pc, u32 op) = 0; virtual std::vector DisassembleOpRange(u32 startpc, u32 endpc) = 0; @@ -245,10 +242,10 @@ public: virtual const std::list &GetDisplayListQueue() = 0; virtual const DisplayList &GetDisplayList(int index) = 0; - virtual int PrimsThisFrame() = 0; - virtual int PrimsLastFrame() = 0; + virtual int PrimsThisFrame() const = 0; + virtual int PrimsLastFrame() const = 0; - virtual void ClearBreakNext() = 0 ; + 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 ; diff --git a/GPU/Debugger/Stepping.cpp b/GPU/Debugger/Stepping.cpp index 0860c1a292..0ec2072d99 100644 --- a/GPU/Debugger/Stepping.cpp +++ b/GPU/Debugger/Stepping.cpp @@ -45,10 +45,6 @@ static bool isStepping; // Number of times we've entered stepping, to detect a resume asynchronously. static int stepCounter = 0; -// Debug stats. -static double g_timeSteppingStarted; -static double g_timeSpentStepping; - static std::mutex pauseLock; static PauseAction pauseAction = PAUSE_CONTINUE; static std::mutex actionLock; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 1ecd09757b..4db72805b3 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -620,7 +620,12 @@ void GPUCommon::PSPFrame() { } else if (dumpThisFrame_) { dumpThisFrame_ = false; } - NotifyBeginFrame(); + + if (breakNext == GPUDebug::BreakNext::VSYNC) { + // Just start stepping as soon as we can once the vblank finishes. + breakNext = GPUDebug::BreakNext::OP; + } + recorder_.NotifyBeginFrame(); } // Returns false on breakpoint. @@ -2019,20 +2024,28 @@ GPUDebug::BreakNext GPUCommon::GetBreakNext() { void GPUCommon::SetBreakNext(GPUDebug::BreakNext next) { breakNext = next; breakAtCount = -1; - if (next == GPUDebug::BreakNext::TEX) { + switch (next) { + case GPUDebug::BreakNext::TEX: breakpoints_.AddTextureChangeTempBreakpoint(); - } else if (next == GPUDebug::BreakNext::PRIM || next == GPUDebug::BreakNext::COUNT) { + break; + case GPUDebug::BreakNext::PRIM: + case GPUDebug::BreakNext::COUNT: breakpoints_.AddCmdBreakpoint(GE_CMD_PRIM, true); breakpoints_.AddCmdBreakpoint(GE_CMD_BEZIER, true); breakpoints_.AddCmdBreakpoint(GE_CMD_SPLINE, true); breakpoints_.AddCmdBreakpoint(GE_CMD_VAP, true); - } else if (next == GPUDebug::BreakNext::CURVE) { + break; + case GPUDebug::BreakNext::CURVE: breakpoints_.AddCmdBreakpoint(GE_CMD_BEZIER, true); breakpoints_.AddCmdBreakpoint(GE_CMD_SPLINE, true); - } else if (next == GPUDebug::BreakNext::DRAW) { + break; + case GPUDebug::BreakNext::DRAW: // This is now handled by switching to BreakNext::PRIM when we encounter a flush. // This will take us to the following actual draw. primAfterDraw_ = true; + break; + default: + break; } if (GPUStepping::IsStepping()) { @@ -2093,12 +2106,13 @@ GPUDebug::NotifyResult GPUCommon::NotifyCommand(u32 pc, GPUBreakpoints *breakpoi if (isBreakpoint) { breakpoints->ClearTempBreakpoints(); - if (coreState == CORE_POWERDOWN || !gpuDebug) { + if (coreState == CORE_POWERDOWN) { breakNext = BreakNext::NONE; return process ? NotifyResult::Execute : NotifyResult::Skip; } - auto info = gpuDebug->DisassembleOp(pc); + u32 op = Memory::Read_U32(pc); + auto info = DisassembleOp(pc, op); NOTICE_LOG(Log::GeDebugger, "Waiting at %08x, %s", pc, info.desc.c_str()); g_skipPcOnce = pc; @@ -2131,23 +2145,6 @@ void GPUCommon::NotifyDisplay(u32 framebuf, u32 stride, int format) { recorder_.NotifyDisplay(framebuf, stride, format); } -void GPUCommon::NotifyBeginFrame() { - using namespace GPUDebug; - if (breakNext == BreakNext::VSYNC) { - // Just start stepping as soon as we can once the vblank finishes. - breakNext = BreakNext::OP; - } - recorder_.NotifyBeginFrame(); -} - -int GPUCommon::PrimsThisFrame() { - return primsThisFrame; -} - -int GPUCommon::PrimsLastFrame() { - return primsLastFrame; -} - bool GPUCommon::SetRestrictPrims(std::string_view rule) { if (rule.empty() || rule == "*") { restrictPrimRanges.clear(); diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index bbac458561..ddaf64c406 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -392,15 +392,18 @@ public: bool SetRestrictPrims(std::string_view rule) override; const char *GetRestrictPrims() override; - int PrimsThisFrame() override; - int PrimsLastFrame() override; + int PrimsThisFrame() const override { + return primsThisFrame; + } + int PrimsLastFrame() const override { + return primsLastFrame; + } void NotifyFlush(); protected: // While debugging is active, these may block. void NotifyDisplay(u32 framebuf, u32 stride, int format); - void NotifyBeginFrame(); bool NeedsSlowInterpreter() const; GPUDebug::NotifyResult NotifyCommand(u32 pc, GPUBreakpoints *breakpoints); diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index bd3bca15f5..ae8193a727 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -150,7 +150,8 @@ void ImGeDisasmView::Draw(GPUDebugInterface *gpuDebug) { if (Memory::IsValid4AlignedAddress(addr)) { draw_list->AddText(lineStart, 0xFFC0C0C0, addrBuffer); - GPUDebugOp op = gpuDebug->DisassembleOp(addr); + u32 opcode = Memory::Read_U32(addr); + GPUDebugOp op = gpuDebug->DisassembleOp(addr, opcode); u32 color = 0xFFFFFFFF; char temp[16]; snprintf(temp, sizeof(temp), "%08x", op.op); @@ -212,7 +213,8 @@ void ImGeDisasmView::Draw(GPUDebugInterface *gpuDebug) { } } else if (Memory::IsValid4AlignedAddress(dragAddr_)) { char buffer[64]; - GPUDebugOp op = gpuDebug->DisassembleOp(pc); + u32 opcode = Memory::Read_U32(dragAddr_); + GPUDebugOp op = gpuDebug->DisassembleOp(dragAddr_, opcode); // affect dragAddr_? if (ImGui::MenuItem("Copy Address", NULL, false)) { snprintf(buffer, sizeof(buffer), "%08x", dragAddr_); diff --git a/Windows/GEDebugger/CtrlDisplayListView.cpp b/Windows/GEDebugger/CtrlDisplayListView.cpp index 3c7e7c4129..6c0f41961f 100644 --- a/Windows/GEDebugger/CtrlDisplayListView.cpp +++ b/Windows/GEDebugger/CtrlDisplayListView.cpp @@ -341,7 +341,8 @@ void CtrlDisplayListView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) char *p = temp, *end = temp + space; for (u32 pos = selectRangeStart; pos < selectRangeEnd && p < end; pos += instructionSize) { - GPUDebugOp op = gpuDebug->DisassembleOp(pos); + u32 opcode = Memory::Read_U32(pos); + GPUDebugOp op = gpuDebug->DisassembleOp(pos, opcode); p += snprintf(p, end - p, "%s\r\n", op.desc.c_str()); }