Loading opengl/java/android/opengl/GLSurfaceView.java +158 −139 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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(); } } } private void startEgl() throws InterruptedException { if (! mHaveEgl) { mHaveEgl = true; sGLThreadManager.start(this); mEglHelper.start(); sGLThreadManager.threadExiting(this); } } 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; Loading @@ -1027,50 +1010,59 @@ 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(); } boolean eventsWaiting = false; synchronized (sGLThreadManager) { while (true) { // Manage acquiring and releasing the SurfaceView // surface and the EGL surface. if (mPaused) { stopEgl(); needStart = true; stopEglLocked(); } while(true) { 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(); if (!mHaveEgl) { if (sGLThreadManager.tryAcquireEglSurface(this)) { mHaveEgl = true; mEglHelper.start(); mRequestRender = true; needStart = true; } } if (!needToWait()) { break; } if (LOG_THREADS) { Log.i("GLThread", "needToWait tid=" + getId()); } wait(); } // 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; Loading @@ -1079,11 +1071,36 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (mHasSurface && mWaitingForSurface) { changed = true; mWaitingForSurface = false; notifyAll(); 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; 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; } Loading Loading @@ -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; } if (mPaused || (! mHasSurface) || (! mHaveEgl)) { return true; } if ((mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) { return false; private boolean isDone() { synchronized (sGLThreadManager) { return mDone; } 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(); } Loading @@ -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(); Loading @@ -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(); } } } Loading @@ -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; Loading @@ -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; Loading Loading @@ -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(); /* * 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; } mGLContextCount++; 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 = Loading @@ -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; Loading Loading
opengl/java/android/opengl/GLSurfaceView.java +158 −139 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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(); } } } private void startEgl() throws InterruptedException { if (! mHaveEgl) { mHaveEgl = true; sGLThreadManager.start(this); mEglHelper.start(); sGLThreadManager.threadExiting(this); } } 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; Loading @@ -1027,50 +1010,59 @@ 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(); } boolean eventsWaiting = false; synchronized (sGLThreadManager) { while (true) { // Manage acquiring and releasing the SurfaceView // surface and the EGL surface. if (mPaused) { stopEgl(); needStart = true; stopEglLocked(); } while(true) { 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(); if (!mHaveEgl) { if (sGLThreadManager.tryAcquireEglSurface(this)) { mHaveEgl = true; mEglHelper.start(); mRequestRender = true; needStart = true; } } if (!needToWait()) { break; } if (LOG_THREADS) { Log.i("GLThread", "needToWait tid=" + getId()); } wait(); } // 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; Loading @@ -1079,11 +1071,36 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (mHasSurface && mWaitingForSurface) { changed = true; mWaitingForSurface = false; notifyAll(); 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; 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; } Loading Loading @@ -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; } if (mPaused || (! mHasSurface) || (! mHaveEgl)) { return true; } if ((mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) { return false; private boolean isDone() { synchronized (sGLThreadManager) { return mDone; } 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(); } Loading @@ -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(); Loading @@ -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(); } } } Loading @@ -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; Loading @@ -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; Loading Loading @@ -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(); /* * 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; } mGLContextCount++; 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 = Loading @@ -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; Loading