mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-18 03:31:31 +12:00
Merge remote-tracking branch 'upstream/master' into stencil-logicop-clear
This commit is contained in:
commit
03733569e0
6 changed files with 133 additions and 12 deletions
40
.github/workflows/build_http.yml
vendored
Normal file
40
.github/workflows/build_http.yml
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
name: HTTP server build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||||
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
# The CMake configure and build commands are platform agnostic and should work equally
|
||||||
|
# well on Windows or Mac. You can convert this to a matrix build if you need
|
||||||
|
# cross-platform coverage.
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Fetch submodules
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
|
||||||
|
- name: Setup Vulkan SDK
|
||||||
|
uses: humbletim/setup-vulkan-sdk@v1.2.0
|
||||||
|
with:
|
||||||
|
vulkan-query-version: latest
|
||||||
|
vulkan-use-cache: true
|
||||||
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, Glslang
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||||
|
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_USER_BUILD=ON -DENABLE_HTTP_SERVER=ON
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
# Build your program with the given configuration
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
|
|
@ -61,7 +61,7 @@ class Emulator {
|
||||||
|
|
||||||
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
|
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
|
||||||
HttpServer httpServer;
|
HttpServer httpServer;
|
||||||
friend class HttpServer;
|
friend struct HttpServer;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Keep the handle for the ROM here to reload when necessary and to prevent deleting it
|
// Keep the handle for the ROM here to reload when necessary and to prevent deleting it
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <filesystem>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
@ -12,12 +13,12 @@
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
enum class HttpActionType { None, Screenshot, Key, TogglePause, Reset };
|
enum class HttpActionType { None, Screenshot, Key, TogglePause, Reset, LoadRom };
|
||||||
|
|
||||||
class Emulator;
|
class Emulator;
|
||||||
namespace httplib {
|
namespace httplib {
|
||||||
class Server;
|
class Server;
|
||||||
class Response;
|
struct Response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper for httplib::Response that allows the HTTP server to wait for the response to be ready
|
// Wrapper for httplib::Response that allows the HTTP server to wait for the response to be ready
|
||||||
|
@ -41,7 +42,8 @@ class HttpAction {
|
||||||
HttpActionType getType() const { return type; }
|
HttpActionType getType() const { return type; }
|
||||||
|
|
||||||
static std::unique_ptr<HttpAction> createScreenshotAction(DeferredResponseWrapper& response);
|
static std::unique_ptr<HttpAction> createScreenshotAction(DeferredResponseWrapper& response);
|
||||||
static std::unique_ptr<HttpAction> createKeyAction(uint32_t key, bool state);
|
static std::unique_ptr<HttpAction> createKeyAction(u32 key, bool state);
|
||||||
|
static std::unique_ptr<HttpAction> createLoadRomAction(DeferredResponseWrapper& response, const std::filesystem::path& path, bool paused);
|
||||||
static std::unique_ptr<HttpAction> createTogglePauseAction();
|
static std::unique_ptr<HttpAction> createTogglePauseAction();
|
||||||
static std::unique_ptr<HttpAction> createResetAction();
|
static std::unique_ptr<HttpAction> createResetAction();
|
||||||
};
|
};
|
||||||
|
|
|
@ -159,8 +159,9 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn
|
||||||
|
|
||||||
// Read ExeFS
|
// Read ExeFS
|
||||||
if (hasExeFS()) {
|
if (hasExeFS()) {
|
||||||
u64 exeFSOffset = fileOffset + exeFS.offset; // Offset of ExeFS in the file = exeFS offset + ncch offset
|
// Offset of ExeFS in the file = exeFS offset + NCCH offset
|
||||||
printf("ExeFS offset: %08llX, size: %08llX (Offset in file = %08llX)\n", exeFS.offset, exeFS.size, exeFSOffset);
|
// exeFS.offset has already been offset by the NCCH offset
|
||||||
|
printf("ExeFS offset: %08llX, size: %08llX (Offset in file = %08llX)\n", exeFS.offset - info.offset, exeFS.size, exeFS.offset);
|
||||||
constexpr size_t exeFSHeaderSize = 0x200;
|
constexpr size_t exeFSHeaderSize = 0x200;
|
||||||
|
|
||||||
u8 exeFSHeader[exeFSHeaderSize];
|
u8 exeFSHeader[exeFSHeaderSize];
|
||||||
|
|
|
@ -118,6 +118,9 @@ void Emulator::run() {
|
||||||
programRunning = true;
|
programRunning = true;
|
||||||
|
|
||||||
while (programRunning) {
|
while (programRunning) {
|
||||||
|
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
|
||||||
|
httpServer.processActions();
|
||||||
|
#endif
|
||||||
runFrame();
|
runFrame();
|
||||||
HIDService& hid = kernel.getServiceManager().getHID();
|
HIDService& hid = kernel.getServiceManager().getHID();
|
||||||
|
|
||||||
|
@ -367,11 +370,8 @@ void Emulator::togglePause() { running ? pause() : resume(); }
|
||||||
|
|
||||||
void Emulator::runFrame() {
|
void Emulator::runFrame() {
|
||||||
if (running) {
|
if (running) {
|
||||||
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
|
cpu.runFrame(); // Run 1 frame of instructions
|
||||||
httpServer.processActions();
|
gpu.display(); // Display graphics
|
||||||
#endif
|
|
||||||
cpu.runFrame(); // Run 1 frame of instructions
|
|
||||||
gpu.display(); // Display graphics
|
|
||||||
|
|
||||||
// Send VBlank interrupts
|
// Send VBlank interrupts
|
||||||
ServiceManager& srv = kernel.getServiceManager();
|
ServiceManager& srv = kernel.getServiceManager();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <system_error>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -40,6 +41,20 @@ class HttpActionKey : public HttpAction {
|
||||||
bool getState() const { return state; }
|
bool getState() const { return state; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class HttpActionLoadRom : public HttpAction {
|
||||||
|
DeferredResponseWrapper& response;
|
||||||
|
const std::filesystem::path& path;
|
||||||
|
bool paused;
|
||||||
|
|
||||||
|
public:
|
||||||
|
HttpActionLoadRom(DeferredResponseWrapper& response, const std::filesystem::path& path, bool paused)
|
||||||
|
: HttpAction(HttpActionType::LoadRom), response(response), path(path), paused(paused) {}
|
||||||
|
|
||||||
|
DeferredResponseWrapper& getResponse() { return response; }
|
||||||
|
const std::filesystem::path& getPath() const { return path; }
|
||||||
|
bool getPaused() const { return paused; }
|
||||||
|
};
|
||||||
|
|
||||||
std::unique_ptr<HttpAction> HttpAction::createScreenshotAction(DeferredResponseWrapper& response) {
|
std::unique_ptr<HttpAction> HttpAction::createScreenshotAction(DeferredResponseWrapper& response) {
|
||||||
return std::make_unique<HttpActionScreenshot>(response);
|
return std::make_unique<HttpActionScreenshot>(response);
|
||||||
}
|
}
|
||||||
|
@ -48,6 +63,10 @@ std::unique_ptr<HttpAction> HttpAction::createKeyAction(u32 key, bool state) { r
|
||||||
std::unique_ptr<HttpAction> HttpAction::createTogglePauseAction() { return std::make_unique<HttpActionTogglePause>(); }
|
std::unique_ptr<HttpAction> HttpAction::createTogglePauseAction() { return std::make_unique<HttpActionTogglePause>(); }
|
||||||
std::unique_ptr<HttpAction> HttpAction::createResetAction() { return std::make_unique<HttpActionReset>(); }
|
std::unique_ptr<HttpAction> HttpAction::createResetAction() { return std::make_unique<HttpActionReset>(); }
|
||||||
|
|
||||||
|
std::unique_ptr<HttpAction> HttpAction::createLoadRomAction(DeferredResponseWrapper& response, const std::filesystem::path& path, bool paused) {
|
||||||
|
return std::make_unique<HttpActionLoadRom>(response, path, paused);
|
||||||
|
}
|
||||||
|
|
||||||
HttpServer::HttpServer(Emulator* emulator)
|
HttpServer::HttpServer(Emulator* emulator)
|
||||||
: emulator(emulator), server(std::make_unique<httplib::Server>()), keyMap({
|
: emulator(emulator), server(std::make_unique<httplib::Server>()), keyMap({
|
||||||
{"A", {HID::Keys::A}},
|
{"A", {HID::Keys::A}},
|
||||||
|
@ -83,6 +102,7 @@ void HttpServer::startHttpServer() {
|
||||||
server->Get("/ping", [](const httplib::Request&, httplib::Response& response) { response.set_content("pong", "text/plain"); });
|
server->Get("/ping", [](const httplib::Request&, httplib::Response& response) { response.set_content("pong", "text/plain"); });
|
||||||
|
|
||||||
server->Get("/screen", [this](const httplib::Request&, httplib::Response& response) {
|
server->Get("/screen", [this](const httplib::Request&, httplib::Response& response) {
|
||||||
|
// TODO: make the below a DeferredResponseWrapper function
|
||||||
DeferredResponseWrapper wrapper(response);
|
DeferredResponseWrapper wrapper(response);
|
||||||
// Lock the mutex before pushing the action to ensure that the condition variable is not notified before we wait on it
|
// Lock the mutex before pushing the action to ensure that the condition variable is not notified before we wait on it
|
||||||
std::unique_lock lock(wrapper.mutex);
|
std::unique_lock lock(wrapper.mutex);
|
||||||
|
@ -122,6 +142,39 @@ void HttpServer::startHttpServer() {
|
||||||
|
|
||||||
server->Get("/status", [this](const httplib::Request&, httplib::Response& response) { response.set_content(status(), "text/plain"); });
|
server->Get("/status", [this](const httplib::Request&, httplib::Response& response) { response.set_content(status(), "text/plain"); });
|
||||||
|
|
||||||
|
server->Get("/load_rom", [this](const httplib::Request& request, httplib::Response& response) {
|
||||||
|
auto it = request.params.find("path");
|
||||||
|
if (it == request.params.end()) {
|
||||||
|
response.set_content("error", "text/plain");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path romPath = it->second;
|
||||||
|
if (romPath.empty()) {
|
||||||
|
response.set_content("error", "text/plain");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
std::error_code error;
|
||||||
|
if (!std::filesystem::is_regular_file(romPath, error)) {
|
||||||
|
std::string message = "error: " + error.message();
|
||||||
|
response.set_content(message, "text/plain");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool paused = false;
|
||||||
|
it = request.params.find("paused");
|
||||||
|
if (it != request.params.end()) {
|
||||||
|
paused = (it->second == "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
DeferredResponseWrapper wrapper(response);
|
||||||
|
std::unique_lock lock(wrapper.mutex);
|
||||||
|
pushAction(HttpAction::createLoadRomAction(wrapper, romPath, paused));
|
||||||
|
response.set_content("ok", "text/plain");
|
||||||
|
wrapper.cv.wait(lock, [&wrapper] { return wrapper.ready; });
|
||||||
|
});
|
||||||
|
|
||||||
server->Get("/togglepause", [this](const httplib::Request&, httplib::Response& response) {
|
server->Get("/togglepause", [this](const httplib::Request&, httplib::Response& response) {
|
||||||
pushAction(HttpAction::createTogglePauseAction());
|
pushAction(HttpAction::createTogglePauseAction());
|
||||||
response.set_content("ok", "text/plain");
|
response.set_content("ok", "text/plain");
|
||||||
|
@ -187,7 +240,32 @@ void HttpServer::processActions() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case HttpActionType::TogglePause: emulator->togglePause(); break;
|
case HttpActionType::LoadRom: {
|
||||||
|
HttpActionLoadRom* loadRomAction = static_cast<HttpActionLoadRom*>(action.get());
|
||||||
|
DeferredResponseWrapper& response = loadRomAction->getResponse();
|
||||||
|
bool loaded = emulator->loadROM(loadRomAction->getPath());
|
||||||
|
|
||||||
|
response.inner_response.set_content(loaded ? "ok" : "error", "text/plain");
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(response.mutex);
|
||||||
|
response.ready = true;
|
||||||
|
response.cv.notify_one();
|
||||||
|
|
||||||
|
if (loaded) {
|
||||||
|
paused = loadRomAction->getPaused();
|
||||||
|
if (paused) {
|
||||||
|
emulator->pause();
|
||||||
|
} else {
|
||||||
|
emulator->resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case HttpActionType::TogglePause:
|
||||||
|
emulator->togglePause();
|
||||||
|
paused = !paused;
|
||||||
|
break;
|
||||||
case HttpActionType::Reset: emulator->reset(Emulator::ReloadOption::Reload); break;
|
case HttpActionType::Reset: emulator->reset(Emulator::ReloadOption::Reload); break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue