Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

The Android documentation says:

There are situations where the EGL rendering context will be lost. This typically happens when device wakes up after going to sleep. When the EGL context is lost, all OpenGL resources (such as textures) that are associated with that context will be automatically deleted. In order to keep rendering correctly, a renderer must recreate any lost resources that it still needs. The onSurfaceCreated(GL10, EGLConfig) method is a convenient place to do this.

But having to reload all the textures in the OpenGL context is both a pain and hurts the game experience for the user when reentering the app after a pause. I know that "Angry Birds" somehow avoids this, I'm looking for suggestions on how to accomplish the same?

I'm working with the Android NDK r5 (CrystaX version.) I did find this possible hack to the problem but I'm trying to avoid building an entire custom SDK version.

share|improve this question
    
sleeping and waking up is refered to device so while user just pause your game or switch processs it should loose any of the EGL context. –  Ali.S May 23 '11 at 16:00

4 Answers 4

up vote 18 down vote accepted

Replica Island has a modified version of GLSurfaceView that deals with this issue (and works with earlier Android versions). According to Chris Pruett:

Basically, I hacked up the original GLSurfaceView to solve a very specific problem: I wanted to go to different Activities within my app without throwing all of my OpenGL state away. The major change was to separate the EGLSurface from the EGLContext, and to throw the former away onPause(), but preserve the latter until the context is explicitly lost. The default implementation of GLSurfaceView (which I didn't write, by the way), throws all GL state away when the activity is paused, and calls onSurfaceCreated() when it is resumed. That meant that, when a dialog box popped up in my game, closing it incurred a delay because all the textures had to be reloaded.

You should use the default GLSurfaceView. If you must have the same functionality that mine has, you can look at mine. But doing what I did exposed all sorts of awful driver bugs in some handsets (see the very long comments near the end of that file), and you can avoid all that mess by just using the default one.

Edit: I just realized you already posted the link to a similar hack. I don't think there is any built-in solution prior to honeycomb. Replica Island is a popular game working on many devices and you might find Chris's implementation and comments helpful.

share|improve this answer
    
After trying various approaches to circumventing this, I've decided the best solution is just to recode the app to recreate the context. This is such a wasteful approach but it doesn't look like there's any good solution code.google.com/p/android/issues/detail?id=12774 –  Nick Gotch May 27 '11 at 18:14

I'd like to add another answer to this that was passed on to me a year or two back by Chris Pruett (Replica Island, Wind-Up Knight, etc). It's especially useful here in 2013 since setPreserveEglContextOnPause(true) doesn't seem to work on 4.3. (I could be wrong about that but that's how it looks to me right now as I update game code last touched in 2011).

Basically the trick is to detach your GLSurfaceView from the view hierarchy from your Activity's onPause(). Since it's not in the view hierarchy at the point onPause() runs, the context never gets destroyed.

So your Activity's onPause() should look like this:

@Override
public void onPause() {
    view.setVisibility(View.GONE);
    super.onPause();
    ...
}

And you restore your GLSurfaceView to the hierarchy not from onResume() but from onWindowFocusChanged() :

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && view.getVisibility() == View.GONE) {
         view.setVisibility(View.VISIBLE);
    }
    ...
}

Note that you never call the GLSurfaceView's onPause() and onResume() and that this is the official SDK GLSurfaceView, no hacked-up alternative version is required.

share|improve this answer
    
In fact this approach doesn't seem to work. Chris Pruett used it in combination with Unity, is it possible that this workaround is not working in native projects? But only not calling GLView.onPause() seems to work!? Are there others who can confirm this? –  sjkm Aug 15 at 18:22

Use honeycomb API. There is an option do preserve your OGL context. Otherwise, you need to reload your context. It is not difficult nor painful.

You need to understand that there is a two cases (Android 2.1):

  • Screen Pause: your application is always the front one => hack available
  • Application Pause: there is another front application => No Solution

Note: old android gpus don't support multi context. So the opengl context is lost when you switch to another application => no solution available (You can hack to preserve your context on screen pause).

Note 2: HoneyComb function is setPreserveEGLContextOnPause

share|improve this answer
    
I'm porting an C++ game to the Android NDK which isn't designed to reload the context easily, so at least for me it is somewhat difficult. Difficulties aside, reloading textures will introduce a delay which isn't present on our other devices (iPhone, PSP, DS, etc..) Glad to hear honeycomb fixes this but unfortunately we need to support 2.1+ –  Nick Gotch May 23 '11 at 21:57
1  
This does not answer his question at all. –  stephelton May 23 '11 at 22:48
1  
If you don't understand, you can't do it. –  Ellis May 24 '11 at 5:54

< rant > I spent a huge amount of time on this problem, I tried many different solutions and none worked until today, I think this is one of the most awful design decision I even seen, but coming from the Android team I'm not really surprised. < /rant >

So, the solution is to move the eglContext member upwards and make it static (global) so it won't be destroyed, then you simply have to check if it's null or not before creating it again.

So far this solution seems to works for us, and we don't care if it breaks on 2005 devices.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.