summaryrefslogtreecommitdiffstats
path: root/opengl/java
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2013-04-03 17:28:14 -0700
committerMathias Agopian <mathias@google.com>2013-04-09 17:55:32 -0700
commit57d019e222abc0de3f8876e682617d42872230c6 (patch)
tree520fc4b9aac469fa18ca180f6c509e00f9b780de /opengl/java
parentcf5ccb8f81f038112e13ce2c9ff73602005595f7 (diff)
downloadframeworks_base-57d019e222abc0de3f8876e682617d42872230c6.zip
frameworks_base-57d019e222abc0de3f8876e682617d42872230c6.tar.gz
frameworks_base-57d019e222abc0de3f8876e682617d42872230c6.tar.bz2
rework GLSurfaceView so it can use the choreographer
GLSurfaceView will now automatically use the Choreographer to schedule render updates on VSYNC. This happens only in RENDERMODE_CONTINUOUSLY. GLSurfaceView was rewriten to use a Looper and a HandlerThread instead of a custom thread. The basic mode of operation is unchanged, however the implementation is largely different. Removed support for older GPUs which had a limited number of contexts. Bug: 8485730 Change-Id: I7b270f7ad7bb1259e858429054b1c8c9cc159dc6
Diffstat (limited to 'opengl/java')
-rw-r--r--opengl/java/android/opengl/GLSurfaceView.java1038
1 files changed, 378 insertions, 660 deletions
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 5a2e261..daa5d13 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -18,7 +18,6 @@ package android.opengl;
import java.io.Writer;
import java.lang.ref.WeakReference;
-import java.util.ArrayList;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
@@ -30,10 +29,13 @@ 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.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.Choreographer;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
@@ -164,11 +166,26 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private final static String TAG = "GLSurfaceView";
private final static boolean LOG_ATTACH_DETACH = false;
private final static boolean LOG_THREADS = false;
- private final static boolean LOG_PAUSE_RESUME = false;
private final static boolean LOG_SURFACE = false;
private final static boolean LOG_RENDERER = false;
private final static boolean LOG_RENDERER_DRAW_FRAME = false;
private final static boolean LOG_EGL = false;
+ private final static boolean TRACE_ENABLED = false;
+
+ private final WeakReference<GLSurfaceView> mThisWeakRef =
+ new WeakReference<GLSurfaceView>(this);
+ private GLThread mGLThread;
+ private Renderer mRenderer;
+ private boolean mDetached;
+ private EGLConfigChooser mEGLConfigChooser;
+ private EGLContextFactory mEGLContextFactory;
+ private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
+ private GLWrapper mGLWrapper;
+ private int mDebugFlags;
+ private int mEGLContextClientVersion;
+ private boolean mPreserveEGLContextOnPause;
+ private int mUserRenderMode;
+
/**
* The renderer only renders
* when the surface is created, or when {@link #requestRender} is called.
@@ -241,13 +258,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
// underlying surface is created and destroyed
SurfaceHolder holder = getHolder();
holder.addCallback(this);
- // setFormat is done by SurfaceView in SDK 2.3 and newer. Uncomment
- // this statement if back-porting to 2.2 or older:
- // holder.setFormat(PixelFormat.RGB_565);
- //
- // setType is not needed for SDK 2.0 or newer. Uncomment this
- // statement if back-porting this code to older SDKs.
- // holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
+ mUserRenderMode = RENDERMODE_CONTINUOUSLY;
}
/**
@@ -346,15 +357,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
public void setRenderer(Renderer renderer) {
checkRenderThreadState();
if (mEGLConfigChooser == null) {
- mEGLConfigChooser = new SimpleEGLConfigChooser(true);
+ mEGLConfigChooser = new SimpleEGLConfigChooser(true, mEGLContextClientVersion);
}
if (mEGLContextFactory == null) {
- mEGLContextFactory = new DefaultContextFactory();
+ mEGLContextFactory = new DefaultContextFactory(mEGLContextClientVersion);
}
if (mEGLWindowSurfaceFactory == null) {
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
}
mRenderer = renderer;
+
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
}
@@ -420,7 +432,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* @param needDepth
*/
public void setEGLConfigChooser(boolean needDepth) {
- setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
+ setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth, mEGLContextClientVersion));
}
/**
@@ -439,7 +451,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
int alphaSize, int depthSize, int stencilSize) {
setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
- blueSize, alphaSize, depthSize, stencilSize));
+ blueSize, alphaSize, depthSize, stencilSize, mEGLContextClientVersion));
}
/**
@@ -466,6 +478,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* If
* {@link #setEGLConfigChooser(EGLConfigChooser)} has been called, then the supplied
* EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible config.
+ *
+ * This method must be called before:
+ * <ul>
+ * <li>{@link #setEGLConfigChooser(boolean)}
+ * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)}
+ * </ul>
+ *
* @param version The EGLContext client version to choose. Use 2 for OpenGL ES 2.0
*/
public void setEGLContextClientVersion(int version) {
@@ -490,6 +509,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* @see #RENDERMODE_WHEN_DIRTY
*/
public void setRenderMode(int renderMode) {
+ switch (renderMode) {
+ case RENDERMODE_WHEN_DIRTY:
+ case RENDERMODE_CONTINUOUSLY:
+ break;
+ default:
+ throw new IllegalArgumentException("renderMode");
+ }
+ mUserRenderMode = renderMode;
mGLThread.setRenderMode(renderMode);
}
@@ -501,7 +528,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* @see #RENDERMODE_WHEN_DIRTY
*/
public int getRenderMode() {
- return mGLThread.getRenderMode();
+ return mUserRenderMode;
}
/**
@@ -582,14 +609,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
}
if (mDetached && (mRenderer != null)) {
- int renderMode = RENDERMODE_CONTINUOUSLY;
- if (mGLThread != null) {
- renderMode = mGLThread.getRenderMode();
- }
mGLThread = new GLThread(mThisWeakRef);
- if (renderMode != RENDERMODE_CONTINUOUSLY) {
- mGLThread.setRenderMode(renderMode);
- }
+ mGLThread.setRenderMode(mUserRenderMode);
mGLThread.start();
}
mDetached = false;
@@ -761,11 +782,15 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
}
- private class DefaultContextFactory implements EGLContextFactory {
- private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ private static class DefaultContextFactory implements EGLContextFactory {
+ private final int mEGLContextClientVersion;
+
+ public DefaultContextFactory(int version) {
+ mEGLContextClientVersion = version;
+ }
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
- int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
+ int[] attrib_list = {EGL14.EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
EGL10.EGL_NONE };
return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
@@ -775,9 +800,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
public void destroyContext(EGL10 egl, EGLDisplay display,
EGLContext context) {
if (!egl.eglDestroyContext(display, context)) {
- Log.e("DefaultContextFactory", "display:" + display + " context: " + context);
+ Log.e(TAG, "display:" + display + " context: " + context);
if (LOG_THREADS) {
- Log.i("DefaultContextFactory", "tid=" + Thread.currentThread().getId());
+ Log.d(TAG, "tid=" + Thread.currentThread().getId());
}
EglHelper.throwEglException("eglDestroyContex", egl.eglGetError());
}
@@ -807,8 +832,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
try {
result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
} catch (IllegalArgumentException e) {
- // This exception indicates that the surface flinger surface
- // is not valid. This can happen if the surface flinger surface has
+ // This exception indicates that the surfaceflinger surface
+ // is not valid. This can happen if the surfaceflinger surface has
// been torn down, but the application has not yet been
// notified via SurfaceHolder.Callback.surfaceDestroyed.
// In theory the application should be notified first,
@@ -844,10 +869,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
}
- private abstract class BaseConfigChooser
+ private static abstract class BaseConfigChooser
implements EGLConfigChooser {
- public BaseConfigChooser(int[] configSpec) {
- mConfigSpec = filterConfigSpec(configSpec);
+
+ public BaseConfigChooser(int[] configSpec, int version) {
+ mConfigSpec = filterConfigSpec(configSpec, version);
}
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
@@ -881,8 +907,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
protected int[] mConfigSpec;
- private int[] filterConfigSpec(int[] configSpec) {
- if (mEGLContextClientVersion != 2) {
+ private int[] filterConfigSpec(int[] configSpec, int version) {
+ if (version != 2) {
return configSpec;
}
/* We know none of the subclasses define EGL_RENDERABLE_TYPE.
@@ -892,7 +918,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
int[] newConfigSpec = new int[len + 2];
System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
- newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
+ newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT;
newConfigSpec[len+1] = EGL10.EGL_NONE;
return newConfigSpec;
}
@@ -902,9 +928,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* Choose a configuration with exactly the specified r,g,b,a sizes,
* and at least the specified depth and stencil sizes.
*/
- private class ComponentSizeChooser extends BaseConfigChooser {
+ private static class ComponentSizeChooser extends BaseConfigChooser {
public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
- int alphaSize, int depthSize, int stencilSize) {
+ int alphaSize, int depthSize, int stencilSize, int version) {
super(new int[] {
EGL10.EGL_RED_SIZE, redSize,
EGL10.EGL_GREEN_SIZE, greenSize,
@@ -912,7 +938,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
EGL10.EGL_ALPHA_SIZE, alphaSize,
EGL10.EGL_DEPTH_SIZE, depthSize,
EGL10.EGL_STENCIL_SIZE, stencilSize,
- EGL10.EGL_NONE});
+ EGL10.EGL_NONE}, version);
mValue = new int[1];
mRedSize = redSize;
mGreenSize = greenSize;
@@ -920,7 +946,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
mAlphaSize = alphaSize;
mDepthSize = depthSize;
mStencilSize = stencilSize;
- }
+ }
@Override
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
@@ -931,14 +957,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
int s = findConfigAttrib(egl, display, config,
EGL10.EGL_STENCIL_SIZE, 0);
if ((d >= mDepthSize) && (s >= mStencilSize)) {
- int r = findConfigAttrib(egl, display, config,
- EGL10.EGL_RED_SIZE, 0);
- int g = findConfigAttrib(egl, display, config,
- EGL10.EGL_GREEN_SIZE, 0);
- int b = findConfigAttrib(egl, display, config,
- EGL10.EGL_BLUE_SIZE, 0);
- int a = findConfigAttrib(egl, display, config,
- EGL10.EGL_ALPHA_SIZE, 0);
+ int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
if ((r == mRedSize) && (g == mGreenSize)
&& (b == mBlueSize) && (a == mAlphaSize)) {
return config;
@@ -965,16 +987,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
protected int mAlphaSize;
protected int mDepthSize;
protected int mStencilSize;
- }
+ }
/**
* This class will choose a RGB_888 surface with
* or without a depth buffer.
*
*/
- private class SimpleEGLConfigChooser extends ComponentSizeChooser {
- public SimpleEGLConfigChooser(boolean withDepthBuffer) {
- super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);
+ private static class SimpleEGLConfigChooser extends ComponentSizeChooser {
+ public SimpleEGLConfigChooser(boolean withDepthBuffer, int version) {
+ super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0, version);
}
}
@@ -991,9 +1013,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* Initialize EGL for a given configuration spec.
* @param configSpec
*/
- public void start() {
+ public void initialize() {
if (LOG_EGL) {
- Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
+ Log.d(TAG, "initialize() tid=" + Thread.currentThread().getId());
}
/*
* Get an EGL instance
@@ -1034,7 +1056,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
throwEglException("createContext");
}
if (LOG_EGL) {
- Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
+ Log.d(TAG, "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
}
mEglSurface = null;
@@ -1048,7 +1070,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
*/
public boolean createSurface() {
if (LOG_EGL) {
- Log.w("EglHelper", "createSurface() tid=" + Thread.currentThread().getId());
+ Log.d(TAG, "createSurface() tid=" + Thread.currentThread().getId());
}
/*
* Check preconditions.
@@ -1083,7 +1105,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
int error = mEgl.eglGetError();
if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
- Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+ Log.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
}
return false;
}
@@ -1097,8 +1119,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* Could not make the context current, probably because the underlying
* SurfaceView surface has been destroyed.
*/
- logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
- return false;
+ logEglErrorAsWarning(TAG, "eglMakeCurrent", mEgl.eglGetError());
+ // we fall-through to "true" here because we do have a
+ // valid EGLSurface at this point.
}
return true;
@@ -1108,8 +1131,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* Create a GL object for the current EGL context.
* @return
*/
- GL createGL() {
-
+ public GL createGL() {
GL gl = mEglContext.getGL();
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
@@ -1145,7 +1167,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
public void destroySurface() {
if (LOG_EGL) {
- Log.w("EglHelper", "destroySurface() tid=" + Thread.currentThread().getId());
+ Log.d(TAG, "destroySurface() tid=" + Thread.currentThread().getId());
}
destroySurfaceImp();
}
@@ -1163,9 +1185,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
}
- public void finish() {
+ public void terminate() {
if (LOG_EGL) {
- Log.w("EglHelper", "finish() tid=" + Thread.currentThread().getId());
+ Log.d(TAG, "terminate() tid=" + Thread.currentThread().getId());
}
if (mEglContext != null) {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
@@ -1187,7 +1209,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
public static void throwEglException(String function, int error) {
String message = formatEglError(function, error);
if (LOG_THREADS) {
- Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " "
+ Log.e(TAG, "throwEglException tid=" + Thread.currentThread().getId() + " "
+ message);
}
throw new RuntimeException(message);
@@ -1207,584 +1229,411 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
EGLSurface mEglSurface;
EGLConfig mEglConfig;
EGLContext mEglContext;
-
}
/**
* A generic GL Thread. Takes care of initializing EGL and GL. Delegates
* 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.
- *
*/
- static class GLThread extends Thread {
- GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
- super();
+
+ static class GLThread extends HandlerThread {
+ // only accessed from GLThread
+ private GL10 mGLContext;
+ private int mWidth;
+ private int mHeight;
+ private boolean mSizeChanged;
+ // current render mode
+ private int mRenderMode;
+ // the EGLSurface exists but isn't working for some reason
+ private boolean mEglSurfaceIsBad;
+ // we have an EGLContext
+ private boolean mHaveEglContext;
+ // we have an EGLSurface
+ private boolean mHaveEglSurface;
+ // we have a Surface (i.e.: EGLNativeWindowType)
+ private boolean mHasSurface;
+ // activity is paused
+ private boolean mPaused;
+
+ // constants
+ private EglHelper mEglHelper;
+ private Handler mGLHandler;
+ private Choreographer mChoreographer;
+
+ /*
+ * Set once at thread construction time, nulled out when the parent view is garbage
+ * called. This weak reference allows the GLSurfaceView to be garbage collected while
+ * the GLThread is still alive.
+ */
+ private final WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
+
+ private final Runnable mExecuteDrawAction = new Runnable() {
+ private int mTraceVsyncCounter = 0;
+ @Override
+ public void run() {
+ if (TRACE_ENABLED) {
+ Trace.traceCounter(Trace.TRACE_TAG_GRAPHICS,
+ "GLSurfaceView VSYNC counter", (mTraceVsyncCounter++) & 0xf);
+ }
+ executeDraw();
+ }
+ };
+
+ public GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
+ super("GLThread", android.os.Process.THREAD_PRIORITY_DISPLAY);
+ if (LOG_THREADS) {
+ Log.d(TAG, "*** Starting GLThread ***");
+ }
mWidth = 0;
mHeight = 0;
- mRequestRender = true;
mRenderMode = RENDERMODE_CONTINUOUSLY;
mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
}
+ private void readyToRun() {
+ mChoreographer = Choreographer.getInstance();
+ mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
+ }
+
@Override
- public void run() {
- setName("GLThread " + getId());
- if (LOG_THREADS) {
- Log.i("GLThread", "starting tid=" + getId());
- }
+ public void start() {
+ super.start();
+ // getLooper() blocks until the thread is running
+ Looper looper = getLooper();
+ mGLHandler = new Handler(looper);
+ // don't return until the GLThread state has been initialized
+ mGLHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ readyToRun();
+ }
+ }, 0);
+ }
+ @Override
+ public void run() {
try {
- guardedRun();
- } catch (InterruptedException e) {
- // fall thru and exit normally
+ super.run();
} finally {
- sGLThreadManager.threadExiting(this);
+ // by definition the GLThread is not running anymore here
+ stopEglContext();
+ stopEglSurface();
}
}
- /*
- * This private method should only be called inside a
- * synchronized(sGLThreadManager) block.
- */
- private void stopEglSurfaceLocked() {
+ // only call from the GLThread
+ private void stopEglSurface() {
if (mHaveEglSurface) {
+ if (LOG_SURFACE) {
+ Log.d(TAG, "releasing EGL surface because paused tid=" + getId());
+ }
mHaveEglSurface = false;
mEglHelper.destroySurface();
}
}
- /*
- * This private method should only be called inside a
- * synchronized(sGLThreadManager) block.
- */
- private void stopEglContextLocked() {
+ // only call from the GLThread
+ private void stopEglContext() {
if (mHaveEglContext) {
- mEglHelper.finish();
+ mEglHelper.terminate();
mHaveEglContext = false;
- sGLThreadManager.releaseEglContextLocked(this);
+ if (LOG_SURFACE) {
+ Log.d(TAG, "releasing EGL context because paused tid=" + getId());
+ }
}
}
- private void guardedRun() throws InterruptedException {
- mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
- mHaveEglContext = false;
- mHaveEglSurface = false;
- try {
- GL10 gl = null;
- boolean createEglContext = false;
- boolean createEglSurface = false;
- boolean createGlInterface = false;
- boolean lostEglContext = false;
- boolean sizeChanged = false;
- boolean wantRenderNotification = false;
- boolean doRenderNotification = false;
- boolean askedToReleaseEglContext = false;
- int w = 0;
- int h = 0;
- Runnable event = null;
-
- while (true) {
- synchronized (sGLThreadManager) {
- while (true) {
- if (mShouldExit) {
- return;
- }
-
- if (! mEventQueue.isEmpty()) {
- event = mEventQueue.remove(0);
- break;
- }
-
- // Update the pause state.
- boolean pausing = false;
- if (mPaused != mRequestPaused) {
- pausing = mRequestPaused;
- mPaused = mRequestPaused;
- sGLThreadManager.notifyAll();
- if (LOG_PAUSE_RESUME) {
- Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId());
- }
- }
-
- // Do we need to give up the EGL context?
- if (mShouldReleaseEglContext) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "releasing EGL context because asked to tid=" + getId());
- }
- stopEglSurfaceLocked();
- stopEglContextLocked();
- mShouldReleaseEglContext = false;
- askedToReleaseEglContext = true;
- }
-
- // Have we lost the EGL context?
- if (lostEglContext) {
- stopEglSurfaceLocked();
- stopEglContextLocked();
- lostEglContext = false;
- }
- // When pausing, release the EGL surface:
- if (pausing && mHaveEglSurface) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
- }
- stopEglSurfaceLocked();
- }
-
- // When pausing, optionally release the EGL Context:
- if (pausing && mHaveEglContext) {
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- boolean preserveEglContextOnPause = view == null ?
- false : view.mPreserveEGLContextOnPause;
- if (!preserveEglContextOnPause || sGLThreadManager.shouldReleaseEGLContextWhenPausing()) {
- stopEglContextLocked();
- if (LOG_SURFACE) {
- Log.i("GLThread", "releasing EGL context because paused tid=" + getId());
- }
- }
- }
-
- // 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) {
- Log.i("GLThread", "noticed surfaceView surface lost tid=" + getId());
- }
- if (mHaveEglSurface) {
- stopEglSurfaceLocked();
- }
- mWaitingForSurface = true;
- mSurfaceIsBad = false;
- sGLThreadManager.notifyAll();
- }
+ private void updateState() {
+ final boolean wasAbleToDraw = isAbleToDraw();
+ if (!isReadyToDraw()) {
+ return;
+ }
- // Have we acquired the surface view surface?
- if (mHasSurface && mWaitingForSurface) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "noticed surfaceView surface acquired tid=" + getId());
- }
- mWaitingForSurface = false;
- sGLThreadManager.notifyAll();
- }
+ if (!mHaveEglSurface || mSizeChanged) {
+ // create EGL context if needed
+ boolean reportSurfaceCreated = false;
+ if (!mHaveEglContext) {
+ mEglHelper.initialize();
+ mHaveEglContext = true;
+ reportSurfaceCreated = true;
+ }
- if (doRenderNotification) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "sending render notification tid=" + getId());
- }
- wantRenderNotification = false;
- doRenderNotification = false;
- mRenderComplete = true;
- sGLThreadManager.notifyAll();
- }
+ // get the GL interface for the active EGLContext
+ mGLContext = (GL10)mEglHelper.createGL();
- // Ready to draw?
- if (readyToDraw()) {
-
- // If we don't have an EGL context, try to acquire one.
- if (! mHaveEglContext) {
- if (askedToReleaseEglContext) {
- askedToReleaseEglContext = false;
- } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) {
- try {
- mEglHelper.start();
- } catch (RuntimeException t) {
- sGLThreadManager.releaseEglContextLocked(this);
- throw t;
- }
- mHaveEglContext = true;
- createEglContext = true;
-
- sGLThreadManager.notifyAll();
- }
- }
-
- if (mHaveEglContext && !mHaveEglSurface) {
- mHaveEglSurface = true;
- createEglSurface = true;
- createGlInterface = true;
- sizeChanged = true;
- }
-
- if (mHaveEglSurface) {
- if (mSizeChanged) {
- sizeChanged = true;
- w = mWidth;
- h = mHeight;
- wantRenderNotification = true;
- if (LOG_SURFACE) {
- Log.i("GLThread",
- "noticing that we want render notification tid="
- + getId());
- }
-
- // Destroy and recreate the EGL surface.
- createEglSurface = true;
-
- mSizeChanged = false;
- }
- mRequestRender = false;
- sGLThreadManager.notifyAll();
- break;
- }
- }
+ // create EGL Surface
+ mHaveEglSurface = mEglHelper.createSurface();
+ mEglSurfaceIsBad = !mHaveEglSurface;
+ mSizeChanged = false;
- // By design, this is the only place in a GLThread thread where we wait().
- if (LOG_THREADS) {
- Log.i("GLThread", "waiting tid=" + getId()
- + " mHaveEglContext: " + mHaveEglContext
- + " mHaveEglSurface: " + mHaveEglSurface
- + " mFinishedCreatingEglSurface: " + mFinishedCreatingEglSurface
- + " mPaused: " + mPaused
- + " mHasSurface: " + mHasSurface
- + " mSurfaceIsBad: " + mSurfaceIsBad
- + " mWaitingForSurface: " + mWaitingForSurface
- + " mWidth: " + mWidth
- + " mHeight: " + mHeight
- + " mRequestRender: " + mRequestRender
- + " mRenderMode: " + mRenderMode);
- }
- sGLThreadManager.wait();
+ // notify use of surface size change
+ GLSurfaceView view = mGLSurfaceViewWeakRef.get();
+ if (view != null) {
+ if (reportSurfaceCreated) {
+ if (LOG_RENDERER) {
+ Log.d(TAG, "onSurfaceCreated");
}
- } // end of synchronized(sGLThreadManager)
-
- if (event != null) {
- event.run();
- event = null;
- continue;
+ view.mRenderer.onSurfaceCreated(mGLContext, mEglHelper.mEglConfig);
}
- if (createEglSurface) {
- if (LOG_SURFACE) {
- Log.w("GLThread", "egl createSurface");
- }
- if (mEglHelper.createSurface()) {
- synchronized(sGLThreadManager) {
- mFinishedCreatingEglSurface = true;
- sGLThreadManager.notifyAll();
- }
- } else {
- synchronized(sGLThreadManager) {
- mFinishedCreatingEglSurface = true;
- mSurfaceIsBad = true;
- sGLThreadManager.notifyAll();
- }
- continue;
- }
- createEglSurface = false;
+ if (LOG_RENDERER) {
+ Log.d(TAG, "onSurfaceChanged(" + mWidth + ", " + mHeight + ")");
}
+ view.mRenderer.onSurfaceChanged(mGLContext, mWidth, mHeight);
+ }
+ }
- if (createGlInterface) {
- gl = (GL10) mEglHelper.createGL();
+ // see if we should kick the rendering loop
+ if (!wasAbleToDraw && isAbleToDraw()) {
+ // we're now able to draw
+ if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
+ requestRender();
+ }
+ }
- sGLThreadManager.checkGLDriver(gl);
- createGlInterface = false;
- }
+ // By design, this is the only place in a GLThread thread where we wait().
+ if (LOG_THREADS) {
+ Log.d(TAG, "waiting tid=" + getId()
+ + " mHaveEglContext: " + mHaveEglContext
+ + " mHaveEglSurface: " + mHaveEglSurface
+ + " mPaused: " + mPaused
+ + " mHasSurface: " + mHasSurface
+ + " mSurfaceIsBad: " + mEglSurfaceIsBad
+ + " mWidth: " + mWidth
+ + " mHeight: " + mHeight
+ + " mRenderMode: " + mRenderMode);
+ }
+ }
- if (createEglContext) {
- if (LOG_RENDERER) {
- Log.w("GLThread", "onSurfaceCreated");
- }
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
- }
- createEglContext = false;
- }
+ private void executeDraw() {
+ if (TRACE_ENABLED) {
+ Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "executeDraw");
+ }
- if (sizeChanged) {
- if (LOG_RENDERER) {
- Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
- }
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- view.mRenderer.onSurfaceChanged(gl, w, h);
- }
- sizeChanged = false;
- }
+ if (isAbleToDraw()) {
+ if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
+ requestRender();
+ }
- if (LOG_RENDERER_DRAW_FRAME) {
- Log.w("GLThread", "onDrawFrame tid=" + getId());
- }
- {
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- view.mRenderer.onDrawFrame(gl);
- }
- }
+ if (LOG_RENDERER_DRAW_FRAME) {
+ Log.d(TAG, "onDrawFrame tid=" + getId());
+ }
+
+ GLSurfaceView view = mGLSurfaceViewWeakRef.get();
+ if (view != null) {
+ view.mRenderer.onDrawFrame(mGLContext);
int swapError = mEglHelper.swap();
switch (swapError) {
case EGL10.EGL_SUCCESS:
break;
case EGL11.EGL_CONTEXT_LOST:
if (LOG_SURFACE) {
- Log.i("GLThread", "egl context lost tid=" + getId());
+ Log.d(TAG, "egl context lost tid=" + getId());
}
- lostEglContext = true;
+ stopEglSurface();
+ stopEglContext();
break;
default:
// Other errors typically mean that the current surface is bad,
// probably because the SurfaceView surface has been destroyed,
// but we haven't been notified yet.
// Log the error to help developers understand why rendering stopped.
- EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError);
-
- synchronized(sGLThreadManager) {
- mSurfaceIsBad = true;
- sGLThreadManager.notifyAll();
- }
+ EglHelper.logEglErrorAsWarning(TAG, "eglSwapBuffers", swapError);
+ mEglSurfaceIsBad = true;
break;
}
-
- if (wantRenderNotification) {
- doRenderNotification = true;
- }
}
+ }
- } finally {
- /*
- * clean-up everything...
- */
- synchronized (sGLThreadManager) {
- stopEglSurfaceLocked();
- stopEglContextLocked();
- }
+ if (TRACE_ENABLED) {
+ Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
}
}
- public boolean ableToDraw() {
- return mHaveEglContext && mHaveEglSurface && readyToDraw();
+ private boolean isAbleToDraw() {
+ return mHaveEglContext && mHaveEglSurface && isReadyToDraw();
}
- private boolean readyToDraw() {
- return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
- && (mWidth > 0) && (mHeight > 0)
- && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
+ private boolean isReadyToDraw() {
+ return (!mPaused) && mHasSurface && (!mEglSurfaceIsBad)
+ && (mWidth > 0) && (mHeight > 0);
}
- public void setRenderMode(int renderMode) {
- if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
- throw new IllegalArgumentException("renderMode");
+ private boolean isEglContextReleasedWhenPausing() {
+ GLSurfaceView view = mGLSurfaceViewWeakRef.get();
+ return (view != null) ? !view.mPreserveEGLContextOnPause : false;
+ }
+
+ public void queueEvent(Runnable r) {
+ if (r == null) {
+ throw new IllegalArgumentException("Runnable r must not be null");
}
- synchronized(sGLThreadManager) {
- mRenderMode = renderMode;
- sGLThreadManager.notifyAll();
+ mGLHandler.post(r);
+ }
+
+ /*
+ * the call-backs below all run on the GLThread and implement state
+ * changes of the GLSurfaceView and Activity life cycle.
+ */
+
+ private void doSurfaceCreated() {
+ mHasSurface = true;
+ updateState();
+ }
+
+ private void doSurfaceDestroyed() {
+ if (mHasSurface) {
+ if (LOG_SURFACE) {
+ Log.d(TAG, "noticed surfaceView surface lost tid=" + getId());
+ }
+ stopEglSurface();
}
+ mHasSurface = false;
}
- public int getRenderMode() {
- synchronized(sGLThreadManager) {
- return mRenderMode;
+ private void doPause() {
+ if (mPaused == false) {
+ mPaused = true;
+ stopEglSurface();
+ // When pausing, optionally release the EGL Context:
+ if (mHaveEglContext && isEglContextReleasedWhenPausing()) {
+ stopEglContext();
+ }
}
}
- public void requestRender() {
- synchronized(sGLThreadManager) {
- mRequestRender = true;
- sGLThreadManager.notifyAll();
+ private void doResume() {
+ mPaused = false;
+ updateState();
+ if (mRenderMode == RENDERMODE_WHEN_DIRTY) {
+ executeDraw();
}
}
+ private void doWindowResize(final int width, final int height) {
+ // we were not drawing yet. Update the window size and
+ // state and attempt to draw a frame.
+ mSizeChanged = (mWidth != width || mHeight != height);
+ mWidth = width;
+ mHeight = height;
+ updateState();
+ // we always (attempt to) draw a frame before returning
+ executeDraw();
+ }
+
+ private void doSetRenderMode(final int renderMode) {
+ mRenderMode = renderMode;
+ requestRender();
+ }
+
+ /*
+ * the call-backs below run on the main UI thread, they just
+ * wait while executing work on the GLThread.
+ */
+
public void surfaceCreated() {
- synchronized(sGLThreadManager) {
- if (LOG_THREADS) {
- Log.i("GLThread", "surfaceCreated tid=" + getId());
+ mGLHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ doSurfaceCreated();
}
- mHasSurface = true;
- mFinishedCreatingEglSurface = false;
- sGLThreadManager.notifyAll();
- while (mWaitingForSurface
- && !mFinishedCreatingEglSurface
- && !mExited) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
+ }, 0);
}
public void surfaceDestroyed() {
- synchronized(sGLThreadManager) {
- if (LOG_THREADS) {
- Log.i("GLThread", "surfaceDestroyed tid=" + getId());
+ mGLHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ doSurfaceDestroyed();
}
- mHasSurface = false;
- sGLThreadManager.notifyAll();
- while((!mWaitingForSurface) && (!mExited)) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
+ }, 0);
}
public void onPause() {
- synchronized (sGLThreadManager) {
- if (LOG_PAUSE_RESUME) {
- Log.i("GLThread", "onPause tid=" + getId());
- }
- mRequestPaused = true;
- sGLThreadManager.notifyAll();
- while ((! mExited) && (! mPaused)) {
- if (LOG_PAUSE_RESUME) {
- Log.i("Main thread", "onPause waiting for mPaused.");
- }
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
+ mGLHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ doPause();
}
- }
+ }, 0);
}
public void onResume() {
- synchronized (sGLThreadManager) {
- if (LOG_PAUSE_RESUME) {
- Log.i("GLThread", "onResume tid=" + getId());
- }
- mRequestPaused = false;
- mRequestRender = true;
- mRenderComplete = false;
- sGLThreadManager.notifyAll();
- while ((! mExited) && mPaused && (!mRenderComplete)) {
- if (LOG_PAUSE_RESUME) {
- Log.i("Main thread", "onResume waiting for !mPaused.");
- }
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
+ mGLHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ doResume();
}
- }
+ }, 0);
}
public void onWindowResize(int w, int h) {
- synchronized (sGLThreadManager) {
- mWidth = w;
- mHeight = h;
- mSizeChanged = true;
- mRequestRender = true;
- mRenderComplete = false;
- sGLThreadManager.notifyAll();
-
- // Wait for thread to react to resize and render a frame
- while (! mExited && !mPaused && !mRenderComplete
- && ableToDraw()) {
- if (LOG_SURFACE) {
- Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + getId());
- }
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
+ final int width = w;
+ final int height = h;
+ mGLHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ doWindowResize(width, height);
}
- }
+ }, 0);
}
- public void requestExitAndWait() {
- // don't call this from GLThread thread or it is a guaranteed
- // deadlock!
- synchronized(sGLThreadManager) {
- mShouldExit = true;
- sGLThreadManager.notifyAll();
- while (! mExited) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
+ /*
+ * the methods below can be called from any thread
+ */
+
+ public void requestRender() {
+ if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
+ mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
+ mExecuteDrawAction, null);
+ } else {
+ /*
+ * in RENDERMODE_WHEN_DIRTY we schedule the draw callback
+ * immediately because the developer is manager her
+ * timing loop manually -- in particular she could be
+ * using the Choreographer already.
+ */
+ mGLHandler.post(mExecuteDrawAction);
}
}
- public void requestReleaseEglContextLocked() {
- mShouldReleaseEglContext = true;
- sGLThreadManager.notifyAll();
+ public void setRenderMode(final int renderMode) {
+ mGLHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ doSetRenderMode(renderMode);
+ }
+ }, 0);
}
- /**
- * Queue an "event" to be run on the GL rendering thread.
- * @param r the runnable to be run on the GL rendering thread.
- */
- public void queueEvent(Runnable r) {
- if (r == null) {
- throw new IllegalArgumentException("r must not be null");
- }
- synchronized(sGLThreadManager) {
- mEventQueue.add(r);
- sGLThreadManager.notifyAll();
+ public void requestExitAndWait() {
+ getLooper().quit();
+ try {
+ this.join();
+ } catch (InterruptedException e) {
}
}
-
- // Once the thread is started, all accesses to the following member
- // variables are protected by the sGLThreadManager monitor
- private boolean mShouldExit;
- private boolean mExited;
- private boolean mRequestPaused;
- private boolean mPaused;
- private boolean mHasSurface;
- private boolean mSurfaceIsBad;
- private boolean mWaitingForSurface;
- private boolean mHaveEglContext;
- private boolean mHaveEglSurface;
- private boolean mFinishedCreatingEglSurface;
- private boolean mShouldReleaseEglContext;
- private int mWidth;
- private int mHeight;
- private int mRenderMode;
- private boolean mRequestRender;
- private boolean mRenderComplete;
- private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
- private boolean mSizeChanged = true;
-
- // End of member variables protected by the sGLThreadManager monitor.
-
- private EglHelper mEglHelper;
-
- /**
- * Set once at thread construction time, nulled out when the parent view is garbage
- * called. This weak reference allows the GLSurfaceView to be garbage collected while
- * the GLThread is still alive.
- */
- private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
-
- }
+ } // class GLThread
static class LogWriter extends Writer {
-
- @Override public void close() {
+ @Override
+ public void close() {
flushBuilder();
}
- @Override public void flush() {
+ @Override
+ public void flush() {
flushBuilder();
}
- @Override public void write(char[] buf, int offset, int count) {
- for(int i = 0; i < count; i++) {
+ @Override
+ public void write(char[] buf, int offset, int count) {
+ for (int i = 0; i < count; i++) {
char c = buf[offset + i];
- if ( c == '\n') {
+ if (c == '\n') {
flushBuilder();
- }
- else {
+ } else {
mBuilder.append(c);
}
}
@@ -1792,7 +1641,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private void flushBuilder() {
if (mBuilder.length() > 0) {
- Log.v("GLSurfaceView", mBuilder.toString());
+ Log.v(TAG, mBuilder.toString());
mBuilder.delete(0, mBuilder.length());
}
}
@@ -1800,141 +1649,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private StringBuilder mBuilder = new StringBuilder();
}
-
private void checkRenderThreadState() {
if (mGLThread != null) {
throw new IllegalStateException(
"setRenderer has already been called for this instance.");
}
}
-
- private static class GLThreadManager {
- private static String TAG = "GLThreadManager";
-
- public synchronized void threadExiting(GLThread thread) {
- if (LOG_THREADS) {
- 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();
-
- private final WeakReference<GLSurfaceView> mThisWeakRef =
- new WeakReference<GLSurfaceView>(this);
- private GLThread mGLThread;
- private Renderer mRenderer;
- private boolean mDetached;
- private EGLConfigChooser mEGLConfigChooser;
- private EGLContextFactory mEGLContextFactory;
- private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
- private GLWrapper mGLWrapper;
- private int mDebugFlags;
- private int mEGLContextClientVersion;
- private boolean mPreserveEGLContextOnPause;
}