• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.opengl;
18 
19 import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY;
20 import static javax.microedition.khronos.egl.EGL10.EGL_NO_DISPLAY;
21 
22 import java.util.ArrayList;
23 
24 import javax.microedition.khronos.egl.EGL10;
25 import javax.microedition.khronos.egl.EGLContext;
26 import javax.microedition.khronos.egl.EGLDisplay;
27 
28 import android.os.Looper;
29 import android.util.Log;
30 
31 import com.google.android.gles_jni.EGLImpl;
32 
33 /**
34  * The per-process memory overhead of hardware accelerated graphics can
35  * be quite large on some devices.  For small memory devices, being able to
36  * terminate all EGL contexts so that this graphics driver memory can be
37  * reclaimed can significant improve the overall behavior of the device.  This
38  * class helps app developers participate in releasing their EGL context
39  * when appropriate and possible.
40  *
41  * <p>To use, simple instantiate this class with the EGLContext you create.
42  * When you have done this, if the device is getting low on memory and all
43  * of the currently created EGL contexts in the process are being managed
44  * through this class, then they will all be asked to terminate through the
45  * call to {@link #onTerminate}.
46  *
47  * @hide
48  */
49 public abstract class ManagedEGLContext {
50     static final String TAG = "ManagedEGLContext";
51 
52     static final ArrayList<ManagedEGLContext> sActive = new ArrayList<ManagedEGLContext>();
53 
54     final EGLContext mContext;
55 
56     /**
57      * Instantiate to manage the given EGLContext.
58      */
ManagedEGLContext(EGLContext context)59     public ManagedEGLContext(EGLContext context) {
60         mContext = context;
61         synchronized (sActive) {
62             sActive.add(this);
63         }
64     }
65 
66     /**
67      * Retrieve the EGLContext being managed by the class.
68      */
getContext()69     public EGLContext getContext() {
70         return mContext;
71     }
72 
73     /**
74      * Force-terminate the ManagedEGLContext.  This will cause
75      * {@link #onTerminate(EGLContext)} to be called.  You <em>must</em>
76      * call this when destroying the EGLContext, so that the framework
77      * knows to stop managing it.
78      */
terminate()79     public void terminate() {
80         execTerminate();
81     }
82 
execTerminate()83     void execTerminate() {
84         onTerminate(mContext);
85     }
86 
87     /**
88      * Override this method to destroy the EGLContext when appropriate.
89      * <em>Note that this method is always called on the main thread
90      * of the process.</em>  If your EGLContext was created on a different
91      * thread, you will need to implement this method to hand off the work
92      * of destroying the context to that thread.
93      */
onTerminate(EGLContext context)94     public abstract void onTerminate(EGLContext context);
95 
96     /** @hide */
doTerminate()97     public static boolean doTerminate() {
98         ArrayList<ManagedEGLContext> active;
99 
100         if (Looper.getMainLooper() != Looper.myLooper()) {
101             throw new IllegalStateException("Called on wrong thread");
102         }
103 
104         synchronized (sActive) {
105             // If there are no active managed contexts, we will not even
106             // try to terminate.
107             if (sActive.size() <= 0) {
108                 return false;
109             }
110 
111             // Need to check how many EGL contexts are actually running,
112             // to compare with how many we are managing.
113             EGL10 egl = (EGL10) EGLContext.getEGL();
114             EGLDisplay display = egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
115 
116             if (display == EGL_NO_DISPLAY) {
117                 Log.w(TAG, "doTerminate failed: no display");
118                 return false;
119             }
120 
121             if (EGLImpl.getInitCount(display) != sActive.size()) {
122                 Log.w(TAG, "doTerminate failed: EGL count is " + EGLImpl.getInitCount(display)
123                         + " but managed count is " + sActive.size());
124                 return false;
125             }
126 
127             active = new ArrayList<ManagedEGLContext>(sActive);
128             sActive.clear();
129         }
130 
131         for (int i = 0; i < active.size(); i++) {
132             active.get(i).execTerminate();
133         }
134 
135         return true;
136     }
137 }
138