Move GPU debug step/pause/messages out of Windows/.

This commit is contained in:
Unknown W. Brackets 2013-10-12 10:02:21 -07:00
parent 72a2ff83ba
commit dc91bf2ca3
7 changed files with 262 additions and 121 deletions

View File

@ -1006,6 +1006,8 @@ add_library(GPU OBJECT
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

184
GPU/Debugger/Stepping.cpp Normal file
View 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
View 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();
};

View File

@ -161,6 +161,7 @@
<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" />
@ -205,6 +206,7 @@
<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" />

View File

@ -154,6 +154,9 @@
<ClInclude Include="Debugger\Breakpoints.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\Stepping.h">
<Filter>Debugger</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
@ -277,6 +280,9 @@
<ClCompile Include="Debugger\Breakpoints.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\Stepping.cpp">
<Filter>Debugger</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -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"
@ -33,115 +34,31 @@
#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>
using namespace GPUBreakpoints;
enum PauseAction {
PAUSE_CONTINUE,
PAUSE_BREAK,
PAUSE_GETFRAMEBUF,
PAUSE_GETDEPTHBUF,
PAUSE_GETSTENCILBUF,
PAUSE_GETTEX,
PAUSE_SETCMDVALUE,
};
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 BreakNextType breakNext = BREAK_NONE;
static bool bufferResult;
static GPUDebugBuffer bufferFrame;
static GPUDebugBuffer bufferDepth;
static GPUDebugBuffer bufferStencil;
static GPUDebugBuffer bufferTex;
static u32 pauseSetCmdValue;
enum PrimaryDisplayType {
PRIMARY_FRAMEBUF,
PRIMARY_DEPTHBUF,
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();
}
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) {
GPUBreakpoints::Init();
@ -227,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();
@ -237,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;
}
@ -264,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()) {
@ -336,7 +256,7 @@ void CGEDebugger::SetBreakNext(BreakNextType type) {
attached = true;
SetupPreviews();
SetPauseAction(PAUSE_CONTINUE, false);
ResumeFromStepping();
breakNext = type;
}
@ -436,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;
}
@ -486,8 +406,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
case WM_GEDBG_SETCMDWPARAM:
{
pauseSetCmdValue = (u32)wParam;
SetPauseAction(PAUSE_SETCMDVALUE);
GPU_SetCmdValue((u32)wParam);
}
break;
}
@ -501,23 +420,12 @@ 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) {

View File

@ -198,6 +198,7 @@ LOCAL_SRC_FILES := \
$(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 \