From af7977267e33428f0875da8ba0923d2090226fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Jul 2026 14:37:32 +0200 Subject: [PATCH] Add NeedsRenderThread property to GraphicsContext --- Common/GraphicsContext.h | 5 +++++ Core/EmuThread.cpp | 17 ++++++++--------- Qt/QtMain.h | 2 ++ SDL/SDLGLGraphicsContext.h | 2 ++ Windows/GPU/WindowsGLContext.h | 2 ++ android/jni/AndroidJavaGLContext.h | 2 ++ ios/ViewController.mm | 1 + libretro/LibretroGLContext.h | 2 ++ libretro/LibretroGLCoreContext.h | 4 ++-- 9 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Common/GraphicsContext.h b/Common/GraphicsContext.h index 59b33ae169..4f7008cad9 100644 --- a/Common/GraphicsContext.h +++ b/Common/GraphicsContext.h @@ -29,6 +29,9 @@ public: // Needs casting to the appropriate type, unfortunately. Should find a better solution.. virtual void *GetAPIContext() { return nullptr; } + // OpenGL returns true here. + virtual bool NeedsRenderThread() const { return false; } + // Called from the render thread from threaded backends. virtual void ThreadStart() {} virtual bool ThreadFrame(bool waitIfEmpty) { return true; } // waitIfEmpty should normally be true, except in exit scenarios. @@ -41,6 +44,8 @@ public: virtual Draw::DrawContext *GetDrawContext() = 0; void ThreadFrameUntilCondition(std::function conditionStopped) { + _dbg_assert_(NeedsRenderThread()); + bool exitOnEmpty = false; INFO_LOG(Log::System, "Executing graphicsContext->ThreadFrame to clear buffers"); diff --git a/Core/EmuThread.cpp b/Core/EmuThread.cpp index eb9d2c1aaf..fb52b85963 100644 --- a/Core/EmuThread.cpp +++ b/Core/EmuThread.cpp @@ -74,23 +74,24 @@ std::thread EmuThread_Start(GraphicsContext *graphicsContext, std::functionThreadFrameUntilCondition([] { - // Need to keep eating frames to allow the EmuThread to exit correctly. - return g_emuThreadState == EmuThreadState::STOPPED; - }); + _dbg_assert_(emuThread.joinable()); + if (graphicsContext->NeedsRenderThread()) { + graphicsContext->ThreadFrameUntilCondition([] { + // Need to keep eating frames to allow the EmuThread to exit correctly. + return g_emuThreadState == EmuThreadState::STOPPED; + }); + } emuThread.join(); emuThread = std::thread(); } void MainThreadFunc(GraphicsContext *graphicsContext, std::function postFrame) { - const bool useEmuThread = g_Config.iGPUBackend == (int)GPUBackend::OPENGL; - if (useEmuThread) { + if (graphicsContext->NeedsRenderThread()) { SetCurrentThreadName("RenderThread"); // This is now the render thread, and will spawn the emu thread below. @@ -139,7 +140,6 @@ void MainThreadFunc(GraphicsContext *graphicsContext, std::function post g_inLoop = true; graphicsContext->ThreadStart(); - while (GetUIState() != UISTATE_EXIT) { // We're here again, so the game quit. Restart Run() which controls the UI. // This way they can load a new game. @@ -158,7 +158,6 @@ void MainThreadFunc(GraphicsContext *graphicsContext, std::function post graphicsContext->ThreadEnd(); graphicsContext->ShutdownFromRenderThread(); - } graphicsContext->Shutdown(); diff --git a/Qt/QtMain.h b/Qt/QtMain.h index f5d89608f8..3f80b5c82d 100644 --- a/Qt/QtMain.h +++ b/Qt/QtMain.h @@ -65,6 +65,8 @@ public: renderManager_ = nullptr; } + bool NeedsRenderThread() const override { return true; } + void Shutdown() override {} void Resize() override {} diff --git a/SDL/SDLGLGraphicsContext.h b/SDL/SDLGLGraphicsContext.h index 362aad00eb..b789976c3d 100644 --- a/SDL/SDLGLGraphicsContext.h +++ b/SDL/SDLGLGraphicsContext.h @@ -12,6 +12,8 @@ public: // Returns 0 on success. int Init(SDL_Window *&window, int x, int y, int w, int h, int mode, std::string *error_message, int force_gl_version); + bool NeedsRenderThread() const override { return true; } + bool InitFromRenderThread(std::string *errorMessage) override; void Shutdown() override {} diff --git a/Windows/GPU/WindowsGLContext.h b/Windows/GPU/WindowsGLContext.h index 0d5482995f..9c473a74bb 100644 --- a/Windows/GPU/WindowsGLContext.h +++ b/Windows/GPU/WindowsGLContext.h @@ -13,6 +13,8 @@ class WindowsGLContext : public WindowsGraphicsContext { public: bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override; + bool NeedsRenderThread() const override { return true; } + bool InitFromRenderThread(std::string *errorMessage) override; void ShutdownFromRenderThread() override; diff --git a/android/jni/AndroidJavaGLContext.h b/android/jni/AndroidJavaGLContext.h index 611df72dba..6ae1374448 100644 --- a/android/jni/AndroidJavaGLContext.h +++ b/android/jni/AndroidJavaGLContext.h @@ -9,6 +9,8 @@ public: AndroidJavaEGLGraphicsContext(); ~AndroidJavaEGLGraphicsContext() override { delete draw_; } + bool NeedsRenderThread() const override { return true; } + // This performs the actual initialization, bool InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) override; diff --git a/ios/ViewController.mm b/ios/ViewController.mm index ec3b1698cc..d5c22cbd39 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -55,6 +55,7 @@ public: ~IOSGLESContext() { delete draw_; } + bool NeedsRenderThread() const override { return true; } Draw::DrawContext *GetDrawContext() override { return draw_; } diff --git a/libretro/LibretroGLContext.h b/libretro/LibretroGLContext.h index f02d847928..6ca8691a28 100644 --- a/libretro/LibretroGLContext.h +++ b/libretro/LibretroGLContext.h @@ -16,6 +16,8 @@ public: hw_render_.bottom_left_origin = true; } + bool NeedsRenderThread() const override { return true; } + bool Init() override; void CreateDrawContext() override; void DestroyDrawContext() override; diff --git a/libretro/LibretroGLCoreContext.h b/libretro/LibretroGLCoreContext.h index d9ee56820f..c84e741aa9 100644 --- a/libretro/LibretroGLCoreContext.h +++ b/libretro/LibretroGLCoreContext.h @@ -7,10 +7,10 @@ class LibretroGLCoreContext : public LibretroHWRenderContext { public: LibretroGLCoreContext() - : LibretroHWRenderContext(RETRO_HW_CONTEXT_OPENGL_CORE, 3, 1) - { + : LibretroHWRenderContext(RETRO_HW_CONTEXT_OPENGL_CORE, 3, 1) { hw_render_.bottom_left_origin = true; } + bool NeedsRenderThread() const override { return true; } bool Init() override; void CreateDrawContext() override;