diff --git a/src/core/system.cpp b/src/core/system.cpp index 65bf31c0a..55bbf95c6 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -72,6 +72,7 @@ Log_SetChannel(System); #ifdef _WIN32 #include "common/windows_headers.h" #include +#include #endif #ifdef ENABLE_DISCORD_PRESENCE @@ -253,8 +254,20 @@ static TinyString GetTimestampStringForFileName() return TinyString::from_format("{:%Y-%m-%d-%H-%M-%S}", fmt::localtime(std::time(nullptr))); } -bool System::Internal::ProcessStartup() +bool System::Internal::CPUThreadInitialize() { +#ifdef _WIN32 + // On Win32, we have a bunch of things which use COM (e.g. SDL, Cubeb, etc). + // We need to initialize COM first, before anything else does, because otherwise they might + // initialize it in single-threaded/apartment mode, which can't be changed to multithreaded. + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (FAILED(hr)) + { + Host::ReportErrorAsync("Error", fmt::format("CoInitializeEx() failed: {:08X}", static_cast(hr))); + return false; + } +#endif + if (!Bus::AllocateMemory()) return false; @@ -279,7 +292,7 @@ bool System::Internal::ProcessStartup() return true; } -void System::Internal::ProcessShutdown() +void System::Internal::CPUThreadShutdown() { #ifdef ENABLE_DISCORD_PRESENCE ShutdownDiscordPresence(); @@ -291,6 +304,10 @@ void System::Internal::ProcessShutdown() CPU::CodeCache::ProcessShutdown(); Bus::ReleaseMemory(); + +#ifdef _WIN32 + CoUninitialize(); +#endif } void System::Internal::IdlePollUpdate() diff --git a/src/core/system.h b/src/core/system.h index bd735444a..b037738e6 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -490,10 +490,10 @@ void UpdateDiscordPresence(bool update_session_time); namespace Internal { /// Called on process startup. -bool ProcessStartup(); +bool CPUThreadInitialize(); /// Called on process shutdown. -void ProcessShutdown(); +void CPUThreadShutdown(); /// Polls input, updates subsystems which are present while paused/inactive. void IdlePollUpdate(); diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index 299c4acca..64ba20d56 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -1603,7 +1603,7 @@ void EmuThread::run() m_started_semaphore.release(); // input source setup must happen on emu thread - if (!System::Internal::ProcessStartup()) + if (!System::Internal::CPUThreadInitialize()) { moveToThread(m_ui_thread); return; @@ -1645,7 +1645,7 @@ void EmuThread::run() System::ShutdownSystem(false); destroyBackgroundControllerPollTimer(); - System::Internal::ProcessShutdown(); + System::Internal::CPUThreadShutdown(); // move back to UI thread moveToThread(m_ui_thread); diff --git a/src/duckstation-regtest/regtest_host.cpp b/src/duckstation-regtest/regtest_host.cpp index e1a65220f..9a386eec4 100644 --- a/src/duckstation-regtest/regtest_host.cpp +++ b/src/duckstation-regtest/regtest_host.cpp @@ -657,7 +657,7 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } - if (!System::Internal::ProcessStartup()) + if (!System::Internal::CPUThreadInitialize()) return EXIT_FAILURE; RegTestHost::HookSignals(); @@ -689,6 +689,6 @@ int main(int argc, char* argv[]) result = 0; cleanup: - System::Internal::ProcessShutdown(); + System::Internal::CPUThreadShutdown(); return result; } diff --git a/src/util/cubeb_audio_stream.cpp b/src/util/cubeb_audio_stream.cpp index 51174f944..686a8374d 100644 --- a/src/util/cubeb_audio_stream.cpp +++ b/src/util/cubeb_audio_stream.cpp @@ -123,16 +123,6 @@ void CubebAudioStream::DestroyContextAndStream() bool CubebAudioStream::Initialize(const char* driver_name, const char* device_name, Error* error) { -#ifdef _WIN32 - HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - m_com_initialized_by_us = SUCCEEDED(hr); - if (FAILED(hr) && hr != RPC_E_CHANGED_MODE) - { - Error::SetHResult(error, "CoInitializeEx() failed: ", hr); - return false; - } -#endif - cubeb_set_log_callback(CUBEB_LOG_NORMAL, LogCallback); int rv =