mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Lift some more debugging functionality into GPUCommon
This commit is contained in:
parent
190af89d9f
commit
54d18bb343
16 changed files with 270 additions and 252 deletions
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -483,7 +483,7 @@ void DrawEngineD3D11::Flush() {
|
|||
|
||||
ResetAfterDrawInline();
|
||||
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
|
||||
GPUDebug::NotifyFlush();
|
||||
gpuCommon_->NotifyFlush();
|
||||
}
|
||||
|
||||
TessellationDataTransferD3D11::TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -570,7 +570,7 @@ void DrawEngineVulkan::Flush() {
|
|||
|
||||
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
|
||||
|
||||
GPUDebug::NotifyFlush();
|
||||
gpuCommon_->NotifyFlush();
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::ResetAfterDraw() {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Reference in a new issue