24

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.

cjserio
  • 2,857
  • 7
  • 29
  • 29

4 Answers4

19

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.

seanhodges
  • 17,426
  • 15
  • 71
  • 93
  • 6
    This would be the exact opposite of what the OP asked; he/she asked how NOT to have to reload textures, not how to kill and restore the OpenGL context. The way to prevent it from happening might be to NOT do what you suggest, in fact. – SomeCallMeTim Nov 29 '10 at 21:03
  • 1
    @SomeCallMeTim good point except from one small fact: you MUST do it. The doc I quoted states: "A GLSurfaceView *must* be notified when the activity is paused and resumed.". My solution implicitly states that the context has to be notified of the pause/resume. If you don't it will fail to recreate the context when the activity is redrawn. This wasn't clear though; I will make it more obvious in my text. – seanhodges Dec 13 '10 at 10:08
  • 1
    I see. Sigh. Frustrating; Android seems to be carefully designed to give users the worst possible experience when playing games. It's sad, really. Thanks for making me dig into this a bit more, by the way; it will likely save me some tears later on. – SomeCallMeTim Dec 13 '10 at 16:55
  • 1
    @SomeCallMeTim keep an eye on the improvements coming in Android 2.3, in particular the OpenGL API improvements and native access to Activity lifecycle: http://developer.android.com/sdk/android-2.3-highlights.html#gaming. I haven't had chance to play with them yet, but as long as backwards-compatibility isn't an issue you might find life a lot easier with the 2.3 SDK... – seanhodges Dec 14 '10 at 14:46
  • In about 3 years, I'm guessing, it will be time for me to target 2.3; I'll read more details about what it offers as that time grows near. ;) I'm currently aiming for 1.6. I want the largest number of users possible to be able to use my apps; I'd want to see AT LEAST 75% of active users on 2.3 before I'd even consider it. But thanks for the note. Now I know what to look forward to a few years out. :) – SomeCallMeTim Dec 21 '10 at 20:22
  • Actually it is also possible to avoid trashing the GL context on Android 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. More on this in 10 minutes... – arberg Jun 19 '12 at 10:13
  • Continuation: It should work for devices which support multiple GL contexts (except for Adreno chips), 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. I could supply my version of the view if I knew a good place to put it. Also, see ReplicaIsland (and upgrade it to api-15). – arberg Jun 19 '12 at 10:53
  • @arberg an interesting concept, could you post your solution (and example view) as a new answer? Or alternatively post it on pastebin.com and link to it here? I would like to try it out... – seanhodges Jun 19 '12 at 19:38
8

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);
arberg
  • 4,148
  • 4
  • 31
  • 39
  • Wow thank you so much for sharing your glsurfaceview. I've been stuck on this for countless hours wondering why my implementation of Chris Pruit's glsurfaceview kept tossing the EGL context (until I finally realized in his version he also tosses the EGL context on all onPause calls) but is more efficient in what textures he reloads. I'll learn from your code, thanks! – YumeApps Oct 19 '12 at 01:53
  • @arberg: I know this answer is quite old by now but I still have a question: Could this cause a crash when there is no memory left on old low-mem devices? – sjkm Jul 12 '14 at 19:20
  • @sjkm: It cannot cause a memory crash, as the memory consumed is the same while game is on screen. When game is off screen then it won't 'crash' (assuming the game isn't looping in the background) but is subject to be killed by OS. If the context is preserved, then the app will continue to use the memory consumed by GL until killed by OS. Which I think means that the app will be much more likely to be killed while in the background because it uses much more memory. – arberg Jul 14 '14 at 09:00
  • @arberg Thank you very much for getting back to me! Interesting, so you never encountered any issues with your implementation? If not, why isn't this part of the android 2.3 os? – sjkm Jul 14 '14 at 12:09
  • @sjkm: It might not be part of 2.3 because it was not on the roadmap for that release, I have no clue. Also likely cause is that it uses more memory when in backgronud, and esp old devices had less memory. We use this and have many users, but users don't report that frequently anymore, it has to be a grave issue for users to go to the review/email page these days, so it might cause issues for some. I have not encountered a (test) device where it caused a problem. Note some GPUs like Mali-400 does not support it, it does not crash but does not save context. – arberg Jul 15 '14 at 07:19
  • @arberg Good afternoon. Thank you for the detailed info. I really appreciate your help! Sounds great - I'm probably going to use your implementation. When the context is lost then I reload the textures and restore the game state anyway but its nice when some more users don't have to wait due to the reloading! Have a nice day – sjkm Jul 15 '14 at 11:44
3

Since API level 11, you can specify whether or not your context must be preserved.

From the doc :

public void setPreserveEGLContextOnPause (boolean preserveOnPause) Since: API Level 11

Control whether the EGL context is preserved when the GLSurfaceView is paused and resumed.

If set to true, then the EGL context may be preserved when the GLSurfaceView is paused. Whether the EGL context is actually preserved or not depends upon whether the Android device that the program is running on can support an arbitrary number of EGL contexts or not. Devices that can only support a limited number of EGL contexts must release the EGL context in order to allow multiple applications to share the GPU.

If set to false, the EGL context will be released when the GLSurfaceView is paused, and recreated when the GLSurfaceView is resumed.

The default is false.

Parameters preserveOnPause preserve the EGL context when paused

rockeye
  • 2,765
  • 2
  • 30
  • 44
  • I've found out that setPreserveEGLContextOnPause sometimes just doesn't work though available. – Vladimir Sep 18 '13 at 14:28
  • 2
    You are right. That why Google carefully put the "may" : "If set to true, then the EGL context *may* be preserved when the GLSurfaceView is paused" – rockeye Oct 01 '13 at 08:33
0

It's been a while since I worked with OpenGL and it was the standard sort on desktop pc's, but I seem to remember standard OpenGL doesn't require a reload of textures on context switch. Of course, that doesn't really help in this case.

Assuming the textures have to be reloaded, the question becomes: how do you speed this up? And then the question becomes, just how many textures do you need at any one time and can you load them on demand? What are their dimensions? I recall that powers of two were usually faster to load, though that may also depend on the OpenGL implementation and drivers.

I've also heard about keeping a context somewhere where it won't get destroyed, somewhat like this thread: opengles view switching problem

Community
  • 1
  • 1
GenericMeatUnit
  • 477
  • 4
  • 9