Merge change I1179efbb into eclair-mr2

* changes:
  resolved conflicts for merge of ba56915a to eclair-mr2
This commit is contained in:
Android (Google) Code Review
2009-11-10 18:03:35 -08:00

View File

@@ -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 * to a Renderer instance to do the actual drawing. Can be configured to
* render continuously or on request. * 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 { class GLThread extends Thread {
GLThread(Renderer renderer) { GLThread(Renderer renderer) {
@@ -974,51 +977,31 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
Log.i("GLThread", "starting tid=" + getId()); 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 { try {
guardedRun(); guardedRun();
} catch (InterruptedException e) { } catch (InterruptedException e) {
// fall thru and exit normally // fall thru and exit normally
} finally { } finally {
synchronized(this) { sGLThreadManager.threadExiting(this);
if (LOG_THREADS) {
Log.i("GLThread", "exiting tid=" + getId());
}
mDone = true;
notifyAll();
}
} }
} }
private void startEgl() throws InterruptedException { /*
if (! mHaveEgl) { * This private method should only be called inside a
mHaveEgl = true; * synchronized(sGLThreadManager) block.
sGLThreadManager.start(this); */
mEglHelper.start(); private void stopEglLocked() {
}
}
private void stopEgl() {
if (mHaveEgl) { if (mHaveEgl) {
mHaveEgl = false; mHaveEgl = false;
mEglHelper.destroySurface(); mEglHelper.destroySurface();
mEglHelper.finish(); mEglHelper.finish();
sGLThreadManager.end(this); sGLThreadManager.releaseEglSurface(this);
} }
} }
private void guardedRun() throws InterruptedException { private void guardedRun() throws InterruptedException {
mEglHelper = new EglHelper(); mEglHelper = new EglHelper();
try { try {
startEgl();
GL10 gl = null; GL10 gl = null;
boolean tellRendererSurfaceCreated = true; boolean tellRendererSurfaceCreated = true;
boolean tellRendererSurfaceChanged = 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 * This is our main activity thread's loop, we go until
* asked to quit. * asked to quit.
*/ */
while (!mDone) { while (!isDone()) {
/* /*
* Update the asynchronous state (window size) * Update the asynchronous state (window size)
*/ */
int w, h; int w = 0;
boolean changed; int h = 0;
boolean changed = false;
boolean needStart = false; boolean needStart = false;
synchronized (this) { 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) {
stopEglLocked();
mWaitingForSurface = true;
sGLThreadManager.notifyAll();
}
} else {
if (!mHaveEgl) {
if (sGLThreadManager.tryAcquireEglSurface(this)) {
mHaveEgl = true;
mEglHelper.start();
mRequestRender = true;
needStart = true;
}
}
}
// 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", "waiting tid=" + getId());
}
sGLThreadManager.wait();
}
} // end of synchronized(sGLThreadManager)
/*
* Handle queued events
*/
if (eventsWaiting) {
Runnable r; Runnable r;
while ((r = getEvent()) != null) { while ((r = getEvent()) != null) {
r.run(); r.run();
} if (isDone()) {
if (mPaused) { return;
stopEgl();
needStart = true;
}
while(true) {
if (!mHasSurface) {
if (!mWaitingForSurface) {
stopEgl();
mWaitingForSurface = true;
notifyAll();
}
} else {
boolean shouldHaveEgl = sGLThreadManager.shouldHaveEgl(this);
if (mHaveEgl && (!shouldHaveEgl)) {
stopEgl();
} else if ((!mHaveEgl) && shouldHaveEgl) {
startEgl();
needStart = true;
}
} }
if (!needToWait()) {
break;
}
if (LOG_THREADS) {
Log.i("GLThread", "needToWait tid=" + getId());
}
wait();
}
if (mDone) {
break;
}
changed = mSizeChanged;
w = mWidth;
h = mHeight;
mSizeChanged = false;
mRequestRender = false;
if (mHasSurface && mWaitingForSurface) {
changed = true;
mWaitingForSurface = false;
notifyAll();
} }
// Go back and see if we need to wait to render.
continue;
} }
if (needStart) { if (needStart) {
startEgl();
tellRendererSurfaceCreated = true; tellRendererSurfaceCreated = true;
changed = true; changed = true;
} }
@@ -1115,71 +1132,63 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
/* /*
* clean-up everything... * clean-up everything...
*/ */
stopEgl(); synchronized (sGLThreadManager) {
stopEglLocked();
}
} }
} }
private boolean needToWait() { private boolean isDone() {
if (mDone) { synchronized (sGLThreadManager) {
return false; 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) { public void setRenderMode(int renderMode) {
if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) { if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
throw new IllegalArgumentException("renderMode"); throw new IllegalArgumentException("renderMode");
} }
synchronized(this) { synchronized(sGLThreadManager) {
mRenderMode = renderMode; mRenderMode = renderMode;
if (renderMode == RENDERMODE_CONTINUOUSLY) { if (renderMode == RENDERMODE_CONTINUOUSLY) {
notifyAll(); sGLThreadManager.notifyAll();
} }
} }
} }
public int getRenderMode() { public int getRenderMode() {
synchronized(this) { synchronized(sGLThreadManager) {
return mRenderMode; return mRenderMode;
} }
} }
public void requestRender() { public void requestRender() {
synchronized(this) { synchronized(sGLThreadManager) {
mRequestRender = true; mRequestRender = true;
notifyAll(); sGLThreadManager.notifyAll();
} }
} }
public void surfaceCreated() { public void surfaceCreated() {
synchronized(this) { synchronized(sGLThreadManager) {
if (LOG_THREADS) { if (LOG_THREADS) {
Log.i("GLThread", "surfaceCreated tid=" + getId()); Log.i("GLThread", "surfaceCreated tid=" + getId());
} }
mHasSurface = true; mHasSurface = true;
notifyAll(); sGLThreadManager.notifyAll();
} }
} }
public void surfaceDestroyed() { public void surfaceDestroyed() {
synchronized(this) { synchronized(sGLThreadManager) {
if (LOG_THREADS) { if (LOG_THREADS) {
Log.i("GLThread", "surfaceDestroyed tid=" + getId()); Log.i("GLThread", "surfaceDestroyed tid=" + getId());
} }
mHasSurface = false; mHasSurface = false;
notifyAll(); sGLThreadManager.notifyAll();
while(!mWaitingForSurface && isAlive() && ! mDone) { while(!mWaitingForSurface && isAlive() && ! mDone) {
try { try {
wait(); sGLThreadManager.wait();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
@@ -1188,35 +1197,35 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
} }
public void onPause() { public void onPause() {
synchronized (this) { synchronized (sGLThreadManager) {
mPaused = true; mPaused = true;
notifyAll(); sGLThreadManager.notifyAll();
} }
} }
public void onResume() { public void onResume() {
synchronized (this) { synchronized (sGLThreadManager) {
mPaused = false; mPaused = false;
mRequestRender = true; mRequestRender = true;
notifyAll(); sGLThreadManager.notifyAll();
} }
} }
public void onWindowResize(int w, int h) { public void onWindowResize(int w, int h) {
synchronized (this) { synchronized (sGLThreadManager) {
mWidth = w; mWidth = w;
mHeight = h; mHeight = h;
mSizeChanged = true; mSizeChanged = true;
notifyAll(); sGLThreadManager.notifyAll();
} }
} }
public void requestExitAndWait() { public void requestExitAndWait() {
// don't call this from GLThread thread or it is a guaranteed // don't call this from GLThread thread or it is a guaranteed
// deadlock! // deadlock!
synchronized(this) { synchronized(sGLThreadManager) {
mDone = true; mDone = true;
notifyAll(); sGLThreadManager.notifyAll();
} }
try { try {
join(); join();
@@ -1232,6 +1241,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
public void queueEvent(Runnable r) { public void queueEvent(Runnable r) {
synchronized(this) { synchronized(this) {
mEventQueue.add(r); mEventQueue.add(r);
synchronized(sGLThreadManager) {
mEventsWaiting = true;
sGLThreadManager.notifyAll();
}
} }
} }
@@ -1245,6 +1258,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
return null; 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 mDone;
private boolean mPaused; private boolean mPaused;
private boolean mHasSurface; private boolean mHasSurface;
@@ -1254,6 +1269,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private int mHeight; private int mHeight;
private int mRenderMode; private int mRenderMode;
private boolean mRequestRender; private boolean mRequestRender;
private boolean mEventsWaiting;
// End of member variables protected by the sGLThreadManager monitor.
private Renderer mRenderer; private Renderer mRenderer;
private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>(); private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
private EglHelper mEglHelper; private EglHelper mEglHelper;
@@ -1300,58 +1318,46 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
} }
private static class GLThreadManager { private static class GLThreadManager {
public boolean shouldHaveEgl(GLThread thread) {
public synchronized void threadExiting(GLThread thread) {
if (LOG_THREADS) {
Log.i("GLThread", "exiting tid=" + thread.getId());
}
thread.mDone = true;
if (mEglOwner == thread) {
mEglOwner = null;
}
notifyAll();
}
/*
* 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) { if (mMultipleGLESContextsAllowed) {
return true; return true;
} else {
synchronized(this) {
return thread == mMostRecentGLThread || mMostRecentGLThread == null;
}
} }
return false;
} }
public void start(GLThread thread) throws InterruptedException { public synchronized void releaseEglSurface(GLThread thread) {
if (! mGLESVersionCheckComplete) { if (mEglOwner == thread) {
mGLESVersion = SystemProperties.getInt( mEglOwner = null;
"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;
}
if (oldThread != null && ! mMultipleGLESContextsAllowed) {
synchronized(oldThread) {
oldThread.notifyAll();
}
}
synchronized(this) {
while ((! mMultipleGLESContextsAllowed)
&& mGLContextCount > 0) {
wait();
}
mGLContextCount++;
}
}
public synchronized void end(GLThread thread) {
mGLContextCount--;
notifyAll(); notifyAll();
if (mMostRecentGLThread == thread) {
mMostRecentGLThread = null;
}
} }
public synchronized void checkGLDriver(GL10 gl) { public synchronized void checkGLDriver(GL10 gl) {
if (! mGLESDriverCheckComplete) { if (! mGLESDriverCheckComplete) {
checkGLESVersion();
if (mGLESVersion < kGLES_20) { if (mGLESVersion < kGLES_20) {
String renderer = gl.glGetString(GL10.GL_RENDERER); String renderer = gl.glGetString(GL10.GL_RENDERER);
mMultipleGLESContextsAllowed = 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 boolean mGLESVersionCheckComplete;
private int mGLESVersion; private int mGLESVersion;
private GLThread mMostRecentGLThread;
private boolean mGLESDriverCheckComplete; private boolean mGLESDriverCheckComplete;
private boolean mMultipleGLESContextsAllowed; private boolean mMultipleGLESContextsAllowed;
private int mGLContextCount; private int mGLContextCount;
private static final int kGLES_20 = 0x20000; private static final int kGLES_20 = 0x20000;
private static final String kMSM7K_RENDERER_PREFIX = private static final String kMSM7K_RENDERER_PREFIX =
"Q3Dimension MSM7500 "; "Q3Dimension MSM7500 ";
}; private GLThread mEglOwner;
}
private static final GLThreadManager sGLThreadManager = new GLThreadManager(); private static final GLThreadManager sGLThreadManager = new GLThreadManager();
private boolean mSizeChanged = true; private boolean mSizeChanged = true;