Refactor so parallel-rdp is in charge of polling inputs and not the EmuThread

This commit is contained in:
SimoneN64
2024-09-25 22:09:44 +02:00
parent 56b9d69861
commit 2744de8d3e
14 changed files with 174 additions and 151 deletions

View File

@@ -2,6 +2,7 @@
#include <ParallelRDPWrapper.hpp> #include <ParallelRDPWrapper.hpp>
#include <memory> #include <memory>
#include <rdp_device.hpp> #include <rdp_device.hpp>
#include <core/mmio/VI.hpp>
using namespace Vulkan; using namespace Vulkan;
using namespace RDP; using namespace RDP;

View File

@@ -1,8 +1,11 @@
#pragma once #pragma once
#include <backend/Core.hpp>
#include <rdp_device.hpp> #include <rdp_device.hpp>
#include <wsi.hpp> #include <wsi.hpp>
#include <SDL3/SDL.h> #include <common.hpp>
namespace n64 {
struct VI;
}
class ParallelRDP { class ParallelRDP {
public: public:

View File

@@ -3,7 +3,7 @@
#include <Scheduler.hpp> #include <Scheduler.hpp>
namespace n64 { namespace n64 {
Core::Core(ParallelRDP &parallel) : cpu(std::make_unique<Interpreter>(parallel)) {} Core::Core() : cpu(std::make_unique<Interpreter>(parallel)) {}
void Core::Stop() { void Core::Stop() {
render = false; render = false;
@@ -106,15 +106,15 @@ void Core::Serialize() {
} }
void Core::Deserialize() { void Core::Deserialize() {
std::vector<u8> dVER(serialized[slot].begin(), serialized[slot].begin() + verSize); std::vector dVER(serialized[slot].begin(), serialized[slot].begin() + verSize);
if (dVER[0] != (KAIZEN_VERSION >> 8) || dVER[1] != (KAIZEN_VERSION >> 4) || dVER[2] != (KAIZEN_VERSION & 0xFF)) { if (dVER[0] != (KAIZEN_VERSION >> 8) || dVER[1] != (KAIZEN_VERSION >> 4) || dVER[2] != (KAIZEN_VERSION & 0xFF)) {
Util::panic("PROBLEMI!"); Util::panic("PROBLEMI!");
} }
cpu->GetMem().Deserialize( cpu->GetMem().Deserialize(
std::vector<u8>(serialized[slot].begin() + verSize, serialized[slot].begin() + verSize + memSize)); std::vector(serialized[slot].begin() + verSize, serialized[slot].begin() + verSize + memSize));
cpu->Deserialize(std::vector<u8>(serialized[slot].begin() + verSize + memSize, cpu->Deserialize(
serialized[slot].begin() + verSize + memSize + cpuSize)); std::vector(serialized[slot].begin() + verSize + memSize, serialized[slot].begin() + verSize + memSize + cpuSize));
serialized[slot].erase(serialized[slot].begin(), serialized[slot].end()); serialized[slot].erase(serialized[slot].begin(), serialized[slot].end());
} }
} // namespace n64 } // namespace n64

View File

@@ -1,14 +1,12 @@
#pragma once #pragma once
#include <ParallelRDPWrapper.hpp>
#include <backend/core/Interpreter.hpp> #include <backend/core/Interpreter.hpp>
#include <backend/core/JIT.hpp> #include <backend/core/JIT.hpp>
#include <string> #include <string>
struct Window;
struct Event;
namespace n64 { namespace n64 {
struct Core { struct Core {
explicit Core(ParallelRDP &); explicit Core();
void Stop(); void Stop();
void LoadROM(const std::string &); void LoadROM(const std::string &);
[[nodiscard]] bool LoadTAS(const fs::path &) const; [[nodiscard]] bool LoadTAS(const fs::path &) const;
@@ -29,5 +27,6 @@ struct Core {
std::vector<u8> serialized[10]{}; std::vector<u8> serialized[10]{};
size_t memSize{}, cpuSize{}, verSize{}; size_t memSize{}, cpuSize{}, verSize{};
int slot = 0; int slot = 0;
ParallelRDP parallel;
}; };
} // namespace n64 } // namespace n64

View File

@@ -2,7 +2,6 @@
#include <capstone/capstone.h> #include <capstone/capstone.h>
#include <utils/log.hpp> #include <utils/log.hpp>
#include <utils/MemoryHelpers.hpp> #include <utils/MemoryHelpers.hpp>
#include <portable_endian_bswap.h>
#include <array> #include <array>
struct Disassembler { struct Disassembler {
@@ -19,7 +18,7 @@ struct Disassembler {
return ret; return ret;
} }
DisassemblyResult Disassemble(u32 address, u32 instruction) { DisassemblyResult Disassemble(const u32 address, const u32 instruction) {
return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction); return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction);
} }
@@ -29,7 +28,7 @@ private:
DisassemblyResult DisassembleDetailed(u32 address, u32 instruction); DisassemblyResult DisassembleDetailed(u32 address, u32 instruction);
DisassemblyResult DisassembleSimple(u32 address, u32 instruction); DisassemblyResult DisassembleSimple(u32 address, u32 instruction);
Disassembler(bool rsp) : rsp(rsp) { explicit Disassembler(const bool rsp) : rsp(rsp) {
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN), &handle) != if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN), &handle) !=
CS_ERR_OK) { CS_ERR_OK) {
Util::panic("Could not initialize {} disassembler!", rsp ? "RSP" : "CPU"); Util::panic("Could not initialize {} disassembler!", rsp ? "RSP" : "CPU");
@@ -43,5 +42,5 @@ private:
bool rsp = false; bool rsp = false;
bool details = true; bool details = true;
csh handle; csh handle{};
}; };

View File

@@ -2,6 +2,7 @@
#include <core/RSP.hpp> #include <core/RSP.hpp>
#include <log.hpp> #include <log.hpp>
#include <parallel-rdp/ParallelRDPWrapper.hpp> #include <parallel-rdp/ParallelRDPWrapper.hpp>
#include <core/Mem.hpp>
namespace n64 { namespace n64 {
RDP::RDP(Mem &mem, ParallelRDP &parallel) : mem(mem), parallel(parallel) { RDP::RDP(Mem &mem, ParallelRDP &parallel) : mem(mem), parallel(parallel) {

View File

@@ -1,102 +1,53 @@
#include <Core.hpp>
#include <EmuThread.hpp> #include <EmuThread.hpp>
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
EmuThread::EmuThread(RenderWidget &renderWidget, SettingsWindow &settings) noexcept : EmuThread::EmuThread(const std::shared_ptr<n64::Core> &core, RenderWidget &renderWidget,
renderWidget(renderWidget), core(parallel), settings(settings) {} SettingsWindow &settings) noexcept : renderWidget(renderWidget), core(core), settings(settings) {}
[[noreturn]] void EmuThread::run() noexcept { [[noreturn]] void EmuThread::run() noexcept {
parallel.Init(renderWidget.qtVkInstanceFactory, renderWidget.wsiPlatform, renderWidget.windowInfo, core->parallel.Init(renderWidget.qtVkInstanceFactory, renderWidget.wsiPlatform, renderWidget.windowInfo,
core.cpu->GetMem().GetRDRAMPtr()); core->cpu->GetMem().GetRDRAMPtr());
SDL_InitSubSystem(SDL_INIT_GAMEPAD); SDL_InitSubSystem(SDL_INIT_GAMEPAD);
bool controllerConnected = false;
if (SDL_AddGamepadMappingsFromFile("resources/gamecontrollerdb.txt") < 0) { if (SDL_AddGamepadMappingsFromFile("resources/gamecontrollerdb.txt") < 0) {
Util::warn("[SDL] Could not load game controller DB"); Util::warn("[SDL] Could not load game controller DB");
} }
auto pollEvents = [&] {
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_EVENT_GAMEPAD_ADDED:
{
const int index = e.gdevice.which;
controller = SDL_OpenGamepad(index);
Util::info("Found controller!");
auto serial = SDL_GetGamepadSerial(controller);
auto name = SDL_GetGamepadName(controller);
auto path = SDL_GetGamepadPath(controller);
Util::info("\tName: {}", name ? name : "Not available");
Util::info("\tSerial: {}", serial ? serial : "Not available");
Util::info("\tPath: {}", path ? path : "Not available");
controllerConnected = true;
}
break;
case SDL_EVENT_GAMEPAD_REMOVED:
{
controllerConnected = false;
SDL_CloseGamepad(controller);
}
break;
}
}
};
while (!isInterruptionRequested()) { while (!isInterruptionRequested()) {
if (!core.pause) { if (!core->pause) {
core.Run(settings.getVolumeL(), settings.getVolumeR()); core->Run(settings.getVolumeL(), settings.getVolumeR());
} }
if (core.render) { if (core->render) {
parallel.UpdateScreen(core.cpu->GetMem().mmio.vi); core->parallel.UpdateScreen(core->cpu->GetMem().mmio.vi);
}
pollEvents();
if (controllerConnected) {
n64::PIF &pif = core.cpu->GetMem().mmio.si.pif;
pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_SOUTH));
pif.UpdateButton(0, n64::Controller::Key::B, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_WEST));
pif.UpdateButton(0, n64::Controller::Key::Z,
SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX);
pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_START));
pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_UP));
pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_DOWN));
pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_LEFT));
pif.UpdateButton(0, n64::Controller::Key::DRight,
SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_DPAD_RIGHT));
pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER));
pif.UpdateButton(0, n64::Controller::Key::RT,
SDL_GetGamepadButton(controller, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER));
pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTY) <= -127);
pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTY) >= 127);
pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTX) <= -127);
pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTX) >= 127);
float xclamped = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTX);
if (xclamped < 0) {
xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MAX));
} else {
xclamped /= SDL_JOYSTICK_AXIS_MAX;
}
xclamped *= 86;
float yclamped = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTY);
if (yclamped < 0) {
yclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN));
} else {
yclamped /= SDL_JOYSTICK_AXIS_MAX;
}
yclamped *= 86;
pif.UpdateAxis(0, n64::Controller::Axis::Y, -yclamped);
pif.UpdateAxis(0, n64::Controller::Axis::X, xclamped);
} }
} }
SetRender(false); SetRender(false);
Stop(); Stop();
} }
void EmuThread::TogglePause() const noexcept {
core->TogglePause();
Util::RPC::GetInstance().Update(core->pause ? Util::RPC::Paused : Util::RPC::GetInstance().GetState(),
core->cpu->GetMem().rom.gameNameDB,
core->cpu->GetMem().mmio.si.pif.movie.GetFilename());
}
void EmuThread::SetRender(bool v) const noexcept { core->render = v; }
void EmuThread::Reset() const noexcept {
core->pause = true;
core->Stop();
core->LoadROM(core->rom);
core->pause = false;
}
void EmuThread::Stop() const noexcept {
Util::RPC::GetInstance().Update(Util::RPC::Idling);
core->rom = {};
core->pause = true;
core->Stop();
}

