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;
}
auto lock = Host::GetSettingsLock();
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
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
if (VMManager::HasValidVM())

View File

@ -955,19 +955,19 @@ GenericInputBindingMapping InputManager::GetGenericBindingMapping(const std::str
}
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);
if (enabled)
{
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
{
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));
return;
@ -994,12 +994,12 @@ static void UpdateInputSourceState(SettingsInterface& si, InputSourceType type,
#include "Frontend/SDLInputSource.h"
#endif
void InputManager::ReloadSources(SettingsInterface& si)
void InputManager::ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock)
{
#ifdef _WIN32
UpdateInputSourceState<XInputSource>(si, InputSourceType::XInput, false);
UpdateInputSourceState<XInputSource>(si, settings_lock, InputSourceType::XInput, false);
#endif
#ifdef SDL_BUILD
UpdateInputSourceState<SDLInputSource>(si, InputSourceType::SDL, true);
UpdateInputSourceState<SDLInputSource>(si, settings_lock, InputSourceType::SDL, true);
#endif
}

View File

@ -229,7 +229,7 @@ namespace InputManager
void ReloadBindings(SettingsInterface& si);
/// 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.
void CloseSources();
@ -271,4 +271,4 @@ namespace Host
/// Called when an input device is disconnected.
void OnInputDeviceDisconnected(const std::string_view& identifier);
}
}

View File

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

View File

@ -22,6 +22,9 @@
#include "common/StringUtil.h"
#include "common/Console.h"
#include <cmath>
#ifdef __APPLE__
#include <dispatch/dispatch.h>
#endif
static const char* s_sdl_axis_names[] = {
"LeftX", // SDL_CONTROLLER_AXIS_LEFTX
@ -91,7 +94,7 @@ SDLInputSource::SDLInputSource() = default;
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");
if (controller_db_data.has_value())
@ -106,11 +109,14 @@ bool SDLInputSource::Initialize(SettingsInterface& si)
}
LoadSettings(si);
settings_lock.unlock();
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;
@ -118,9 +124,11 @@ void SDLInputSource::UpdateSettings(SettingsInterface& si)
if (m_controller_enhanced_mode != old_controller_enhanced_mode)
{
settings_lock.unlock();
ShutdownSubsystem();
SetHints();
InitializeSubsystem();
settings_lock.lock();
}
}
@ -142,7 +150,17 @@ void SDLInputSource::SetHints()
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");
return false;
@ -160,7 +178,13 @@ void SDLInputSource::ShutdownSubsystem()
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);
#endif
m_sdl_subsystem_initialized = false;
}
}

View File

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

View File

@ -94,7 +94,7 @@ 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)
// 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;
}
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();
bool Initialize(SettingsInterface& si) override;
void UpdateSettings(SettingsInterface& si) override;
bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
void Shutdown() override;
void PollEvents() override;

View File

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