From 906d8770194c85f8c593fb97e09ad76a171fbf4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Jul 2026 18:19:15 +0200 Subject: [PATCH] Android: Remove some state and a race condition --- android/jni/AndroidGraphicsContext.h | 12 ------------ android/jni/AndroidJavaGLContext.cpp | 4 ---- android/jni/AndroidVulkanContext.cpp | 3 --- android/jni/app-android.cpp | 26 +++++--------------------- 4 files changed, 5 insertions(+), 40 deletions(-) diff --git a/android/jni/AndroidGraphicsContext.h b/android/jni/AndroidGraphicsContext.h index f51b7e96c7..544b5c2c06 100644 --- a/android/jni/AndroidGraphicsContext.h +++ b/android/jni/AndroidGraphicsContext.h @@ -16,13 +16,6 @@ enum { ANDROID_VERSION_NOUGAT_1 = 25, }; -enum class GraphicsContextState { - PENDING, - INITIALIZED, - FAILED_INIT, - SHUTDOWN, -}; - class AndroidGraphicsContext : public GraphicsContext { public: // This is different than the base class function since on @@ -30,11 +23,6 @@ public: virtual bool InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) = 0; virtual void BeginAndroidShutdown() {} - virtual GraphicsContextState GetState() const { return state_; } - -protected: - GraphicsContextState state_ = GraphicsContextState::PENDING; - private: using GraphicsContext::InitFromRenderThread; }; diff --git a/android/jni/AndroidJavaGLContext.cpp b/android/jni/AndroidJavaGLContext.cpp index 12e4862592..4fc9473b8c 100644 --- a/android/jni/AndroidJavaGLContext.cpp +++ b/android/jni/AndroidJavaGLContext.cpp @@ -14,7 +14,6 @@ bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int INFO_LOG(Log::G3D, "AndroidJavaEGLGraphicsContext::InitFromRenderThread"); if (!CheckGLExtensions()) { ERROR_LOG(Log::G3D, "CheckGLExtensions failed - not gonna attempt starting up."); - state_ = GraphicsContextState::FAILED_INIT; return false; } @@ -29,10 +28,8 @@ bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int if (!draw_->CreatePresets()) { // This can't really happen now that compilation is async - they're only really queued for compile here. _assert_msg_(false, "Failed to compile preset shaders"); - state_ = GraphicsContextState::FAILED_INIT; return false; } - state_ = GraphicsContextState::INITIALIZED; return true; } @@ -41,5 +38,4 @@ void AndroidJavaEGLGraphicsContext::ShutdownFromRenderThread() { renderManager_ = nullptr; // owned by draw_. delete draw_; draw_ = nullptr; - state_ = GraphicsContextState::SHUTDOWN; } diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 65773bb08a..0b7df65fe1 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -32,7 +32,6 @@ bool AndroidVulkanContext::InitAPI() { std::string errorStr; if (!VulkanLoad(&errorStr)) { ERROR_LOG(Log::G3D, "Failed to load Vulkan driver library: %s", errorStr.c_str()); - state_ = GraphicsContextState::FAILED_INIT; return false; } @@ -49,12 +48,10 @@ bool AndroidVulkanContext::InitAPI() { if (!g_Vulkan->CreateInstanceAndDevice(info)) { delete g_Vulkan; g_Vulkan = nullptr; - state_ = GraphicsContextState::FAILED_INIT; return false; } INFO_LOG(Log::G3D, "Vulkan device created!"); - state_ = GraphicsContextState::INITIALIZED; return true; } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index efc30133d6..58159ba082 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -267,35 +267,19 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) { static void EmuThreadFunc() { SetCurrentThreadName("Entering EmuThread"); - // Name the thread in the JVM, because why not (might result in better debug output in Play Console). - // TODO: Do something clever with getEnv() and stored names from SetCurrentThreadName? - JNIEnv *env; - JavaVMAttachArgs args{}; - args.version = JNI_VERSION_1_6; - args.name = "EmuThread"; - gJvm->AttachCurrentThread(&env, &args); + AndroidJNIThreadContext jniContext; + JNIEnv *env = getEnv(); // TODO: Make it gettable from AndroidJNIThreadContext INFO_LOG(Log::System, "Entering emu thread"); // Wait for render loop to get started. INFO_LOG(Log::System, "Runloop: Waiting for displayInit..."); _dbg_assert_(graphicsContext); - while (graphicsContext->GetState() == GraphicsContextState::PENDING) { - sleep_ms(5, "graphics-poll"); - } // Check the state of the graphics context before we try to feed it into NativeInitGraphics. - if (graphicsContext->GetState() != GraphicsContextState::INITIALIZED) { - ERROR_LOG(Log::G3D, "Failed to initialize the graphics context! %d", (int)graphicsContext->GetState()); - emuThreadState = (int)EmuThreadState::QUIT_REQUESTED; - gJvm->DetachCurrentThread(); - return; - } - if (!NativeInitGraphics(graphicsContext)) { _assert_msg_(false, "NativeInitGraphics failed, might as well bail"); emuThreadState = (int)EmuThreadState::QUIT_REQUESTED; - gJvm->DetachCurrentThread(); return; } @@ -323,7 +307,6 @@ static void EmuThreadFunc() { NativeShutdownGraphics(); - gJvm->DetachCurrentThread(); INFO_LOG(Log::System, "Leaving EmuThread"); } @@ -865,8 +848,7 @@ retry: case (int)GPUBackend::OPENGL: INFO_LOG(Log::System, "NativeApp.init() -- creating OpenGL context (JavaGL)"); graphicsContext = new AndroidJavaEGLGraphicsContext(); - INFO_LOG(Log::System, "NativeApp.init() - launching emu thread"); - EmuThreadStart(); + INFO_LOG(Log::System, "NativeApp.init() - not yet launching emuthread, waiting to displayInit"); break; case (int)GPUBackend::VULKAN: { @@ -1056,6 +1038,8 @@ extern "C" jboolean Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * e System_Toast("Graphics initialization failed. Quitting."); return false; } + // This is where we start the emuthread now - after InitFromRenderThread. This eliminates a race condition. + EmuThreadStart(); graphicsContext->GetDrawContext()->SetErrorCallback([](const char *shortDesc, const char *details, void *userdata) { g_OSD.Show(OSDType::MESSAGE_ERROR, details, 5.0);