Merge commit '79447b2087c8c820d742185dda7305101f9656f0' into eclair-mr2-plus-aosp * commit '79447b2087c8c820d742185dda7305101f9656f0': Improve GLSurfaceView to avoid deadlocks and race conditions.
This commit is contained in:
@@ -146,6 +146,7 @@ import android.view.SurfaceView;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
|
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
|
private final static boolean LOG_THREADS = false;
|
||||||
/**
|
/**
|
||||||
* The renderer only renders
|
* The renderer only renders
|
||||||
* when the surface is created, or when {@link #requestRender} is called.
|
* when the surface is created, or when {@link #requestRender} is called.
|
||||||
@@ -964,11 +965,15 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
mRequestRender = true;
|
mRequestRender = true;
|
||||||
mRenderMode = RENDERMODE_CONTINUOUSLY;
|
mRenderMode = RENDERMODE_CONTINUOUSLY;
|
||||||
mRenderer = renderer;
|
mRenderer = renderer;
|
||||||
setName("GLThread");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
setName("GLThread " + getId());
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "starting tid=" + getId());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When the android framework launches a second instance of
|
* When the android framework launches a second instance of
|
||||||
* an activity, the new instance's onCreate() method may be
|
* an activity, the new instance's onCreate() method may be
|
||||||
@@ -978,12 +983,26 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
* accesses EGL.
|
* accesses EGL.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
sGLAccessLock.acquire();
|
try {
|
||||||
|
sGLThreadManager.start(this);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
guardedRun();
|
guardedRun();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// fall thru and exit normally
|
// fall thru and exit normally
|
||||||
} finally {
|
} finally {
|
||||||
sGLAccessLock.release();
|
try {
|
||||||
|
sGLThreadManager.end(this);
|
||||||
|
} finally {
|
||||||
|
synchronized(this) {
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "exiting tid=" + getId());
|
||||||
|
}
|
||||||
|
mDone = true;
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1019,11 +1038,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
needStart = true;
|
needStart = true;
|
||||||
}
|
}
|
||||||
while (needToWait()) {
|
while (needToWait()) {
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "needToWait tid=" + getId());
|
||||||
|
}
|
||||||
if (!mHasSurface) {
|
if (!mHasSurface) {
|
||||||
if (!mWaitingForSurface) {
|
if (!mWaitingForSurface) {
|
||||||
mEglHelper.destroySurface();
|
mEglHelper.destroySurface();
|
||||||
mWaitingForSurface = true;
|
mWaitingForSurface = true;
|
||||||
notify();
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wait();
|
wait();
|
||||||
@@ -1039,6 +1061,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
if (mHasSurface && mWaitingForSurface) {
|
if (mHasSurface && mWaitingForSurface) {
|
||||||
changed = true;
|
changed = true;
|
||||||
mWaitingForSurface = false;
|
mWaitingForSurface = false;
|
||||||
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (needStart) {
|
if (needStart) {
|
||||||
@@ -1048,7 +1071,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
gl = (GL10) mEglHelper.createSurface(getHolder());
|
gl = (GL10) mEglHelper.createSurface(getHolder());
|
||||||
sGLAccessLock.checkGLDriver(gl);
|
sGLThreadManager.checkGLDriver(gl);
|
||||||
tellRendererSurfaceChanged = true;
|
tellRendererSurfaceChanged = true;
|
||||||
}
|
}
|
||||||
if (tellRendererSurfaceCreated) {
|
if (tellRendererSurfaceCreated) {
|
||||||
@@ -1080,6 +1103,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean needToWait() {
|
private boolean needToWait() {
|
||||||
|
if (sGLThreadManager.shouldQuit(this)) {
|
||||||
|
mDone = true;
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
if (mDone) {
|
if (mDone) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1102,7 +1129,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
mRenderMode = renderMode;
|
mRenderMode = renderMode;
|
||||||
if (renderMode == RENDERMODE_CONTINUOUSLY) {
|
if (renderMode == RENDERMODE_CONTINUOUSLY) {
|
||||||
notify();
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1116,22 +1143,28 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
public void requestRender() {
|
public void requestRender() {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
mRequestRender = true;
|
mRequestRender = true;
|
||||||
notify();
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceCreated() {
|
public void surfaceCreated() {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "surfaceCreated tid=" + getId());
|
||||||
|
}
|
||||||
mHasSurface = true;
|
mHasSurface = true;
|
||||||
notify();
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceDestroyed() {
|
public void surfaceDestroyed() {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "surfaceDestroyed tid=" + getId());
|
||||||
|
}
|
||||||
mHasSurface = false;
|
mHasSurface = false;
|
||||||
notify();
|
notifyAll();
|
||||||
while(!mWaitingForSurface && isAlive()) {
|
while(!mWaitingForSurface && isAlive() && ! mDone) {
|
||||||
try {
|
try {
|
||||||
wait();
|
wait();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -1144,13 +1177,15 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
public void onPause() {
|
public void onPause() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mPaused = true;
|
mPaused = true;
|
||||||
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mPaused = false;
|
mPaused = false;
|
||||||
notify();
|
mRequestRender = true;
|
||||||
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1159,7 +1194,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
mWidth = w;
|
mWidth = w;
|
||||||
mHeight = h;
|
mHeight = h;
|
||||||
mSizeChanged = true;
|
mSizeChanged = true;
|
||||||
notify();
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1168,7 +1203,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
// deadlock!
|
// deadlock!
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
mDone = true;
|
mDone = true;
|
||||||
notify();
|
notifyAll();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
join();
|
join();
|
||||||
@@ -1250,9 +1285,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GLAccessLock {
|
private static class GLThreadManager {
|
||||||
public synchronized void acquire() throws InterruptedException {
|
public void start(GLThread thread) throws InterruptedException {
|
||||||
if (! mGLESVersionCheckComplete) {
|
if (! mGLESVersionCheckComplete) {
|
||||||
mGLESVersion = SystemProperties.getInt(
|
mGLESVersion = SystemProperties.getInt(
|
||||||
"ro.opengles.version",
|
"ro.opengles.version",
|
||||||
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
|
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
|
||||||
@@ -1262,18 +1297,32 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
mGLESVersionCheckComplete = true;
|
mGLESVersionCheckComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((! mMultipleGLESContextsAllowed)
|
GLThread oldThread = null;
|
||||||
&& mGLContextCount > 0) {
|
synchronized(this) {
|
||||||
wait();
|
mMostRecentGLThread = thread;
|
||||||
|
oldThread = mMostRecentGLThread;
|
||||||
|
|
||||||
|
while ((! mMultipleGLESContextsAllowed)
|
||||||
|
&& mGLContextCount > 0) {
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
mGLContextCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
mGLContextCount++;
|
if (oldThread != null && ! mMultipleGLESContextsAllowed) {
|
||||||
|
synchronized(oldThread) {
|
||||||
|
oldThread.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void release() {
|
public synchronized void end(GLThread thread) {
|
||||||
mGLContextCount--;
|
mGLContextCount--;
|
||||||
notifyAll();
|
notifyAll();
|
||||||
|
if (mMostRecentGLThread == thread) {
|
||||||
|
mMostRecentGLThread = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void checkGLDriver(GL10 gl) {
|
public synchronized void checkGLDriver(GL10 gl) {
|
||||||
@@ -1288,8 +1337,15 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean shouldQuit(GLThread thread) {
|
||||||
|
synchronized(this) {
|
||||||
|
return thread != mMostRecentGLThread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -1298,8 +1354,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
"Q3Dimension MSM7500 ";
|
"Q3Dimension MSM7500 ";
|
||||||
};
|
};
|
||||||
|
|
||||||
private static GLAccessLock sGLAccessLock = new GLAccessLock();
|
private static final GLThreadManager sGLThreadManager = new GLThreadManager();
|
||||||
|
|
||||||
private boolean mSizeChanged = true;
|
private boolean mSizeChanged = true;
|
||||||
|
|
||||||
private GLThread mGLThread;
|
private GLThread mGLThread;
|
||||||
|
|||||||
Reference in New Issue
Block a user