Permalink
Browse files

Debugger: Add an event for GE dump recording.

  • Loading branch information...
unknownbrackets committed Sep 1, 2018
1 parent 4ce2b64 commit 653129c52891830d65b151954ca525c5266da443
View
@@ -1432,6 +1432,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/Debugger/WebSocket/GameSubscriber.h
Core/Debugger/WebSocket/GPUBufferSubscriber.cpp
Core/Debugger/WebSocket/GPUBufferSubscriber.h
Core/Debugger/WebSocket/GPURecordSubscriber.cpp
Core/Debugger/WebSocket/GPURecordSubscriber.h
Core/Debugger/WebSocket/HLESubscriber.cpp
Core/Debugger/WebSocket/HLESubscriber.h
Core/Debugger/WebSocket/LogBroadcaster.cpp
View
@@ -188,6 +188,7 @@
<ClCompile Include="Debugger\WebSocket\GameBroadcaster.cpp" />
<ClCompile Include="Debugger\WebSocket\GameSubscriber.cpp" />
<ClCompile Include="Debugger\WebSocket\GPUBufferSubscriber.cpp" />
<ClCompile Include="Debugger\WebSocket\GPURecordSubscriber.cpp" />
<ClCompile Include="Debugger\WebSocket\HLESubscriber.cpp" />
<ClCompile Include="Debugger\WebSocket\LogBroadcaster.cpp" />
<ClCompile Include="Debugger\WebSocket\DisasmSubscriber.cpp" />
@@ -549,6 +550,7 @@
<ClInclude Include="Debugger\WebSocket\GameSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\DisasmSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\GPUBufferSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\GPURecordSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\HLESubscriber.h" />
<ClInclude Include="Debugger\WebSocket\SteppingSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\WebSocketUtils.h" />
@@ -734,6 +734,9 @@
<ClCompile Include="HLE\sceUsbAcc.cpp">
<Filter>HLE\Libraries</Filter>
</ClCompile>
<ClCompile Include="Debugger\WebSocket\GPURecordSubscriber.cpp">
<Filter>Debugger\WebSocket</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@@ -1361,6 +1364,9 @@
<ClInclude Include="HLE\sceUsbAcc.h">
<Filter>HLE\Libraries</Filter>
</ClInclude>
<ClInclude Include="Debugger\WebSocket\GPURecordSubscriber.h">
<Filter>Debugger\WebSocket</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
@@ -53,6 +53,7 @@
#include "Core/Debugger/WebSocket/DisasmSubscriber.h"
#include "Core/Debugger/WebSocket/GameSubscriber.h"
#include "Core/Debugger/WebSocket/GPUBufferSubscriber.h"
#include "Core/Debugger/WebSocket/GPURecordSubscriber.h"
#include "Core/Debugger/WebSocket/HLESubscriber.h"
#include "Core/Debugger/WebSocket/SteppingSubscriber.h"
@@ -63,6 +64,7 @@ static const std::vector<SubscriberInit> subscribers({
&WebSocketDisasmInit,
&WebSocketGameInit,
&WebSocketGPUBufferInit,
&WebSocketGPURecordInit,
&WebSocketHLEInit,
&WebSocketSteppingInit,
});
@@ -0,0 +1,107 @@
// Copyright (c) 2018- 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 "data/base64.h"
#include "Common/FileUtil.h"
#include "Core/Debugger/WebSocket/GPURecordSubscriber.h"
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
#include "Core/System.h"
#include "GPU/Debugger/Record.h"
struct WebSocketGPURecordState : public DebuggerSubscriber {
~WebSocketGPURecordState() override;
void Dump(DebuggerRequest &req);
void Broadcast(net::WebSocketServer *ws) override;
protected:
bool pending_ = false;
std::string lastTicket_;
std::string lastFilename_;
};
DebuggerSubscriber *WebSocketGPURecordInit(DebuggerEventHandlerMap &map) {
auto p = new WebSocketGPURecordState();
map["gpu.record.dump"] = std::bind(&WebSocketGPURecordState::Dump, p, std::placeholders::_1);
return p;
}
WebSocketGPURecordState::~WebSocketGPURecordState() {
// Clear the callback to hopefully avoid a crash.
if (pending_)
GPURecord::SetCallback(nullptr);
}
// Begin recording (gpu.record.dump)
//
// No parameters.
//
// Response (same event name):
// - uri: data: URI containing debug dump data.
//
// Note: recording may take a moment.
void WebSocketGPURecordState::Dump(DebuggerRequest &req) {
if (!PSP_IsInited())
return req.Fail("CPU not started");
if (!GPURecord::Activate())
return req.Fail("Recording already in progress");
pending_ = true;
GPURecord::SetCallback([=](const std::string &filename) {
lastFilename_ = filename;
pending_ = false;
});
const JsonNode *value = req.data.get("ticket");
lastTicket_ = value ? json_stringify(value) : "";
}
// This handles the asynchronous gpu.record.dump response.
void WebSocketGPURecordState::Broadcast(net::WebSocketServer *ws) {
if (!lastFilename_.empty()) {
FILE *fp = File::OpenCFile(lastFilename_, "rb");
if (!fp) {
lastFilename_.clear();
return;
}
// We write directly to the stream since this is a large chunk of data.
ws->AddFragment(false, R"({"event":"gpu.record.dump")");
if (!lastTicket_.empty()) {
ws->AddFragment(false, R"(,"ticket":)");
ws->AddFragment(false, lastTicket_);
}
ws->AddFragment(false, R"(,"uri":"data:application/octet-stream;base64,)");
// Divisible by 3 for base64 reasons.
const size_t BUF_SIZE = 16383;
std::vector<uint8_t> buf;
buf.resize(BUF_SIZE);
while (!feof(fp)) {
size_t bytes = fread(&buf[0], 1, BUF_SIZE, fp);
ws->AddFragment(false, Base64Encode(&buf[0], bytes));
}
fclose(fp);
ws->AddFragment(true, R"("})");
lastFilename_.clear();
lastTicket_.clear();
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2018- 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 "Core/Debugger/WebSocket/WebSocketUtils.h"
DebuggerSubscriber *WebSocketGPURecordInit(DebuggerEventHandlerMap &map);
View
@@ -48,6 +48,7 @@ static const int VERSION = 2;
static bool active = false;
static bool nextFrame = false;
static bool writePending = false;
static std::function<void(const std::string &)> writeCallback;
enum class CommandType : u8 {
INIT = 0,
@@ -409,7 +410,7 @@ static void WriteCompressed(FILE *fp, const void *p, size_t sz) {
delete [] compressed;
}
static void WriteRecording() {
static std::string WriteRecording() {
FlushRegisters();
EmitDisplayBuf();
@@ -430,6 +431,8 @@ static void WriteRecording() {
WriteCompressed(fp, pushbuf.data(), bufsz);
fclose(fp);
return filename;
}
static void GetVertDataSizes(int vcount, const void *indices, u32 &vbytes, u32 &ibytes) {
@@ -641,23 +644,39 @@ bool IsActivePending() {
return nextFrame || active;
}
void Activate() {
nextFrame = true;
bool Activate() {
if (!nextFrame) {
nextFrame = true;
return true;
}
return false;
}
void SetCallback(const std::function<void(const std::string &)> callback) {
writeCallback = callback;
}
static void FinishRecording() {
// We're done - this was just to write the result out.
std::string filename = WriteRecording();
commands.clear();
pushbuf.clear();
NOTICE_LOG(SYSTEM, "Recording finished");
writePending = false;
active = false;
if (writeCallback)
writeCallback(filename);
writeCallback = nullptr;
}
void NotifyCommand(u32 pc) {
if (!active) {
return;
}
if (writePending) {
WriteRecording();
commands.clear();
pushbuf.clear();
writePending = false;
// We're done - this was just to write the result out.
NOTICE_LOG(SYSTEM, "Recording finished");
active = false;
FinishRecording();
return;
}
View
@@ -17,14 +17,17 @@
#pragma once
#include <functional>
#include <string>
#include "Common/CommonTypes.h"
namespace GPURecord {
bool IsActive();
bool IsActivePending();
void Activate();
bool Activate();
// Call only if Activate() returns true.
void SetCallback(const std::function<void(const std::string &)> callback);
void NotifyCommand(u32 pc);
void NotifyMemcpy(u32 dest, u32 src, u32 sz);
View
@@ -310,6 +310,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/Debugger/WebSocket/GameBroadcaster.cpp \
$(SRC)/Core/Debugger/WebSocket/GameSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/GPUBufferSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/GPURecordSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/HLESubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/LogBroadcaster.cpp \
$(SRC)/Core/Debugger/WebSocket/SteppingBroadcaster.cpp \

0 comments on commit 653129c

Please sign in to comment.