Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent onPause from trashing OpenGL Context

Tags:

I'm writing an Android application that uses OpenGL ES (GLSurfaceView and GLSurfaceView.Renderer). The problem is that when the user switches applications and then switches back to my app, the GLSurfaceView destroys and recreates the GL context. This is what it's supposed to do according to the documentation but is there a way to prevent this from happening?

It takes a long time to load textures into the context and i'd like to prevent having to reload them.

like image 750
cjserio Avatar asked Jan 21 '10 20:01

cjserio


2 Answers

I think what you are looking for is discussed in the GLSurfaceView documentation:

A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView clients are required to call onPause() when the activity pauses and onResume() when the activity resumes. These calls allow GLSurfaceView to pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate the OpenGL display.

When using the standard Android SDK, you must release/recreate your context whenever the activity is paused/resumed (including screen orientation changes). Not doing so will cause the GL context to be release and not restored when the activity is loaded back into memory. Remember that we are dealing with very limited resources (particularly on low-spec devices). So the short answer is: you can't prevent it without breaking your app.

Assuming you are using the standard Android/OpenGL framework, you need to do the following...

In your activity, ensure you have the following overridden methods:

public void onPause() {     myGlSurfaceView.onPause(); }  public void onResume() {     myGlSurfaceView.onResume(); } 

Anything you hold outside the GL environment will still need to be preserved and restored manually however (bitmaps, game state, etc), for these you'll need to use static fields or a mechanism like SharedPreferences.

Update

Android 3.x provides a function to preserve the GL context on pause without needing to be recreated. However, there are several caveats:

  1. Android 3.x features are not available to approx. 90% of devices on the market at this time
  2. The devices must also support multiple EGL contexts, it is unclear how many devices on the market currently support this.

Using some API reflection to check capabilities, it may be possible to make use of this function on supporting devices. However, you would still need to fall back to recreating the context for the rest. In my opinion, until more devices run Android 3 it would be better to hold off using setPreserveEGLContextOnPause and focus on ensuring the context recreation approach is sufficiently tested.

like image 140
seanhodges Avatar answered Dec 19 '22 17:12

seanhodges


As mentioned in a comment above it is also possible to avoid trashing the GL context earlier Android releases (1.x, 2.x), the solution is to copy the GLSurfaceView from Android-15 SDK source code, change its package name, and then use your own copy of the GlSurfaceView.

It should work for devices which support multiple GL contexts (except for Adreno chips, at the moment), regardless of Android version. A caveat is that GLSurfaceView from Android-15 only contains the necessary stuff to work with android-15, our version must handle all OS-versions.

We use our own implemention of the GlSurfaceView based on a copy from ReplicaIsland, where Chriss Pruit also used his own implementation.

In our version we added the setPreserveEGLContextOnPause from SDK-15, which allows to preserve GL context on for instance a nexus one running android 2.3.

We have also changed other stuff to suit our needs, which is not relevant for this question (such as 32-bit rendering on phones which support it, otherwise 16bit).

Our GlSurfaceView: http://pastebin.com/U4x5JjAr

Here is the original SDK-15 version of the GlSurfaceView formatted by same (Android) style as above http://pastebin.com/hziRmB3E (so that it is easy to compare and see the changes)

Remember to enable the context preservation by calling:

    glSurfaceView.setPreserveEGLContextOnPause(true); 
like image 39
arberg Avatar answered Dec 19 '22 18:12

arberg