Qt: Initialize COM ourselves on EmuThread

If we don't, SDL initializes it first in STA mode, which prevents MT
mode from being used, which prevents us from using XAudio2.
This commit is contained in:
Connor McLaughlin 2022-05-24 00:20:29 +10:00 committed by refractionpcsx2
parent 6a4df2a641
commit b6308bab4f
4 changed files with 31 additions and 5 deletions

View File

@ -228,7 +228,8 @@ void EmuThread::run()
m_event_loop = new QEventLoop();
m_started_semaphore.release();
if (!VMManager::Internal::InitializeMemory())
// neither of these should ever fail.
if (!VMManager::Internal::InitializeGlobals() || !VMManager::Internal::InitializeMemory())
pxFailRel("Failed to allocate memory map");
// we need input sources ready for binding
@ -252,6 +253,7 @@ void EmuThread::run()
InputManager::CloseSources();
VMManager::WaitForSaveStateFlush();
VMManager::Internal::ReleaseMemory();
VMManager::Internal::ReleaseGlobals();
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
moveToThread(m_ui_thread);
deleteLater();

View File

@ -86,13 +86,11 @@ bool QtHost::Initialize()
if (!InitializeConfig())
{
Console.WriteLn("Failed to initialize config.");
// NOTE: No point translating this, because no config means the language won't be loaded anyway.
QMessageBox::critical(nullptr, QStringLiteral("Error"), QStringLiteral("Failed to initialize config."));
return false;
}
if (!VMManager::Internal::InitializeGlobals())
return false;
HookSignals();
return true;
}

View File

@ -62,6 +62,10 @@
#include "common/emitter/x86_intrin.h"
#endif
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#endif
namespace VMManager
{
static void LoadSettings();
@ -187,6 +191,18 @@ std::string VMManager::GetGameName()
bool VMManager::Internal::InitializeGlobals()
{
// On Win32, we have a bunch of things which use COM (e.g. SDL, XAudio2, 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.
#ifdef _WIN32
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
{
Host::ReportErrorAsync("Error", fmt::format("CoInitializeEx() failed: {:08X}", hr));
return false;
}
#endif
x86caps.Identify();
x86caps.CountCores();
x86caps.SIMD_EstablishMXCSRmask();
@ -196,6 +212,13 @@ bool VMManager::Internal::InitializeGlobals()
return true;
}
void VMManager::Internal::ReleaseGlobals()
{
#ifdef _WIN32
CoUninitialize();
#endif
}
bool VMManager::Internal::InitializeMemory()
{
pxAssert(!s_vm_memory && !s_cpu_provider_pack);

View File

@ -153,6 +153,9 @@ namespace VMManager
/// Performs early global initialization.
bool InitializeGlobals();
/// Releases resources allocated in InitializeGlobals().
void ReleaseGlobals();
/// Reserves memory for the virtual machines.
bool InitializeMemory();