summaryrefslogtreecommitdiffstats
path: root/opengl
diff options
context:
space:
mode:
authorJack Palevich <jackpal@google.com>2012-03-29 12:23:57 -0700
committerJack Palevich <jackpal@google.com>2012-03-29 12:23:57 -0700
commitdb6c78b5bdf264abe8f6de97f67ca5e90fb6a05a (patch)
treecf23eb1f3affd7590cc1ac34d8f53bd66d4814e7 /opengl
parentdb2026000a1d832b60d73e0a046bc8137fbb1960 (diff)
downloadframeworks_base-db6c78b5bdf264abe8f6de97f67ca5e90fb6a05a.zip
frameworks_base-db6c78b5bdf264abe8f6de97f67ca5e90fb6a05a.tar.gz
frameworks_base-db6c78b5bdf264abe8f6de97f67ca5e90fb6a05a.tar.bz2
Make GLSurfaceView handle eglSwapBuffers errors more robustly.
A careful reading of the EGL spec, as well as experience with many different EGL drivers, has shown that it is error prone to attempt to discriminate between different error conditions. We now treat any error besides EGL_CONTEXT_LOST as an indication that the EGL context is in a bad state, most likely due to the window manager having removed the underlying surface flinger surface. In addition, we changed the way we deal with this kind of error: Previously we would ignore the error and keep rendering. But if the EGL context and surface has become invalid, it would be better to stop drawing. We now stop drawing until the surface view surface is recreated. See b/6032663 for an example of this problem affecting the GMM app, but note that GMM is using their own version of GLSurfaceView, so this change won't help them directly. They'll have to make a similar change to their version of GLSurfaceView. Change-Id: Iffe3e1e3a3c7a91d03140fd34391eadeaecf777e Signed-off-by: Jack Palevich <jackpal@google.com>
Diffstat (limited to 'opengl')
-rw-r--r--opengl/java/android/opengl/GLSurfaceView.java65
1 files changed, 31 insertions, 34 deletions
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index f69fc53..b868049 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1130,36 +1130,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
/**
* Display the current render surface.
- * @return false if the context has been lost.
+ * @return the EGL error code from eglSwapBuffers.
*/
- public boolean swap() {
+ public int swap() {
if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
-
- /*
- * Check for EGL_CONTEXT_LOST, which means the context
- * and all associated data were lost (For instance because
- * the device went to sleep). We need to sleep until we
- * get a new surface.
- */
- int error = mEgl.eglGetError();
- switch(error) {
- case EGL11.EGL_CONTEXT_LOST:
- return false;
- case EGL10.EGL_BAD_CURRENT_SURFACE:
- // The current surface is bad, probably because the window manager has closed
- // the associated window. Ignore this error, on the assumption that the
- // application will be closed soon.
- break;
- case EGL10.EGL_BAD_NATIVE_WINDOW:
- // The native window is bad, probably because the window manager has closed it.
- // Ignore this error, on the assumption that the application will be closed
- // soon.
- break;
- default:
- throwEglException("eglSwapBuffers", error);
- }
+ return mEgl.eglGetError();
}
- return true;
+ return EGL10.EGL_SUCCESS;
}
public void destroySurface() {
@@ -1366,6 +1343,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
stopEglSurfaceLocked();
}
mWaitingForSurface = true;
+ mSurfaceIsBad = false;
sGLThreadManager.notifyAll();
}
@@ -1423,7 +1401,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
h = mHeight;
wantRenderNotification = true;
if (LOG_SURFACE) {
- Log.i("GLThread", "noticing that we want render notification tid=" + getId());
+ Log.i("GLThread",
+ "noticing that we want render notification tid="
+ + getId());
}
// Destroy and recreate the EGL surface.
@@ -1444,6 +1424,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
+ " mHaveEglSurface: " + mHaveEglSurface
+ " mPaused: " + mPaused
+ " mHasSurface: " + mHasSurface
+ + " mSurfaceIsBad: " + mSurfaceIsBad
+ " mWaitingForSurface: " + mWaitingForSurface
+ " mWidth: " + mWidth
+ " mHeight: " + mHeight
@@ -1509,11 +1490,26 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
view.mRenderer.onDrawFrame(gl);
}
}
- if (!mEglHelper.swap()) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "egl context lost tid=" + getId());
- }
- lostEglContext = true;
+ int swapError = mEglHelper.swap();
+ switch (swapError) {
+ case EGL10.EGL_SUCCESS:
+ break;
+ case EGL11.EGL_CONTEXT_LOST:
+ if (LOG_SURFACE) {
+ Log.i("GLThread", "egl context lost tid=" + getId());
+ }
+ lostEglContext = true;
+ break;
+ default:
+ // Other errors typically mean that the current surface is bad,
+ // probably because the surfaceview surface has been destroyed,
+ // but we haven't been notified yet.
+ // Log the error to help developers understand why rendering stopped.
+ Log.w("GLThread", "eglSwapBuffers error: " + swapError +
+ ". Assume surfaceview surface is being destroyed. tid="
+ + getId());
+ mSurfaceIsBad = true;
+ break;
}
if (wantRenderNotification) {
@@ -1537,7 +1533,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
private boolean readyToDraw() {
- return (!mPaused) && mHasSurface
+ return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
&& (mWidth > 0) && (mHeight > 0)
&& (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
}
@@ -1707,6 +1703,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private boolean mRequestPaused;
private boolean mPaused;
private boolean mHasSurface;
+ private boolean mSurfaceIsBad;
private boolean mWaitingForSurface;
private boolean mHaveEglContext;
private boolean mHaveEglSurface;