mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-08 14:58:36 +00:00
Merge pull request #4144 from unknownbrackets/debugger
Debugger changes, mostly reorganizing
This commit is contained in:
commit
1f99be4131
@ -1004,6 +1004,10 @@ add_library(GPU OBJECT
|
||||
GPU/Common/PostShader.cpp
|
||||
GPU/Common/PostShader.h
|
||||
GPU/Common/SplineCommon.h
|
||||
GPU/Debugger/Breakpoints.cpp
|
||||
GPU/Debugger/Breakpoints.h
|
||||
GPU/Debugger/Stepping.cpp
|
||||
GPU/Debugger/Stepping.h
|
||||
GPU/GLES/GLES_GPU.cpp
|
||||
GPU/GLES/GLES_GPU.h
|
||||
GPU/GLES/FragmentShaderGenerator.cpp
|
||||
|
@ -141,8 +141,7 @@ static inline void UpdateRunLoop() {
|
||||
NativeRender();
|
||||
}
|
||||
|
||||
void Core_RunLoop()
|
||||
{
|
||||
void Core_RunLoop() {
|
||||
while (globalUIState != UISTATE_INGAME && globalUIState != UISTATE_EXIT) {
|
||||
time_update();
|
||||
|
||||
@ -162,7 +161,7 @@ void Core_RunLoop()
|
||||
#endif
|
||||
}
|
||||
|
||||
while (!coreState) {
|
||||
while (!coreState && globalUIState == UISTATE_INGAME) {
|
||||
time_update();
|
||||
UpdateRunLoop();
|
||||
#ifdef _WIN32
|
||||
|
@ -321,8 +321,13 @@ int ElfReader::LoadInto(u32 loadAddress)
|
||||
return SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE;
|
||||
|
||||
// technically ELFCLASSNONE would freeze the system, but that's not really desireable
|
||||
if (header->e_ident[EI_CLASS] != ELFCLASS32)
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
if (header->e_ident[EI_CLASS] != ELFCLASS32) {
|
||||
if (header->e_ident[EI_CLASS] != 0) {
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
ERROR_LOG(LOADER, "Bad ELF, EI_CLASS (fifth byte) is 0x00, should be 0x01 - would lock up a PSP.");
|
||||
}
|
||||
|
||||
if (header->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
|
@ -26,7 +26,7 @@ char* GetAssembleError()
|
||||
void SplitLine(const char* Line, char* Name, char* Arguments)
|
||||
{
|
||||
while (*Line == ' ' || *Line == '\t') Line++;
|
||||
while (*Line != ' ')
|
||||
while (*Line != ' ' && *Line != '\t')
|
||||
{
|
||||
if (*Line == 0)
|
||||
{
|
||||
|
322
GPU/Debugger/Breakpoints.cpp
Normal file
322
GPU/Debugger/Breakpoints.cpp
Normal file
@ -0,0 +1,322 @@
|
||||
// Copyright (c) 2013- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "base/mutex.h"
|
||||
#include "GPU/Debugger/Breakpoints.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
namespace GPUBreakpoints {
|
||||
|
||||
static recursive_mutex breaksLock;
|
||||
static std::vector<bool> breakCmds;
|
||||
static std::set<u32> breakPCs;
|
||||
static std::set<u32> breakTextures;
|
||||
// Small optimization to avoid a lock/lookup for the common case.
|
||||
static size_t breakPCsCount = 0;
|
||||
static size_t breakTexturesCount = 0;
|
||||
|
||||
// If these are set, the above are also, but they should be temporary.
|
||||
static std::vector<bool> breakCmdsTemp;
|
||||
static std::set<u32> breakPCsTemp;
|
||||
static std::set<u32> breakTexturesTemp;
|
||||
static bool textureChangeTemp = false;
|
||||
|
||||
static u32 lastTexture = 0xFFFFFFFF;
|
||||
|
||||
// These are commands we run before breaking on a texture.
|
||||
// They are commands that affect the decoding of the texture.
|
||||
const static u8 textureRelatedCmds[] = {
|
||||
GE_CMD_TEXADDR0, GE_CMD_TEXADDR1, GE_CMD_TEXADDR2, GE_CMD_TEXADDR3, GE_CMD_TEXADDR4, GE_CMD_TEXADDR5, GE_CMD_TEXADDR6, GE_CMD_TEXADDR7,
|
||||
GE_CMD_TEXBUFWIDTH0, GE_CMD_TEXBUFWIDTH1, GE_CMD_TEXBUFWIDTH2, GE_CMD_TEXBUFWIDTH3, GE_CMD_TEXBUFWIDTH4, GE_CMD_TEXBUFWIDTH5, GE_CMD_TEXBUFWIDTH6, GE_CMD_TEXBUFWIDTH7,
|
||||
GE_CMD_TEXSIZE0, GE_CMD_TEXSIZE1, GE_CMD_TEXSIZE2, GE_CMD_TEXSIZE3, GE_CMD_TEXSIZE4, GE_CMD_TEXSIZE5, GE_CMD_TEXSIZE6, GE_CMD_TEXSIZE7,
|
||||
|
||||
GE_CMD_CLUTADDR, GE_CMD_CLUTADDRUPPER, GE_CMD_LOADCLUT, GE_CMD_CLUTFORMAT,
|
||||
GE_CMD_TEXFORMAT, GE_CMD_TEXMODE, GE_CMD_TEXTUREMAPENABLE,
|
||||
|
||||
// Sometimes found between clut/texture params.
|
||||
GE_CMD_TEXFLUSH, GE_CMD_TEXSYNC,
|
||||
};
|
||||
static std::vector<bool> nonTextureCmds;
|
||||
|
||||
void Init() {
|
||||
ClearAllBreakpoints();
|
||||
|
||||
nonTextureCmds.clear();
|
||||
nonTextureCmds.resize(256, true);
|
||||
for (size_t i = 0; i < ARRAY_SIZE(textureRelatedCmds); ++i) {
|
||||
nonTextureCmds[textureRelatedCmds[i]] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AddNonTextureTempBreakpoints() {
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
if (nonTextureCmds[i]) {
|
||||
AddCmdBreakpoint(i, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetAdjustedTextureAddress(u32 op) {
|
||||
const 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) {
|
||||
return (u32)-1;
|
||||
}
|
||||
|
||||
int level = cmd <= GE_CMD_TEXADDR7 ? cmd - GE_CMD_TEXADDR0 : cmd - GE_CMD_TEXBUFWIDTH0;
|
||||
u32 addr;
|
||||
|
||||
// Okay, so would this op modify the low or high part?
|
||||
if (cmd <= GE_CMD_TEXADDR7) {
|
||||
addr = (op & 0xFFFFF0) | ((gstate.texbufwidth[level] << 8) & 0x0F000000);
|
||||
} else {
|
||||
addr = (gstate.texaddr[level] & 0xFFFFF0) | ((op << 8) & 0x0F000000);
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
bool IsTextureChangeBreakpoint(u32 op, u32 addr) {
|
||||
if (!textureChangeTemp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const u8 cmd = op >> 24;
|
||||
bool enabled = gstate.isTextureMapEnabled();
|
||||
|
||||
// Only for level 0.
|
||||
if (cmd != GE_CMD_TEXADDR0 && cmd != GE_CMD_TEXBUFWIDTH0) {
|
||||
// But we don't break when it's not enabled.
|
||||
if (cmd == GE_CMD_TEXTUREMAPENABLE) {
|
||||
enabled = (op & 1) != 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (enabled && addr != lastTexture) {
|
||||
textureChangeTemp = false;
|
||||
lastTexture = addr;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsTextureCmdBreakpoint(u32 op) {
|
||||
const u32 addr = GetAdjustedTextureAddress(op);
|
||||
if (addr != (u32)-1) {
|
||||
return IsTextureChangeBreakpoint(op, addr) || IsTextureBreakpoint(addr);
|
||||
} else {
|
||||
return IsTextureChangeBreakpoint(op, gstate.getTextureAddress(0));
|
||||
}
|
||||
}
|
||||
|
||||
bool IsBreakpoint(u32 pc, u32 op) {
|
||||
if (IsAddressBreakpoint(pc) || IsOpBreakpoint(op)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((breakTexturesCount != 0 || textureChangeTemp) && IsTextureCmdBreakpoint(op)) {
|
||||
// Break on the next non-texture.
|
||||
AddNonTextureTempBreakpoints();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAddressBreakpoint(u32 addr, bool &temp) {
|
||||
if (breakPCsCount == 0) {
|
||||
temp = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
lock_guard guard(breaksLock);
|
||||
temp = breakPCsTemp.find(addr) != breakPCsTemp.end();
|
||||
return breakPCs.find(addr) != breakPCs.end();
|
||||
}
|
||||
|
||||
bool IsAddressBreakpoint(u32 addr) {
|
||||
if (breakPCsCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lock_guard guard(breaksLock);
|
||||
return breakPCs.find(addr) != breakPCs.end();
|
||||
}
|
||||
|
||||
bool IsTextureBreakpoint(u32 addr, bool &temp) {
|
||||
if (breakTexturesCount == 0) {
|
||||
temp = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
lock_guard guard(breaksLock);
|
||||
temp = breakTexturesTemp.find(addr) != breakTexturesTemp.end();
|
||||
return breakTextures.find(addr) != breakTextures.end();
|
||||
}
|
||||
|
||||
bool IsTextureBreakpoint(u32 addr) {
|
||||
if (breakTexturesCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lock_guard guard(breaksLock);
|
||||
return breakTextures.find(addr) != breakTextures.end();
|
||||
}
|
||||
|
||||
bool IsCmdBreakpoint(u8 cmd, bool &temp) {
|
||||
temp = breakCmdsTemp[cmd];
|
||||
return breakCmds[cmd];
|
||||
}
|
||||
|
||||
bool IsCmdBreakpoint(u8 cmd) {
|
||||
return breakCmds[cmd];
|
||||
}
|
||||
|
||||
void AddAddressBreakpoint(u32 addr, bool temp) {
|
||||
lock_guard guard(breaksLock);
|
||||
|
||||
if (temp) {
|
||||
if (breakPCs.find(addr) == breakPCs.end()) {
|
||||
breakPCsTemp.insert(addr);
|
||||
breakPCs.insert(addr);
|
||||
}
|
||||
// Already normal breakpoint, let's not make it temporary.
|
||||
} else {
|
||||
// Remove the temporary marking.
|
||||
breakPCsTemp.erase(addr);
|
||||
breakPCs.insert(addr);
|
||||
}
|
||||
|
||||
breakPCsCount = breakPCs.size();
|
||||
}
|
||||
|
||||
void AddCmdBreakpoint(u8 cmd, bool temp) {
|
||||
if (temp) {
|
||||
if (!breakCmds[cmd]) {
|
||||
breakCmdsTemp[cmd] = true;
|
||||
breakCmds[cmd] = true;
|
||||
}
|
||||
// Ignore adding a temp breakpoint when a normal one exists.
|
||||
} else {
|
||||
// This is no longer temporary.
|
||||
breakCmdsTemp[cmd] = false;
|
||||
breakCmds[cmd] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AddTextureBreakpoint(u32 addr, bool temp) {
|
||||
lock_guard guard(breaksLock);
|
||||
|
||||
if (temp) {
|
||||
if (breakTextures.find(addr) == breakTextures.end()) {
|
||||
breakTexturesTemp.insert(addr);
|
||||
breakTextures.insert(addr);
|
||||
}
|
||||
} else {
|
||||
breakTexturesTemp.erase(addr);
|
||||
breakTextures.insert(addr);
|
||||
}
|
||||
|
||||
breakTexturesCount = breakTextures.size();
|
||||
}
|
||||
|
||||
void AddTextureChangeTempBreakpoint() {
|
||||
textureChangeTemp = true;
|
||||
}
|
||||
|
||||
void RemoveAddressBreakpoint(u32 addr) {
|
||||
lock_guard guard(breaksLock);
|
||||
|
||||
breakPCsTemp.erase(addr);
|
||||
breakPCs.erase(addr);
|
||||
|
||||
breakPCsCount = breakPCs.size();
|
||||
}
|
||||
|
||||
void RemoveCmdBreakpoint(u8 cmd) {
|
||||
breakCmdsTemp[cmd] = false;
|
||||
breakCmds[cmd] = false;
|
||||
}
|
||||
|
||||
void RemoveTextureBreakpoint(u32 addr) {
|
||||
lock_guard guard(breaksLock);
|
||||
|
||||
breakTexturesTemp.erase(addr);
|
||||
breakTextures.erase(addr);
|
||||
|
||||
breakTexturesCount = breakTextures.size();
|
||||
}
|
||||
|
||||
void RemoveTextureChangeTempBreakpoint() {
|
||||
textureChangeTemp = false;
|
||||
}
|
||||
|
||||
void UpdateLastTexture(u32 addr) {
|
||||
lastTexture = addr;
|
||||
}
|
||||
|
||||
void ClearAllBreakpoints() {
|
||||
lock_guard guard(breaksLock);
|
||||
|
||||
breakCmds.clear();
|
||||
breakCmds.resize(256, false);
|
||||
breakPCs.clear();
|
||||
breakTextures.clear();
|
||||
|
||||
breakCmdsTemp.clear();
|
||||
breakCmdsTemp.resize(256, false);
|
||||
breakPCsTemp.clear();
|
||||
breakTexturesTemp.clear();
|
||||
|
||||
breakPCsCount = breakPCs.size();
|
||||
breakTexturesCount = breakTextures.size();
|
||||
|
||||
textureChangeTemp = false;
|
||||
}
|
||||
|
||||
void ClearTempBreakpoints() {
|
||||
lock_guard guard(breaksLock);
|
||||
|
||||
// Reset ones that were temporary back to non-breakpoints in the primary arrays.
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
if (breakCmdsTemp[i]) {
|
||||
breakCmds[i] = false;
|
||||
breakCmdsTemp[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = breakPCsTemp.begin(), end = breakPCsTemp.end(); it != end; ++it) {
|
||||
breakPCs.erase(*it);
|
||||
}
|
||||
breakPCsTemp.clear();
|
||||
breakPCsCount = breakPCs.size();
|
||||
|
||||
for (auto it = breakTexturesTemp.begin(), end = breakTexturesTemp.end(); it != end; ++it) {
|
||||
breakTextures.erase(*it);
|
||||
}
|
||||
breakTexturesTemp.clear();
|
||||
breakPCsCount = breakTextures.size();
|
||||
|
||||
textureChangeTemp = false;
|
||||
}
|
||||
|
||||
};
|
56
GPU/Debugger/Breakpoints.h
Normal file
56
GPU/Debugger/Breakpoints.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2013- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace GPUBreakpoints {
|
||||
void Init();
|
||||
|
||||
bool IsBreakpoint(u32 pc, u32 op);
|
||||
|
||||
bool IsAddressBreakpoint(u32 addr, bool &temp);
|
||||
bool IsAddressBreakpoint(u32 addr);
|
||||
bool IsCmdBreakpoint(u8 cmd, bool &temp);
|
||||
bool IsCmdBreakpoint(u8 cmd);
|
||||
bool IsTextureBreakpoint(u32 addr, bool &temp);
|
||||
bool IsTextureBreakpoint(u32 addr);
|
||||
|
||||
void AddAddressBreakpoint(u32 addr, bool temp = false);
|
||||
void AddCmdBreakpoint(u8 cmd, bool temp = false);
|
||||
void AddTextureBreakpoint(u32 addr, bool temp = false);
|
||||
void AddTextureChangeTempBreakpoint();
|
||||
|
||||
void RemoveAddressBreakpoint(u32 addr);
|
||||
void RemoveCmdBreakpoint(u8 cmd);
|
||||
void RemoveTextureBreakpoint(u32 addr);
|
||||
void RemoveTextureChangeTempBreakpoint();
|
||||
|
||||
void UpdateLastTexture(u32 addr);
|
||||
|
||||
void ClearAllBreakpoints();
|
||||
void ClearTempBreakpoints();
|
||||
|
||||
static inline bool IsOpBreakpoint(u32 op, bool &temp) {
|
||||
return IsCmdBreakpoint(op >> 24, temp);
|
||||
}
|
||||
|
||||
static inline bool IsOpBreakpoint(u32 op) {
|
||||
return IsCmdBreakpoint(op >> 24);
|
||||
}
|
||||
};
|
184
GPU/Debugger/Stepping.cpp
Normal file
184
GPU/Debugger/Stepping.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
// Copyright (c) 2013- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "base/mutex.h"
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
#include "GPU/Debugger/Stepping.h"
|
||||
#include "Core/Core.h"
|
||||
|
||||
namespace GPUStepping {
|
||||
|
||||
enum PauseAction {
|
||||
PAUSE_CONTINUE,
|
||||
PAUSE_BREAK,
|
||||
PAUSE_GETFRAMEBUF,
|
||||
PAUSE_GETDEPTHBUF,
|
||||
PAUSE_GETSTENCILBUF,
|
||||
PAUSE_GETTEX,
|
||||
PAUSE_SETCMDVALUE,
|
||||
};
|
||||
|
||||
static bool isStepping;
|
||||
|
||||
static recursive_mutex pauseLock;
|
||||
static condition_variable pauseWait;
|
||||
static PauseAction pauseAction = PAUSE_CONTINUE;
|
||||
static recursive_mutex actionLock;
|
||||
static condition_variable actionWait;
|
||||
// In case of accidental wakeup.
|
||||
static bool actionComplete;
|
||||
|
||||
// Many things need to run on the GPU thread. For example, reading the framebuffer.
|
||||
// A message system is used to achieve this (temporarily "unpausing" the thread.)
|
||||
// Below are values used to perform actions that return results.
|
||||
|
||||
static bool bufferResult;
|
||||
static GPUDebugBuffer bufferFrame;
|
||||
static GPUDebugBuffer bufferDepth;
|
||||
static GPUDebugBuffer bufferStencil;
|
||||
static GPUDebugBuffer bufferTex;
|
||||
static u32 pauseSetCmdValue;
|
||||
|
||||
static void SetPauseAction(PauseAction act, bool waitComplete = true) {
|
||||
{
|
||||
lock_guard guard(pauseLock);
|
||||
actionLock.lock();
|
||||
pauseAction = act;
|
||||
}
|
||||
|
||||
actionComplete = false;
|
||||
pauseWait.notify_one();
|
||||
while (waitComplete && !actionComplete) {
|
||||
actionWait.wait(actionLock);
|
||||
}
|
||||
actionLock.unlock();
|
||||
}
|
||||
|
||||
static void RunPauseAction() {
|
||||
lock_guard guard(actionLock);
|
||||
|
||||
switch (pauseAction) {
|
||||
case PAUSE_CONTINUE:
|
||||
// Don't notify, just go back, woke up by accident.
|
||||
return;
|
||||
|
||||
case PAUSE_BREAK:
|
||||
break;
|
||||
|
||||
case PAUSE_GETFRAMEBUF:
|
||||
bufferResult = gpuDebug->GetCurrentFramebuffer(bufferFrame);
|
||||
break;
|
||||
|
||||
case PAUSE_GETDEPTHBUF:
|
||||
bufferResult = gpuDebug->GetCurrentDepthbuffer(bufferDepth);
|
||||
break;
|
||||
|
||||
case PAUSE_GETSTENCILBUF:
|
||||
bufferResult = gpuDebug->GetCurrentStencilbuffer(bufferStencil);
|
||||
break;
|
||||
|
||||
case PAUSE_GETTEX:
|
||||
bufferResult = gpuDebug->GetCurrentTexture(bufferTex);
|
||||
break;
|
||||
|
||||
case PAUSE_SETCMDVALUE:
|
||||
gpuDebug->SetCmdValue(pauseSetCmdValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(HLE, "Unsupported pause action, forgot to add it to the switch.");
|
||||
}
|
||||
|
||||
actionComplete = true;
|
||||
actionWait.notify_one();
|
||||
pauseAction = PAUSE_BREAK;
|
||||
}
|
||||
|
||||
bool EnterStepping(std::function<void()> callback) {
|
||||
lock_guard guard(pauseLock);
|
||||
if (coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME) {
|
||||
// Shutting down, don't try to step.
|
||||
return false;
|
||||
}
|
||||
if (!gpuDebug) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just to be sure.
|
||||
if (pauseAction == PAUSE_CONTINUE) {
|
||||
pauseAction = PAUSE_BREAK;
|
||||
}
|
||||
isStepping = true;
|
||||
|
||||
callback();
|
||||
|
||||
do {
|
||||
RunPauseAction();
|
||||
pauseWait.wait(pauseLock);
|
||||
} while (pauseAction != PAUSE_CONTINUE);
|
||||
|
||||
isStepping = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetBuffer(const GPUDebugBuffer *&buffer, PauseAction type, const GPUDebugBuffer &resultBuffer) {
|
||||
if (!isStepping) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetPauseAction(type);
|
||||
buffer = &resultBuffer;
|
||||
return bufferResult;
|
||||
}
|
||||
|
||||
bool GPU_GetCurrentFramebuffer(const GPUDebugBuffer *&buffer) {
|
||||
return GetBuffer(buffer, PAUSE_GETFRAMEBUF, bufferFrame);
|
||||
}
|
||||
|
||||
bool GPU_GetCurrentDepthbuffer(const GPUDebugBuffer *&buffer) {
|
||||
return GetBuffer(buffer, PAUSE_GETDEPTHBUF, bufferDepth);
|
||||
}
|
||||
|
||||
bool GPU_GetCurrentStencilbuffer(const GPUDebugBuffer *&buffer) {
|
||||
return GetBuffer(buffer, PAUSE_GETSTENCILBUF, bufferStencil);
|
||||
}
|
||||
|
||||
bool GPU_GetCurrentTexture(const GPUDebugBuffer *&buffer) {
|
||||
return GetBuffer(buffer, PAUSE_GETTEX, bufferTex);
|
||||
}
|
||||
|
||||
bool GPU_SetCmdValue(u32 op) {
|
||||
if (!isStepping) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pauseSetCmdValue = op;
|
||||
SetPauseAction(PAUSE_SETCMDVALUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResumeFromStepping() {
|
||||
SetPauseAction(PAUSE_CONTINUE, false);
|
||||
}
|
||||
|
||||
void ForceUnpause() {
|
||||
SetPauseAction(PAUSE_CONTINUE, false);
|
||||
actionComplete = true;
|
||||
actionWait.notify_one();
|
||||
}
|
||||
|
||||
};
|
38
GPU/Debugger/Stepping.h
Normal file
38
GPU/Debugger/Stepping.h
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2013- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/functional.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
|
||||
namespace GPUStepping {
|
||||
// Should be called from the GPU thread.
|
||||
// Begins stepping and calls callback while inside a lock preparing stepping.
|
||||
// This would be a good place to deliver a message to code that stepping is ready.
|
||||
bool EnterStepping(std::function<void()> callback);
|
||||
|
||||
bool GPU_GetCurrentFramebuffer(const GPUDebugBuffer *&buffer);
|
||||
bool GPU_GetCurrentDepthbuffer(const GPUDebugBuffer *&buffer);
|
||||
bool GPU_GetCurrentStencilbuffer(const GPUDebugBuffer *&buffer);
|
||||
bool GPU_GetCurrentTexture(const GPUDebugBuffer *&buffer);
|
||||
bool GPU_SetCmdValue(u32 op);
|
||||
|
||||
void ResumeFromStepping();
|
||||
void ForceUnpause();
|
||||
};
|
@ -160,6 +160,8 @@
|
||||
<ClInclude Include="Common\PostShader.h" />
|
||||
<ClInclude Include="Common\SplineCommon.h" />
|
||||
<ClInclude Include="Common\VertexDecoderCommon.h" />
|
||||
<ClInclude Include="Debugger\Breakpoints.h" />
|
||||
<ClInclude Include="Debugger\Stepping.h" />
|
||||
<ClInclude Include="Directx9\GPU_DX9.h" />
|
||||
<ClInclude Include="Directx9\helper\dx_state.h" />
|
||||
<ClInclude Include="Directx9\helper\fbo.h" />
|
||||
@ -203,6 +205,8 @@
|
||||
<ClCompile Include="Common\IndexGenerator.cpp" />
|
||||
<ClCompile Include="Common\PostShader.cpp" />
|
||||
<ClCompile Include="Common\VertexDecoderCommon.cpp" />
|
||||
<ClCompile Include="Debugger\Breakpoints.cpp" />
|
||||
<ClCompile Include="Debugger\Stepping.cpp" />
|
||||
<ClCompile Include="Directx9\GPU_DX9.cpp" />
|
||||
<ClCompile Include="Directx9\helper\dx_state.cpp" />
|
||||
<ClCompile Include="Directx9\helper\fbo.cpp" />
|
||||
|
@ -19,6 +19,9 @@
|
||||
<Filter Include="DirectX9\helper">
|
||||
<UniqueIdentifier>{ba434472-5d5e-4b08-ab16-bfb7ec8e7068}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Debugger">
|
||||
<UniqueIdentifier>{0cbddc00-4aa3-41d0-bed2-a454d37f838e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ge_constants.h">
|
||||
@ -148,6 +151,12 @@
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\PostShader.h" />
|
||||
<ClInclude Include="Debugger\Breakpoints.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\Stepping.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Math3D.cpp">
|
||||
@ -268,6 +277,12 @@
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Common\PostShader.cpp" />
|
||||
<ClCompile Include="Debugger\Breakpoints.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\Stepping.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "Windows/InputBox.h"
|
||||
#include "Windows/Main.h"
|
||||
#include "Core/Config.h"
|
||||
#include "GPU/Debugger/Breakpoints.h"
|
||||
#include <algorithm>
|
||||
|
||||
const PTCHAR CtrlDisplayListView::windowClass = _T("CtrlDisplayListView");
|
||||
@ -205,7 +206,7 @@ void CtrlDisplayListView::onPaint(WPARAM wParam, LPARAM lParam)
|
||||
DeleteObject(backgroundPen);
|
||||
|
||||
// display address/symbol
|
||||
if (CGEDebugger::IsAddressBreakPoint(address))
|
||||
if (GPUBreakpoints::IsAddressBreakpoint(address))
|
||||
{
|
||||
textColor = 0x0000FF;
|
||||
int yOffset = std::max(-1,(rowHeight-14+1)/2);
|
||||
|
@ -19,7 +19,8 @@
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include "native/base/mutex.h"
|
||||
#include "base/functional.h"
|
||||
#include "base/mutex.h"
|
||||
#include "Windows/GEDebugger/GEDebugger.h"
|
||||
#include "Windows/GEDebugger/SimpleGLWindow.h"
|
||||
#include "Windows/GEDebugger/CtrlDisplayListView.h"
|
||||
@ -32,44 +33,20 @@
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/Debugger/Breakpoints.h"
|
||||
#include "GPU/Debugger/Stepping.h"
|
||||
#include "Core/Config.h"
|
||||
#include <windowsx.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
enum PauseAction {
|
||||
PAUSE_CONTINUE,
|
||||
PAUSE_BREAK,
|
||||
PAUSE_GETFRAMEBUF,
|
||||
PAUSE_GETDEPTHBUF,
|
||||
PAUSE_GETSTENCILBUF,
|
||||
PAUSE_GETTEX,
|
||||
PAUSE_SETCMDVALUE,
|
||||
};
|
||||
using namespace GPUBreakpoints;
|
||||
using namespace GPUStepping;
|
||||
|
||||
static bool attached = false;
|
||||
// TODO
|
||||
static bool textureCaching = true;
|
||||
static recursive_mutex pauseLock;
|
||||
static condition_variable pauseWait;
|
||||
static PauseAction pauseAction = PAUSE_CONTINUE;
|
||||
static recursive_mutex actionLock;
|
||||
static condition_variable actionWait;
|
||||
static bool actionComplete;
|
||||
|
||||
static recursive_mutex breaksLock;
|
||||
static std::vector<bool> breakCmds;
|
||||
static std::set<u32> breakPCs;
|
||||
static u32 tempBreakpoint = -1;
|
||||
static std::set<u32> breakTextures;
|
||||
static BreakNextType breakNext = BREAK_NONE;
|
||||
static u32 lastTexture = -1;
|
||||
|
||||
static bool bufferResult;
|
||||
static GPUDebugBuffer bufferFrame;
|
||||
static GPUDebugBuffer bufferDepth;
|
||||
static GPUDebugBuffer bufferStencil;
|
||||
static GPUDebugBuffer bufferTex;
|
||||
static u32 pauseSetCmdValue;
|
||||
|
||||
enum PrimaryDisplayType {
|
||||
PRIMARY_FRAMEBUF,
|
||||
@ -77,129 +54,14 @@ enum PrimaryDisplayType {
|
||||
PRIMARY_STENCILBUF,
|
||||
};
|
||||
|
||||
// TODO: Simplify and move out of windows stuff, just block in a common way for everyone.
|
||||
|
||||
void CGEDebugger::Init() {
|
||||
SimpleGLWindow::RegisterClass();
|
||||
CtrlDisplayListView::registerClass();
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
// Hmm, this is probably kinda slow now...
|
||||
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 (breakNext == BREAK_NEXT_NONTEX) {
|
||||
// Okay, so we hit an interesting texture, but let's not break if this is a clut/etc.
|
||||
// Otherwise we get garbage widths and colors. It's annoying.
|
||||
bool textureCmd = interesting || cmd == GE_CMD_CLUTADDR || cmd == GE_CMD_CLUTADDRUPPER || cmd == GE_CMD_LOADCLUT || cmd == GE_CMD_CLUTFORMAT;
|
||||
textureCmd = textureCmd || (cmd >= GE_CMD_TEXSIZE0 && cmd <= GE_CMD_TEXSIZE7);
|
||||
textureCmd = textureCmd || cmd == GE_CMD_TEXFORMAT || cmd == GE_CMD_TEXMODE || cmd == GE_CMD_TEXTUREMAPENABLE;
|
||||
if (!textureCmd) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
int level = cmd <= GE_CMD_TEXADDR7 ? cmd - GE_CMD_TEXADDR0 : cmd - GE_CMD_TEXBUFWIDTH0;
|
||||
|
||||
// Are we breaking on any texture? As long as it's level 0.
|
||||
if (level == 0 && breakNext == BREAK_NEXT_TEX && lastTexture != state.getTextureAddress(level)) {
|
||||
// Don't break right away, we'll get a garbage texture...
|
||||
breakNext = BREAK_NEXT_NONTEX;
|
||||
}
|
||||
|
||||
lock_guard guard(breaksLock);
|
||||
if (breakTextures.find(state.getTextureAddress(level)) != breakTextures.end() && breakNext == BREAK_NONE) {
|
||||
breakNext = BREAK_NEXT_NONTEX;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CGEDebugger::IsOpOrTextureBreakPoint(u32 op) {
|
||||
return IsOpBreakPoint(op) || IsTextureBreakPoint(op);
|
||||
}
|
||||
|
||||
static void SetPauseAction(PauseAction act, bool waitComplete = true) {
|
||||
{
|
||||
lock_guard guard(pauseLock);
|
||||
actionLock.lock();
|
||||
pauseAction = act;
|
||||
}
|
||||
|
||||
actionComplete = false;
|
||||
pauseWait.notify_one();
|
||||
while (waitComplete && !actionComplete) {
|
||||
actionWait.wait(actionLock);
|
||||
}
|
||||
actionLock.unlock();
|
||||
}
|
||||
|
||||
static void RunPauseAction() {
|
||||
lock_guard guard(actionLock);
|
||||
|
||||
switch (pauseAction) {
|
||||
case PAUSE_CONTINUE:
|
||||
// Don't notify, just go back, woke up by accident.
|
||||
return;
|
||||
|
||||
case PAUSE_BREAK:
|
||||
break;
|
||||
|
||||
case PAUSE_GETFRAMEBUF:
|
||||
bufferResult = gpuDebug->GetCurrentFramebuffer(bufferFrame);
|
||||
break;
|
||||
|
||||
case PAUSE_GETDEPTHBUF:
|
||||
bufferResult = gpuDebug->GetCurrentDepthbuffer(bufferDepth);
|
||||
break;
|
||||
|
||||
case PAUSE_GETSTENCILBUF:
|
||||
bufferResult = gpuDebug->GetCurrentStencilbuffer(bufferStencil);
|
||||
break;
|
||||
|
||||
case PAUSE_GETTEX:
|
||||
bufferResult = gpuDebug->GetCurrentTexture(bufferTex);
|
||||
break;
|
||||
|
||||
case PAUSE_SETCMDVALUE:
|
||||
gpuDebug->SetCmdValue(pauseSetCmdValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(HLE, "Unsupported pause action, forgot to add it to the switch.");
|
||||
}
|
||||
|
||||
actionComplete = true;
|
||||
actionWait.notify_one();
|
||||
pauseAction = PAUSE_BREAK;
|
||||
}
|
||||
|
||||
static void ForceUnpause() {
|
||||
SetPauseAction(PAUSE_CONTINUE, false);
|
||||
actionComplete = true;
|
||||
actionWait.notify_one();
|
||||
}
|
||||
|
||||
CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent)
|
||||
: Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent), frameWindow(NULL), texWindow(NULL) {
|
||||
breakCmds.resize(256, false);
|
||||
GPUBreakpoints::Init();
|
||||
Core_ListenShutdown(ForceUnpause);
|
||||
|
||||
// minimum size = a little more than the default
|
||||
@ -282,9 +144,9 @@ void CGEDebugger::UpdatePreviews() {
|
||||
// TODO: Do something different if not paused?
|
||||
|
||||
wchar_t desc[256];
|
||||
GPUDebugBuffer *primaryBuffer = NULL;
|
||||
const GPUDebugBuffer *primaryBuffer = NULL;
|
||||
bool bufferResult = false;
|
||||
GPUgstate state;
|
||||
bufferResult = false;
|
||||
|
||||
if (gpuDebug != NULL) {
|
||||
state = gpuDebug->GetGState();
|
||||
@ -292,21 +154,24 @@ void CGEDebugger::UpdatePreviews() {
|
||||
|
||||
switch (PrimaryDisplayType(fbTabs->CurrentTabIndex())) {
|
||||
case PRIMARY_FRAMEBUF:
|
||||
SetPauseAction(PAUSE_GETFRAMEBUF);
|
||||
primaryBuffer = &bufferFrame;
|
||||
_snwprintf(desc, ARRAY_SIZE(desc), L"Color: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight());
|
||||
bufferResult = GPU_GetCurrentFramebuffer(primaryBuffer);
|
||||
if (bufferResult) {
|
||||
_snwprintf(desc, ARRAY_SIZE(desc), L"Color: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight());
|
||||
}
|
||||
break;
|
||||
|
||||
case PRIMARY_DEPTHBUF:
|
||||
SetPauseAction(PAUSE_GETDEPTHBUF);
|
||||
primaryBuffer = &bufferDepth;
|
||||
_snwprintf(desc, ARRAY_SIZE(desc), L"Depth: 0x%08x (%dx%d)", state.getDepthBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight());
|
||||
bufferResult = GPU_GetCurrentDepthbuffer(primaryBuffer);
|
||||
if (bufferResult) {
|
||||
_snwprintf(desc, ARRAY_SIZE(desc), L"Depth: 0x%08x (%dx%d)", state.getDepthBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight());
|
||||
}
|
||||
break;
|
||||
|
||||
case PRIMARY_STENCILBUF:
|
||||
SetPauseAction(PAUSE_GETSTENCILBUF);
|
||||
primaryBuffer = &bufferStencil;
|
||||
_snwprintf(desc, ARRAY_SIZE(desc), L"Stencil: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight());
|
||||
bufferResult = GPU_GetCurrentStencilbuffer(primaryBuffer);
|
||||
if (bufferResult) {
|
||||
_snwprintf(desc, ARRAY_SIZE(desc), L"Stencil: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -319,12 +184,12 @@ void CGEDebugger::UpdatePreviews() {
|
||||
SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, L"Failed");
|
||||
}
|
||||
|
||||
bufferResult = false;
|
||||
SetPauseAction(PAUSE_GETTEX);
|
||||
const GPUDebugBuffer *bufferTex = NULL;
|
||||
bufferResult = GPU_GetCurrentTexture(bufferTex);
|
||||
|
||||
if (bufferResult) {
|
||||
auto fmt = SimpleGLWindow::Format(bufferTex.GetFormat());
|
||||
texWindow->Draw(bufferTex.GetData(), bufferTex.GetStride(), bufferTex.GetHeight(), bufferTex.GetFlipped(), fmt);
|
||||
auto fmt = SimpleGLWindow::Format(bufferTex->GetFormat());
|
||||
texWindow->Draw(bufferTex->GetData(), bufferTex->GetStride(), bufferTex->GetHeight(), bufferTex->GetFlipped(), fmt);
|
||||
|
||||
if (gpuDebug != NULL) {
|
||||
if (state.isTextureAlphaUsed()) {
|
||||
@ -335,9 +200,9 @@ void CGEDebugger::UpdatePreviews() {
|
||||
_snwprintf(desc, ARRAY_SIZE(desc), L"Texture: 0x%08x (%dx%d)", state.getTextureAddress(0), state.getTextureWidth(0), state.getTextureHeight(0));
|
||||
SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, desc);
|
||||
|
||||
lastTexture = state.getTextureAddress(0);
|
||||
UpdateLastTexture(state.getTextureAddress(0));
|
||||
} else {
|
||||
lastTexture = -1;
|
||||
UpdateLastTexture((u32)-1);
|
||||
}
|
||||
} else {
|
||||
texWindow->Clear();
|
||||
@ -346,7 +211,7 @@ void CGEDebugger::UpdatePreviews() {
|
||||
} else {
|
||||
SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, L"Texture: disabled");
|
||||
}
|
||||
lastTexture = -1;
|
||||
UpdateLastTexture((u32)-1);
|
||||
}
|
||||
|
||||
DisplayList list;
|
||||
@ -391,7 +256,7 @@ void CGEDebugger::SetBreakNext(BreakNextType type) {
|
||||
attached = true;
|
||||
SetupPreviews();
|
||||
|
||||
SetPauseAction(PAUSE_CONTINUE, false);
|
||||
ResumeFromStepping();
|
||||
breakNext = type;
|
||||
}
|
||||
|
||||
@ -458,6 +323,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
break;
|
||||
|
||||
case IDC_GEDBG_STEPTEX:
|
||||
AddTextureChangeTempBreakpoint();
|
||||
SetBreakNext(BREAK_NEXT_TEX);
|
||||
break;
|
||||
|
||||
@ -467,13 +333,17 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
|
||||
case IDC_GEDBG_BREAKTEX:
|
||||
{
|
||||
u32 texAddr;
|
||||
if (!gpuDebug) {
|
||||
break;
|
||||
}
|
||||
const auto state = gpuDebug->GetGState();
|
||||
u32 texAddr = state.getTextureAddress(0);
|
||||
// TODO: Better interface that allows add/remove or something.
|
||||
if (InputBox_GetHex(GetModuleHandle(NULL), m_hDlg, L"Texture Address", lastTexture, texAddr)) {
|
||||
if (breakTextures.find(texAddr) != breakTextures.end()) {
|
||||
breakTextures.erase(texAddr);
|
||||
if (InputBox_GetHex(GetModuleHandle(NULL), m_hDlg, L"Texture Address", texAddr, texAddr)) {
|
||||
if (IsTextureBreakpoint(texAddr)) {
|
||||
RemoveTextureBreakpoint(texAddr);
|
||||
} else {
|
||||
breakTextures.insert(texAddr);
|
||||
AddTextureBreakpoint(texAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -486,7 +356,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, L"");
|
||||
|
||||
// TODO: detach? Should probably have separate UI, or just on activate?
|
||||
SetPauseAction(PAUSE_CONTINUE, false);
|
||||
ResumeFromStepping();
|
||||
breakNext = BREAK_NONE;
|
||||
break;
|
||||
}
|
||||
@ -495,7 +365,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
case WM_GEDBG_BREAK_CMD:
|
||||
{
|
||||
u32 pc = (u32)wParam;
|
||||
tempBreakpoint = -1;
|
||||
ClearTempBreakpoints();
|
||||
auto info = gpuDebug->DissassembleOp(pc);
|
||||
NOTICE_LOG(COMMON, "Waiting at %08x, %s", pc, info.desc.c_str());
|
||||
UpdatePreviews();
|
||||
@ -515,29 +385,28 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
|
||||
case WM_GEDBG_TOGGLEPCBREAKPOINT:
|
||||
{
|
||||
lock_guard guard(breaksLock);
|
||||
u32 pc = (u32)wParam;
|
||||
auto iter = breakPCs.find(pc);
|
||||
if (iter != breakPCs.end())
|
||||
breakPCs.erase(iter);
|
||||
else
|
||||
breakPCs.insert(pc);
|
||||
bool temp;
|
||||
bool isBreak = IsAddressBreakpoint(pc, temp);
|
||||
if (isBreak && !temp) {
|
||||
RemoveAddressBreakpoint(pc);
|
||||
} else {
|
||||
AddAddressBreakpoint(pc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_GEDBG_RUNTOWPARAM:
|
||||
{
|
||||
lock_guard guard(breaksLock);
|
||||
u32 pc = (u32)wParam;
|
||||
tempBreakpoint = pc;
|
||||
AddAddressBreakpoint(pc, true);
|
||||
SendMessage(m_hDlg,WM_COMMAND,IDC_GEDBG_RESUME,0);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_GEDBG_SETCMDWPARAM:
|
||||
{
|
||||
pauseSetCmdValue = (u32)wParam;
|
||||
SetPauseAction(PAUSE_SETCMDVALUE);
|
||||
GPU_SetCmdValue((u32)wParam);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -551,30 +420,19 @@ bool WindowsHost::GPUDebuggingActive() {
|
||||
return attached;
|
||||
}
|
||||
|
||||
static void PauseWithMessage(UINT msg, WPARAM wParam = NULL, LPARAM lParam = NULL) {
|
||||
lock_guard guard(pauseLock);
|
||||
if (coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME) {
|
||||
return;
|
||||
}
|
||||
|
||||
static void DeliverMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
PostMessage(geDebuggerWindow->GetDlgHandle(), msg, wParam, lParam);
|
||||
}
|
||||
|
||||
// Just to be sure.
|
||||
if (pauseAction == PAUSE_CONTINUE) {
|
||||
pauseAction = PAUSE_BREAK;
|
||||
}
|
||||
|
||||
do {
|
||||
RunPauseAction();
|
||||
pauseWait.wait(pauseLock);
|
||||
} while (pauseAction != PAUSE_CONTINUE);
|
||||
static void PauseWithMessage(UINT msg, WPARAM wParam = NULL, LPARAM lParam = NULL) {
|
||||
EnterStepping(std::bind(&DeliverMessage, msg, wParam, lParam));
|
||||
}
|
||||
|
||||
void WindowsHost::GPUNotifyCommand(u32 pc) {
|
||||
u32 op = Memory::ReadUnchecked_U32(pc);
|
||||
u8 cmd = op >> 24;
|
||||
|
||||
if (breakNext == BREAK_NEXT_OP || CGEDebugger::IsOpOrTextureBreakPoint(op) || CGEDebugger::IsAddressBreakPoint(pc) || pc == tempBreakpoint) {
|
||||
if (breakNext == BREAK_NEXT_OP || IsBreakpoint(pc, op)) {
|
||||
PauseWithMessage(WM_GEDBG_BREAK_CMD, (WPARAM) pc);
|
||||
}
|
||||
}
|
||||
|
@ -56,12 +56,6 @@ 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);
|
||||
|
||||
|
@ -197,6 +197,8 @@ LOCAL_SRC_FILES := \
|
||||
$(SRC)/GPU/Common/VertexDecoderCommon.cpp.arm \
|
||||
$(SRC)/GPU/Common/TextureDecoder.cpp \
|
||||
$(SRC)/GPU/Common/PostShader.cpp \
|
||||
$(SRC)/GPU/Debugger/Breakpoints.cpp \
|
||||
$(SRC)/GPU/Debugger/Stepping.cpp \
|
||||
$(SRC)/GPU/GLES/Framebuffer.cpp \
|
||||
$(SRC)/GPU/GLES/GLES_GPU.cpp.arm \
|
||||
$(SRC)/GPU/GLES/TextureCache.cpp.arm \
|
||||
|
Loading…
x
Reference in New Issue
Block a user