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.
|
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
|
Additional documentation
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
|
@ -68,17 +68,17 @@ public class SDLActivity extends Activity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
protected void onPause() {
|
/*protected void onPause() {
|
||||||
Log.v("SDL", "onPause()");
|
Log.v("SDL", "onPause()");
|
||||||
super.onPause();
|
super.onPause();
|
||||||
SDLActivity.nativePause();
|
// Don't call SDLActivity.nativePause(); here, it will be called by SDLSurface::surfaceDestroyed
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
Log.v("SDL", "onResume()");
|
Log.v("SDL", "onResume()");
|
||||||
super.onResume();
|
super.onResume();
|
||||||
SDLActivity.nativeResume();
|
// Don't call SDLActivity.nativeResume(); here, it will be called via SDLSurface::surfaceChanged->SDLActivity::startApp
|
||||||
}
|
}*/
|
||||||
|
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
@ -249,12 +249,15 @@ public class SDLActivity extends Activity {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
|
if (egl.eglGetCurrentContext() != SDLActivity.mEGLContext) {
|
||||||
Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
|
|
||||||
createEGLContext();
|
|
||||||
if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
|
if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
|
||||||
Log.e("SDL", "Failed making EGL Context current");
|
Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
|
||||||
return false;
|
// 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;
|
SDLActivity.mEGLSurface = surface;
|
||||||
|
@ -426,7 +429,6 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
Log.v("SDL", "surfaceCreated()");
|
Log.v("SDL", "surfaceCreated()");
|
||||||
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
||||||
SDLActivity.createEGLSurface();
|
|
||||||
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,8 @@ extern "C" void Java_org_libsdl_app_SDLActivity_nativePause(
|
||||||
JNIEnv* env, jclass cls)
|
JNIEnv* env, jclass cls)
|
||||||
{
|
{
|
||||||
if (Android_Window) {
|
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_FOCUS_LOST, 0, 0);
|
||||||
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 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)
|
JNIEnv* env, jclass cls)
|
||||||
{
|
{
|
||||||
if (Android_Window) {
|
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_FOCUS_GAINED, 0, 0);
|
||||||
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0);
|
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,37 @@
|
||||||
void
|
void
|
||||||
Android_PumpEvents(_THIS)
|
Android_PumpEvents(_THIS)
|
||||||
{
|
{
|
||||||
|
static int isPaused = 0;
|
||||||
/* No polling necessary */
|
/* 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 */
|
#endif /* SDL_VIDEO_DRIVER_ANDROID */
|
||||||
|
|
|
@ -64,6 +64,7 @@ extern void Android_GL_DeleteContext(_THIS, SDL_GLContext context);
|
||||||
int Android_ScreenWidth = 0;
|
int Android_ScreenWidth = 0;
|
||||||
int Android_ScreenHeight = 0;
|
int Android_ScreenHeight = 0;
|
||||||
Uint32 Android_ScreenFormat = SDL_PIXELFORMAT_UNKNOWN;
|
Uint32 Android_ScreenFormat = SDL_PIXELFORMAT_UNKNOWN;
|
||||||
|
SDL_sem *Android_PauseSem = NULL, *Android_ResumeSem = NULL;
|
||||||
|
|
||||||
/* Currently only one window */
|
/* Currently only one window */
|
||||||
SDL_Window *Android_Window = NULL;
|
SDL_Window *Android_Window = NULL;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#ifndef _SDL_androidvideo_h
|
#ifndef _SDL_androidvideo_h
|
||||||
#define _SDL_androidvideo_h
|
#define _SDL_androidvideo_h
|
||||||
|
|
||||||
|
#include "SDL_mutex.h"
|
||||||
#include "../SDL_sysvideo.h"
|
#include "../SDL_sysvideo.h"
|
||||||
|
|
||||||
/* Called by the JNI layer when the screen changes size or format */
|
/* 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_ScreenWidth;
|
||||||
extern int Android_ScreenHeight;
|
extern int Android_ScreenHeight;
|
||||||
extern Uint32 Android_ScreenFormat;
|
extern Uint32 Android_ScreenFormat;
|
||||||
|
extern SDL_sem *Android_PauseSem, *Android_ResumeSem;
|
||||||
extern SDL_Window *Android_Window;
|
extern SDL_Window *Android_Window;
|
||||||
|
|
||||||
|
|
||||||
#endif /* _SDL_androidvideo_h */
|
#endif /* _SDL_androidvideo_h */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -35,6 +35,8 @@ Android_CreateWindow(_THIS, SDL_Window * window)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Android_Window = window;
|
Android_Window = window;
|
||||||
|
Android_PauseSem = SDL_CreateSemaphore(0);
|
||||||
|
Android_ResumeSem = SDL_CreateSemaphore(0);
|
||||||
|
|
||||||
/* Adjust the window data to match the screen */
|
/* Adjust the window data to match the screen */
|
||||||
window->x = 0;
|
window->x = 0;
|
||||||
|
@ -62,6 +64,10 @@ Android_DestroyWindow(_THIS, SDL_Window * window)
|
||||||
{
|
{
|
||||||
if (window == Android_Window) {
|
if (window == Android_Window) {
|
||||||
Android_Window = NULL;
|
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