From 7e27e1420e9bf6545a6f642987f56ac335649bcd Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 23 Jun 2024 08:37:37 +0200 Subject: [PATCH] input: try to fix macOS SDL crash --- rpcs3/Input/sdl_pad_handler.cpp | 197 +++++++++++++++++--------------- 1 file changed, 107 insertions(+), 90 deletions(-) diff --git a/rpcs3/Input/sdl_pad_handler.cpp b/rpcs3/Input/sdl_pad_handler.cpp index 856250669e..7477f2200e 100644 --- a/rpcs3/Input/sdl_pad_handler.cpp +++ b/rpcs3/Input/sdl_pad_handler.cpp @@ -9,8 +9,110 @@ LOG_CHANNEL(sdl_log, "SDL"); -std::mutex g_sdl_mutex; -u32 g_sdl_handler_count = 0; +struct sdl_instance +{ +public: + sdl_instance() = default; + ~sdl_instance() + { + // Only quit SDL once on exit. SDL uses a global state internally... + if (m_initialized) + { + sdl_log.notice("Quitting SDL ..."); + SDL_Quit(); + } + } + + bool initialize() + { + // Only init SDL once. SDL uses a global state internally... + if (m_initialized) + { + return true; + } + + sdl_log.notice("Initializing SDL ..."); + + // Set non-dynamic hints before SDL_Init + if (!SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1")) + { + sdl_log.error("Could not set SDL_HINT_JOYSTICK_THREAD: %s", SDL_GetError()); + } + + if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER) < 0) + { + sdl_log.error("Could not initialize! SDL Error: %s", SDL_GetError()); + return false; + } + + SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE); + SDL_LogSetOutputFunction([](void*, int category, SDL_LogPriority priority, const char* message) + { + std::string category_name; + switch (category) + { + case SDL_LOG_CATEGORY_APPLICATION: + category_name = "app"; + break; + case SDL_LOG_CATEGORY_ERROR: + category_name = "error"; + break; + case SDL_LOG_CATEGORY_ASSERT: + category_name = "assert"; + break; + case SDL_LOG_CATEGORY_SYSTEM: + category_name = "system"; + break; + case SDL_LOG_CATEGORY_AUDIO: + category_name = "audio"; + break; + case SDL_LOG_CATEGORY_VIDEO: + category_name = "video"; + break; + case SDL_LOG_CATEGORY_RENDER: + category_name = "render"; + break; + case SDL_LOG_CATEGORY_INPUT: + category_name = "input"; + break; + case SDL_LOG_CATEGORY_TEST: + category_name = "test"; + break; + default: + category_name = fmt::format("unknown(%d)", category); + break; + } + + switch (priority) + { + case SDL_LOG_PRIORITY_VERBOSE: + case SDL_LOG_PRIORITY_DEBUG: + sdl_log.trace("%s: %s", category_name, message); + break; + case SDL_LOG_PRIORITY_INFO: + sdl_log.notice("%s: %s", category_name, message); + break; + case SDL_LOG_PRIORITY_WARN: + sdl_log.warning("%s: %s", category_name, message); + break; + case SDL_LOG_PRIORITY_ERROR: + sdl_log.error("%s: %s", category_name, message); + break; + case SDL_LOG_PRIORITY_CRITICAL: + sdl_log.error("%s: %s", category_name, message); + break; + default: + break; + } + }, nullptr); + + m_initialized = true; + return true; + } + +private: + bool m_initialized = false; +}; constexpr u32 rumble_duration_ms = 500; // Some high number to keep rumble updates at a minimum. constexpr u32 rumble_refresh_ms = rumble_duration_ms - 100; // We need to keep updating the rumble. Choose a refresh timeout that is unlikely to run into missed rumble updates. @@ -87,14 +189,6 @@ sdl_pad_handler::~sdl_pad_handler() controller.second->sdl.game_controller = nullptr; } } - - // Only quit SDL if this is the last instance of the handler. SDL uses a global state internally... - std::lock_guard lock(g_sdl_mutex); - if (g_sdl_handler_count > 0 && --g_sdl_handler_count == 0) - { - sdl_log.notice("Quitting SDL ..."); - SDL_Quit(); - } } void sdl_pad_handler::init_config(cfg_pad* cfg) @@ -159,86 +253,9 @@ bool sdl_pad_handler::Init() if (m_is_init) return true; - std::lock_guard lock(g_sdl_mutex); - - // Only init SDL if this is the first instance of the handler. SDL uses a global state internally... - if (g_sdl_handler_count++ == 0) - { - sdl_log.notice("Initializing SDL ..."); - - // Set non-dynamic hints before SDL_Init - if (!SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1")) - { - sdl_log.error("Could not set SDL_HINT_JOYSTICK_THREAD: %s", SDL_GetError()); - } - - if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER) < 0) - { - sdl_log.error("Could not initialize! SDL Error: %s", SDL_GetError()); - return false; - } - - SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE); - SDL_LogSetOutputFunction([](void*, int category, SDL_LogPriority priority, const char* message) - { - std::string category_name; - switch (category) - { - case SDL_LOG_CATEGORY_APPLICATION: - category_name = "app"; - break; - case SDL_LOG_CATEGORY_ERROR: - category_name = "error"; - break; - case SDL_LOG_CATEGORY_ASSERT: - category_name = "assert"; - break; - case SDL_LOG_CATEGORY_SYSTEM: - category_name = "system"; - break; - case SDL_LOG_CATEGORY_AUDIO: - category_name = "audio"; - break; - case SDL_LOG_CATEGORY_VIDEO: - category_name = "video"; - break; - case SDL_LOG_CATEGORY_RENDER: - category_name = "render"; - break; - case SDL_LOG_CATEGORY_INPUT: - category_name = "input"; - break; - case SDL_LOG_CATEGORY_TEST: - category_name = "test"; - break; - default: - category_name = fmt::format("unknown(%d)", category); - break; - } - - switch (priority) - { - case SDL_LOG_PRIORITY_VERBOSE: - case SDL_LOG_PRIORITY_DEBUG: - sdl_log.trace("%s: %s", category_name, message); - break; - case SDL_LOG_PRIORITY_INFO: - sdl_log.notice("%s: %s", category_name, message); - break; - case SDL_LOG_PRIORITY_WARN: - sdl_log.warning("%s: %s", category_name, message); - break; - case SDL_LOG_PRIORITY_ERROR: - sdl_log.error("%s: %s", category_name, message); - break; - case SDL_LOG_PRIORITY_CRITICAL: - sdl_log.error("%s: %s", category_name, message); - break; - default: - break; - } - }, nullptr); - } + static sdl_instance s_sdl_instance {}; + if (!s_sdl_instance.initialize()) + return false; if (g_cfg.io.load_sdl_mappings) {