View File

@@ -1,46 +1,27 @@
#pragma once #pragma once
#include <Core.hpp>
#include <Discord.hpp> #include <Discord.hpp>
#include <QThread> #include <QThread>
#include <RenderWidget.hpp> #include <RenderWidget.hpp>
#include <SDL3/SDL_gamepad.h>
#include <SettingsWindow.hpp> #include <SettingsWindow.hpp>
#include <memory> #include <memory>
namespace n64 {
struct Core;
}
class EmuThread : public QThread { class EmuThread : public QThread {
Q_OBJECT Q_OBJECT
RenderWidget &renderWidget; RenderWidget &renderWidget;
public: public:
explicit EmuThread(RenderWidget &, SettingsWindow &) noexcept; explicit EmuThread(const std::shared_ptr<n64::Core> &, RenderWidget &, SettingsWindow &) noexcept;
[[noreturn]] void run() noexcept override; [[noreturn]] void run() noexcept override;
void TogglePause() const noexcept;
void SetRender(bool v) const noexcept;
void Reset() const noexcept;
void Stop() const noexcept;
SDL_Gamepad *controller{}; std::shared_ptr<n64::Core> core;
ParallelRDP parallel;
n64::Core core;
SettingsWindow &settings; SettingsWindow &settings;
void TogglePause() {
core.TogglePause();
Util::RPC::GetInstance().Update(core.pause ? Util::RPC::Paused : Util::RPC::GetInstance().GetState(),
core.cpu->GetMem().rom.gameNameDB,
core.cpu->GetMem().mmio.si.pif.movie.GetFilename());
}
void SetRender(bool v) { core.render = v; }
void Reset() {
core.pause = true;
core.Stop();
core.LoadROM(core.rom);
core.pause = false;
}
void Stop() {
Util::RPC::GetInstance().Update(Util::RPC::Idling);
core.rom = {};
core.pause = true;
core.Stop();
}
}; };

