diff options
Diffstat (limited to 'opengl/java/android')
-rw-r--r-- | opengl/java/android/opengl/EGLLogWrapper.java | 10 | ||||
-rw-r--r-- | opengl/java/android/opengl/GLSurfaceView.java | 20 | ||||
-rw-r--r-- | opengl/java/android/opengl/ManagedEGLContext.java | 136 |
3 files changed, 163 insertions, 3 deletions
diff --git a/opengl/java/android/opengl/EGLLogWrapper.java b/opengl/java/android/opengl/EGLLogWrapper.java index 6c0fdb3..36e88a2 100644 --- a/opengl/java/android/opengl/EGLLogWrapper.java +++ b/opengl/java/android/opengl/EGLLogWrapper.java @@ -314,6 +314,16 @@ class EGLLogWrapper implements EGL11 { checkError(); return result; } + + /** @hide **/ + public boolean eglReleaseThread() { + begin("eglReleaseThread"); + end(); + boolean result = mEgl10.eglReleaseThread(); + returns(result); + checkError(); + return result; + } public boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface) { begin("eglInitialize"); diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 51b7c58..8fd866c 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -781,6 +781,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback * {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)} */ public interface EGLWindowSurfaceFactory { + /** + * @return null if the surface cannot be constructed. + */ EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, Object nativeWindow); void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface); @@ -790,7 +793,19 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, Object nativeWindow) { - return egl.eglCreateWindowSurface(display, config, nativeWindow, null); + EGLSurface result = null; + 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 + // been torn down, but the application has not yet been + // notified via SurfaceHolder.Callback.surfaceDestroyed. + // In theory the application should be notified first, + // but in practice sometimes it is not. See b/4588890 + Log.e(TAG, "eglCreateWindowSurface", e); + } + return result; } public void destroySurface(EGL10 egl, EGLDisplay display, @@ -1054,9 +1069,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback int error = mEgl.eglGetError(); if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); - return null; } - throwEglException("createWindowSurface", error); + return null; } /* diff --git a/opengl/java/android/opengl/ManagedEGLContext.java b/opengl/java/android/opengl/ManagedEGLContext.java new file mode 100644 index 0000000..d3a3662 --- /dev/null +++ b/opengl/java/android/opengl/ManagedEGLContext.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.opengl; + +import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY; +import static javax.microedition.khronos.egl.EGL10.EGL_NO_DISPLAY; + +import java.util.ArrayList; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; + +import android.os.Looper; +import android.util.Log; + +import com.google.android.gles_jni.EGLImpl; + +/** + * The per-process memory overhead of hardware accelerated graphics can + * be quite large on some devices. For small memory devices, being able to + * terminate all EGL contexts so that this graphics driver memory can be + * reclaimed can significant improve the overall behavior of the device. This + * class helps app developers participate in releasing their EGL context + * when appropriate and possible. + * + * <p>To use, simple instantiate this class with the EGLContext you create. + * When you have done this, if the device is getting low on memory and all + * of the currently created EGL contexts in the process are being managed + * through this class, then they will all be asked to terminate through the + * call to {@link #onTerminate}. + */ +public abstract class ManagedEGLContext { + static final String TAG = "ManagedEGLContext"; + + static final ArrayList<ManagedEGLContext> sActive + = new ArrayList<ManagedEGLContext>(); + + final EGLContext mContext; + + /** + * Instantiate to manage the given EGLContext. + */ + public ManagedEGLContext(EGLContext context) { + mContext = context; + synchronized (sActive) { + sActive.add(this); + } + } + + /** + * Retrieve the EGLContext being managed by the class. + */ + public EGLContext getContext() { + return mContext; + } + + /** + * Force-terminate the ManagedEGLContext. This will cause + * {@link #onTerminate(EGLContext)} to be called. You <em>must</em> + * call this when destroying the EGLContext, so that the framework + * knows to stop managing it. + */ + public void terminate() { + execTerminate(); + } + + void execTerminate() { + onTerminate(mContext); + } + + /** + * Override this method to destroy the EGLContext when appropriate. + * <em>Note that this method is always called on the main thread + * of the process.</em> If your EGLContext was created on a different + * thread, you will need to implement this method to hand off the work + * of destroying the context to that thread. + */ + public abstract void onTerminate(EGLContext context); + + /** @hide */ + public static boolean doTerminate() { + ArrayList<ManagedEGLContext> active; + + if (Looper.getMainLooper() != Looper.myLooper()) { + throw new IllegalStateException("Called on wrong thread"); + } + + synchronized (sActive) { + // If there are no active managed contexts, we will not even + // try to terminate. + if (sActive.size() <= 0) { + return false; + } + + // Need to check how many EGL contexts are actually running, + // to compare with how many we are managing. + EGL10 egl = (EGL10) EGLContext.getEGL(); + EGLDisplay display = egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); + + if (display == EGL_NO_DISPLAY) { + Log.w(TAG, "doTerminate failed: no display"); + return false; + } + + if (EGLImpl.getInitCount(display) != sActive.size()) { + Log.w(TAG, "doTerminate failed: EGL count is " + EGLImpl.getInitCount(display) + + " but managed count is " + sActive.size()); + return false; + } + + active = new ArrayList<ManagedEGLContext>(sActive); + sActive.clear(); + } + + for (int i=0; i<active.size(); i++) { + active.get(i).execTerminate(); + } + + return true; + } +} |