| /* |
| * 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}. |
| * |
| * @hide |
| */ |
| 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; |
| } |
| } |