View File

@@ -1,16 +1,17 @@
#include <Core.hpp>
#include <KaizenQt.hpp> #include <KaizenQt.hpp>
#include <QApplication> #include <QApplication>
#include <QDropEvent> #include <QDropEvent>
#include <QMessageBox> #include <QMessageBox>
#include <QMimeData> #include <QMimeData>
#include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
KaizenQt::KaizenQt() noexcept : QWidget(nullptr) { KaizenQt::KaizenQt() noexcept : QWidget(nullptr) {
mainWindow = std::make_unique<MainWindow>(); core = std::make_shared<n64::Core>();
mainWindow = std::make_unique<MainWindow>(core);
settingsWindow = std::make_unique<SettingsWindow>(); settingsWindow = std::make_unique<SettingsWindow>();
emuThread = std::make_unique<EmuThread>(*mainWindow->vulkanWidget, *settingsWindow); emuThread = std::make_unique<EmuThread>(core, *mainWindow->vulkanWidget, *settingsWindow);
debugger = std::make_unique<Debugger>(); debugger = std::make_unique<Debugger>();
ConnectMainWindowSignalsToSlots(); ConnectMainWindowSignalsToSlots();
@@ -53,9 +54,9 @@ void KaizenQt::LoadROM(const QString &fileName) noexcept {
mainWindow->actionReset->setEnabled(true); mainWindow->actionReset->setEnabled(true);
mainWindow->actionStop->setEnabled(true); mainWindow->actionStop->setEnabled(true);
emuThread->start(); emuThread->start();
emuThread->core.LoadROM(fileName.toStdString()); emuThread->core->LoadROM(fileName.toStdString());
auto gameNameDB = emuThread->core.cpu->GetMem().rom.gameNameDB; auto gameNameDB = emuThread->core->cpu->GetMem().rom.gameNameDB;
mainWindow->setWindowTitle(emuThread->core.cpu->GetMem().rom.gameNameDB.c_str()); mainWindow->setWindowTitle(emuThread->core->cpu->GetMem().rom.gameNameDB.c_str());
Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB); Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB);
} }
@@ -69,15 +70,19 @@ void KaizenQt::Quit() noexcept {
} }
void KaizenQt::LoadTAS(const QString &fileName) const noexcept { void KaizenQt::LoadTAS(const QString &fileName) const noexcept {
emuThread->core.LoadTAS(fs::path(fileName.toStdString())); if (emuThread->core->LoadTAS(fs::path(fileName.toStdString()))) {
auto gameNameDB = emuThread->core.cpu->GetMem().rom.gameNameDB; auto gameNameDB = emuThread->core->cpu->GetMem().rom.gameNameDB;
auto movieName = fs::path(fileName.toStdString()).stem().string(); auto movieName = fs::path(fileName.toStdString()).stem().string();
Util::RPC::GetInstance().Update(Util::RPC::MovieReplay, gameNameDB, movieName); Util::RPC::GetInstance().Update(Util::RPC::MovieReplay, gameNameDB, movieName);
return;
}
Util::panic("Could not load TAS movie {}!", fileName.toStdString());
} }
void KaizenQt::keyPressEvent(QKeyEvent *e) { void KaizenQt::keyPressEvent(QKeyEvent *e) {
emuThread->core.pause = true; emuThread->core->pause = true;
n64::Mem &mem = emuThread->core.cpu->GetMem(); n64::Mem &mem = emuThread->core->cpu->GetMem();
n64::PIF &pif = mem.mmio.si.pif; n64::PIF &pif = mem.mmio.si.pif;
auto k = static_cast<Qt::Key>(e->key()); auto k = static_cast<Qt::Key>(e->key());
@@ -95,13 +100,13 @@ void KaizenQt::keyPressEvent(QKeyEvent *e) {
if (k == settingsWindow->keyMap[17]) if (k == settingsWindow->keyMap[17])
pif.UpdateAxis(0, n64::Controller::Axis::X, 86); pif.UpdateAxis(0, n64::Controller::Axis::X, 86);
emuThread->core.pause = false; emuThread->core->pause = false;
QWidget::keyPressEvent(e); QWidget::keyPressEvent(e);
} }
void KaizenQt::keyReleaseEvent(QKeyEvent *e) { void KaizenQt::keyReleaseEvent(QKeyEvent *e) {
emuThread->core.pause = true; emuThread->core->pause = true;
n64::Mem &mem = emuThread->core.cpu->GetMem(); n64::Mem &mem = emuThread->core->cpu->GetMem();
n64::PIF &pif = mem.mmio.si.pif; n64::PIF &pif = mem.mmio.si.pif;
auto k = static_cast<Qt::Key>(e->key()); auto k = static_cast<Qt::Key>(e->key());
@@ -119,6 +124,6 @@ void KaizenQt::keyReleaseEvent(QKeyEvent *e) {
if (k == settingsWindow->keyMap[17]) if (k == settingsWindow->keyMap[17])
pif.UpdateAxis(0, n64::Controller::Axis::X, 0); pif.UpdateAxis(0, n64::Controller::Axis::X, 0);
emuThread->core.pause = false; emuThread->core->pause = false;
QWidget::keyReleaseEvent(e); QWidget::keyReleaseEvent(e);
} }

View File

@@ -3,6 +3,7 @@
#include <EmuThread.hpp> #include <EmuThread.hpp>
#include <MainWindow.hpp> #include <MainWindow.hpp>
#include <SettingsWindow.hpp> #include <SettingsWindow.hpp>
#include <log.hpp>
enum class CompositorCategory { Windows, MacOS, XCB, Wayland }; enum class CompositorCategory { Windows, MacOS, XCB, Wayland };
@@ -39,4 +40,5 @@ private:
std::unique_ptr<SettingsWindow> settingsWindow; std::unique_ptr<SettingsWindow> settingsWindow;
std::unique_ptr<EmuThread> emuThread; std::unique_ptr<EmuThread> emuThread;
std::unique_ptr<Debugger> debugger; std::unique_ptr<Debugger> debugger;
std::shared_ptr<n64::Core> core;
}; };

