Loading opengl/java/android/opengl/GLSurfaceView.java +31 −131 Original line number Diff line number Diff line Loading @@ -16,6 +16,13 @@ package android.opengl; import android.content.Context; import android.os.Trace; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import java.io.Writer; import java.lang.ref.WeakReference; import java.util.ArrayList; Loading @@ -29,15 +36,6 @@ import javax.microedition.khronos.egl.EGLSurface; import javax.microedition.khronos.opengles.GL; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.content.pm.ConfigurationInfo; import android.os.SystemProperties; import android.os.Trace; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying OpenGL rendering. Loading Loading @@ -119,9 +117,9 @@ import android.view.SurfaceView; * {@link #setRenderMode}. The default is continuous rendering. * <p> * <h3>Activity Life-cycle</h3> * A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView clients * are required to call {@link #onPause()} when the activity pauses and * {@link #onResume()} when the activity resumes. These calls allow GLSurfaceView to * A GLSurfaceView must be notified when to pause and resume rendering. GLSurfaceView clients * are required to call {@link #onPause()} when the activity stops and * {@link #onResume()} when the activity starts. These calls allow GLSurfaceView to * pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate * the OpenGL display. * <p> Loading Loading @@ -294,10 +292,12 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback * resumed. * <p> * If set to true, then the EGL context may be preserved when the GLSurfaceView is paused. * Whether the EGL context is actually preserved or not depends upon whether the * Android device that the program is running on can support an arbitrary number of EGL * contexts or not. Devices that can only support a limited number of EGL contexts must * release the EGL context in order to allow multiple applications to share the GPU. * <p> * Prior to API level 11, whether the EGL context is actually preserved or not * depends upon whether the Android device can support an arbitrary number of * EGL contexts or not. Devices that can only support a limited number of EGL * contexts must release the EGL context in order to allow multiple applications * to share the GPU. * <p> * If set to false, the EGL context will be released when the GLSurfaceView is paused, * and recreated when the GLSurfaceView is resumed. Loading Loading @@ -554,9 +554,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback /** * Inform the view that the activity is paused. The owner of this view must * call this method when the activity is paused. Calling this method will * pause the rendering thread. * Pause the rendering thread, optionally tearing down the EGL context * depending upon the value of {@link #setPreserveEGLContextOnPause(boolean)}. * * This method should be called when it is no longer desirable for the * GLSurfaceView to continue rendering, such as in response to * {@link android.app.Activity#onStop Activity.onStop}. * * Must not be called before a renderer has been set. */ public void onPause() { Loading @@ -564,10 +568,12 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } /** * Inform the view that the activity is resumed. The owner of this view must * call this method when the activity is resumed. Calling this method will * recreate the OpenGL display and resume the rendering * thread. * Resumes the rendering thread, re-creating the OpenGL context if necessary. It * is the counterpart to {@link #onPause()}. * * This method should typically be called in * {@link android.app.Activity#onStart Activity.onStart}. * * Must not be called before a renderer has been set. */ public void onResume() { Loading Loading @@ -1354,7 +1360,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback GLSurfaceView view = mGLSurfaceViewWeakRef.get(); boolean preserveEglContextOnPause = view == null ? false : view.mPreserveEGLContextOnPause; if (!preserveEglContextOnPause || sGLThreadManager.shouldReleaseEGLContextWhenPausing()) { if (!preserveEglContextOnPause) { stopEglContextLocked(); if (LOG_SURFACE) { Log.i("GLThread", "releasing EGL context because paused tid=" + getId()); Loading @@ -1362,16 +1368,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } } // When pausing, optionally terminate EGL: if (pausing) { if (sGLThreadManager.shouldTerminateEGLWhenPausing()) { mEglHelper.finish(); if (LOG_SURFACE) { Log.i("GLThread", "terminating EGL because paused tid=" + getId()); } } } // Have we lost the SurfaceView surface? if ((! mHasSurface) && (! mWaitingForSurface)) { if (LOG_SURFACE) { Loading Loading @@ -1411,7 +1407,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (! mHaveEglContext) { if (askedToReleaseEglContext) { askedToReleaseEglContext = false; } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) { } else { try { mEglHelper.start(); } catch (RuntimeException t) { Loading Loading @@ -1506,7 +1502,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (createGlInterface) { gl = (GL10) mEglHelper.createGL(); sGLThreadManager.checkGLDriver(gl); createGlInterface = false; } Loading Loading @@ -1888,111 +1883,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback Log.i("GLThread", "exiting tid=" + thread.getId()); } thread.mExited = true; if (mEglOwner == thread) { mEglOwner = null; } notifyAll(); } /* * Tries once to acquire the right to use an EGL * context. Does not block. Requires that we are already * in the sGLThreadManager monitor when this is called. * * @return true if the right to use an EGL context was acquired. */ public boolean tryAcquireEglContextLocked(GLThread thread) { if (mEglOwner == thread || mEglOwner == null) { mEglOwner = thread; notifyAll(); return true; } checkGLESVersion(); 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; } /* * Releases the EGL context. Requires that we are already in the * sGLThreadManager monitor when this is called. */ public void releaseEglContextLocked(GLThread thread) { if (mEglOwner == thread) { mEglOwner = null; } notifyAll(); } public synchronized boolean shouldReleaseEGLContextWhenPausing() { // Release the EGL context when pausing even if // the hardware supports multiple EGL contexts. // Otherwise the device could run out of EGL contexts. return mLimitedGLESContexts; } public synchronized boolean shouldTerminateEGLWhenPausing() { checkGLESVersion(); return !mMultipleGLESContextsAllowed; } public synchronized void checkGLDriver(GL10 gl) { if (! mGLESDriverCheckComplete) { checkGLESVersion(); String renderer = gl.glGetString(GL10.GL_RENDERER); if (mGLESVersion < kGLES_20) { mMultipleGLESContextsAllowed = ! renderer.startsWith(kMSM7K_RENDERER_PREFIX); notifyAll(); } mLimitedGLESContexts = !mMultipleGLESContextsAllowed; if (LOG_SURFACE) { Log.w(TAG, "checkGLDriver renderer = \"" + renderer + "\" multipleContextsAllowed = " + mMultipleGLESContextsAllowed + " mLimitedGLESContexts = " + mLimitedGLESContexts); } mGLESDriverCheckComplete = true; } } private void checkGLESVersion() { if (! mGLESVersionCheckComplete) { mGLESVersion = SystemProperties.getInt( "ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); if (mGLESVersion >= kGLES_20) { mMultipleGLESContextsAllowed = true; } if (LOG_SURFACE) { Log.w(TAG, "checkGLESVersion mGLESVersion =" + " " + mGLESVersion + " mMultipleGLESContextsAllowed = " + mMultipleGLESContextsAllowed); } mGLESVersionCheckComplete = true; } } /** * This check was required for some pre-Android-3.0 hardware. Android 3.0 provides * support for hardware-accelerated views, therefore multiple EGL contexts are * supported on all Android 3.0+ EGL drivers. */ private boolean mGLESVersionCheckComplete; private int mGLESVersion; private boolean mGLESDriverCheckComplete; private boolean mMultipleGLESContextsAllowed; private boolean mLimitedGLESContexts; 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(); Loading Loading
opengl/java/android/opengl/GLSurfaceView.java +31 −131 Original line number Diff line number Diff line Loading @@ -16,6 +16,13 @@ package android.opengl; import android.content.Context; import android.os.Trace; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import java.io.Writer; import java.lang.ref.WeakReference; import java.util.ArrayList; Loading @@ -29,15 +36,6 @@ import javax.microedition.khronos.egl.EGLSurface; import javax.microedition.khronos.opengles.GL; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.content.pm.ConfigurationInfo; import android.os.SystemProperties; import android.os.Trace; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying OpenGL rendering. Loading Loading @@ -119,9 +117,9 @@ import android.view.SurfaceView; * {@link #setRenderMode}. The default is continuous rendering. * <p> * <h3>Activity Life-cycle</h3> * A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView clients * are required to call {@link #onPause()} when the activity pauses and * {@link #onResume()} when the activity resumes. These calls allow GLSurfaceView to * A GLSurfaceView must be notified when to pause and resume rendering. GLSurfaceView clients * are required to call {@link #onPause()} when the activity stops and * {@link #onResume()} when the activity starts. These calls allow GLSurfaceView to * pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate * the OpenGL display. * <p> Loading Loading @@ -294,10 +292,12 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback * resumed. * <p> * If set to true, then the EGL context may be preserved when the GLSurfaceView is paused. * Whether the EGL context is actually preserved or not depends upon whether the * Android device that the program is running on can support an arbitrary number of EGL * contexts or not. Devices that can only support a limited number of EGL contexts must * release the EGL context in order to allow multiple applications to share the GPU. * <p> * Prior to API level 11, whether the EGL context is actually preserved or not * depends upon whether the Android device can support an arbitrary number of * EGL contexts or not. Devices that can only support a limited number of EGL * contexts must release the EGL context in order to allow multiple applications * to share the GPU. * <p> * If set to false, the EGL context will be released when the GLSurfaceView is paused, * and recreated when the GLSurfaceView is resumed. Loading Loading @@ -554,9 +554,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback /** * Inform the view that the activity is paused. The owner of this view must * call this method when the activity is paused. Calling this method will * pause the rendering thread. * Pause the rendering thread, optionally tearing down the EGL context * depending upon the value of {@link #setPreserveEGLContextOnPause(boolean)}. * * This method should be called when it is no longer desirable for the * GLSurfaceView to continue rendering, such as in response to * {@link android.app.Activity#onStop Activity.onStop}. * * Must not be called before a renderer has been set. */ public void onPause() { Loading @@ -564,10 +568,12 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } /** * Inform the view that the activity is resumed. The owner of this view must * call this method when the activity is resumed. Calling this method will * recreate the OpenGL display and resume the rendering * thread. * Resumes the rendering thread, re-creating the OpenGL context if necessary. It * is the counterpart to {@link #onPause()}. * * This method should typically be called in * {@link android.app.Activity#onStart Activity.onStart}. * * Must not be called before a renderer has been set. */ public void onResume() { Loading Loading @@ -1354,7 +1360,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback GLSurfaceView view = mGLSurfaceViewWeakRef.get(); boolean preserveEglContextOnPause = view == null ? false : view.mPreserveEGLContextOnPause; if (!preserveEglContextOnPause || sGLThreadManager.shouldReleaseEGLContextWhenPausing()) { if (!preserveEglContextOnPause) { stopEglContextLocked(); if (LOG_SURFACE) { Log.i("GLThread", "releasing EGL context because paused tid=" + getId()); Loading @@ -1362,16 +1368,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } } // When pausing, optionally terminate EGL: if (pausing) { if (sGLThreadManager.shouldTerminateEGLWhenPausing()) { mEglHelper.finish(); if (LOG_SURFACE) { Log.i("GLThread", "terminating EGL because paused tid=" + getId()); } } } // Have we lost the SurfaceView surface? if ((! mHasSurface) && (! mWaitingForSurface)) { if (LOG_SURFACE) { Loading Loading @@ -1411,7 +1407,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (! mHaveEglContext) { if (askedToReleaseEglContext) { askedToReleaseEglContext = false; } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) { } else { try { mEglHelper.start(); } catch (RuntimeException t) { Loading Loading @@ -1506,7 +1502,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (createGlInterface) { gl = (GL10) mEglHelper.createGL(); sGLThreadManager.checkGLDriver(gl); createGlInterface = false; } Loading Loading @@ -1888,111 +1883,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback Log.i("GLThread", "exiting tid=" + thread.getId()); } thread.mExited = true; if (mEglOwner == thread) { mEglOwner = null; } notifyAll(); } /* * Tries once to acquire the right to use an EGL * context. Does not block. Requires that we are already * in the sGLThreadManager monitor when this is called. * * @return true if the right to use an EGL context was acquired. */ public boolean tryAcquireEglContextLocked(GLThread thread) { if (mEglOwner == thread || mEglOwner == null) { mEglOwner = thread; notifyAll(); return true; } checkGLESVersion(); 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; } /* * Releases the EGL context. Requires that we are already in the * sGLThreadManager monitor when this is called. */ public void releaseEglContextLocked(GLThread thread) { if (mEglOwner == thread) { mEglOwner = null; } notifyAll(); } public synchronized boolean shouldReleaseEGLContextWhenPausing() { // Release the EGL context when pausing even if // the hardware supports multiple EGL contexts. // Otherwise the device could run out of EGL contexts. return mLimitedGLESContexts; } public synchronized boolean shouldTerminateEGLWhenPausing() { checkGLESVersion(); return !mMultipleGLESContextsAllowed; } public synchronized void checkGLDriver(GL10 gl) { if (! mGLESDriverCheckComplete) { checkGLESVersion(); String renderer = gl.glGetString(GL10.GL_RENDERER); if (mGLESVersion < kGLES_20) { mMultipleGLESContextsAllowed = ! renderer.startsWith(kMSM7K_RENDERER_PREFIX); notifyAll(); } mLimitedGLESContexts = !mMultipleGLESContextsAllowed; if (LOG_SURFACE) { Log.w(TAG, "checkGLDriver renderer = \"" + renderer + "\" multipleContextsAllowed = " + mMultipleGLESContextsAllowed + " mLimitedGLESContexts = " + mLimitedGLESContexts); } mGLESDriverCheckComplete = true; } } private void checkGLESVersion() { if (! mGLESVersionCheckComplete) { mGLESVersion = SystemProperties.getInt( "ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); if (mGLESVersion >= kGLES_20) { mMultipleGLESContextsAllowed = true; } if (LOG_SURFACE) { Log.w(TAG, "checkGLESVersion mGLESVersion =" + " " + mGLESVersion + " mMultipleGLESContextsAllowed = " + mMultipleGLESContextsAllowed); } mGLESVersionCheckComplete = true; } } /** * This check was required for some pre-Android-3.0 hardware. Android 3.0 provides * support for hardware-accelerated views, therefore multiple EGL contexts are * supported on all Android 3.0+ EGL drivers. */ private boolean mGLESVersionCheckComplete; private int mGLESVersion; private boolean mGLESDriverCheckComplete; private boolean mMultipleGLESContextsAllowed; private boolean mLimitedGLESContexts; 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(); Loading