Qt: Fix SDL initialization crash on macOS

This commit is contained in:
TellowKrinkle 2022-05-23 23:47:23 -05:00 committed by refractionpcsx2
parent 9c61e9eda3
commit d862f8cd53
9 changed files with 48 additions and 24 deletions

View File

@ -498,9 +498,9 @@ void EmuThread::reloadInputSources()
return; return;
} }
auto lock = Host::GetSettingsLock(); std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface(); SettingsInterface* si = Host::GetSettingsInterface();
InputManager::ReloadSources(*si); InputManager::ReloadSources(*si, lock);
// skip loading bindings if we're not running, since it'll get done on startup anyway // skip loading bindings if we're not running, since it'll get done on startup anyway
if (VMManager::HasValidVM()) if (VMManager::HasValidVM())

View File

@ -955,19 +955,19 @@ GenericInputBindingMapping InputManager::GetGenericBindingMapping(const std::str
} }
template <typename T> template <typename T>
static void UpdateInputSourceState(SettingsInterface& si, InputSourceType type, bool default_state) static void UpdateInputSourceState(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock, InputSourceType type, bool default_state)
{ {
const bool enabled = si.GetBoolValue("InputSources", InputManager::InputSourceToString(type), default_state); const bool enabled = si.GetBoolValue("InputSources", InputManager::InputSourceToString(type), default_state);
if (enabled) if (enabled)
{ {
if (s_input_sources[static_cast<u32>(type)]) if (s_input_sources[static_cast<u32>(type)])
{ {
s_input_sources[static_cast<u32>(type)]->UpdateSettings(si); s_input_sources[static_cast<u32>(type)]->UpdateSettings(si, settings_lock);
} }
else else
{ {
std::unique_ptr<InputSource> source = std::make_unique<T>(); std::unique_ptr<InputSource> source = std::make_unique<T>();
if (!source->Initialize(si)) if (!source->Initialize(si, settings_lock))
{ {
Console.Error("(InputManager) Source '%s' failed to initialize.", InputManager::InputSourceToString(type)); Console.Error("(InputManager) Source '%s' failed to initialize.", InputManager::InputSourceToString(type));
return; return;
@ -994,12 +994,12 @@ static void UpdateInputSourceState(SettingsInterface& si, InputSourceType type,
#include "Frontend/SDLInputSource.h" #include "Frontend/SDLInputSource.h"
#endif #endif
void InputManager::ReloadSources(SettingsInterface& si) void InputManager::ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock)
{ {
#ifdef _WIN32 #ifdef _WIN32
UpdateInputSourceState<XInputSource>(si, InputSourceType::XInput, false); UpdateInputSourceState<XInputSource>(si, settings_lock, InputSourceType::XInput, false);
#endif #endif
#ifdef SDL_BUILD #ifdef SDL_BUILD
UpdateInputSourceState<SDLInputSource>(si, InputSourceType::SDL, true); UpdateInputSourceState<SDLInputSource>(si, settings_lock, InputSourceType::SDL, true);
#endif #endif
} }

View File

@ -229,7 +229,7 @@ namespace InputManager
void ReloadBindings(SettingsInterface& si); void ReloadBindings(SettingsInterface& si);
/// Re-parses the sources part of the config and initializes any backends. /// Re-parses the sources part of the config and initializes any backends.
void ReloadSources(SettingsInterface& si); void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock);
/// Shuts down any enabled input sources. /// Shuts down any enabled input sources.
void CloseSources(); void CloseSources();
@ -271,4 +271,4 @@ namespace Host
/// Called when an input device is disconnected. /// Called when an input device is disconnected.
void OnInputDeviceDisconnected(const std::string_view& identifier); void OnInputDeviceDisconnected(const std::string_view& identifier);
} }

View File

@ -31,8 +31,8 @@ public:
InputSource(); InputSource();
virtual ~InputSource(); virtual ~InputSource();
virtual bool Initialize(SettingsInterface& si) = 0; virtual bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
virtual void UpdateSettings(SettingsInterface& si) = 0; virtual void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
virtual void PollEvents() = 0; virtual void PollEvents() = 0;

View File

@ -22,6 +22,9 @@
#include "common/StringUtil.h" #include "common/StringUtil.h"
#include "common/Console.h" #include "common/Console.h"
#include <cmath> #include <cmath>
#ifdef __APPLE__
#include <dispatch/dispatch.h>
#endif
static const char* s_sdl_axis_names[] = { static const char* s_sdl_axis_names[] = {
"LeftX", // SDL_CONTROLLER_AXIS_LEFTX "LeftX", // SDL_CONTROLLER_AXIS_LEFTX
@ -91,7 +94,7 @@ SDLInputSource::SDLInputSource() = default;
SDLInputSource::~SDLInputSource() { pxAssert(m_controllers.empty()); } SDLInputSource::~SDLInputSource() { pxAssert(m_controllers.empty()); }
bool SDLInputSource::Initialize(SettingsInterface& si) bool SDLInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock)
{ {
std::optional<std::vector<u8>> controller_db_data = Host::ReadResourceFile("game_controller_db.txt"); std::optional<std::vector<u8>> controller_db_data = Host::ReadResourceFile("game_controller_db.txt");
if (controller_db_data.has_value()) if (controller_db_data.has_value())
@ -106,11 +109,14 @@ bool SDLInputSource::Initialize(SettingsInterface& si)
} }
LoadSettings(si); LoadSettings(si);
settings_lock.unlock();
SetHints(); SetHints();
return InitializeSubsystem(); bool result = InitializeSubsystem();
settings_lock.lock();
return result;
} }
void SDLInputSource::UpdateSettings(SettingsInterface& si) void SDLInputSource::UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock)
{ {
const bool old_controller_enhanced_mode = m_controller_enhanced_mode; const bool old_controller_enhanced_mode = m_controller_enhanced_mode;
@ -118,9 +124,11 @@ void SDLInputSource::UpdateSettings(SettingsInterface& si)
if (m_controller_enhanced_mode != old_controller_enhanced_mode) if (m_controller_enhanced_mode != old_controller_enhanced_mode)
{ {
settings_lock.unlock();
ShutdownSubsystem(); ShutdownSubsystem();
SetHints(); SetHints();
InitializeSubsystem(); InitializeSubsystem();
settings_lock.lock();
} }
} }
@ -142,7 +150,17 @@ void SDLInputSource::SetHints()
bool SDLInputSource::InitializeSubsystem() bool SDLInputSource::InitializeSubsystem()
{ {
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) < 0) int result;
#ifdef __APPLE__
// On macOS, SDL_InitSubSystem runs a main-thread-only call to some GameController framework method
// So send this to be run on the main thread
dispatch_sync_f(dispatch_get_main_queue(), &result, [](void* ctx){
*static_cast<int*>(ctx) = SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC);
});
#else
result = SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC);
#endif
if (result < 0)
{ {
Console.Error("SDL_InitSubSystem(SDL_INIT_JOYSTICK |SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) failed"); Console.Error("SDL_InitSubSystem(SDL_INIT_JOYSTICK |SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) failed");
return false; return false;
@ -160,7 +178,13 @@ void SDLInputSource::ShutdownSubsystem()
if (m_sdl_subsystem_initialized) if (m_sdl_subsystem_initialized)
{ {
#ifdef __APPLE__
dispatch_sync_f(dispatch_get_main_queue(), nullptr, [](void*){
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC);
});
#else
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC); SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC);
#endif
m_sdl_subsystem_initialized = false; m_sdl_subsystem_initialized = false;
} }
} }