View File

@@ -1,6 +1,6 @@
#include <MainWindow.hpp> #include <MainWindow.hpp>
MainWindow::MainWindow() noexcept { MainWindow::MainWindow(const std::shared_ptr<n64::Core> &core) noexcept {
if (objectName().isEmpty()) if (objectName().isEmpty())
setObjectName("MainWindow"); setObjectName("MainWindow");
resize(800, 646); resize(800, 646);
@@ -26,7 +26,7 @@ MainWindow::MainWindow() noexcept {
verticalLayout->setSpacing(0); verticalLayout->setSpacing(0);
verticalLayout->setObjectName("verticalLayout"); verticalLayout->setObjectName("verticalLayout");
verticalLayout->setContentsMargins(0, 0, 0, 0); verticalLayout->setContentsMargins(0, 0, 0, 0);
vulkanWidget = std::make_unique<RenderWidget>(); vulkanWidget = std::make_unique<RenderWidget>(core);
vulkanWidget->setObjectName("vulkanWidget"); vulkanWidget->setObjectName("vulkanWidget");
verticalLayout->addWidget(vulkanWidget.get()); verticalLayout->addWidget(vulkanWidget.get());

View File

@@ -16,7 +16,7 @@ class MainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
public: public:
MainWindow() noexcept; MainWindow(const std::shared_ptr<n64::Core> &) noexcept;
std::unique_ptr<QAction> actionOpenDebuggerWindow{}; std::unique_ptr<QAction> actionOpenDebuggerWindow{};
std::unique_ptr<QAction> actionAbout{}; std::unique_ptr<QAction> actionAbout{};

View File

@@ -1,7 +1,9 @@
#include <Core.hpp>
#include <KaizenQt.hpp> #include <KaizenQt.hpp>
#include <RenderWidget.hpp> #include <RenderWidget.hpp>
#include <SDL3/SDL_events.h>
RenderWidget::RenderWidget() : QWidget(nullptr) { RenderWidget::RenderWidget(const std::shared_ptr<n64::Core> &core) : QWidget(nullptr) {
setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_PaintOnScreen);
if (GetOSCompositorCategory() == CompositorCategory::Wayland) { if (GetOSCompositorCategory() == CompositorCategory::Wayland) {
@@ -22,6 +24,76 @@ RenderWidget::RenderWidget() : QWidget(nullptr) {
windowHandle()->setVulkanInstance(&qtVkInstanceFactory->handle); windowHandle()->setVulkanInstance(&qtVkInstanceFactory->handle);
windowHandle()->create(); windowHandle()->create();
wsiPlatform = std::make_shared<QtWSIPlatform>(windowHandle()); wsiPlatform = std::make_shared<QtWSIPlatform>(core, windowHandle());
windowInfo = std::make_shared<QtParallelRdpWindowInfo>(windowHandle()); windowInfo = std::make_shared<QtParallelRdpWindowInfo>(windowHandle());
} }
void QtWSIPlatform::poll_input() {
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_EVENT_GAMEPAD_ADDED:
{
const auto index = e.gdevice.which;
gamepad = SDL_OpenGamepad(index);
Util::info("Found controller!");
const auto serial = SDL_GetGamepadSerial(gamepad);
const auto name = SDL_GetGamepadName(gamepad);
const auto path = SDL_GetGamepadPath(gamepad);
Util::info("\tName: {}", name ? name : "Not available");
Util::info("\tSerial: {}", serial ? serial : "Not available");
Util::info("\tPath: {}", path ? path : "Not available");
gamepadConnected = true;
}
break;
case SDL_EVENT_GAMEPAD_REMOVED:
{
gamepadConnected = false;
SDL_CloseGamepad(gamepad);
}
break;
default:
break;
}
}
if (gamepadConnected) {
n64::PIF &pif = core->cpu->GetMem().mmio.si.pif;
pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH));
pif.UpdateButton(0, n64::Controller::Key::B, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_WEST));
pif.UpdateButton(0, n64::Controller::Key::Z,
SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX);
pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_START));
pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_UP));
pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_DOWN));
pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_LEFT));
pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_RIGHT));
pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER));
pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER));
pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) <= -127);
pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) >= 127);
pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) <= -127);
pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) >= 127);
float xclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX);
if (xclamped < 0) {
xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MAX));
} else {
xclamped /= SDL_JOYSTICK_AXIS_MAX;
}
xclamped *= 86;
float yclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY);
if (yclamped < 0) {
yclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN));
} else {
yclamped /= SDL_JOYSTICK_AXIS_MAX;
}
yclamped *= 86;
pif.UpdateAxis(0, n64::Controller::Axis::Y, -yclamped);
pif.UpdateAxis(0, n64::Controller::Axis::X, xclamped);
}
}

