开发者

Prevent onPause from trashing OpenGL Context

I'm writing an Android a开发者_JAVA百科pplication 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.


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.


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);


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


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