1717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn/*
2717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * Copyright (C) 2010 The Android Open Source Project
3717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn *
4717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * you may not use this file except in compliance with the License.
6717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * You may obtain a copy of the License at
7717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn *
8717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn *
10717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * See the License for the specific language governing permissions and
14717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * limitations under the License.
15717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn */
16717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
17717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornpackage android.opengl;
18717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
19717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY;
20717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport static javax.microedition.khronos.egl.EGL10.EGL_NO_DISPLAY;
21717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
22717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport java.util.ArrayList;
23717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
24717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport javax.microedition.khronos.egl.EGL10;
25717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport javax.microedition.khronos.egl.EGLContext;
26717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport javax.microedition.khronos.egl.EGLDisplay;
27717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
28717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport android.os.Looper;
29717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport android.util.Log;
30717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
31717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport com.google.android.gles_jni.EGLImpl;
32717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
33717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn/**
34717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * The per-process memory overhead of hardware accelerated graphics can
35717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * be quite large on some devices.  For small memory devices, being able to
36717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * terminate all EGL contexts so that this graphics driver memory can be
37717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * reclaimed can significant improve the overall behavior of the device.  This
38717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * class helps app developers participate in releasing their EGL context
39717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * when appropriate and possible.
40717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn *
41717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * <p>To use, simple instantiate this class with the EGLContext you create.
42717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * When you have done this, if the device is getting low on memory and all
43717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * of the currently created EGL contexts in the process are being managed
44717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * through this class, then they will all be asked to terminate through the
45717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn * call to {@link #onTerminate}.
46dccf73a50cb2a219182e141bac1d9da82fdaf4d7Romain Guy *
47dccf73a50cb2a219182e141bac1d9da82fdaf4d7Romain Guy * @hide
48717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn */
49717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornpublic abstract class ManagedEGLContext {
50717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    static final String TAG = "ManagedEGLContext";
51717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
5231f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy    static final ArrayList<ManagedEGLContext> sActive = new ArrayList<ManagedEGLContext>();
53717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
54717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    final EGLContext mContext;
55717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
56717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    /**
57717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * Instantiate to manage the given EGLContext.
58717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     */
59717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    public ManagedEGLContext(EGLContext context) {
60717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        mContext = context;
61717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        synchronized (sActive) {
62717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            sActive.add(this);
63717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        }
64717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    }
65717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
66717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    /**
67717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * Retrieve the EGLContext being managed by the class.
68717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     */
69717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    public EGLContext getContext() {
70717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        return mContext;
71717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    }
72717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
73717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    /**
74717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * Force-terminate the ManagedEGLContext.  This will cause
75717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * {@link #onTerminate(EGLContext)} to be called.  You <em>must</em>
76717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * call this when destroying the EGLContext, so that the framework
77717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * knows to stop managing it.
78717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     */
79717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    public void terminate() {
80717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        execTerminate();
81717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    }
82717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
83717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    void execTerminate() {
84717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        onTerminate(mContext);
85717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    }
86717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
87717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    /**
88717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * Override this method to destroy the EGLContext when appropriate.
89717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * <em>Note that this method is always called on the main thread
90717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * of the process.</em>  If your EGLContext was created on a different
91717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * thread, you will need to implement this method to hand off the work
92717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     * of destroying the context to that thread.
93717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn     */
94717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    public abstract void onTerminate(EGLContext context);
95717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
96717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    /** @hide */
97717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    public static boolean doTerminate() {
98717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        ArrayList<ManagedEGLContext> active;
99717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
100717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        if (Looper.getMainLooper() != Looper.myLooper()) {
101717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            throw new IllegalStateException("Called on wrong thread");
102717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        }
103717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
104717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        synchronized (sActive) {
105717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            // If there are no active managed contexts, we will not even
106717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            // try to terminate.
107717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            if (sActive.size() <= 0) {
108717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                return false;
109717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            }
110717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
111717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            // Need to check how many EGL contexts are actually running,
112717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            // to compare with how many we are managing.
113717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            EGL10 egl = (EGL10) EGLContext.getEGL();
114717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            EGLDisplay display = egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
115717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
116717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            if (display == EGL_NO_DISPLAY) {
117717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                Log.w(TAG, "doTerminate failed: no display");
118717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                return false;
119717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            }
120717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
121717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            if (EGLImpl.getInitCount(display) != sActive.size()) {
122717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                Log.w(TAG, "doTerminate failed: EGL count is " + EGLImpl.getInitCount(display)
123717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        + " but managed count is " + sActive.size());
124717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                return false;
125717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            }
126717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
127717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            active = new ArrayList<ManagedEGLContext>(sActive);
128717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            sActive.clear();
129717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        }
130717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
13131f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy        for (int i = 0; i < active.size(); i++) {
132717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            active.get(i).execTerminate();
133717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        }
134717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
135717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        return true;
136717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn    }
137717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn}
138