Lift some more debugging functionality into GPUCommon

This commit is contained in:
Henrik Rydgård 2024-12-15 14:03:05 +01:00
parent 190af89d9f
commit 54d18bb343
16 changed files with 270 additions and 252 deletions

View file

@ -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:

View file

@ -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<int> &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;

View file

@ -483,7 +483,7 @@ void DrawEngineD3D11::Flush() {
ResetAfterDrawInline();
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
GPUDebug::NotifyFlush();
gpuCommon_->NotifyFlush();
}
TessellationDataTransferD3D11::TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device)

View file

@ -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<std::pair<int, int>> 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<int, int> &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<std::pair<int, int>> *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();
}
}

View file

@ -37,32 +37,13 @@ enum class BreakNext {
COUNT,
};
const char *BreakNextToString(BreakNext next);
bool ParsePrimRanges(std::string_view rule, std::vector<std::pair<int, int>> *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<std::pair<int, int>> *output);
} // namespace

View file

@ -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) {

View file

@ -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.

View file

@ -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();
}

View file

@ -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<std::pair<int, int>> restrictPrimRanges;
std::string restrictPrimRule;
private:
void DoExecuteCall(u32 target);
void PopDLQueue();

View file

@ -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) {

View file

@ -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);
}

View file

@ -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) {

View file

@ -141,8 +141,8 @@ public:
static bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &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);

View file

@ -570,7 +570,7 @@ void DrawEngineVulkan::Flush() {
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
GPUDebug::NotifyFlush();
gpuCommon_->NotifyFlush();
}
void DrawEngineVulkan::ResetAfterDraw() {

View file

@ -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 {

View file

@ -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: