Fixes #1422, restores GL context automatically under Android
authorGabriel Jacobo <gabomdq@gmail.com>
Tue, 19 Jun 2012 13:57:42 -0300
changeset 63300fa55ca2efdd
parent 6329 77dcb8c486e9
child 6331 5732e1a80bde
Fixes #1422, restores GL context automatically under Android
README.android
android-project/src/org/libsdl/app/SDLActivity.java
src/core/android/SDL_android.cpp
src/video/android/SDL_androidevents.c
src/video/android/SDL_androidvideo.c
src/video/android/SDL_androidvideo.h
src/video/android/SDL_androidwindow.c
     1.1 --- a/README.android	Tue Jun 19 12:29:53 2012 -0400
     1.2 +++ b/README.android	Tue Jun 19 13:57:42 2012 -0300
     1.3 @@ -74,6 +74,24 @@
     1.4  
     1.5  
     1.6  ================================================================================
     1.7 + Pause / Resume behaviour
     1.8 +================================================================================
     1.9 +
    1.10 +If SDL is compiled with SDL_ANDROID_BLOCK_ON_PAUSE defined, the event loop will
    1.11 +block itself when the app is paused (ie, when the user returns to the main
    1.12 +Android dashboard). Blocking is better in terms of battery use, and it allows your
    1.13 +app to spring back to life instantaneously after resume (versus polling for
    1.14 +a resume message).
    1.15 +Upon resume, SDL will attempt to restore the GL context automatically.
    1.16 +In modern devices (Android 3.0 and up) this will most likely succeed and your
    1.17 +app can continue to operate as it was.
    1.18 +However, there's a chance (on older hardware, or on systems under heavy load),
    1.19 +where the GL context can not be restored. In that case you have to listen for
    1.20 +a specific message, (which is not yet implemented!) and restore your textures
    1.21 +manually or quit the app (which is actually the kind of behaviour you'll see
    1.22 +under iOS, if the OS can not restore your GL context it will just kill your app)
    1.23 +
    1.24 +================================================================================
    1.25   Additional documentation
    1.26  ================================================================================
    1.27  
     2.1 --- a/android-project/src/org/libsdl/app/SDLActivity.java	Tue Jun 19 12:29:53 2012 -0400
     2.2 +++ b/android-project/src/org/libsdl/app/SDLActivity.java	Tue Jun 19 13:57:42 2012 -0300
     2.3 @@ -68,17 +68,17 @@
     2.4      }
     2.5  
     2.6      // Events
     2.7 -    protected void onPause() {
     2.8 +    /*protected void onPause() {
     2.9          Log.v("SDL", "onPause()");
    2.10          super.onPause();
    2.11 -        SDLActivity.nativePause();
    2.12 +        // Don't call SDLActivity.nativePause(); here, it will be called by SDLSurface::surfaceDestroyed
    2.13      }
    2.14  
    2.15      protected void onResume() {
    2.16          Log.v("SDL", "onResume()");
    2.17          super.onResume();
    2.18 -        SDLActivity.nativeResume();
    2.19 -    }
    2.20 +        // Don't call SDLActivity.nativeResume(); here, it will be called via SDLSurface::surfaceChanged->SDLActivity::startApp
    2.21 +    }*/
    2.22  
    2.23      protected void onDestroy() {
    2.24          super.onDestroy();
    2.25 @@ -249,12 +249,15 @@
    2.26                  return false;
    2.27              }
    2.28  
    2.29 -            if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
    2.30 -                Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
    2.31 -                createEGLContext();
    2.32 +            if (egl.eglGetCurrentContext() != SDLActivity.mEGLContext) {
    2.33                  if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
    2.34 -                    Log.e("SDL", "Failed making EGL Context current");
    2.35 -                    return false;
    2.36 +                    Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
    2.37 +                    // TODO: Notify the user via a message that the old context could not be restored, and that textures need to be manually restored.
    2.38 +                    createEGLContext();
    2.39 +                    if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
    2.40 +                        Log.e("SDL", "Failed making EGL Context current");
    2.41 +                        return false;
    2.42 +                    }
    2.43                  }
    2.44              }
    2.45              SDLActivity.mEGLSurface = surface;
    2.46 @@ -426,7 +429,6 @@
    2.47      public void surfaceCreated(SurfaceHolder holder) {
    2.48          Log.v("SDL", "surfaceCreated()");
    2.49          holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
    2.50 -        SDLActivity.createEGLSurface();
    2.51          enableSensor(Sensor.TYPE_ACCELEROMETER, true);
    2.52      }
    2.53  
     3.1 --- a/src/core/android/SDL_android.cpp	Tue Jun 19 12:29:53 2012 -0400
     3.2 +++ b/src/core/android/SDL_android.cpp	Tue Jun 19 13:57:42 2012 -0300
     3.3 @@ -176,6 +176,8 @@
     3.4                                      JNIEnv* env, jclass cls)
     3.5  {
     3.6      if (Android_Window) {
     3.7 +        /* Signal the pause semaphore so the event loop knows to pause and (optionally) block itself */
     3.8 +        if (!SDL_SemValue(Android_PauseSem)) SDL_SemPost(Android_PauseSem);
     3.9          SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
    3.10          SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    3.11      }
    3.12 @@ -186,6 +188,11 @@
    3.13                                      JNIEnv* env, jclass cls)
    3.14  {
    3.15      if (Android_Window) {
    3.16 +        /* Signal the resume semaphore so the event loop knows to resume and restore the GL Context
    3.17 +         * We can't restore the GL Context here because it needs to be done on the SDL main thread
    3.18 +         * and this function will be called from the Java thread instead.
    3.19 +         */
    3.20 +        if (!SDL_SemValue(Android_ResumeSem)) SDL_SemPost(Android_ResumeSem);
    3.21          SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
    3.22          SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0);
    3.23      }
     4.1 --- a/src/video/android/SDL_androidevents.c	Tue Jun 19 12:29:53 2012 -0400
     4.2 +++ b/src/video/android/SDL_androidevents.c	Tue Jun 19 13:57:42 2012 -0300
     4.3 @@ -27,7 +27,37 @@
     4.4  void
     4.5  Android_PumpEvents(_THIS)
     4.6  {
     4.7 +    static int isPaused = 0;
     4.8      /* No polling necessary */
     4.9 +
    4.10 +    /*
    4.11 +     * Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
    4.12 +     * When the pause semaphoe is signaled, if SDL_ANDROID_BLOCK_ON_PAUSE is defined the event loop will block until the resume signal is emitted.
    4.13 +     * When the resume semaphore is signaled, SDL_GL_CreateContext is called which in turn calls Java code
    4.14 +     * SDLActivity::createGLContext -> SDLActivity:: initEGL -> SDLActivity::createEGLSurface -> SDLActivity::createEGLContext
    4.15 +     */
    4.16 +    if (isPaused) {
    4.17 +#if SDL_ANDROID_BLOCK_ON_PAUSE
    4.18 +        if(SDL_SemWait(Android_ResumeSem) == 0) {
    4.19 +#else
    4.20 +        if(SDL_SemTryWait(Android_ResumeSem) == 0) {
    4.21 +#endif
    4.22 +            isPaused = 0;
    4.23 +            /* TODO: Should we double check if we are on the same thread as the one that made the original GL context?
    4.24 +             * This call will go through the following chain of calls in Java:
    4.25 +             * SDLActivity::createGLContext -> SDLActivity:: initEGL -> SDLActivity::createEGLSurface -> SDLActivity::createEGLContext
    4.26 +             * SDLActivity::createEGLContext will attempt to restore the GL context first, and if that fails it will create a new one
    4.27 +             * If a new GL context is created, the user needs to restore the textures manually (TODO: notify the user that this happened with a message)
    4.28 +             */
    4.29 +            SDL_GL_CreateContext(Android_Window);
    4.30 +        }
    4.31 +    }
    4.32 +    else {
    4.33 +        if(SDL_SemTryWait(Android_PauseSem) == 0) {
    4.34 +            /* If we fall in here, the system is/was paused */
    4.35 +            isPaused = 1;
    4.36 +        }
    4.37 +    }
    4.38  }
    4.39  
    4.40  #endif /* SDL_VIDEO_DRIVER_ANDROID */
     5.1 --- a/src/video/android/SDL_androidvideo.c	Tue Jun 19 12:29:53 2012 -0400
     5.2 +++ b/src/video/android/SDL_androidvideo.c	Tue Jun 19 13:57:42 2012 -0300
     5.3 @@ -64,6 +64,7 @@
     5.4  int Android_ScreenWidth = 0;
     5.5  int Android_ScreenHeight = 0;
     5.6  Uint32 Android_ScreenFormat = SDL_PIXELFORMAT_UNKNOWN;
     5.7 +SDL_sem *Android_PauseSem = NULL, *Android_ResumeSem = NULL;
     5.8  
     5.9  /* Currently only one window */
    5.10  SDL_Window *Android_Window = NULL;
     6.1 --- a/src/video/android/SDL_androidvideo.h	Tue Jun 19 12:29:53 2012 -0400
     6.2 +++ b/src/video/android/SDL_androidvideo.h	Tue Jun 19 13:57:42 2012 -0300
     6.3 @@ -23,6 +23,7 @@
     6.4  #ifndef _SDL_androidvideo_h
     6.5  #define _SDL_androidvideo_h
     6.6  
     6.7 +#include "SDL_mutex.h"
     6.8  #include "../SDL_sysvideo.h"
     6.9  
    6.10  /* Called by the JNI layer when the screen changes size or format */
    6.11 @@ -33,8 +34,10 @@
    6.12  extern int Android_ScreenWidth;
    6.13  extern int Android_ScreenHeight;
    6.14  extern Uint32 Android_ScreenFormat;
    6.15 +extern SDL_sem *Android_PauseSem, *Android_ResumeSem;
    6.16  extern SDL_Window *Android_Window;
    6.17  
    6.18 +
    6.19  #endif /* _SDL_androidvideo_h */
    6.20  
    6.21  /* vi: set ts=4 sw=4 expandtab: */
     7.1 --- a/src/video/android/SDL_androidwindow.c	Tue Jun 19 12:29:53 2012 -0400
     7.2 +++ b/src/video/android/SDL_androidwindow.c	Tue Jun 19 13:57:42 2012 -0300
     7.3 @@ -35,6 +35,8 @@
     7.4          return -1;
     7.5      }
     7.6      Android_Window = window;
     7.7 +    Android_PauseSem = SDL_CreateSemaphore(0);
     7.8 +    Android_ResumeSem = SDL_CreateSemaphore(0);
     7.9  
    7.10      /* Adjust the window data to match the screen */
    7.11      window->x = 0;
    7.12 @@ -62,6 +64,10 @@
    7.13  {
    7.14      if (window == Android_Window) {
    7.15          Android_Window = NULL;
    7.16 +        if (Android_PauseSem) SDL_DestroySemaphore(Android_PauseSem);
    7.17 +        if (Android_ResumeSem) SDL_DestroySemaphore(Android_ResumeSem);
    7.18 +        Android_PauseSem = NULL;
    7.19 +        Android_ResumeSem = NULL;
    7.20      }
    7.21  }
    7.22