diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 3e6863ae90..349a11fc8f 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -50,8 +50,10 @@ static PauseAction pauseAction = PAUSE_CONTINUE; static recursive_mutex actionLock; static condition_variable actionWait; +static recursive_mutex breaksLock; static std::vector breakCmds; static std::set breakPCs; +static std::set breakTextures; static bool breakNextOp = false; static bool breakNextDraw = false; @@ -67,9 +69,38 @@ void CGEDebugger::Init() { } bool CGEDebugger::IsAddressBreakPoint(u32 pc) { + lock_guard guard(breaksLock); return breakPCs.find(pc) != breakPCs.end(); } +bool CGEDebugger::IsOpBreakPoint(u32 op) { + u8 cmd = op >> 24; + return breakCmds[cmd]; +} + +bool CGEDebugger::IsTextureBreakPoint(u32 op) { + u8 cmd = op >> 24; + bool interesting = (cmd >= GE_CMD_TEXADDR0 && cmd <= GE_CMD_TEXADDR7); + interesting = interesting || (cmd >= GE_CMD_TEXBUFWIDTH0 && cmd <= GE_CMD_TEXBUFWIDTH7); + if (!interesting || !gpuDebug) { + return false; + } + + // Okay, so we just set a texture of some sort, check if it was one we were waiting for. + auto state = gpuDebug->GetGState(); + lock_guard guard(breaksLock); + for (int level = 0; level <= 7; ++level) { + if (breakTextures.find(state.getTextureAddress(level)) != breakTextures.end()) { + return true; + } + } + return false; +} + +bool CGEDebugger::IsOpOrTextureBreakPoint(u32 op) { + return IsOpBreakPoint(op) || IsTextureBreakPoint(op); +} + static void SetPauseAction(PauseAction act) { { lock_guard guard(pauseLock); @@ -348,8 +379,8 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case WM_GEDBG_TOGGLEPCBREAKPOINT: { - // TODO: does this need mutexes? - u32 pc = wParam; + lock_guard guard(breaksLock); + u32 pc = (u32)wParam; auto iter = breakPCs.find(pc); if (iter != breakPCs.end()) breakPCs.erase(iter); @@ -387,8 +418,7 @@ void WindowsHost::GPUNotifyCommand(u32 pc) { u32 op = Memory::ReadUnchecked_U32(pc); u8 cmd = op >> 24; - const bool breakPC = breakPCs.find(pc) != breakPCs.end(); - if (breakNextOp || breakCmds[cmd] || breakPC) { + if (breakNextOp || CGEDebugger::IsOpOrTextureBreakPoint(op) || CGEDebugger::IsAddressBreakPoint(pc)) { PauseWithMessage(WM_GEDBG_BREAK_CMD, (WPARAM) pc); } } diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index dec741f1c1..241739e464 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -46,6 +46,11 @@ public: static void Init(); static bool IsAddressBreakPoint(u32 pc); + static bool IsOpBreakPoint(u32 op); + static bool IsTextureBreakPoint(u32 op); + // Separate so the UI can just show op break points separately. + static bool IsOpOrTextureBreakPoint(u32 op); + protected: BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); diff --git a/Windows/GEDebugger/TabState.cpp b/Windows/GEDebugger/TabState.cpp index 6547edce4d..9015d8b18a 100644 --- a/Windows/GEDebugger/TabState.cpp +++ b/Windows/GEDebugger/TabState.cpp @@ -22,6 +22,7 @@ #include "GPU/GeDisasm.h" #include "GPU/Common/GPUDebugInterface.h" +// TODO: Show an icon or something for breakpoints, toggle. static const GenericListViewColumn stateValuesCols[] = { { L"Name", 0.50f }, { L"Value", 0.50f },