Fixes #1422, restores GL context automatically under Android
This commit is contained in:
parent
b2b4372f55
commit
8fbd4fb107
7 changed files with 77 additions and 10 deletions
|
@ -73,6 +73,24 @@ android-project/
|
|||
src/org/libsdl/app/SDLActivity.java - the Java class handling the initialization and binding to SDL. Be very careful changing this, as the SDL library relies on this implementation.
|
||||
|
||||
|
||||
================================================================================
|
||||
Pause / Resume behaviour
|
||||
================================================================================
|
||||
|
||||
If SDL is compiled with SDL_ANDROID_BLOCK_ON_PAUSE defined, the event loop will
|
||||
block itself when the app is paused (ie, when the user returns to the main
|
||||
Android dashboard). Blocking is better in terms of battery use, and it allows your
|
||||
app to spring back to life instantaneously after resume (versus polling for
|
||||
a resume message).
|
||||
Upon resume, SDL will attempt to restore the GL context automatically.
|
||||
In modern devices (Android 3.0 and up) this will most likely succeed and your
|
||||
app can continue to operate as it was.
|
||||
However, there's a chance (on older hardware, or on systems under heavy load),
|
||||
where the GL context can not be restored. In that case you have to listen for
|
||||
a specific message, (which is not yet implemented!) and restore your textures
|
||||
manually or quit the app (which is actually the kind of behaviour you'll see
|
||||
under iOS, if the OS can not restore your GL context it will just kill your app)
|
||||
|
||||
================================================================================
|
||||
Additional documentation
|
||||
================================================================================
|
||||
|
|
|
@ -68,17 +68,17 @@ public class SDLActivity extends Activity {
|
|||
}
|
||||
|
||||
// Events
|
||||
protected void onPause() {
|
||||
/*protected void onPause() {
|
||||
Log.v("SDL", "onPause()");
|
||||
super.onPause();
|
||||
SDLActivity.nativePause();
|
||||
// Don't call SDLActivity.nativePause(); here, it will be called by SDLSurface::surfaceDestroyed
|
||||
}
|
||||
|
||||
protected void onResume() {
|
||||
Log.v("SDL", "onResume()");
|
||||
super.onResume();
|
||||
SDLActivity.nativeResume();
|
||||
}
|
||||
// Don't call SDLActivity.nativeResume(); here, it will be called via SDLSurface::surfaceChanged->SDLActivity::startApp
|
||||
}*/
|
||||
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
@ -249,14 +249,17 @@ public class SDLActivity extends Activity {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (egl.eglGetCurrentContext() != SDLActivity.mEGLContext) {
|
||||
if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
|
||||
Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
|
||||
// TODO: Notify the user via a message that the old context could not be restored, and that textures need to be manually restored.
|
||||
createEGLContext();
|
||||
if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
|
||||
Log.e("SDL", "Failed making EGL Context current");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
SDLActivity.mEGLSurface = surface;
|
||||
return true;
|
||||
}
|
||||
|
@ -426,7 +429,6 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.v("SDL", "surfaceCreated()");
|
||||
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
||||
SDLActivity.createEGLSurface();
|
||||
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -176,6 +176,8 @@ extern "C" void Java_org_libsdl_app_SDLActivity_nativePause(
|
|||
JNIEnv* env, jclass cls)
|
||||
{
|
||||
if (Android_Window) {
|
||||
/* Signal the pause semaphore so the event loop knows to pause and (optionally) block itself */
|
||||
if (!SDL_SemValue(Android_PauseSem)) SDL_SemPost(Android_PauseSem);
|
||||
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
|
||||
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
|
||||
}
|
||||
|
@ -186,6 +188,11 @@ extern "C" void Java_org_libsdl_app_SDLActivity_nativeResume(
|
|||
JNIEnv* env, jclass cls)
|
||||
{
|
||||
if (Android_Window) {
|
||||
/* Signal the resume semaphore so the event loop knows to resume and restore the GL Context
|
||||
* We can't restore the GL Context here because it needs to be done on the SDL main thread
|
||||
* and this function will be called from the Java thread instead.
|
||||
*/
|
||||
if (!SDL_SemValue(Android_ResumeSem)) SDL_SemPost(Android_ResumeSem);
|
||||
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
|
||||
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,37 @@
|
|||
void
|
||||
Android_PumpEvents(_THIS)
|
||||
{
|
||||
static int isPaused = 0;
|
||||
/* No polling necessary */
|
||||
|
||||
/*
|
||||
* Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
|
||||
* 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.
|
||||
* When the resume semaphore is signaled, SDL_GL_CreateContext is called which in turn calls Java code
|
||||
* SDLActivity::createGLContext -> SDLActivity:: initEGL -> SDLActivity::createEGLSurface -> SDLActivity::createEGLContext
|
||||
*/
|
||||
if (isPaused) {
|
||||
#if SDL_ANDROID_BLOCK_ON_PAUSE
|
||||
if(SDL_SemWait(Android_ResumeSem) == 0) {
|
||||
#else
|
||||
if(SDL_SemTryWait(Android_ResumeSem) == 0) {
|
||||
#endif
|
||||
isPaused = 0;
|
||||
/* TODO: Should we double check if we are on the same thread as the one that made the original GL context?
|
||||
* This call will go through the following chain of calls in Java:
|
||||
* SDLActivity::createGLContext -> SDLActivity:: initEGL -> SDLActivity::createEGLSurface -> SDLActivity::createEGLContext
|
||||
* SDLActivity::createEGLContext will attempt to restore the GL context first, and if that fails it will create a new one
|
||||
* 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)
|
||||
*/
|
||||
SDL_GL_CreateContext(Android_Window);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(SDL_SemTryWait(Android_PauseSem) == 0) {
|
||||
/* If we fall in here, the system is/was paused */
|
||||
isPaused = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_ANDROID */
|
||||
|
|
|
@ -64,6 +64,7 @@ extern void Android_GL_DeleteContext(_THIS, SDL_GLContext context);
|
|||
int Android_ScreenWidth = 0;
|
||||
int Android_ScreenHeight = 0;
|
||||
Uint32 Android_ScreenFormat = SDL_PIXELFORMAT_UNKNOWN;
|
||||
SDL_sem *Android_PauseSem = NULL, *Android_ResumeSem = NULL;
|
||||
|
||||
/* Currently only one window */
|
||||
SDL_Window *Android_Window = NULL;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#ifndef _SDL_androidvideo_h
|
||||
#define _SDL_androidvideo_h
|
||||
|
||||
#include "SDL_mutex.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
/* Called by the JNI layer when the screen changes size or format */
|
||||
|
@ -33,8 +34,10 @@ extern void Android_SetScreenResolution(int width, int height, Uint32 format);
|
|||
extern int Android_ScreenWidth;
|
||||
extern int Android_ScreenHeight;
|
||||
extern Uint32 Android_ScreenFormat;
|
||||
extern SDL_sem *Android_PauseSem, *Android_ResumeSem;
|
||||
extern SDL_Window *Android_Window;
|
||||
|
||||
|
||||
#endif /* _SDL_androidvideo_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -35,6 +35,8 @@ Android_CreateWindow(_THIS, SDL_Window * window)
|
|||
return -1;
|
||||
}
|
||||
Android_Window = window;
|
||||
Android_PauseSem = SDL_CreateSemaphore(0);
|
||||
Android_ResumeSem = SDL_CreateSemaphore(0);
|
||||
|
||||
/* Adjust the window data to match the screen */
|
||||
window->x = 0;
|
||||
|
@ -62,6 +64,10 @@ Android_DestroyWindow(_THIS, SDL_Window * window)
|
|||
{
|
||||
if (window == Android_Window) {
|
||||
Android_Window = NULL;
|
||||
if (Android_PauseSem) SDL_DestroySemaphore(Android_PauseSem);
|
||||
if (Android_ResumeSem) SDL_DestroySemaphore(Android_ResumeSem);
|
||||
Android_PauseSem = NULL;
|
||||
Android_ResumeSem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue