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/Core/Debugger/WebSocket/GPURecordSubscriber.cpp
Views: 1401
// Copyright (c) 2018- 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 "Common/Data/Encoding/Base64.h"18#include "Common/File/FileUtil.h"19#include "Core/Debugger/WebSocket/GPURecordSubscriber.h"20#include "Core/Debugger/WebSocket/WebSocketUtils.h"21#include "Core/System.h"22#include "GPU/Debugger/Record.h"2324struct WebSocketGPURecordState : public DebuggerSubscriber {25~WebSocketGPURecordState();26void Dump(DebuggerRequest &req);2728void Broadcast(net::WebSocketServer *ws) override;2930protected:31bool pending_ = false;32std::string lastTicket_;33Path lastFilename_;34};3536DebuggerSubscriber *WebSocketGPURecordInit(DebuggerEventHandlerMap &map) {37auto p = new WebSocketGPURecordState();38map["gpu.record.dump"] = std::bind(&WebSocketGPURecordState::Dump, p, std::placeholders::_1);3940return p;41}4243WebSocketGPURecordState::~WebSocketGPURecordState() {44// Clear the callback to hopefully avoid a crash.45if (pending_)46GPURecord::ClearCallback();47}4849// Begin recording (gpu.record.dump)50//51// No parameters.52//53// Response (same event name):54// - uri: data: URI containing debug dump data.55//56// Note: recording may take a moment.57void WebSocketGPURecordState::Dump(DebuggerRequest &req) {58if (!PSP_IsInited()) {59return req.Fail("CPU not started");60}6162bool result = GPURecord::RecordNextFrame([=](const Path &filename) {63lastFilename_ = filename;64pending_ = false;65});6667if (!result) {68return req.Fail("Recording already in progress");69}7071pending_ = true;7273const JsonNode *value = req.data.get("ticket");74lastTicket_ = value ? json_stringify(value) : "";75}7677// This handles the asynchronous gpu.record.dump response.78void WebSocketGPURecordState::Broadcast(net::WebSocketServer *ws) {79if (!lastFilename_.empty()) {80FILE *fp = File::OpenCFile(lastFilename_, "rb");81if (!fp) {82lastFilename_.clear();83return;84}8586// We write directly to the stream since this is a large chunk of data.87ws->AddFragment(false, R"({"event":"gpu.record.dump")");88if (!lastTicket_.empty()) {89ws->AddFragment(false, R"(,"ticket":)");90ws->AddFragment(false, lastTicket_);91}92ws->AddFragment(false, R"(,"uri":"data:application/octet-stream;base64,)");9394// Divisible by 3 for base64 reasons.95const size_t BUF_SIZE = 16383;96std::vector<uint8_t> buf;97buf.resize(BUF_SIZE);98while (!feof(fp)) {99size_t bytes = fread(&buf[0], 1, BUF_SIZE, fp);100ws->AddFragment(false, Base64Encode(&buf[0], bytes));101}102fclose(fp);103104ws->AddFragment(true, R"("})");105106lastFilename_.clear();107lastTicket_.clear();108}109}110111112