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 Reset() const noexcept;
|
||||
void Stop() const noexcept;
|
||||
void requestInterruption() { interruptionRequested = true; }
|
||||
|
||||
bool interruptionRequested = false, isRunning = false, parallelRDPInitialized = false;
|
||||
std::shared_ptr<n64::Core> core;
|
||||
|
||||
@@ -149,6 +149,9 @@ namespace gui {
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
inline void EndFrame() {
|
||||
inline void Cleanup() {
|
||||
ImGui_ImplVulkan_Shutdown();
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
}
|
||||
@@ -7,18 +7,26 @@
|
||||
namespace gui {
|
||||
struct PopupWindow {
|
||||
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) {
|
||||
exec = func;
|
||||
}
|
||||
void setFunc(std::function<void()>&& func) { exec = func; }
|
||||
|
||||
void setOpened(bool v) { opened = v; }
|
||||
void setOnClose(std::function<void()>&& func) { onClose = func; }
|
||||
void setOnOpen(std::function<void()>&& func) { onOpen = func; }
|
||||
|
||||
bool render() {
|
||||
if(!opened)
|
||||
if(!opened) {
|
||||
if(onClose)
|
||||
onClose();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ImGui::IsPopupOpen(title.c_str()))
|
||||
{
|
||||
if(onOpen)
|
||||
onOpen();
|
||||
ImGui::OpenPopup(title.c_str());
|
||||
}
|
||||
|
||||
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
@@ -27,6 +35,7 @@ struct PopupWindow {
|
||||
{
|
||||
if(exec)
|
||||
exec();
|
||||
|
||||
ImGui::EndPopup();
|
||||
|
||||
return true;
|
||||
@@ -36,6 +45,8 @@ struct PopupWindow {
|
||||
}
|
||||
private:
|
||||
std::function<void()> exec;
|
||||
std::function<void()> onClose;
|
||||
std::function<void()> onOpen;
|
||||
std::string title;
|
||||
bool opened = false;
|
||||
};
|
||||
|
||||
@@ -14,10 +14,18 @@ InputSettings::InputSettings(nlohmann::json &settings) : settings(settings) {
|
||||
|
||||
devices.addItem({"Keyboard/Mouse"});
|
||||
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
||||
}
|
||||
|
||||
void InputSettings::RegisterEventWatchers() {
|
||||
SDL_AddEventWatch(QueryDevices, this);
|
||||
SDL_AddEventWatch(PollGamepad, this);
|
||||
}
|
||||
|
||||
void InputSettings::UnregisterEventWatchers() {
|
||||
SDL_RemoveEventWatch(QueryDevices, this);
|
||||
SDL_RemoveEventWatch(PollGamepad, this);
|
||||
}
|
||||
|
||||
bool InputSettings::render() {
|
||||
if(devices.render()) {
|
||||
auto currentlySelectedDevice = devices.getCurrentlySelected();
|
||||
|
||||
@@ -59,4 +59,6 @@ public:
|
||||
bool getModified() { return modified; }
|
||||
nlohmann::json &settings;
|
||||
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([&]() {
|
||||
ImGui::Text("Kaizen is a Nintendo 64 emulator that strives");
|
||||
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());
|
||||
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() {
|
||||
gui::StartFrame();
|
||||
statusBar.render();
|
||||
@@ -114,17 +113,22 @@ void KaizenGui::LoadROM(const std::string &path) noexcept {
|
||||
Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB);
|
||||
}
|
||||
|
||||
int KaizenGui::run() {
|
||||
void KaizenGui::run() {
|
||||
while(!quit) {
|
||||
if(vulkanWidget.wsiPlatform->quitRequested) {
|
||||
emuExitFunc();
|
||||
emuThread.run();
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
ImGui_ImplSDL3_ProcessEvent(&e);
|
||||
switch(e.type) {
|
||||
case SDL_EVENT_QUIT:
|
||||
quit = true;
|
||||
emuThread.Stop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RenderUI();
|
||||
emuThread.run();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void KaizenGui::LoadTAS(const std::string &path) const noexcept {
|
||||
|
||||
@@ -11,6 +11,7 @@ class KaizenGui final {
|
||||
gui::NativeWindow window;
|
||||
public:
|
||||
explicit KaizenGui() noexcept;
|
||||
~KaizenGui();
|
||||
double fpsCounter = -1.0;
|
||||
gui::MenuBar<true> menuBar;
|
||||
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::StatusBar statusBar{};
|
||||
|
||||
int run();
|
||||
void run();
|
||||
void LoadTAS(const std::string &path) const noexcept;
|
||||
void LoadROM(const std::string &path) noexcept;
|
||||
private:
|
||||
|
||||
@@ -10,79 +10,3 @@ RenderWidget::RenderWidget(const std::shared_ptr<n64::Core> &core, SDL_Window* w
|
||||
windowInfo = std::make_shared<SDLParallelRdpWindowInfo>(window);
|
||||
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 {
|
||||
public:
|
||||
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 {
|
||||
auto vec = std::vector<const char *>();
|
||||
@@ -44,7 +48,9 @@ public:
|
||||
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; }
|
||||
|
||||
@@ -52,7 +58,7 @@ public:
|
||||
|
||||
bool alive(Vulkan::WSI &) override { return true; }
|
||||
|
||||
void poll_input() override;
|
||||
void poll_input() override {}
|
||||
void poll_input_async(Granite::InputTrackerHandler *handler) override {}
|
||||
|
||||
void event_frame_tick(double frame, double elapsed) override {}
|
||||
@@ -63,7 +69,6 @@ public:
|
||||
|
||||
SDL_Window* window{};
|
||||
VkSurfaceKHR surface;
|
||||
bool quitRequested = false;
|
||||
private:
|
||||
std::shared_ptr<n64::Core> core;
|
||||
SDL_Gamepad *gamepad{};
|
||||
|
||||
@@ -52,6 +52,14 @@ SettingsWindow::SettingsWindow() : settings{JSONOpenOrCreate("resources/settings
|
||||
|
||||
apply.setEnabled(false);
|
||||
|
||||
popup.setOnOpen([&]() {
|
||||
inputSettings.RegisterEventWatchers();
|
||||
});
|
||||
|
||||
popup.setOnClose([&]() {
|
||||
inputSettings.UnregisterEventWatchers();
|
||||
});
|
||||
|
||||
popup.setFunc([&]() {
|
||||
tabs.render();
|
||||
|
||||
|
||||
@@ -13,5 +13,7 @@ int main(int argc, char **argv) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return kaizenGui.run();
|
||||
kaizenGui.run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user