mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 07:05:40 +12:00
[Qt] Add proper message queue for thread communication
This commit is contained in:
parent
5984c27960
commit
8d5485fbeb
2 changed files with 60 additions and 22 deletions
|
@ -9,9 +9,11 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "emulator.hpp"
|
#include "emulator.hpp"
|
||||||
#include "panda_qt/screen.hpp"
|
#include "panda_qt/screen.hpp"
|
||||||
|
#include "services/hid.hpp"
|
||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -23,15 +25,34 @@ class MainWindow : public QMainWindow {
|
||||||
Dark = 2,
|
Dark = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Types of messages we might send from the GUI thread to the emulator thread
|
||||||
|
enum class MessageType {
|
||||||
|
LoadROM, Reset, Pause, Resume, TogglePause, DumpRomFS, PressKey, ReleaseKey
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tagged union representing our message queue messages
|
||||||
|
struct EmulatorMessage {
|
||||||
|
MessageType type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
std::filesystem::path* p;
|
||||||
|
} path;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u32 key;
|
||||||
|
} key;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// This would normally be an std::unique_ptr but it's shared between threads so definitely not
|
// This would normally be an std::unique_ptr but it's shared between threads so definitely not
|
||||||
Emulator* emu = nullptr;
|
Emulator* emu = nullptr;
|
||||||
std::thread emuThread;
|
std::thread emuThread;
|
||||||
|
|
||||||
std::atomic<bool> appRunning = true; // Is the application itself running?
|
std::atomic<bool> appRunning = true; // Is the application itself running?
|
||||||
std::mutex messageQueueMutex; // Used for synchronizing messages between the emulator and UI
|
// Used for synchronizing messages between the emulator and UI
|
||||||
std::filesystem::path romToLoad = "";
|
std::mutex messageQueueMutex;
|
||||||
|
std::vector<EmulatorMessage> messageQueue;
|
||||||
bool needToLoadROM = false;
|
|
||||||
|
|
||||||
ScreenWidget screen;
|
ScreenWidget screen;
|
||||||
QComboBox* themeSelect = nullptr;
|
QComboBox* themeSelect = nullptr;
|
||||||
|
@ -43,6 +64,8 @@ class MainWindow : public QMainWindow {
|
||||||
void emuThreadMainLoop();
|
void emuThreadMainLoop();
|
||||||
void selectROM();
|
void selectROM();
|
||||||
void dumpRomFS();
|
void dumpRomFS();
|
||||||
|
void sendMessage(const EmulatorMessage& message);
|
||||||
|
void dispatchMessage(const EmulatorMessage& message);
|
||||||
|
|
||||||
// Tracks whether we are using an OpenGL-backed renderer or a Vulkan-backed renderer
|
// Tracks whether we are using an OpenGL-backed renderer or a Vulkan-backed renderer
|
||||||
bool usingGL = false;
|
bool usingGL = false;
|
||||||
|
|
|
@ -73,13 +73,13 @@ void MainWindow::emuThreadMainLoop() {
|
||||||
{
|
{
|
||||||
std::unique_lock lock(messageQueueMutex);
|
std::unique_lock lock(messageQueueMutex);
|
||||||
|
|
||||||
if (needToLoadROM) {
|
// Dispatch all messages in the message queue
|
||||||
needToLoadROM = false;
|
if (!messageQueue.empty()) {
|
||||||
|
for (const auto& msg : messageQueue) {
|
||||||
bool success = emu->loadROM(romToLoad);
|
dispatchMessage(msg);
|
||||||
if (!success) {
|
|
||||||
printf("Failed to load ROM");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
messageQueue.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,23 +102,15 @@ void MainWindow::swapEmuBuffer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::selectROM() {
|
void MainWindow::selectROM() {
|
||||||
// Are we already waiting for a ROM to be loaded? Then complain about it!
|
|
||||||
{
|
|
||||||
std::unique_lock lock(messageQueueMutex);
|
|
||||||
if (needToLoadROM) {
|
|
||||||
QMessageBox::warning(this, tr("Already loading ROM"), tr("Panda3DS is already busy loading a ROM, please wait"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto path =
|
auto path =
|
||||||
QFileDialog::getOpenFileName(this, tr("Select 3DS ROM to load"), "", tr("Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.3dsx *.elf *.axf)"));
|
QFileDialog::getOpenFileName(this, tr("Select 3DS ROM to load"), "", tr("Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.3dsx *.elf *.axf)"));
|
||||||
|
|
||||||
if (!path.isEmpty()) {
|
if (!path.isEmpty()) {
|
||||||
std::unique_lock lock(messageQueueMutex);
|
std::filesystem::path* p = new std::filesystem::path(path.toStdU16String());
|
||||||
|
|
||||||
romToLoad = path.toStdU16String();
|
EmulatorMessage message{.type = MessageType::LoadROM};
|
||||||
needToLoadROM = true;
|
message.path.p = p;
|
||||||
|
sendMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +127,12 @@ MainWindow::~MainWindow() {
|
||||||
delete themeSelect;
|
delete themeSelect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send a message to the emulator thread. Lock the mutex and just push back to the vector.
|
||||||
|
void MainWindow::sendMessage(const EmulatorMessage& message) {
|
||||||
|
std::unique_lock lock(messageQueueMutex);
|
||||||
|
messageQueue.push_back(message);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::setTheme(Theme theme) {
|
void MainWindow::setTheme(Theme theme) {
|
||||||
currentTheme = theme;
|
currentTheme = theme;
|
||||||
|
|
||||||
|
@ -226,3 +224,20 @@ void MainWindow::dumpRomFS() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::dispatchMessage(const EmulatorMessage& message) {
|
||||||
|
switch (message.type) {
|
||||||
|
case MessageType::LoadROM:
|
||||||
|
emu->loadROM(*message.path.p);
|
||||||
|
// Clean up the allocated path
|
||||||
|
delete message.path.p;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MessageType::Pause: emu->pause(); break;
|
||||||
|
case MessageType::Resume: emu->resume(); break;
|
||||||
|
case MessageType::TogglePause: emu->togglePause(); break;
|
||||||
|
case MessageType::Reset: emu->reset(Emulator::ReloadOption::Reload); break;
|
||||||
|
case MessageType::PressKey: emu->getServiceManager().getHID().pressKey(message.key.key); break;
|
||||||
|
case MessageType::ReleaseKey: emu->getServiceManager().getHID().releaseKey(message.key.key); break;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue