Merge remote-tracking branch 'upstream/master' into stencil-logicop-clear

This commit is contained in:
wheremyfoodat 2023-07-27 14:23:00 +03:00
commit 03733569e0
6 changed files with 133 additions and 12 deletions

40
.github/workflows/build_http.yml vendored Normal file
View 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}}

View file

@ -61,7 +61,7 @@ class Emulator {
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
HttpServer httpServer;
friend class HttpServer;
friend struct HttpServer;
#endif
// Keep the handle for the ROM here to reload when necessary and to prevent deleting it

View file

@ -4,6 +4,7 @@
#include <array>
#include <atomic>
#include <condition_variable>
#include <filesystem>
#include <map>
#include <memory>
#include <mutex>
@ -12,12 +13,12 @@
#include "helpers.hpp"
enum class HttpActionType { None, Screenshot, Key, TogglePause, Reset };
enum class HttpActionType { None, Screenshot, Key, TogglePause, Reset, LoadRom };
class Emulator;
namespace httplib {
class Server;
class Response;
struct Response;
}
// 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; }
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> createResetAction();
};

View file

@ -159,8 +159,9 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn
// Read ExeFS
if (hasExeFS()) {
u64 exeFSOffset = fileOffset + exeFS.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);
// Offset of ExeFS in the file = exeFS offset + NCCH offset
// 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;
u8 exeFSHeader[exeFSHeaderSize];

View file

@ -118,6 +118,9 @@ void Emulator::run() {
programRunning = true;
while (programRunning) {
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
httpServer.processActions();
#endif
runFrame();
HIDService& hid = kernel.getServiceManager().getHID();
@ -367,11 +370,8 @@ void Emulator::togglePause() { running ? pause() : resume(); }
void Emulator::runFrame() {
if (running) {
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
httpServer.processActions();
#endif
cpu.runFrame(); // Run 1 frame of instructions
gpu.display(); // Display graphics
cpu.runFrame(); // Run 1 frame of instructions
gpu.display(); // Display graphics
// Send VBlank interrupts
ServiceManager& srv = kernel.getServiceManager();

View file

@ -4,6 +4,7 @@
#include <fstream>
#include <sstream>
#include <string>
#include <system_error>
#include <thread>
#include <vector>
@ -40,6 +41,20 @@ class HttpActionKey : public HttpAction {
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) {
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::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)
: emulator(emulator), server(std::make_unique<httplib::Server>()), keyMap({
{"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("/screen", [this](const httplib::Request&, httplib::Response& response) {
// TODO: make the below a DeferredResponseWrapper function
DeferredResponseWrapper wrapper(response);
// 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);
@ -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("/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) {
pushAction(HttpAction::createTogglePauseAction());
response.set_content("ok", "text/plain");
@ -187,7 +240,32 @@ void HttpServer::processActions() {
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;
default: break;