From a73fcc7b4b9d0d9aaa83bde08da56f140e6d38ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 19 Jul 2026 12:04:06 +0200 Subject: [PATCH] Windows: Call NativeInit/NativeShutdown outside the EmuThread. --- Windows/EmuThread.cpp | 21 ++++++--------------- Windows/EmuThread.h | 4 +--- Windows/main.cpp | 8 +++++++- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index edebbd644f..407792bcf5 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -43,24 +43,16 @@ static std::thread mainThread; static std::string g_error_message; static bool g_inLoop; -static const char** g_argv; -static int g_argc; - extern std::vector GetWideCmdLine(); class GraphicsContext; static GraphicsContext *g_graphicsContext; -void MainThreadFunc(int argc, const char *argv[]); +void MainThreadFunc(); -void MainThread_Start(int argc, const char *argv[]) { - // This is just to survive WM_USER_RESTART_EMUTHREAD. - if (g_argc == 0) { - g_argc = argc; - g_argv = argv; - } +void MainThread_Start() { mainThread = std::thread([]() { - MainThreadFunc(g_argc, g_argv); + MainThreadFunc(); }); } @@ -153,7 +145,7 @@ bool CreateGraphicsBackend(std::string *error_message, GraphicsContext **ctx) { } } -void MainThreadFunc(int argc, const char *argv[]) { +void MainThreadFunc() { const bool useEmuThread = g_Config.iGPUBackend == (int)GPUBackend::OPENGL; SetCurrentThreadName(useEmuThread ? "RenderThread" : "EmuThread"); @@ -161,7 +153,6 @@ void MainThreadFunc(int argc, const char *argv[]) { System_SetWindowTitle(""); const bool performingRestart = NativeIsRestarting(); - NativeInit(argc, argv, "", "", nullptr); if (g_Config.sFailedGPUBackends.find("ALL") != std::string::npos) { Reporting::ReportMessage("Graphics init error: %s", "ALL"); @@ -249,6 +240,7 @@ void MainThreadFunc(int argc, const char *argv[]) { graphicsContext->ThreadStart(); if (useEmuThread) { + // Again, this thread becomes the render thread. while (true) { if (equals_any(g_emuThreadState, EmuThreadState::QUIT_REQUESTED, EmuThreadState::STOPPED)) { break; @@ -259,6 +251,7 @@ void MainThreadFunc(int argc, const char *argv[]) { } } } else { + // Same contents as EmuThread. while (GetUIState() != UISTATE_EXIT) { // && GetUIState() != UISTATE_EXCEPTION // We're here again, so the game quit. Restart Run() which controls the UI. // This way they can load a new game. @@ -297,7 +290,5 @@ void MainThreadFunc(int argc, const char *argv[]) { delete g_graphicsContext; g_graphicsContext = nullptr; - NativeShutdown(); - PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_UPDATE_UI, 0, 0); } diff --git a/Windows/EmuThread.h b/Windows/EmuThread.h index 34dc544fe7..f630b50763 100644 --- a/Windows/EmuThread.h +++ b/Windows/EmuThread.h @@ -17,8 +17,6 @@ #pragma once -void MainThread_Start(int argc, const char *argv[]); +void MainThread_Start(); void MainThread_Stop(); bool MainThread_Ready(); - -void MainThreadFunc(int argc, const char *argv[]); diff --git a/Windows/main.cpp b/Windows/main.cpp index 8169216eff..6435da6684 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -1149,11 +1149,13 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin MainWindow::Minimize(); } + NativeInit((int)args.size(), args.data(), "", "", nullptr); + // Emu thread (and render thread, if any) is always running! // OpenGL uses an externally managed render thread (due to GL's single-threaded context design). // Vulkan manages its own render thread. Our D3D backend doesn't have a render thread. // The Emu thread calls NativeInit() and NativeMain() etc. - MainThread_Start((int)args.size(), args.data()); + MainThread_Start(); g_InputManager.BeginPolling(); @@ -1200,6 +1202,10 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin } } + // When we've exited the loop, MainThread_Stop has already been called. + // So it's safe to call NativeShutdown. + NativeShutdown(); + g_VFS.Clear(); // g_InputManager.StopPolling() is called in WM_DESTROY