View File

@@ -4,6 +4,11 @@
#include <QVulkanWindow> #include <QVulkanWindow>
#include <QWidget> #include <QWidget>
#include <QWindow> #include <QWindow>
#include <SDL3/SDL_gamepad.h>
namespace n64 {
struct Core;
}
struct QtInstanceFactory : Vulkan::InstanceFactory { struct QtInstanceFactory : Vulkan::InstanceFactory {
VkInstance create_instance(const VkInstanceCreateInfo *info) override { VkInstance create_instance(const VkInstanceCreateInfo *info) override {
@@ -29,7 +34,7 @@ struct QtInstanceFactory : Vulkan::InstanceFactory {
class QtParallelRdpWindowInfo : public ParallelRDP::WindowInfo { class QtParallelRdpWindowInfo : public ParallelRDP::WindowInfo {
public: public:
explicit QtParallelRdpWindowInfo(QWindow* window) : window(window) {} explicit QtParallelRdpWindowInfo(QWindow *window) : window(window) {}
CoordinatePair get_window_size() override { CoordinatePair get_window_size() override {
return CoordinatePair{static_cast<float>(window->width()), static_cast<float>(window->height())}; return CoordinatePair{static_cast<float>(window->width()), static_cast<float>(window->height())};
} }
@@ -40,7 +45,7 @@ private:
class QtWSIPlatform final : public Vulkan::WSIPlatform { class QtWSIPlatform final : public Vulkan::WSIPlatform {
public: public:
explicit QtWSIPlatform(QWindow* window) : window(window) {} explicit QtWSIPlatform(const std::shared_ptr<n64::Core> &core, QWindow *window) : window(window), core(core) {}
std::vector<const char *> get_instance_extensions() override { std::vector<const char *> get_instance_extensions() override {
auto vec = std::vector<const char *>(); auto vec = std::vector<const char *>();
@@ -64,7 +69,7 @@ public:
bool alive(Vulkan::WSI &) override { return true; } bool alive(Vulkan::WSI &) override { return true; }
void poll_input() override {} void poll_input() override;
void poll_input_async(Granite::InputTrackerHandler *handler) override {} void poll_input_async(Granite::InputTrackerHandler *handler) override {}
void event_frame_tick(double frame, double elapsed) override {} void event_frame_tick(double frame, double elapsed) override {}
@@ -74,15 +79,19 @@ public:
VkApplicationInfo appInfo{.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .apiVersion = VK_API_VERSION_1_3}; VkApplicationInfo appInfo{.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .apiVersion = VK_API_VERSION_1_3};
std::shared_ptr<QWindow> window{}; std::shared_ptr<QWindow> window{};
private:
std::shared_ptr<n64::Core> core;
SDL_Gamepad *gamepad{};
bool gamepadConnected = false;
}; };
class RenderWidget : public QWidget { class RenderWidget : public QWidget {
public: public:
[[nodiscard]] VkInstance instance() const { return qtVkInstanceFactory->handle.vkInstance(); } [[nodiscard]] VkInstance instance() const { return qtVkInstanceFactory->handle.vkInstance(); }
explicit RenderWidget(); explicit RenderWidget(const std::shared_ptr<n64::Core> &);
[[nodiscard]] QPaintEngine *paintEngine() const override { return nullptr; } [[nodiscard]] QPaintEngine *paintEngine() const override { return nullptr; }
std::shared_ptr<ParallelRDP::WindowInfo> windowInfo; std::shared_ptr<ParallelRDP::WindowInfo> windowInfo;
std::shared_ptr<Vulkan::WSIPlatform> wsiPlatform; std::shared_ptr<Vulkan::WSIPlatform> wsiPlatform;
std::shared_ptr<QtInstanceFactory> qtVkInstanceFactory; std::shared_ptr<QtInstanceFactory> qtVkInstanceFactory;