Fix crash with event watchers + handle SDL loop better + shut down more appropriately
This commit is contained in:
@@ -18,7 +18,6 @@ public:
|
|||||||
void TogglePause() const noexcept;
|
void TogglePause() const noexcept;
|
||||||
void Reset() const noexcept;
|
void Reset() const noexcept;
|
||||||
void Stop() const noexcept;
|
void Stop() const noexcept;
|
||||||
void requestInterruption() { interruptionRequested = true; }
|
|
||||||
|
|
||||||
bool interruptionRequested = false, isRunning = false, parallelRDPInitialized = false;
|
bool interruptionRequested = false, isRunning = false, parallelRDPInitialized = false;
|
||||||
std::shared_ptr<n64::Core> core;
|
std::shared_ptr<n64::Core> core;
|
||||||
|
|||||||
@@ -149,6 +149,9 @@ namespace gui {
|
|||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void EndFrame() {
|
inline void Cleanup() {
|
||||||
|
ImGui_ImplVulkan_Shutdown();
|
||||||
|
ImGui_ImplSDL3_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,18 +7,26 @@
|
|||||||
namespace gui {
|
namespace gui {
|
||||||
struct PopupWindow {
|
struct PopupWindow {
|
||||||
PopupWindow(const std::string& title, std::function<void()>&& func = nullptr, bool opened = false) : title(title), exec(func), opened(opened) {}
|
PopupWindow(const std::string& title, std::function<void()>&& func = nullptr, bool opened = false) : title(title), exec(func), opened(opened) {}
|
||||||
void setFunc(std::function<void()>&& func) {
|
void setFunc(std::function<void()>&& func) { exec = func; }
|
||||||
exec = func;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOpened(bool v) { opened = v; }
|
void setOpened(bool v) { opened = v; }
|
||||||
|
void setOnClose(std::function<void()>&& func) { onClose = func; }
|
||||||
|
void setOnOpen(std::function<void()>&& func) { onOpen = func; }
|
||||||
|
|
||||||
bool render() {
|
bool render() {
|
||||||
if(!opened)
|
if(!opened) {
|
||||||
|
if(onClose)
|
||||||
|
onClose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ImGui::IsPopupOpen(title.c_str()))
|
if (!ImGui::IsPopupOpen(title.c_str()))
|
||||||
|
{
|
||||||
|
if(onOpen)
|
||||||
|
onOpen();
|
||||||
ImGui::OpenPopup(title.c_str());
|
ImGui::OpenPopup(title.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||||
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||||
@@ -27,6 +35,7 @@ struct PopupWindow {
|
|||||||
{
|
{
|
||||||
if(exec)
|
if(exec)
|
||||||
exec();
|
exec();
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -36,6 +45,8 @@ struct PopupWindow {
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::function<void()> exec;
|
std::function<void()> exec;
|
||||||
|
std::function<void()> onClose;
|
||||||
|
std::function<void()> onOpen;
|
||||||
std::string title;
|
std::string title;
|
||||||
bool opened = false;
|
bool opened = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,10 +14,18 @@ InputSettings::InputSettings(nlohmann::json &settings) : settings(settings) {
|
|||||||
|
|
||||||
devices.addItem({"Keyboard/Mouse"});
|
devices.addItem({"Keyboard/Mouse"});
|
||||||
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSettings::RegisterEventWatchers() {
|
||||||
SDL_AddEventWatch(QueryDevices, this);
|
SDL_AddEventWatch(QueryDevices, this);
|
||||||
SDL_AddEventWatch(PollGamepad, this);
|
SDL_AddEventWatch(PollGamepad, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputSettings::UnregisterEventWatchers() {
|
||||||
|
SDL_RemoveEventWatch(QueryDevices, this);
|
||||||
|
SDL_RemoveEventWatch(PollGamepad, this);
|
||||||
|
}
|
||||||
|
|
||||||
bool InputSettings::render() {
|
bool InputSettings::render() {
|
||||||
if(devices.render()) {
|
if(devices.render()) {
|
||||||
auto currentlySelectedDevice = devices.getCurrentlySelected();
|
auto currentlySelectedDevice = devices.getCurrentlySelected();
|
||||||
|
|||||||
@@ -59,4 +59,6 @@ public:
|
|||||||
bool getModified() { return modified; }
|
bool getModified() { return modified; }
|
||||||
nlohmann::json &settings;
|
nlohmann::json &settings;
|
||||||
std::array<SDL_Keycode, 18> GetMappedKeys();
|
std::array<SDL_Keycode, 18> GetMappedKeys();
|
||||||
|
void RegisterEventWatchers();
|
||||||
|
void UnregisterEventWatchers();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,14 +23,6 @@ KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_sha
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
emuExitFunc = [&]() {
|
|
||||||
quit = true;
|
|
||||||
if (emuThread.isRunning) {
|
|
||||||
emuThread.requestInterruption();
|
|
||||||
while (emuThread.isRunning) {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
about.setFunc([&]() {
|
about.setFunc([&]() {
|
||||||
ImGui::Text("Kaizen is a Nintendo 64 emulator that strives");
|
ImGui::Text("Kaizen is a Nintendo 64 emulator that strives");
|
||||||
ImGui::Text("to offer a friendly user experience and compatibility.");
|
ImGui::Text("to offer a friendly user experience and compatibility.");
|
||||||
@@ -63,7 +55,10 @@ KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_sha
|
|||||||
Util::panic("Error: {}", NFD::GetError());
|
Util::panic("Error: {}", NFD::GetError());
|
||||||
LoadROM(path.get());
|
LoadROM(path.get());
|
||||||
}},
|
}},
|
||||||
{"Exit", std::move(emuExitFunc)}
|
{"Exit", [&]() {
|
||||||
|
quit = true;
|
||||||
|
emuThread.Stop();
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -85,6 +80,10 @@ KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_sha
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KaizenGui::~KaizenGui() {
|
||||||
|
gui::Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
void KaizenGui::RenderUI() {
|
void KaizenGui::RenderUI() {
|
||||||
gui::StartFrame();
|
gui::StartFrame();
|
||||||
statusBar.render();
|
statusBar.render();
|
||||||
@@ -114,17 +113,22 @@ void KaizenGui::LoadROM(const std::string &path) noexcept {
|
|||||||
Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB);
|
Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB);
|
||||||
}
|
}
|
||||||
|
|
||||||
int KaizenGui::run() {
|
void KaizenGui::run() {
|
||||||
while(!quit) {
|
while(!quit) {
|
||||||
if(vulkanWidget.wsiPlatform->quitRequested) {
|
emuThread.run();
|
||||||
emuExitFunc();
|
SDL_Event e;
|
||||||
|
while (SDL_PollEvent(&e)) {
|
||||||
|
ImGui_ImplSDL3_ProcessEvent(&e);
|
||||||
|
switch(e.type) {
|
||||||
|
case SDL_EVENT_QUIT:
|
||||||
|
quit = true;
|
||||||
|
emuThread.Stop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderUI();
|
RenderUI();
|
||||||
emuThread.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KaizenGui::LoadTAS(const std::string &path) const noexcept {
|
void KaizenGui::LoadTAS(const std::string &path) const noexcept {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class KaizenGui final {
|
|||||||
gui::NativeWindow window;
|
gui::NativeWindow window;
|
||||||
public:
|
public:
|
||||||
explicit KaizenGui() noexcept;
|
explicit KaizenGui() noexcept;
|
||||||
|
~KaizenGui();
|
||||||
double fpsCounter = -1.0;
|
double fpsCounter = -1.0;
|
||||||
gui::MenuBar<true> menuBar;
|
gui::MenuBar<true> menuBar;
|
||||||
gui::MenuItem actionPause{"Pause", nullptr, false}, actionStop{"Stop", nullptr, false}, actionReset{"Reset", nullptr, false};
|
gui::MenuItem actionPause{"Pause", nullptr, false}, actionStop{"Stop", nullptr, false}, actionReset{"Reset", nullptr, false};
|
||||||
@@ -21,7 +22,7 @@ public:
|
|||||||
gui::PopupWindow about{"About Kaizen"};
|
gui::PopupWindow about{"About Kaizen"};
|
||||||
gui::StatusBar statusBar{};
|
gui::StatusBar statusBar{};
|
||||||
|
|
||||||
int run();
|
void run();
|
||||||
void LoadTAS(const std::string &path) const noexcept;
|
void LoadTAS(const std::string &path) const noexcept;
|
||||||
void LoadROM(const std::string &path) noexcept;
|
void LoadROM(const std::string &path) noexcept;
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -10,79 +10,3 @@ RenderWidget::RenderWidget(const std::shared_ptr<n64::Core> &core, SDL_Window* w
|
|||||||
windowInfo = std::make_shared<SDLParallelRdpWindowInfo>(window);
|
windowInfo = std::make_shared<SDLParallelRdpWindowInfo>(window);
|
||||||
core->parallel.Init(wsiPlatform, windowInfo, core->cpu->GetMem().GetRDRAMPtr());
|
core->parallel.Init(wsiPlatform, windowInfo, core->cpu->GetMem().GetRDRAMPtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLWSIPlatform::poll_input() {
|
|
||||||
SDL_Event e;
|
|
||||||
while (SDL_PollEvent(&e)) {
|
|
||||||
ImGui_ImplSDL3_ProcessEvent(&e);
|
|
||||||
switch (e.type) {
|
|
||||||
case SDL_EVENT_QUIT:
|
|
||||||
quitRequested = true;
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_GAMEPAD_ADDED:
|
|
||||||
{
|
|
||||||
const auto index = e.gdevice.which;
|
|
||||||
|
|
||||||
gamepad = SDL_OpenGamepad(index);
|
|
||||||
Util::info("Controller found!");
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ private:
|
|||||||
class SDLWSIPlatform final : public Vulkan::WSIPlatform {
|
class SDLWSIPlatform final : public Vulkan::WSIPlatform {
|
||||||
public:
|
public:
|
||||||
explicit SDLWSIPlatform(const std::shared_ptr<n64::Core> &core, SDL_Window* window) : window(window), core(core) {}
|
explicit SDLWSIPlatform(const std::shared_ptr<n64::Core> &core, SDL_Window* window) : window(window), core(core) {}
|
||||||
|
~SDLWSIPlatform() {
|
||||||
|
if(gamepadConnected)
|
||||||
|
SDL_CloseGamepad(gamepad);
|
||||||
|
}
|
||||||
|
|
||||||
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 *>();
|
||||||
@@ -44,7 +48,9 @@ public:
|
|||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_surface(VkInstance, VkSurfaceKHR) override {}
|
void destroy_surface(VkInstance instance, VkSurfaceKHR surface) override {
|
||||||
|
SDL_Vulkan_DestroySurface(instance, surface, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t get_surface_width() override { return 640; }
|
uint32_t get_surface_width() override { return 640; }
|
||||||
|
|
||||||
@@ -52,7 +58,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 {}
|
||||||
@@ -63,7 +69,6 @@ public:
|
|||||||
|
|
||||||
SDL_Window* window{};
|
SDL_Window* window{};
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
bool quitRequested = false;
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<n64::Core> core;
|
std::shared_ptr<n64::Core> core;
|
||||||
SDL_Gamepad *gamepad{};
|
SDL_Gamepad *gamepad{};
|
||||||
|
|||||||
@@ -52,6 +52,14 @@ SettingsWindow::SettingsWindow() : settings{JSONOpenOrCreate("resources/settings
|
|||||||
|
|
||||||
apply.setEnabled(false);
|
apply.setEnabled(false);
|
||||||
|
|
||||||
|
popup.setOnOpen([&]() {
|
||||||
|
inputSettings.RegisterEventWatchers();
|
||||||
|
});
|
||||||
|
|
||||||
|
popup.setOnClose([&]() {
|
||||||
|
inputSettings.UnregisterEventWatchers();
|
||||||
|
});
|
||||||
|
|
||||||
popup.setFunc([&]() {
|
popup.setFunc([&]() {
|
||||||
tabs.render();
|
tabs.render();
|
||||||
|
|
||||||
|
|||||||
@@ -13,5 +13,7 @@ int main(int argc, char **argv) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return kaizenGui.run();
|
kaizenGui.run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user