summaryrefslogtreecommitdiffstats
path: root/opengl
diff options
context:
space:
mode:
authorJack Palevich <jackpal@google.com>2010-07-13 19:09:37 -0700
committerJack Palevich <jackpal@google.com>2010-07-13 19:09:37 -0700
commit1b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6 (patch)
tree19f69c9eabca7460fb55801da2b106c6d8036f7d /opengl
parent70c6c9a1e2240e82d8eb442b34efa9629ef2bba4 (diff)
downloadframeworks_base-1b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6.zip
frameworks_base-1b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6.tar.gz
frameworks_base-1b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6.tar.bz2
Fix deadlock when switching between two GLSurfaceViews
Some devices only support a single active EGL context. On those devices, when a second activity that uses a GLSurfaceView is started in the same process, the second activity can potentially hang in GLSurfaceView.onWindowResize waiting for its GLSurfaceView render thread to draw a frame. The second activity's render thread is waiting to acquire an EGL context, but the first activity's render thread doesn't know it should release the EGL context. The fix is to detect the potential hang, and ask the first activity's render thread to release the EGL context. Change-Id: Ibb342c68772297744c973bcf5010581cd132db67
Diffstat (limited to 'opengl')
-rw-r--r--opengl/java/android/opengl/GLSurfaceView.java92
1 files changed, 74 insertions, 18 deletions
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 2ff231d..41207f7 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -222,6 +222,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
// underlying surface is created and destroyed
SurfaceHolder holder = getHolder();
holder.addCallback(this);
+ // setFormat is done by SurfaceView in SDK 2.3 and newer. Uncomment
+ // this statement if back-porting to 2.2 or older:
+ // holder.setFormat(PixelFormat.RGB_565);
+ //
// setType is not needed for SDK 2.0 or newer. Uncomment this
// statement if back-porting this code to older SDKs.
// holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
@@ -1103,7 +1107,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
mRenderer = renderer;
}
-
@Override
public void run() {
setName("GLThread " + getId());
@@ -1154,6 +1157,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
boolean sizeChanged = false;
boolean wantRenderNotification = false;
boolean doRenderNotification = false;
+ boolean askedToReleaseEglContext = false;
int w = 0;
int h = 0;
Runnable event = null;
@@ -1179,6 +1183,17 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
}
+ // Do we need to give up the EGL context?
+ if (mShouldReleaseEglContext) {
+ if (LOG_SURFACE) {
+ Log.i("GLThread", "releasing EGL context because asked to tid=" + getId());
+ }
+ stopEglSurfaceLocked();
+ stopEglContextLocked();
+ mShouldReleaseEglContext = false;
+ askedToReleaseEglContext = true;
+ }
+
// Have we lost the EGL context?
if (lostEglContext) {
stopEglSurfaceLocked();
@@ -1228,6 +1243,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
if (doRenderNotification) {
+ if (LOG_SURFACE) {
+ Log.i("GLThread", "sending render notification tid=" + getId());
+ }
wantRenderNotification = false;
doRenderNotification = false;
mRenderComplete = true;
@@ -1235,22 +1253,24 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
// Ready to draw?
- if ((!mPaused) && mHasSurface
- && (mWidth > 0) && (mHeight > 0)
- && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) {
+ if (readyToDraw()) {
// If we don't have an EGL context, try to acquire one.
- if ((! mHaveEglContext) && sGLThreadManager.tryAcquireEglContextLocked(this)) {
- try {
- mEglHelper.start();
- } catch (RuntimeException t) {
- sGLThreadManager.releaseEglContextLocked(this);
- throw t;
- }
- mHaveEglContext = true;
- createEglContext = true;
+ if (! mHaveEglContext) {
+ if (askedToReleaseEglContext) {
+ askedToReleaseEglContext = false;
+ } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) {
+ try {
+ mEglHelper.start();
+ } catch (RuntimeException t) {
+ sGLThreadManager.releaseEglContextLocked(this);
+ throw t;
+ }
+ mHaveEglContext = true;
+ createEglContext = true;
- sGLThreadManager.notifyAll();
+ sGLThreadManager.notifyAll();
+ }
}
if (mHaveEglContext && !mHaveEglSurface) {
@@ -1265,6 +1285,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
w = mWidth;
h = mHeight;
wantRenderNotification = true;
+ if (LOG_SURFACE) {
+ Log.i("GLThread", "noticing that we want render notification tid=" + getId());
+ }
if (DRAW_TWICE_AFTER_SIZE_CHANGED) {
// We keep mRequestRender true so that we draw twice after the size changes.
@@ -1284,7 +1307,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
// By design, this is the only place in a GLThread thread where we wait().
if (LOG_THREADS) {
- Log.i("GLThread", "waiting tid=" + getId());
+ Log.i("GLThread", "waiting tid=" + getId()
+ + " mHaveEglContext: " + mHaveEglContext
+ + " mHaveEglSurface: " + mHaveEglSurface
+ + " mPaused: " + mPaused
+ + " mHasSurface: " + mHasSurface
+ + " mWaitingForSurface: " + mWaitingForSurface
+ + " mWidth: " + mWidth
+ + " mHeight: " + mHeight
+ + " mRequestRender: " + mRequestRender
+ + " mRenderMode: " + mRenderMode);
}
sGLThreadManager.wait();
}
@@ -1326,7 +1358,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
if (LOG_RENDERER_DRAW_FRAME) {
- Log.w("GLThread", "onDrawFrame");
+ Log.w("GLThread", "onDrawFrame tid=" + getId());
}
mRenderer.onDrawFrame(gl);
if (!mEglHelper.swap()) {
@@ -1352,6 +1384,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
}
+ public boolean ableToDraw() {
+ return mHaveEglContext && mHaveEglSurface && readyToDraw();
+ }
+
+ private boolean readyToDraw() {
+ return (!mPaused) && mHasSurface
+ && (mWidth > 0) && (mHeight > 0)
+ && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
+ }
+
public void setRenderMode(int renderMode) {
if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
throw new IllegalArgumentException("renderMode");
@@ -1461,9 +1503,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
sGLThreadManager.notifyAll();
// Wait for thread to react to resize and render a frame
- while (! mExited && !mPaused && !mRenderComplete ) {
+ while (! mExited && !mPaused && !mRenderComplete
+ && (mGLThread != null && mGLThread.ableToDraw())) {
if (LOG_SURFACE) {
- Log.i("Main thread", "onWindowResize waiting for render complete.");
+ Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + mGLThread.getId());
}
try {
sGLThreadManager.wait();
@@ -1490,6 +1533,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
}
+ public void requestReleaseEglContextLocked() {
+ mShouldReleaseEglContext = true;
+ sGLThreadManager.notifyAll();
+ }
+
/**
* Queue an "event" to be run on the GL rendering thread.
* @param r the runnable to be run on the GL rendering thread.
@@ -1514,6 +1562,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private boolean mWaitingForSurface;
private boolean mHaveEglContext;
private boolean mHaveEglSurface;
+ private boolean mShouldReleaseEglContext;
private int mWidth;
private int mHeight;
private int mRenderMode;
@@ -1598,6 +1647,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
if (mMultipleGLESContextsAllowed) {
return true;
}
+ // Notify the owning thread that it should release the context.
+ // TODO: implement a fairness policy. Currently
+ // if the owning thread is drawing continuously it will just
+ // reacquire the EGL context.
+ if (mEglOwner != null) {
+ mEglOwner.requestReleaseEglContextLocked();
+ }
return false;
}