From 8020b60dda7992d4c32dbf121e289ea5921f436d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 26 Jul 2026 13:42:16 +0200 Subject: [PATCH] Use the new common RunMainLoop on Android --- Core/EmuThread.cpp | 62 ++++++++++++++++++------------------- Core/EmuThread.h | 7 ++++- android/jni/app-android.cpp | 26 +++------------- 3 files changed, 41 insertions(+), 54 deletions(-) diff --git a/Core/EmuThread.cpp b/Core/EmuThread.cpp index 811c0b8b90..a7ae64d646 100644 --- a/Core/EmuThread.cpp +++ b/Core/EmuThread.cpp @@ -70,7 +70,6 @@ static void EmuThreadFunc(GraphicsContext *graphicsContext, Application *applica // This normally calls NativeShutdownGraphics() application->ShutdownGraphics(graphicsContext); - delete application; INFO_LOG(Log::System, "Leaving separate emu thread"); @@ -102,6 +101,36 @@ void EmuThread_Join(GraphicsContext *graphicsContext, std::thread &emuThread) { emuThread = std::thread(); } +bool RunMainLoop(GraphicsContext *graphicsContext, Application *application, std::function runCondition, std::function postFrame) { + // This is the main thread. the graphics contexts will spawn and handle its own threads if needed. + // InitFromRenderThread/ShutdownFromRenderThread are not used. + + application->InitGraphics(graphicsContext); + // NativeResized(); + + DEBUG_LOG(Log::Boot, "Done."); + + g_inLoop = true; + + while (runCondition()) { + // We're here again, so the game quit. Restart Run() which controls the UI. + // This way they can load a new game. + application->Frame(graphicsContext); + postFrame(); + } + Core_Stop(); + + // Process the shutdown. Without this, non-GL delays 800ms on shutdown. + Core_StateProcessed(); + application->Frame(graphicsContext); + + g_inLoop = false; + + application->ShutdownGraphics(graphicsContext); + delete application; + return true; +} + // Call InitAPI and ShutdownAPI outside this! bool MainThreadFunc(GraphicsContext *graphicsContext, Application *application, WindowSystem windowSystem, void *windowData1, void *windowData2, std::function postFrame) { // This is now the render thread, and will spawn the emu thread below. @@ -143,36 +172,7 @@ bool MainThreadFunc(GraphicsContext *graphicsContext, Application *application, } else { SetCurrentThreadName("MainThread"); - // This is the main thread. the graphics contexts will spawn and handle its own threads if needed. - // InitFromRenderThread/ShutdownFromRenderThread are not used. - - std::string error_string; - - application->InitGraphics(graphicsContext); - // NativeResized(); - - DEBUG_LOG(Log::Boot, "Done."); - - 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. - application->Frame(graphicsContext); - postFrame(); - } - Core_Stop(); - - // Process the shutdown. Without this, non-GL delays 800ms on shutdown. - Core_StateProcessed(); - application->Frame(graphicsContext); - - g_inLoop = false; - - application->ShutdownGraphics(graphicsContext); - - graphicsContext->ThreadEnd(); + RunMainLoop(graphicsContext, application, []() { return GetUIState() != UISTATE_EXIT; }, postFrame); } graphicsContext->ShutdownSurface(); diff --git a/Core/EmuThread.h b/Core/EmuThread.h index f1a89115f8..d32cefce28 100644 --- a/Core/EmuThread.h +++ b/Core/EmuThread.h @@ -34,7 +34,12 @@ class GraphicsContext; bool MainThreadFunc(GraphicsContext * graphicsContext, Application *application, WindowSystem windowSystem, void *windowData1, void *windowData2, std::function postFrame); // If you're not using MainThreadFunc, you can at least use these to manage a spinning EmuThread (that calls NativeFrame), -// whether your graphics context requires multithreading or not. +// whether your graphics context requires multithreading or not. Then use RunMainLoop to implement your main loop for +// the case where a separate EmuThread is not needed. // NOTE: Does take ownership over Application (which is just a wrapper for NativeInitGraphics/NativeShutdownGraphics/NativeFrame). std::thread EmuThread_Start(GraphicsContext *graphicsContext, Application *application, std::function postFrame); void EmuThread_Join(GraphicsContext *graphicsContext, std::thread &emuThread); + +// Call from the main thread. +// NOTE: Does take ownership over Application (which is just a wrapper for NativeInitGraphics/NativeShutdownGraphics/NativeFrame). +bool RunMainLoop(GraphicsContext *graphicsContext, Application *application, std::function runCondition, std::function postFrame); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 7d7ea9940d..fa065128e7 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -182,7 +182,8 @@ static jobject ppssppActivity; static std::atomic exitRenderLoop; static std::atomic renderLoopRunning; -static bool renderer_inited = false; + +static bool renderer_inited = false; // only used with OpenGL. static bool sustainedPerfSupported = false; static std::string g_installerName; @@ -1701,27 +1702,8 @@ static void VulkanEmuThread(ANativeWindow *wnd, GraphicsContext *graphicsContext return; } - if (!exitRenderLoop) { - INFO_LOG(Log::G3D, "Calling NativeInitGraphics"); - if (!NativeInitGraphics(graphicsContext)) { - ERROR_LOG(Log::G3D, "Failed to initialize graphics."); - // Gonna be in a weird state here.. - } - renderer_inited = true; - - // The main loop. - while (!exitRenderLoop) { - NativeFrame(graphicsContext); - ProcessFrameCommands(); - } - - INFO_LOG(Log::G3D, "Leaving Vulkan main loop."); - } else { - INFO_LOG(Log::G3D, "Not entering main loop."); - } - - NativeShutdownGraphics(graphicsContext); - + renderer_inited = true; + RunMainLoop(graphicsContext, new NativeApplication(), []() { return !exitRenderLoop; }, []() { ProcessFrameCommands(); }); renderer_inited = false; // Shut the graphics context down to the same state it was in when we entered the render thread.