View File

@ -29,8 +29,8 @@ public:
SDLInputSource(); SDLInputSource();
~SDLInputSource(); ~SDLInputSource();
bool Initialize(SettingsInterface& si) override; bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
void UpdateSettings(SettingsInterface& si) override; void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
void Shutdown() override; void Shutdown() override;
void PollEvents() override; void PollEvents() override;

View File

@ -94,7 +94,7 @@ XInputSource::XInputSource() = default;
XInputSource::~XInputSource() = default; XInputSource::~XInputSource() = default;
bool XInputSource::Initialize(SettingsInterface& si) bool XInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock)
{ {
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
// xinput1_3.dll is flawed and obsolete, but it's also commonly used by wrappers. // xinput1_3.dll is flawed and obsolete, but it's also commonly used by wrappers.
@ -142,7 +142,7 @@ bool XInputSource::Initialize(SettingsInterface& si)
return true; return true;
} }
void XInputSource::UpdateSettings(SettingsInterface& si) void XInputSource::UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock)
{ {
} }

View File

@ -63,8 +63,8 @@ public:
XInputSource(); XInputSource();
~XInputSource(); ~XInputSource();
bool Initialize(SettingsInterface& si) override; bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
void UpdateSettings(SettingsInterface& si) override; void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
void Shutdown() override; void Shutdown() override;
void PollEvents() override; void PollEvents() override;

View File

@ -292,12 +292,12 @@ SysCpuProviderPack& GetCpuProviders()
void VMManager::LoadSettings() void VMManager::LoadSettings()
{ {
auto lock = Host::GetSettingsLock(); std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface(); SettingsInterface* si = Host::GetSettingsInterface();
SettingsLoadWrapper slw(*si); SettingsLoadWrapper slw(*si);
EmuConfig.LoadSave(slw); EmuConfig.LoadSave(slw);
PAD::LoadConfig(*si); PAD::LoadConfig(*si);
InputManager::ReloadSources(*si); InputManager::ReloadSources(*si, lock);
InputManager::ReloadBindings(*si); InputManager::ReloadBindings(*si);
// Remove any user-specified hacks in the config (we don't want stale/conflicting values when it's globally disabled). // Remove any user-specified hacks in the config (we don't want stale/conflicting values when it's globally disabled).