Merge pull request #19733 from hrydgard/ge-debugger-merge

Ge debugger refactor: Lift even more functionality into GPUCommon
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2024-12-15 18:47:58 +01:00
commit 04a8c43514
31 files changed
+340 -375

No files matched your search

+4 -4
View File
@@ -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;
}
+9 -3
View File
@@ -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;
@@ -89,9 +94,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.
@@ -331,4 +335,6 @@ protected:
Vec2f minOffset_;
Vec2f maxOffset_;
bool offsetOutsideEdge_;
GPUCommon *gpuCommon_;
};
+2 -4
View File
@@ -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 {
@@ -3258,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();
}
}
+1 -5
View File
@@ -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 &params, u32 skipDrawReason);
+2 -2
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:
+12 -4
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;
@@ -212,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<GPUDebugOp> DisassembleOpRange(u32 startpc, u32 endpc) = 0;
@@ -225,7 +223,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;
@@ -244,6 +242,16 @@ public:
virtual const std::list<int> &GetDisplayListQueue() = 0;
virtual const DisplayList &GetDisplayList(int index) = 0;
virtual int PrimsThisFrame() const = 0;
virtual int PrimsLastFrame() const = 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;
+1 -1
View File
@@ -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;
+5 -7
View File
@@ -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();
@@ -465,10 +467,6 @@ void DrawEngineD3D11::DoFlush() {
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);
@@ -485,7 +483,7 @@ void DrawEngineD3D11::DoFlush() {
ResetAfterDrawInline();
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
GPUDebug::NotifyFlush();
gpuCommon_->NotifyFlush();
}
TessellationDataTransferD3D11::TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device)
+1 -16
View File
@@ -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);
+1
View File
@@ -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_);
+3 -176
View File
@@ -18,7 +18,6 @@
#include <vector>
#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"
@@ -26,21 +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 double lastStepTime = -1.0;
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,";
@@ -57,152 +41,6 @@ const char *BreakNextToString(BreakNext next) {
}
}
bool NeedsSlowInterpreter() {
return breakNext != BreakNext::NONE;
}
void ClearBreak() {
breakNext = BreakNext::NONE;
breakAtCount = -1;
GPUStepping::ResumeFromStepping();
lastStepTime = -1.0;
}
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();
}
lastStepTime = next == BreakNext::NONE ? -1.0 : time_now_d();
}
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);
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());
}
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)
@@ -212,14 +50,9 @@ static bool ParseRange(const std::string &s, std::pair<int, int> &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<std::pair<int, int>> *output) {
constexpr int MAX_PRIMS = 0x7FFFFFFF;
static constexpr int MAX_PRIMS = 0x7FFFFFFF;
std::vector<std::string> parts;
SplitString(rule, ',', parts);
@@ -272,14 +105,8 @@ bool SetRestrictPrims(const char *rule) {
updated.push_back(range);
}
}
restrictPrimRanges = updated;
restrictPrimRule = rule;
*output = updated;
return true;
}
const char *GetRestrictPrims() {
return restrictPrimRule.c_str();
}
}
+5 -18
View File
@@ -17,6 +17,9 @@
#pragma once
#include <string_view>
#include <vector>
#include <string>
#include "Common/CommonTypes.h"
namespace GPUDebug {
@@ -34,29 +37,13 @@ enum class BreakNext {
COUNT,
};
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(const char *rule);
const char *GetRestrictPrims();
const char *BreakNextToString(GPUDebug::BreakNext next);
bool ParsePrimRanges(std::string_view rule, std::vector<std::pair<int, int>> *output);
} // namespace
+1 -5
View File
@@ -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;
@@ -143,7 +139,7 @@ static void RunPauseAction() {
break;
case PAUSE_FLUSHDRAW:
gpuDebug->DispatchFlush();
gpuDebug->Flush();
break;
default:
+5 -7
View File
@@ -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();
@@ -402,10 +404,6 @@ void DrawEngineDX9::DoFlush() {
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)) {
@@ -421,7 +419,7 @@ void DrawEngineDX9::DoFlush() {
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) {
+1 -14
View File
@@ -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();
+1
View File
@@ -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_);
+5 -3
View File
@@ -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;
@@ -434,7 +437,6 @@ void DrawEngineGLES::DoFlush() {
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();
@@ -451,7 +453,7 @@ void DrawEngineGLES::DoFlush() {
bail:
ResetAfterDrawInline();
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
GPUDebug::NotifyFlush();
gpuCommon_->NotifyFlush();
}
// TODO: Refactor this to a single USE flag.
+1 -14
View File
@@ -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();
}
+1
View File
@@ -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_);
+167 -11
View File
@@ -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) :
@@ -624,7 +620,11 @@ void GPUCommon::PSPFrame() {
} else if (dumpThisFrame_) {
dumpThisFrame_ = false;
}
GPUDebug::NotifyBeginFrame();
if (breakNext == GPUDebug::BreakNext::VSYNC) {
// Just start stepping as soon as we can once the vblank finishes.
breakNext = GPUDebug::BreakNext::OP;
}
recorder_.NotifyBeginFrame();
}
@@ -632,7 +632,7 @@ void GPUCommon::PSPFrame() {
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);
@@ -791,7 +791,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
@@ -882,7 +882,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) {
@@ -1348,7 +1348,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 +1363,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;
@@ -2007,3 +2007,159 @@ 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;
switch (next) {
case GPUDebug::BreakNext::TEX:
breakpoints_.AddTextureChangeTempBreakpoint();
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);
break;
case GPUDebug::BreakNext::CURVE:
breakpoints_.AddCmdBreakpoint(GE_CMD_BEZIER, true);
breakpoints_.AddCmdBreakpoint(GE_CMD_SPLINE, true);
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()) {
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) {
breakNext = BreakNext::NONE;
return process ? NotifyResult::Execute : NotifyResult::Skip;
}
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;
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);
}
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();
}
+40 -3
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"
@@ -305,9 +306,7 @@ public:
static int EstimatePerVertexCost();
// Note: Not virtual!
void Flush();
void DispatchFlush() override;
#ifdef USE_CRT_DBG
#undef new
@@ -386,7 +385,29 @@ 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() 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);
bool NeedsSlowInterpreter() const;
GPUDebug::NotifyResult NotifyCommand(u32 pc, GPUBreakpoints *breakpoints);
virtual void ClearCacheNextFrame() {}
virtual void CheckRenderResized() {}
@@ -469,7 +490,6 @@ protected:
bool dumpNextFrame_ = false;
bool dumpThisFrame_ = false;
bool useFastRunLoop_ = false;
bool debugRecording_ = false;
bool interruptsEnabled_ = false;
bool displayResized_ = false;
bool renderResized_ = false;
@@ -510,9 +530,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();
+9 -7
View File
@@ -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,8 @@ void GPUCommonHW::BeginHostFrame() {
}
void GPUCommonHW::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format, &recorder_);
framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format);
NotifyDisplay(framebuf, stride, format);
}
void GPUCommonHW::CheckFlushOp(int cmd, u32 diff) {
@@ -521,7 +523,7 @@ void GPUCommonHW::CheckFlushOp(int cmd, u32 diff) {
if (dumpThisFrame_) {
NOTICE_LOG(Log::G3D, "================ FLUSH ================");
}
drawEngineCommon_->DispatchFlush();
drawEngineCommon_->Flush();
}
}
@@ -531,7 +533,7 @@ void GPUCommonHW::PreExecuteOp(u32 op, u32 diff) {
void GPUCommonHW::CopyDisplayToOutput(bool reallyDirty) {
// Flush anything left over.
drawEngineCommon_->DispatchFlush();
drawEngineCommon_->Flush();
shaderManager_->DirtyLastShader();
@@ -847,7 +849,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)) {
@@ -1253,7 +1255,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;
@@ -1300,7 +1302,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();
@@ -1372,7 +1374,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();
+14 -13
View File
@@ -436,6 +436,7 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
if (!drawEngine_)
return;
drawEngine_->SetGPUCommon(this);
drawEngine_->Init();
drawEngineCommon_ = drawEngine_;
@@ -493,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;
@@ -651,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);
@@ -839,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);
@@ -1004,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)) {
@@ -1032,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());
}
}
@@ -1040,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) {
@@ -1051,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);
@@ -1272,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);
}
+7 -7
View File
@@ -66,8 +66,8 @@ void SoftwareDrawEngine::NotifyConfigChanged() {
decOptions_.applySkinInDecode = true;
}
void SoftwareDrawEngine::DispatchFlush() {
transformUnit.Flush("debug");
void SoftwareDrawEngine::Flush() {
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) {
+3 -3
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);
@@ -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;
+6 -5
View File
@@ -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();
@@ -551,9 +555,6 @@ void DrawEngineVulkan::DoFlush() {
// 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();
@@ -569,7 +570,7 @@ void DrawEngineVulkan::DoFlush() {
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
GPUDebug::NotifyFlush();
gpuCommon_->NotifyFlush();
}
void DrawEngineVulkan::ResetAfterDraw() {
+2 -16
View File
@@ -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();
+1
View File
@@ -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_);
+14 -12
View File
@@ -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_);
@@ -359,34 +361,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 +408,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 {
+2 -1
View File
@@ -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());
}
+14 -14
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: