summaryrefslogtreecommitdiffstats
path: root/opengl
diff options
context:
space:
mode:
authorJack Palevich <jackpal@google.com>2009-11-10 18:11:04 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2009-11-10 18:11:04 -0800
commitcbce240a0d64f4e3ae52aadf233c708a759a7ecb (patch)
treeea5e2e9738a548a0a5eb05c14f65e0b9f2cd4bf6 /opengl
parentebb8d3bcf7c5559034091e4609d8ddccae2c2a1a (diff)
parent99cf71b0856e00c1ae9631db91702349cceb9bf8 (diff)
downloadframeworks_base-cbce240a0d64f4e3ae52aadf233c708a759a7ecb.zip
frameworks_base-cbce240a0d64f4e3ae52aadf233c708a759a7ecb.tar.gz
frameworks_base-cbce240a0d64f4e3ae52aadf233c708a759a7ecb.tar.bz2
am 99cf71b0: am 83536cee: Merge change I1179efbb into eclair-mr2
Merge commit '99cf71b0856e00c1ae9631db91702349cceb9bf8' * commit '99cf71b0856e00c1ae9631db91702349cceb9bf8': Fix multi-lock ordering issues in GLSurfaceView
Diffstat (limited to 'opengl')
-rw-r--r--opengl/java/android/opengl/GLSurfaceView.java297
1 files changed, 158 insertions, 139 deletions
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index bb90ef8..8cc0f6f 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -955,6 +955,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* to a Renderer instance to do the actual drawing. Can be configured to
* render continuously or on request.
*
+ * All potentially blocking synchronization is done through the
+ * sGLThreadManager object. This avoids multiple-lock ordering issues.
+ *
*/
class GLThread extends Thread {
GLThread(Renderer renderer) {
@@ -974,51 +977,31 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
Log.i("GLThread", "starting tid=" + getId());
}
- /*
- * When the android framework launches a second instance of
- * an activity, the new instance's onCreate() method may be
- * called before the first instance returns from onDestroy().
- *
- * This semaphore ensures that only one instance at a time
- * accesses EGL.
- */
try {
guardedRun();
} catch (InterruptedException e) {
// fall thru and exit normally
} finally {
- synchronized(this) {
- if (LOG_THREADS) {
- Log.i("GLThread", "exiting tid=" + getId());
- }
- mDone = true;
- notifyAll();
- }
+ sGLThreadManager.threadExiting(this);
}
}
- private void startEgl() throws InterruptedException {
- if (! mHaveEgl) {
- mHaveEgl = true;
- sGLThreadManager.start(this);
- mEglHelper.start();
- }
- }
-
- private void stopEgl() {
+ /*
+ * This private method should only be called inside a
+ * synchronized(sGLThreadManager) block.
+ */
+ private void stopEglLocked() {
if (mHaveEgl) {
mHaveEgl = false;
mEglHelper.destroySurface();
mEglHelper.finish();
- sGLThreadManager.end(this);
+ sGLThreadManager.releaseEglSurface(this);
}
}
private void guardedRun() throws InterruptedException {
mEglHelper = new EglHelper();
try {
- startEgl();
-
GL10 gl = null;
boolean tellRendererSurfaceCreated = true;
boolean tellRendererSurfaceChanged = true;
@@ -1027,63 +1010,97 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* This is our main activity thread's loop, we go until
* asked to quit.
*/
- while (!mDone) {
-
+ while (!isDone()) {
/*
* Update the asynchronous state (window size)
*/
- int w, h;
- boolean changed;
+ int w = 0;
+ int h = 0;
+ boolean changed = false;
boolean needStart = false;
- synchronized (this) {
- Runnable r;
- while ((r = getEvent()) != null) {
- r.run();
- }
- if (mPaused) {
- stopEgl();
- needStart = true;
- }
- while(true) {
+ boolean eventsWaiting = false;
+
+ synchronized (sGLThreadManager) {
+ while (true) {
+ // Manage acquiring and releasing the SurfaceView
+ // surface and the EGL surface.
+ if (mPaused) {
+ stopEglLocked();
+ }
if (!mHasSurface) {
if (!mWaitingForSurface) {
- stopEgl();
+ stopEglLocked();
mWaitingForSurface = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
} else {
- boolean shouldHaveEgl = sGLThreadManager.shouldHaveEgl(this);
- if (mHaveEgl && (!shouldHaveEgl)) {
- stopEgl();
- } else if ((!mHaveEgl) && shouldHaveEgl) {
- startEgl();
- needStart = true;
+ if (!mHaveEgl) {
+ if (sGLThreadManager.tryAcquireEglSurface(this)) {
+ mHaveEgl = true;
+ mEglHelper.start();
+ mRequestRender = true;
+ needStart = true;
+ }
}
}
- if (!needToWait()) {
+
+ // Check if we need to wait. If not, update any state
+ // that needs to be updated, copy any state that
+ // needs to be copied, and use "break" to exit the
+ // wait loop.
+
+ if (mDone) {
+ return;
+ }
+
+ if (mEventsWaiting) {
+ eventsWaiting = true;
+ mEventsWaiting = false;
+ break;
+ }
+
+ if ( (! mPaused) && mHasSurface && mHaveEgl
+ && (mWidth > 0) && (mHeight > 0)
+ && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))
+ ) {
+ changed = mSizeChanged;
+ w = mWidth;
+ h = mHeight;
+ mSizeChanged = false;
+ mRequestRender = false;
+ if (mHasSurface && mWaitingForSurface) {
+ changed = true;
+ mWaitingForSurface = false;
+ sGLThreadManager.notifyAll();
+ }
break;
}
+
+ // By design, this is the only place where we wait().
+
if (LOG_THREADS) {
- Log.i("GLThread", "needToWait tid=" + getId());
+ Log.i("GLThread", "waiting tid=" + getId());
}
- wait();
- }
- if (mDone) {
- break;
+ sGLThreadManager.wait();
}
- changed = mSizeChanged;
- w = mWidth;
- h = mHeight;
- mSizeChanged = false;
- mRequestRender = false;
- if (mHasSurface && mWaitingForSurface) {
- changed = true;
- mWaitingForSurface = false;
- notifyAll();
+ } // end of synchronized(sGLThreadManager)
+
+ /*
+ * Handle queued events
+ */
+ if (eventsWaiting) {
+ Runnable r;
+ while ((r = getEvent()) != null) {
+ r.run();
+ if (isDone()) {
+ return;
+ }
}
+ // Go back and see if we need to wait to render.
+ continue;
}
+
if (needStart) {
- startEgl();
tellRendererSurfaceCreated = true;
changed = true;
}
@@ -1115,71 +1132,63 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
/*
* clean-up everything...
*/
- stopEgl();
+ synchronized (sGLThreadManager) {
+ stopEglLocked();
+ }
}
}
- private boolean needToWait() {
- if (mDone) {
- return false;
+ private boolean isDone() {
+ synchronized (sGLThreadManager) {
+ return mDone;
}
-
- if (mPaused || (! mHasSurface) || (! mHaveEgl)) {
- return true;
- }
-
- if ((mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) {
- return false;
- }
-
- return true;
}
public void setRenderMode(int renderMode) {
if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
throw new IllegalArgumentException("renderMode");
}
- synchronized(this) {
+ synchronized(sGLThreadManager) {
mRenderMode = renderMode;
if (renderMode == RENDERMODE_CONTINUOUSLY) {
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
}
public int getRenderMode() {
- synchronized(this) {
+ synchronized(sGLThreadManager) {
return mRenderMode;
}
}
public void requestRender() {
- synchronized(this) {
+ synchronized(sGLThreadManager) {
mRequestRender = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void surfaceCreated() {
- synchronized(this) {
+ synchronized(sGLThreadManager) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceCreated tid=" + getId());
}
mHasSurface = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void surfaceDestroyed() {
- synchronized(this) {
+ synchronized(sGLThreadManager) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceDestroyed tid=" + getId());
}
mHasSurface = false;
- notifyAll();
+ sGLThreadManager.notifyAll();
while(!mWaitingForSurface && isAlive() && ! mDone) {
try {
- wait();
+ sGLThreadManager.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
@@ -1188,35 +1197,35 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
public void onPause() {
- synchronized (this) {
+ synchronized (sGLThreadManager) {
mPaused = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void onResume() {
- synchronized (this) {
+ synchronized (sGLThreadManager) {
mPaused = false;
mRequestRender = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void onWindowResize(int w, int h) {
- synchronized (this) {
+ synchronized (sGLThreadManager) {
mWidth = w;
mHeight = h;
mSizeChanged = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void requestExitAndWait() {
// don't call this from GLThread thread or it is a guaranteed
// deadlock!
- synchronized(this) {
+ synchronized(sGLThreadManager) {
mDone = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
try {
join();
@@ -1232,6 +1241,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
public void queueEvent(Runnable r) {
synchronized(this) {
mEventQueue.add(r);
+ synchronized(sGLThreadManager) {
+ mEventsWaiting = true;
+ sGLThreadManager.notifyAll();
+ }
}
}
@@ -1245,6 +1258,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
return null;
}
+ // Once the thread is started, all accesses to the following member
+ // variables are protected by the sGLThreadManager monitor
private boolean mDone;
private boolean mPaused;
private boolean mHasSurface;
@@ -1254,6 +1269,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private int mHeight;
private int mRenderMode;
private boolean mRequestRender;
+ private boolean mEventsWaiting;
+ // End of member variables protected by the sGLThreadManager monitor.
+
private Renderer mRenderer;
private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
private EglHelper mEglHelper;
@@ -1300,58 +1318,46 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
private static class GLThreadManager {
- public boolean shouldHaveEgl(GLThread thread) {
- if (mMultipleGLESContextsAllowed) {
- return true;
- } else {
- synchronized(this) {
- return thread == mMostRecentGLThread || mMostRecentGLThread == null;
- }
- }
- }
- public void start(GLThread thread) throws InterruptedException {
- if (! mGLESVersionCheckComplete) {
- mGLESVersion = SystemProperties.getInt(
- "ro.opengles.version",
- ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
- if (mGLESVersion >= kGLES_20) {
- mMultipleGLESContextsAllowed = true;
- }
- mGLESVersionCheckComplete = true;
- }
-
- GLThread oldThread = null;
- synchronized(this) {
- oldThread = mMostRecentGLThread;
- mMostRecentGLThread = thread;
+ public synchronized void threadExiting(GLThread thread) {
+ if (LOG_THREADS) {
+ Log.i("GLThread", "exiting tid=" + thread.getId());
}
- if (oldThread != null && ! mMultipleGLESContextsAllowed) {
- synchronized(oldThread) {
- oldThread.notifyAll();
- }
+ thread.mDone = true;
+ if (mEglOwner == thread) {
+ mEglOwner = null;
}
+ notifyAll();
+ }
- synchronized(this) {
- while ((! mMultipleGLESContextsAllowed)
- && mGLContextCount > 0) {
- wait();
- }
-
- mGLContextCount++;
+ /*
+ * Tries to acquire the right to use an EGL
+ * surface. Does not block.
+ * @return true if the right to use an EGL surface was acquired.
+ */
+ public synchronized boolean tryAcquireEglSurface(GLThread thread) {
+ if (mEglOwner == thread || mEglOwner == null) {
+ mEglOwner = thread;
+ notifyAll();
+ return true;
+ }
+ checkGLESVersion();
+ if (mMultipleGLESContextsAllowed) {
+ return true;
}
+ return false;
}
- public synchronized void end(GLThread thread) {
- mGLContextCount--;
- notifyAll();
- if (mMostRecentGLThread == thread) {
- mMostRecentGLThread = null;
+ public synchronized void releaseEglSurface(GLThread thread) {
+ if (mEglOwner == thread) {
+ mEglOwner = null;
}
+ notifyAll();
}
public synchronized void checkGLDriver(GL10 gl) {
if (! mGLESDriverCheckComplete) {
+ checkGLESVersion();
if (mGLESVersion < kGLES_20) {
String renderer = gl.glGetString(GL10.GL_RENDERER);
mMultipleGLESContextsAllowed =
@@ -1362,16 +1368,29 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
}
+ private void checkGLESVersion() {
+ if (! mGLESVersionCheckComplete) {
+ mGLESVersion = SystemProperties.getInt(
+ "ro.opengles.version",
+ ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
+ if (mGLESVersion >= kGLES_20) {
+ mMultipleGLESContextsAllowed = true;
+ }
+ mGLESVersionCheckComplete = true;
+ }
+
+ }
+
private boolean mGLESVersionCheckComplete;
private int mGLESVersion;
- private GLThread mMostRecentGLThread;
private boolean mGLESDriverCheckComplete;
private boolean mMultipleGLESContextsAllowed;
private int mGLContextCount;
private static final int kGLES_20 = 0x20000;
private static final String kMSM7K_RENDERER_PREFIX =
"Q3Dimension MSM7500 ";
- };
+ private GLThread mEglOwner;
+ }
private static final GLThreadManager sGLThreadManager = new GLThreadManager();
private boolean mSizeChanged = true;