CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/GPU/Debugger/Stepping.cpp
Views: 1401
// Copyright (c) 2013- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <mutex>18#include <condition_variable>1920#include "Common/Log.h"21#include "Core/Core.h"22#include "GPU/Common/GPUDebugInterface.h"23#include "GPU/Debugger/Stepping.h"24#include "GPU/GPUState.h"2526namespace GPUStepping {2728enum PauseAction {29PAUSE_CONTINUE,30PAUSE_BREAK,31PAUSE_GETOUTPUTBUF,32PAUSE_GETFRAMEBUF,33PAUSE_GETDEPTHBUF,34PAUSE_GETSTENCILBUF,35PAUSE_GETTEX,36PAUSE_GETCLUT,37PAUSE_SETCMDVALUE,38PAUSE_FLUSHDRAW,39};4041static bool isStepping;42// Number of times we've entered stepping, to detect a resume asynchronously.43static int stepCounter = 0;4445static std::mutex pauseLock;46static std::condition_variable pauseWait;47static PauseAction pauseAction = PAUSE_CONTINUE;48static std::mutex actionLock;49static std::condition_variable actionWait;50// In case of accidental wakeup.51static volatile bool actionComplete;5253// Many things need to run on the GPU thread. For example, reading the framebuffer.54// A message system is used to achieve this (temporarily "unpausing" the thread.)55// Below are values used to perform actions that return results.5657static bool bufferResult;58static GPUDebugFramebufferType bufferType = GPU_DBG_FRAMEBUF_RENDER;59static GPUDebugBuffer bufferFrame;60static GPUDebugBuffer bufferDepth;61static GPUDebugBuffer bufferStencil;62static GPUDebugBuffer bufferTex;63static GPUDebugBuffer bufferClut;64static int bufferLevel;65static bool lastWasFramebuffer;66static u32 pauseSetCmdValue;6768static GPUgstate lastGState;6970static void SetPauseAction(PauseAction act, bool waitComplete = true) {71pauseLock.lock();72std::unique_lock<std::mutex> guard(actionLock);73pauseAction = act;74pauseLock.unlock();7576if (coreState == CORE_STEPPING && act != PAUSE_CONTINUE)77Core_UpdateSingleStep();7879actionComplete = false;80pauseWait.notify_all();81while (waitComplete && !actionComplete) {82actionWait.wait(guard);83}84}8586static void RunPauseAction() {87std::lock_guard<std::mutex> guard(actionLock);8889switch (pauseAction) {90case PAUSE_CONTINUE:91// Don't notify, just go back, woke up by accident.92return;9394case PAUSE_BREAK:95break;9697case PAUSE_GETOUTPUTBUF:98bufferResult = gpuDebug->GetOutputFramebuffer(bufferFrame);99break;100101case PAUSE_GETFRAMEBUF:102bufferResult = gpuDebug->GetCurrentFramebuffer(bufferFrame, bufferType);103break;104105case PAUSE_GETDEPTHBUF:106bufferResult = gpuDebug->GetCurrentDepthbuffer(bufferDepth);107break;108109case PAUSE_GETSTENCILBUF:110bufferResult = gpuDebug->GetCurrentStencilbuffer(bufferStencil);111break;112113case PAUSE_GETTEX:114bufferResult = gpuDebug->GetCurrentTexture(bufferTex, bufferLevel, &lastWasFramebuffer);115break;116117case PAUSE_GETCLUT:118bufferResult = gpuDebug->GetCurrentClut(bufferClut);119break;120121case PAUSE_SETCMDVALUE:122gpuDebug->SetCmdValue(pauseSetCmdValue);123break;124125case PAUSE_FLUSHDRAW:126gpuDebug->DispatchFlush();127break;128129default:130ERROR_LOG(Log::G3D, "Unsupported pause action, forgot to add it to the switch.");131}132133actionComplete = true;134actionWait.notify_all();135pauseAction = PAUSE_BREAK;136}137138static void StartStepping() {139if (lastGState.cmdmem[1] == 0) {140lastGState = gstate;141// Play it safe so we don't keep resetting.142lastGState.cmdmem[1] |= 0x01000000;143}144gpuDebug->NotifySteppingEnter();145isStepping = true;146}147148static void StopStepping() {149gpuDebug->NotifySteppingExit();150lastGState = gstate;151isStepping = false;152}153154bool SingleStep() {155std::unique_lock<std::mutex> guard(pauseLock);156if (coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME && coreState != CORE_STEPPING) {157// Shutting down, don't try to step.158actionComplete = true;159actionWait.notify_all();160return false;161}162if (!gpuDebug || pauseAction == PAUSE_CONTINUE) {163actionComplete = true;164actionWait.notify_all();165return false;166}167168StartStepping();169RunPauseAction();170StopStepping();171return true;172}173174bool EnterStepping() {175std::unique_lock<std::mutex> guard(pauseLock);176if (coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME && coreState != CORE_STEPPING) {177// Shutting down, don't try to step.178actionComplete = true;179actionWait.notify_all();180return false;181}182if (!gpuDebug) {183actionComplete = true;184actionWait.notify_all();185return false;186}187188StartStepping();189190// Just to be sure.191if (pauseAction == PAUSE_CONTINUE) {192pauseAction = PAUSE_BREAK;193}194stepCounter++;195196do {197RunPauseAction();198pauseWait.wait(guard);199} while (pauseAction != PAUSE_CONTINUE);200201StopStepping();202return true;203}204205bool IsStepping() {206return isStepping;207}208209int GetSteppingCounter() {210return stepCounter;211}212213static bool GetBuffer(const GPUDebugBuffer *&buffer, PauseAction type, const GPUDebugBuffer &resultBuffer) {214if (!isStepping && coreState != CORE_STEPPING) {215return false;216}217218SetPauseAction(type);219buffer = &resultBuffer;220return bufferResult;221}222223bool GPU_GetOutputFramebuffer(const GPUDebugBuffer *&buffer) {224return GetBuffer(buffer, PAUSE_GETOUTPUTBUF, bufferFrame);225}226227bool GPU_GetCurrentFramebuffer(const GPUDebugBuffer *&buffer, GPUDebugFramebufferType type) {228bufferType = type;229return GetBuffer(buffer, PAUSE_GETFRAMEBUF, bufferFrame);230}231232bool GPU_GetCurrentDepthbuffer(const GPUDebugBuffer *&buffer) {233return GetBuffer(buffer, PAUSE_GETDEPTHBUF, bufferDepth);234}235236bool GPU_GetCurrentStencilbuffer(const GPUDebugBuffer *&buffer) {237return GetBuffer(buffer, PAUSE_GETSTENCILBUF, bufferStencil);238}239240bool GPU_GetCurrentTexture(const GPUDebugBuffer *&buffer, int level, bool *isFramebuffer) {241bufferLevel = level;242bool result = GetBuffer(buffer, PAUSE_GETTEX, bufferTex);243*isFramebuffer = lastWasFramebuffer;244return result;245}246247bool GPU_GetCurrentClut(const GPUDebugBuffer *&buffer) {248return GetBuffer(buffer, PAUSE_GETCLUT, bufferClut);249}250251bool GPU_SetCmdValue(u32 op) {252if (!isStepping && coreState != CORE_STEPPING) {253return false;254}255256pauseSetCmdValue = op;257SetPauseAction(PAUSE_SETCMDVALUE);258return true;259}260261bool GPU_FlushDrawing() {262if (!isStepping && coreState != CORE_STEPPING) {263return false;264}265266SetPauseAction(PAUSE_FLUSHDRAW);267return true;268}269270void ResumeFromStepping() {271SetPauseAction(PAUSE_CONTINUE, false);272}273274void ForceUnpause() {275SetPauseAction(PAUSE_CONTINUE, false);276actionComplete = true;277actionWait.notify_all();278}279280GPUgstate LastState() {281return lastGState;282}283284} // namespace285286287