From 1b8f7729c401f45f7ccf83e937740fd8d21a6181 Mon Sep 17 00:00:00 2001 From: Gillou68310 Date: Wed, 13 May 2015 14:08:05 +0200 Subject: [PATCH] front: Fixed GL context restoring --- .../src/video/android/SDL_androidevents.c | 2 +- jni/ae-bridge/ae_exports.cpp | 12 +- .../game/GameLifecycleHandler.java | 7 +- .../mupen64plusae/game/GameMenuHandler.java | 2 + .../mupen64plusae/game/GameSurface.java | 129 +++++++++++------- .../android/mupen64plusae/jni/NativeSDL.java | 2 +- 6 files changed, 101 insertions(+), 53 deletions(-) diff --git a/jni/SDL2/src/video/android/SDL_androidevents.c b/jni/SDL2/src/video/android/SDL_androidevents.c index 528fce5c66..f8cf921a86 100644 --- a/jni/SDL2/src/video/android/SDL_androidevents.c +++ b/jni/SDL2/src/video/android/SDL_androidevents.c @@ -23,7 +23,7 @@ #if SDL_VIDEO_DRIVER_ANDROID /* We're going to do this by default */ -#define SDL_ANDROID_BLOCK_ON_PAUSE 1 +//#define SDL_ANDROID_BLOCK_ON_PAUSE 1 #include "SDL_androidevents.h" #include "SDL_events.h" diff --git a/jni/ae-bridge/ae_exports.cpp b/jni/ae-bridge/ae_exports.cpp index 5d8628219a..344009c532 100644 --- a/jni/ae-bridge/ae_exports.cpp +++ b/jni/ae-bridge/ae_exports.cpp @@ -55,6 +55,8 @@ typedef void (*pSdlSetScreen) (int width, int height, Uint32 format); typedef void (*pVoidFunc) (); typedef m64p_error (*pCoreDoCommand) (m64p_command, int, void *); typedef int (*pFrontMain) (int argc, char* argv[]); +typedef void (*pNativeResume) (JNIEnv* env, jclass cls); +typedef void (*pNativePause) (JNIEnv* env, jclass cls); // Function pointers static pAeiInit aeiInit = NULL; @@ -63,6 +65,8 @@ static pSdlSetScreen sdlSetScreen = NULL; static pVoidFunc sdlMainReady = NULL; static pCoreDoCommand coreDoCommand = NULL; static pFrontMain frontMain = NULL; +static pNativeResume nativeResume = NULL; +static pNativePause nativePause = NULL; void checkLibraryError(const char* message) { @@ -160,9 +164,11 @@ extern "C" DECLSPEC void SDLCALL Java_paulscode_android_mupen64plusae_jni_Native sdlMainReady = (pVoidFunc) locateFunction(handleSDL, "SDL2", "SDL_SetMainReady"); coreDoCommand = (pCoreDoCommand) locateFunction(handleCore, "mupen64plus-core", "CoreDoCommand"); frontMain = (pFrontMain) locateFunction(handleFront, "mupen64plus-ui-console", "SDL_main"); + nativeResume = (pNativeResume) locateFunction(handleSDL, "SDL2", "Java_org_libsdl_app_SDLActivity_nativeResume"); + nativePause = (pNativePause) locateFunction(handleSDL, "SDL2", "Java_org_libsdl_app_SDLActivity_nativePause"); // Make sure we don't have any typos - if (!aeiInit || !sdlInit || !sdlSetScreen || !sdlMainReady || !coreDoCommand || !frontMain) + if (!aeiInit || !sdlInit || !sdlSetScreen || !sdlMainReady || !coreDoCommand || !frontMain || !nativeResume || !nativePause) { LOGE("Could not load library functions: be sure they are named and typedef'd correctly"); } @@ -188,6 +194,8 @@ extern "C" DECLSPEC void SDLCALL Java_paulscode_android_mupen64plusae_jni_Native sdlMainReady = NULL; coreDoCommand = NULL; frontMain = NULL; + nativeResume = NULL; + nativePause = NULL; // Close shared libraries unloadLibrary(handleFront, "mupen64plus-ui-console"); @@ -242,12 +250,14 @@ extern "C" DECLSPEC void Java_paulscode_android_mupen64plusae_jni_NativeExports_ extern "C" DECLSPEC void Java_paulscode_android_mupen64plusae_jni_NativeExports_emuResume(JNIEnv* env, jclass cls) { + if (nativeResume) nativeResume(env, cls); if (coreDoCommand) coreDoCommand(M64CMD_RESUME, 0, NULL); } extern "C" DECLSPEC void Java_paulscode_android_mupen64plusae_jni_NativeExports_emuPause(JNIEnv* env, jclass cls) { if (coreDoCommand) coreDoCommand(M64CMD_PAUSE, 0, NULL); + if (nativePause) nativePause(env, cls); } extern "C" DECLSPEC void Java_paulscode_android_mupen64plusae_jni_NativeExports_emuAdvanceFrame(JNIEnv* env, jclass cls) diff --git a/src/paulscode/android/mupen64plusae/game/GameLifecycleHandler.java b/src/paulscode/android/mupen64plusae/game/GameLifecycleHandler.java index 989fb49d96..b27071cc11 100644 --- a/src/paulscode/android/mupen64plusae/game/GameLifecycleHandler.java +++ b/src/paulscode/android/mupen64plusae/game/GameLifecycleHandler.java @@ -280,8 +280,10 @@ public void onWindowFocusChanged( boolean hasFocus ) Log.i( "GameLifecycleHandler", "onWindowFocusChanged: " + hasFocus ); mIsFocused = hasFocus; if( hasFocus ) + { hideSystemBars(); - tryRunning(); + tryRunning(); + } } public void onPause() @@ -298,7 +300,8 @@ public void surfaceDestroyed( SurfaceHolder holder ) { Log.i( "GameLifecycleHandler", "surfaceDestroyed" ); mIsSurface = false; - tryStopping(); + tryPausing(); + mSurface.destroyGLSurface(); } public void onStop() diff --git a/src/paulscode/android/mupen64plusae/game/GameMenuHandler.java b/src/paulscode/android/mupen64plusae/game/GameMenuHandler.java index a7fee40101..8994984973 100644 --- a/src/paulscode/android/mupen64plusae/game/GameMenuHandler.java +++ b/src/paulscode/android/mupen64plusae/game/GameMenuHandler.java @@ -281,6 +281,8 @@ public void onOptionsItemSelected( MenuItem item ) setIme(); break; case R.id.menuItem_exit: + CoreInterface.pauseEmulator(true); + CoreInterface.shutdownEmulator(); mActivity.finish(); break; default: diff --git a/src/paulscode/android/mupen64plusae/game/GameSurface.java b/src/paulscode/android/mupen64plusae/game/GameSurface.java index a43161e5e4..56ea33e38c 100644 --- a/src/paulscode/android/mupen64plusae/game/GameSurface.java +++ b/src/paulscode/android/mupen64plusae/game/GameSurface.java @@ -44,9 +44,11 @@ public class GameSurface extends SurfaceView private static final String EGL_INITIALIZE_FAIL = "Failed to initialize EGL display connection"; private static final String EGL_INITIALIZE = "Initialized EGL display connection"; + private static final String EGL_INITIALIZE_NOCHANGE = "Re-used EGL display connection"; private static final String EGL_CHOOSE_CONFIG_FAIL = "Failed to find compatible EGL frame buffer configuration"; private static final String EGL_CHOOSE_CONFIG = "Found compatible EGL frame buffer configuration"; + private static final String EGL_CHOOSE_CONFIG_NOCHANGE = "Re-used EGL frame buffer configuration"; private static final String EGL_CREATE_CONTEXT_FAIL = "Failed to create EGL rendering context"; private static final String EGL_CREATE_CONTEXT = "Created EGL rendering context"; @@ -220,6 +222,26 @@ public boolean destroyGLContext() return false; } + /** + * Unbind the previously-created OpenGL ES rendering context and destroy the window surface. + * + * @return True, if successful. + * @see GameSurface#destroyGLSurface() + */ + public boolean destroyGLSurface() + { + Log.i( TAG, "Destroying GL surface" ); + if( unbindEGLContext() ) + { + if( destroyEGLSurface() ) + { + return true; + } + } + Log.e( TAG, "Failed to destroy GL surface" ); + return false; + } + /** * Swap the OpenGL ES framebuffers. Requires valid, bound rendering context and window surface. * @@ -229,7 +251,8 @@ public void flipBuffers() { // Uncomment the next line only for debugging; otherwise don't waste the time // assertPrecondition( Precondition.surface ); - mEgl.eglSwapBuffers( mEglDisplay, mEglSurface ); + if( mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE ) + mEgl.eglSwapBuffers( mEglDisplay, mEglSurface ); } /** @@ -247,59 +270,69 @@ private boolean initializeEGL( int majorVersion, int minorVersion, int[] configS mEgl = (EGL10) EGLContext.getEGL(); // Get an EGL display connection for the native display - mEglDisplay = mEgl.eglGetDisplay( EGL10.EGL_DEFAULT_DISPLAY ); - if( mEglDisplay == EGL10.EGL_NO_DISPLAY ) + if ( mEglDisplay == null || mEglDisplay == EGL10.EGL_NO_DISPLAY ) { - Log.e( TAG, EGL_GET_DISPLAY_FAIL ); - return false; - } - Log.v( TAG, EGL_GET_DISPLAY ); + mEglDisplay = mEgl.eglGetDisplay( EGL10.EGL_DEFAULT_DISPLAY ); + if( mEglDisplay == EGL10.EGL_NO_DISPLAY ) + { + Log.e( TAG, EGL_GET_DISPLAY_FAIL ); + return false; + } + Log.v( TAG, EGL_GET_DISPLAY ); - // Initialize the EGL display connection and obtain the GLES version supported by the device - final int[] version = new int[2]; - if( !mEgl.eglInitialize( mEglDisplay, version ) ) - { - Log.e( TAG, EGL_INITIALIZE_FAIL ); - return false; + // Initialize the EGL display connection and obtain the GLES version supported by the device + int[] version = new int[2]; + if( !mEgl.eglInitialize( mEglDisplay, version ) ) + { + Log.e( TAG, EGL_INITIALIZE_FAIL ); + return false; + } + Log.v( TAG, EGL_INITIALIZE ); } - Log.v( TAG, EGL_INITIALIZE ); + else + Log.v( TAG, EGL_INITIALIZE_NOCHANGE ); // Set the EGL frame buffer configuration and ensure that it supports the requested GLES // version, display connection, and frame buffer configuration // (http://stackoverflow.com/a/5930935/254218) - // Get the number of compatible EGL frame buffer configurations - final int[] numConfigOut = new int[1]; - mEgl.eglChooseConfig( mEglDisplay, configSpec, null, 0, numConfigOut ); - final int numConfig = numConfigOut[0]; - - // Get the compatible EGL frame buffer configurations - final EGLConfig[] configs = new EGLConfig[numConfig]; - boolean success = mEgl.eglChooseConfig( mEglDisplay, configSpec, configs, numConfig, null ); - if( !success || numConfig == 0 ) - { - Log.e( TAG, EGL_CHOOSE_CONFIG_FAIL ); - return false; - } - - // Select the best configuration - for( int i = 0; i < numConfig; i++ ) + if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) { - // "Best" config is the first one that is fast and egl-conformant - // So we test for the "caveat" flag which would indicate slow/non-conformant - int[] value = new int[1]; - mEgl.eglGetConfigAttrib( mEglDisplay, configs[i], EGL10.EGL_CONFIG_CAVEAT, value ); - if( value[0] == EGL10.EGL_NONE ) + // Get the number of compatible EGL frame buffer configurations + int[] numConfigOut = new int[1]; + mEgl.eglChooseConfig( mEglDisplay, configSpec, null, 0, numConfigOut ); + int numConfig = numConfigOut[0]; + + // Get the compatible EGL frame buffer configurations + EGLConfig[] configs = new EGLConfig[numConfig]; + boolean success = mEgl.eglChooseConfig( mEglDisplay, configSpec, configs, numConfig, null ); + if( !success || numConfig == 0 ) + { + Log.e( TAG, EGL_CHOOSE_CONFIG_FAIL ); + return false; + } + + // Select the best configuration + for( int i = 0; i < numConfig; i++ ) { - mEglConfig = configs[i]; - break; + // "Best" config is the first one that is fast and egl-conformant + // So we test for the "caveat" flag which would indicate slow/non-conformant + int[] value = new int[1]; + mEgl.eglGetConfigAttrib( mEglDisplay, configs[i], EGL10.EGL_CONFIG_CAVEAT, value ); + if( value[0] == EGL10.EGL_NONE ) + { + mEglConfig = configs[i]; + break; + } } + Log.v( TAG, EGL_CHOOSE_CONFIG ); } + else + Log.v( TAG, EGL_CHOOSE_CONFIG_NOCHANGE ); // Record the major version mGlMajorVersion = majorVersion; - Log.v( TAG, EGL_CHOOSE_CONFIG ); return true; } @@ -313,13 +346,13 @@ private boolean initializeEGL( int majorVersion, int minorVersion, int[] configS */ private boolean createEGLContext( boolean forceCreate ) { - assertPrecondition( Precondition.CONFIG ); + // assertPrecondition( Precondition.CONFIG ); // Create EGL rendering context if( forceCreate || mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT ) { - final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - final int[] contextAttrs = new int[] { + int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + int[] contextAttrs = new int[] { EGL_CONTEXT_CLIENT_VERSION, mGlMajorVersion, EGL10.EGL_NONE }; @@ -347,7 +380,7 @@ private boolean createEGLContext( boolean forceCreate ) */ private boolean createEGLSurface( boolean forceCreate ) { - assertPrecondition( Precondition.CONTEXT ); + // assertPrecondition( Precondition.CONTEXT ); // Create window surface if( forceCreate || mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE ) @@ -374,7 +407,7 @@ private boolean createEGLSurface( boolean forceCreate ) */ private boolean bindEGLContext() { - assertPrecondition( Precondition.SURFACE ); + // assertPrecondition( Precondition.SURFACE ); // Bind the EGL rendering context to the window surface and current rendering thread if( mEgl.eglGetCurrentContext() != mEglContext ) @@ -400,10 +433,10 @@ private boolean bindEGLContext() */ private boolean unbindEGLContext() { - assertPrecondition( Precondition.DISPLAY ); + // assertPrecondition( Precondition.DISPLAY ); // Unbind rendering context and window surface - if( mEglDisplay != null ) + if( mEglDisplay != null && mEglDisplay != EGL10.EGL_NO_DISPLAY ) { if( !mEgl.eglMakeCurrent( mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT ) ) @@ -427,7 +460,7 @@ private boolean unbindEGLContext() */ private boolean destroyEGLSurface() { - assertPrecondition( Precondition.DISPLAY ); + // assertPrecondition( Precondition.DISPLAY ); // Destroy window surface if( mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE ) @@ -454,7 +487,7 @@ private boolean destroyEGLSurface() */ private boolean destroyEGLContext() { - assertPrecondition( Precondition.DISPLAY ); + // assertPrecondition( Precondition.DISPLAY ); // Destroy rendering context if( mEglContext != null && mEglContext != EGL10.EGL_NO_CONTEXT ) @@ -482,7 +515,7 @@ private boolean destroyEGLContext() */ private boolean terminateEGL() { - assertPrecondition( Precondition.EGL ); + // assertPrecondition( Precondition.EGL ); // Terminate display connection if( mEglDisplay != null && mEglDisplay != EGL10.EGL_NO_DISPLAY ) diff --git a/src/paulscode/android/mupen64plusae/jni/NativeSDL.java b/src/paulscode/android/mupen64plusae/jni/NativeSDL.java index 5be6c3c360..c38c88d9d6 100644 --- a/src/paulscode/android/mupen64plusae/jni/NativeSDL.java +++ b/src/paulscode/android/mupen64plusae/jni/NativeSDL.java @@ -51,7 +51,7 @@ public class NativeSDL extends CoreInterface */ public static boolean createGLContext( int majorVersion, int minorVersion, int[] configSpec ) { - boolean result = sSurface.createGLContext( majorVersion, minorVersion, configSpec, true ); + boolean result = sSurface.createGLContext( majorVersion, minorVersion, configSpec, false ); if( !result ) {