GLSurfaceView.java revision 57d019e222abc0de3f8876e682617d42872230c6
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.opengl;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.Writer;
2080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevichimport java.lang.ref.WeakReference;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGL10;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGL11;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGLConfig;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGLContext;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGLDisplay;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGLSurface;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.opengles.GL;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.opengles.GL10;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
3257d019e222abc0de3f8876e682617d42872230c6Mathias Agopianimport android.os.Handler;
3357d019e222abc0de3f8876e682617d42872230c6Mathias Agopianimport android.os.HandlerThread;
3457d019e222abc0de3f8876e682617d42872230c6Mathias Agopianimport android.os.Looper;
3557d019e222abc0de3f8876e682617d42872230c6Mathias Agopianimport android.os.Trace;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
3857d019e222abc0de3f8876e682617d42872230c6Mathias Agopianimport android.view.Choreographer;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.SurfaceHolder;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.SurfaceView;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An implementation of SurfaceView that uses the dedicated surface for
44b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * displaying OpenGL rendering.
45b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
46b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * A GLSurfaceView provides the following features:
47b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
48b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <ul>
49b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Manages a surface, which is a special piece of memory that can be
50b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * composited into the Android view system.
51b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Manages an EGL display, which enables OpenGL to render into a surface.
52b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Accepts a user-provided Renderer object that does the actual rendering.
53b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Renders on a dedicated thread to decouple rendering performance from the
54b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * UI thread.
55b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Supports both on-demand and continuous rendering.
56b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Optionally wraps, traces, and/or error-checks the renderer's OpenGL calls.
57b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </ul>
58b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *
5961fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <div class="special reference">
6061fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <h3>Developer Guides</h3>
6161fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <p>For more information about how to use OpenGL, read the
6261fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a> developer guide.</p>
6361fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * </div>
6461fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez *
65b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Using GLSurfaceView</h3>
66b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
67b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Typically you use GLSurfaceView by subclassing it and overriding one or more of the
68b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * View system input event methods. If your application does not need to override event
69b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * methods then GLSurfaceView can be used as-is. For the most part
70b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * GLSurfaceView behavior is customized by calling "set" methods rather than by subclassing.
71b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * For example, unlike a regular View, drawing is delegated to a separate Renderer object which
72b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * is registered with the GLSurfaceView
73b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * using the {@link #setRenderer(Renderer)} call.
74b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
75b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Initializing GLSurfaceView</h3>
76b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * All you have to do to initialize a GLSurfaceView is call {@link #setRenderer(Renderer)}.
77b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * However, if desired, you can modify the default behavior of GLSurfaceView by calling one or
78b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * more of these methods before calling setRenderer:
79b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <ul>
80b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setDebugFlags(int)}
81b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setEGLConfigChooser(boolean)}
82b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setEGLConfigChooser(EGLConfigChooser)}
83b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)}
84b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setGLWrapper(GLWrapper)}
85b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </ul>
86b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
8783835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * <h4>Specifying the android.view.Surface</h4>
8829e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian * By default GLSurfaceView will create a PixelFormat.RGB_888 format surface. If a translucent
8983835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * surface is required, call getHolder().setFormat(PixelFormat.TRANSLUCENT).
9083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * The exact format of a TRANSLUCENT surface is device dependent, but it will be
9183835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * a 32-bit-per-pixel surface with 8 bits per component.
9283835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * <p>
93b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h4>Choosing an EGL Configuration</h4>
9483835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * A given Android device may support multiple EGLConfig rendering configurations.
9583835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * The available configurations may differ in how may channels of data are present, as
96b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * well as how many bits are allocated to each channel. Therefore, the first thing
9783835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * GLSurfaceView has to do when starting to render is choose what EGLConfig to use.
9883835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * <p>
9929e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian * By default GLSurfaceView chooses a EGLConfig that has an RGB_888 pixel format,
10083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * with at least a 16-bit depth buffer and no stencil.
101b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
10283835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * If you would prefer a different EGLConfig
10383835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * you can override the default behavior by calling one of the
104b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * setEGLConfigChooser methods.
105b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
106b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h4>Debug Behavior</h4>
107b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * You can optionally modify the behavior of GLSurfaceView by calling
108b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * one or more of the debugging methods {@link #setDebugFlags(int)},
109b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * and {@link #setGLWrapper}. These methods may be called before and/or after setRenderer, but
110b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * typically they are called before setRenderer so that they take effect immediately.
111b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
112b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h4>Setting a Renderer</h4>
113b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Finally, you must call {@link #setRenderer} to register a {@link Renderer}.
114b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * The renderer is
115b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * responsible for doing the actual OpenGL rendering.
116b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
117b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Rendering Mode</h3>
118b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Once the renderer is set, you can control whether the renderer draws
119b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * continuously or on-demand by calling
120b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * {@link #setRenderMode}. The default is continuous rendering.
121b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
122b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Activity Life-cycle</h3>
123b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView clients
124b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * are required to call {@link #onPause()} when the activity pauses and
125b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * {@link #onResume()} when the activity resumes. These calls allow GLSurfaceView to
126b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate
127b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * the OpenGL display.
128b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
129b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Handling events</h3>
130b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>
131b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * To handle an event you will typically subclass GLSurfaceView and override the
132b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * appropriate method, just as you would with any other View. However, when handling
133b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * the event, you may need to communicate with the Renderer object
134b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * that's running in the rendering thread. You can do this using any
135b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * standard Java cross-thread communication mechanism. In addition,
136b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * one relatively easy way to communicate with your renderer is
137b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * to call
138b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * {@link #queueEvent(Runnable)}. For example:
139b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <pre class="prettyprint">
140b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * class MyGLSurfaceView extends GLSurfaceView {
141b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *
142b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *     private MyRenderer mMyRenderer;
143b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *
144b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *     public void start() {
145b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *         mMyRenderer = ...;
146b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *         setRenderer(mMyRenderer);
147b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *     }
148b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *
149b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *     public boolean onKeyDown(int keyCode, KeyEvent event) {
150b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
151b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *             queueEvent(new Runnable() {
152b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *                 // This method will be called on the rendering
153b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *                 // thread:
154b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *                 public void run() {
155b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *                     mMyRenderer.handleDpadCenter();
156b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *                 }});
157b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *             return true;
158b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *         }
159b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *         return super.onKeyDown(keyCode, event);
160b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich *     }
161b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * }
162b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </pre>
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
1662ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich    private final static String TAG = "GLSurfaceView";
1672ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich    private final static boolean LOG_ATTACH_DETACH = false;
16857c6a46bd0c84c4b349d49f8df12f30a8cfcdaa2Jack Palevich    private final static boolean LOG_THREADS = false;
1694a65900cd69b79e6e47d275575eaeb5bb2487f9fJack Palevich    private final static boolean LOG_SURFACE = false;
1704a65900cd69b79e6e47d275575eaeb5bb2487f9fJack Palevich    private final static boolean LOG_RENDERER = false;
1714a2221ec4a929976be570ad096252c8dea326e19Jack Palevich    private final static boolean LOG_RENDERER_DRAW_FRAME = false;
1724a65900cd69b79e6e47d275575eaeb5bb2487f9fJack Palevich    private final static boolean LOG_EGL = false;
17357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private final static boolean TRACE_ENABLED = false;
17457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
17557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private final WeakReference<GLSurfaceView> mThisWeakRef =
17657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            new WeakReference<GLSurfaceView>(this);
17757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private GLThread mGLThread;
17857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private Renderer mRenderer;
17957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private boolean mDetached;
18057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private EGLConfigChooser mEGLConfigChooser;
18157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private EGLContextFactory mEGLContextFactory;
18257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
18357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private GLWrapper mGLWrapper;
18457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private int mDebugFlags;
18557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private int mEGLContextClientVersion;
18657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private boolean mPreserveEGLContextOnPause;
18757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private int mUserRenderMode;
18857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
189b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
190b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * The renderer only renders
191b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * when the surface is created, or when {@link #requestRender} is called.
192b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *
193b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #getRenderMode()
194b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #setRenderMode(int)
195840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich     * @see #requestRender()
196b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static int RENDERMODE_WHEN_DIRTY = 0;
198b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
199b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * The renderer is called
200b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * continuously to re-render the scene.
201b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *
202b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #getRenderMode()
203b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #setRenderMode(int)
204b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
2053e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich    public final static int RENDERMODE_CONTINUOUSLY = 1;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
208b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Check glError() after every GL call and throw an exception if glError indicates
209b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * that an error has occurred. This can be used to help track down which OpenGL ES call
210b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * is causing an error.
211b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *
212b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #getDebugFlags
213b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #setDebugFlags
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static int DEBUG_CHECK_GL_ERROR = 1;
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView".
219b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *
220b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #getDebugFlags
221b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #setDebugFlags
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static int DEBUG_LOG_GL_CALLS = 2;
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
225b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
226b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Standard View constructor. In order to render something, you
227b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * must call {@link #setRenderer} to register a renderer.
228b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GLSurfaceView(Context context) {
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context);
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        init();
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
234b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
235b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Standard View constructor. In order to render something, you
236b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * must call {@link #setRenderer} to register a renderer.
237b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GLSurfaceView(Context context, AttributeSet attrs) {
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, attrs);
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        init();
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich    @Override
24480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich    protected void finalize() throws Throwable {
24580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich        try {
24680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            if (mGLThread != null) {
24780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                // GLThread may still be running if this view was never
24880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                // attached to a window.
24980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                mGLThread.requestExitAndWait();
25080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            }
25180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich        } finally {
25280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            super.finalize();
25380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich        }
25480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich    }
25580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void init() {
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Install a SurfaceHolder.Callback so we get notified when the
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // underlying surface is created and destroyed
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SurfaceHolder holder = getHolder();
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        holder.addCallback(this);
26157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        mUserRenderMode = RENDERMODE_CONTINUOUSLY;
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
265b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Set the glWrapper. If the glWrapper is not null, its
266b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * {@link GLWrapper#wrap(GL)} method is called
267b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * whenever a surface is created. A GLWrapper can be used to wrap
268b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * the GL object that's passed to the renderer. Wrapping a GL
269b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * object enables examining and modifying the behavior of the
270b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * GL calls made by the renderer.
271b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
272b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Wrapping is typically used for debugging purposes.
273b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
274b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * The default value is null.
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param glWrapper the new GLWrapper
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGLWrapper(GLWrapper glWrapper) {
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLWrapper = glWrapper;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
282b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Set the debug flags to a new value. The value is
283b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * constructed by OR-together zero or more
284b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * of the DEBUG_CHECK_* constants. The debug flags take effect
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * whenever a surface is created. The default value is zero.
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param debugFlags the new debug flags
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #DEBUG_CHECK_GL_ERROR
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #DEBUG_LOG_GL_CALLS
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setDebugFlags(int debugFlags) {
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDebugFlags = debugFlags;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
294b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
295b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Get the current value of the debug flags.
296b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @return the current value of the debug flags.
297b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getDebugFlags() {
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mDebugFlags;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3038432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * Control whether the EGL context is preserved when the GLSurfaceView is paused and
3048432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * resumed.
3058432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * <p>
3068432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * If set to true, then the EGL context may be preserved when the GLSurfaceView is paused.
3078432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * Whether the EGL context is actually preserved or not depends upon whether the
3088432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * Android device that the program is running on can support an arbitrary number of EGL
3098432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * contexts or not. Devices that can only support a limited number of EGL contexts must
3108432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * release the  EGL context in order to allow multiple applications to share the GPU.
3118432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * <p>
3128432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * If set to false, the EGL context will be released when the GLSurfaceView is paused,
3138432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * and recreated when the GLSurfaceView is resumed.
3148432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * <p>
3158432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     *
3168432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * The default is false.
3178432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     *
3188432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * @param preserveOnPause preserve the EGL context when paused
3198432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     */
3208432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich    public void setPreserveEGLContextOnPause(boolean preserveOnPause) {
3218432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich        mPreserveEGLContextOnPause = preserveOnPause;
3228432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich    }
3238432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich
3248432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich    /**
3258432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     * @return true if the EGL context will be preserved when paused
3268432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich     */
3278432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich    public boolean getPreserveEGLContextOnPause() {
3288432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich        return mPreserveEGLContextOnPause;
3298432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich    }
3308432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich
3318432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich    /**
332b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Set the renderer associated with this view. Also starts the thread that
333b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * will call the renderer, which in turn causes the rendering to start.
334b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>This method should be called once and only once in the life-cycle of
335b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * a GLSurfaceView.
336b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>The following GLSurfaceView methods can only be called <em>before</em>
337b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * setRenderer is called:
338b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <ul>
339b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <li>{@link #setEGLConfigChooser(boolean)}
340b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <li>{@link #setEGLConfigChooser(EGLConfigChooser)}
341b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)}
342b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * </ul>
343b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
344b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * The following GLSurfaceView methods can only be called <em>after</em>
345b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * setRenderer is called:
346b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <ul>
347b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <li>{@link #getRenderMode()}
348b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <li>{@link #onPause()}
349b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <li>{@link #onResume()}
350b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <li>{@link #queueEvent(Runnable)}
351b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <li>{@link #requestRender()}
352b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <li>{@link #setRenderMode(int)}
353b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * </ul>
354b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *
355b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @param renderer the renderer to use to perform OpenGL drawing.
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setRenderer(Renderer renderer) {
35815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        checkRenderThreadState();
359a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        if (mEGLConfigChooser == null) {
36057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mEGLConfigChooser = new SimpleEGLConfigChooser(true, mEGLContextClientVersion);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        if (mEGLContextFactory == null) {
36357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mEGLContextFactory = new DefaultContextFactory(mEGLContextClientVersion);
36415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        }
36515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        if (mEGLWindowSurfaceFactory == null) {
36615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
36715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        }
3682ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        mRenderer = renderer;
36957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
37080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich        mGLThread = new GLThread(mThisWeakRef);
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLThread.start();
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
37515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * Install a custom EGLContextFactory.
37615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * <p>If this method is
37715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * called, it must be called before {@link #setRenderer(Renderer)}
37815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * is called.
37915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * <p>
38015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * If this method is not called, then by default
38115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * a context will be created with no shared context and
38215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * with a null attribute list.
38315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     */
384a8fecb87c5eaaefc9ca6272e3b59ef88d293dd6dJack Palevich    public void setEGLContextFactory(EGLContextFactory factory) {
38515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        checkRenderThreadState();
38615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        mEGLContextFactory = factory;
38715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    }
38815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
38915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    /**
39015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * Install a custom EGLWindowSurfaceFactory.
39115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * <p>If this method is
39215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * called, it must be called before {@link #setRenderer(Renderer)}
39315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * is called.
39415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * <p>
39515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * If this method is not called, then by default
39615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * a window surface will be created with a null attribute list.
39715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     */
398a8fecb87c5eaaefc9ca6272e3b59ef88d293dd6dJack Palevich    public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
39915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        checkRenderThreadState();
40015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        mEGLWindowSurfaceFactory = factory;
40115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    }
40215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
40315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    /**
404b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Install a custom EGLConfigChooser.
405b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>If this method is
406b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * called, it must be called before {@link #setRenderer(Renderer)}
407a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * is called.
408a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * <p>
409b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * If no setEGLConfigChooser method is called, then by default the
41083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * view will choose an EGLConfig that is compatible with the current
41183835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * android.view.Surface, with a depth buffer depth of
41283835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * at least 16 bits.
413a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * @param configChooser
414a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     */
415a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    public void setEGLConfigChooser(EGLConfigChooser configChooser) {
41615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        checkRenderThreadState();
417a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        mEGLConfigChooser = configChooser;
418a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    }
419a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
420a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    /**
421b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Install a config chooser which will choose a config
422a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * as close to 16-bit RGB as possible, with or without an optional depth
423a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * buffer as close to 16-bits as possible.
424b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>If this method is
425b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * called, it must be called before {@link #setRenderer(Renderer)}
426b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * is called.
427a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * <p>
42883835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * If no setEGLConfigChooser method is called, then by default the
42929e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian     * view will choose an RGB_888 surface with a depth buffer depth of
43083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * at least 16 bits.
431a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     *
432a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * @param needDepth
433a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     */
434a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    public void setEGLConfigChooser(boolean needDepth) {
43557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth, mEGLContextClientVersion));
436a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    }
437a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
438a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    /**
439b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Install a config chooser which will choose a config
44083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * with at least the specified depthSize and stencilSize,
44183835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * and exactly the specified redSize, greenSize, blueSize and alphaSize.
442b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>If this method is
443a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * called, it must be called before {@link #setRenderer(Renderer)}
444a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * is called.
445a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * <p>
446b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * If no setEGLConfigChooser method is called, then by default the
44729e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian     * view will choose an RGB_888 surface with a depth buffer depth of
44883835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * at least 16 bits.
449a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     *
450a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     */
451a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
452a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            int alphaSize, int depthSize, int stencilSize) {
453a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
45457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                blueSize, alphaSize, depthSize, stencilSize, mEGLContextClientVersion));
455a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    }
4566ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich
4576ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich    /**
4586ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * Inform the default EGLContextFactory and default EGLConfigChooser
4596ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * which EGLContext client version to pick.
4606ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * <p>Use this method to create an OpenGL ES 2.0-compatible context.
4616ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * Example:
4626ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * <pre class="prettyprint">
4636ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     *     public MyView(Context context) {
4646ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     *         super(context);
4656ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     *         setEGLContextClientVersion(2); // Pick an OpenGL ES 2.0 context.
4666ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     *         setRenderer(new MyRenderer());
4676ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     *     }
4686ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * </pre>
4696ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * <p>Note: Activities which require OpenGL ES 2.0 should indicate this by
4706ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * setting @lt;uses-feature android:glEsVersion="0x00020000" /> in the activity's
4716ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * AndroidManifest.xml file.
4726ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * <p>If this method is called, it must be called before {@link #setRenderer(Renderer)}
4736ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * is called.
4746ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * <p>This method only affects the behavior of the default EGLContexFactory and the
4756ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * default EGLConfigChooser. If
4766ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then the supplied
4776ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * EGLContextFactory is responsible for creating an OpenGL ES 2.0-compatible context.
4786ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * If
4796ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * {@link #setEGLConfigChooser(EGLConfigChooser)} has been called, then the supplied
4806ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible config.
48157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian     *
48257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian     * This method must be called before:
48357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian     * <ul>
48457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian     * <li>{@link #setEGLConfigChooser(boolean)}
48557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian     * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)}
48657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian     * </ul>
48757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian     *
4886ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     * @param version The EGLContext client version to choose. Use 2 for OpenGL ES 2.0
4896ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich     */
4906ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich    public void setEGLContextClientVersion(int version) {
4916ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich        checkRenderThreadState();
4926ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich        mEGLContextClientVersion = version;
4936ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich    }
4946ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich
495a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    /**
496b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Set the rendering mode. When renderMode is
4973e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich     * RENDERMODE_CONTINUOUSLY, the renderer is called
498b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * repeatedly to re-render the scene. When renderMode
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface
5003e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich     * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY.
501b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
502b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance
503b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * by allowing the GPU and CPU to idle when the view does not need to be updated.
504b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
505b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * This method can only be called after {@link #setRenderer(Renderer)}
506b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param renderMode one of the RENDERMODE_X constants
5083e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich     * @see #RENDERMODE_CONTINUOUSLY
509b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #RENDERMODE_WHEN_DIRTY
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setRenderMode(int renderMode) {
51257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        switch (renderMode) {
51357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            case RENDERMODE_WHEN_DIRTY:
51457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            case RENDERMODE_CONTINUOUSLY:
51557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                break;
51657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            default:
51757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                throw new IllegalArgumentException("renderMode");
51857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
51957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        mUserRenderMode = renderMode;
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLThread.setRenderMode(renderMode);
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the current rendering mode. May be called
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * from any thread. Must not be called before a renderer has been set.
526b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @return the current rendering mode.
5273e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich     * @see #RENDERMODE_CONTINUOUSLY
528b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #RENDERMODE_WHEN_DIRTY
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getRenderMode() {
53157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        return mUserRenderMode;
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
535b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Request that the renderer render a frame.
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This method is typically used when the render mode has been set to
537b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand.
538b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * May be called
539b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * from any thread. Must not be called before a renderer has been set.
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void requestRender() {
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLThread.requestRender();
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
545b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
546b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * This method is part of the SurfaceHolder.Callback interface, and is
547b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * not normally called or subclassed by clients of GLSurfaceView.
548b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void surfaceCreated(SurfaceHolder holder) {
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLThread.surfaceCreated();
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
553b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
554b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * This method is part of the SurfaceHolder.Callback interface, and is
555b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * not normally called or subclassed by clients of GLSurfaceView.
556b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void surfaceDestroyed(SurfaceHolder holder) {
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Surface will be destroyed when we return
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLThread.surfaceDestroyed();
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
562b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
563b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * This method is part of the SurfaceHolder.Callback interface, and is
564b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * not normally called or subclassed by clients of GLSurfaceView.
565b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLThread.onWindowResize(w, h);
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Inform the view that the activity is paused. The owner of this view must
572b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * call this method when the activity is paused. Calling this method will
573b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * pause the rendering thread.
574b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Must not be called before a renderer has been set.
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onPause() {
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLThread.onPause();
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Inform the view that the activity is resumed. The owner of this view must
582b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * call this method when the activity is resumed. Calling this method will
583b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * recreate the OpenGL display and resume the rendering
584b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * thread.
585b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Must not be called before a renderer has been set.
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onResume() {
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLThread.onResume();
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
592b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Queue a runnable to be run on the GL rendering thread. This can be used
593b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * to communicate with the Renderer on the rendering thread.
594b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Must not be called before a renderer has been set.
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param r the runnable to be run on the GL rendering thread.
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void queueEvent(Runnable r) {
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGLThread.queueEvent(r);
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
601b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
602b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * This method is used as part of the View class and is not normally
603b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * called or subclassed by clients of GLSurfaceView.
6042ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich     */
6052ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich    @Override
6062ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich    protected void onAttachedToWindow() {
6072ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        super.onAttachedToWindow();
6082ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        if (LOG_ATTACH_DETACH) {
6092ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich            Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
6102ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        }
6112ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        if (mDetached && (mRenderer != null)) {
61280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            mGLThread = new GLThread(mThisWeakRef);
61357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLThread.setRenderMode(mUserRenderMode);
6142ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich            mGLThread.start();
6152ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        }
6162ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        mDetached = false;
6172ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich    }
6182ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich
6192ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich    /**
6202ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich     * This method is used as part of the View class and is not normally
6212ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich     * called or subclassed by clients of GLSurfaceView.
622b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Must not be called before a renderer has been set.
623b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onDetachedFromWindow() {
6262ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        if (LOG_ATTACH_DETACH) {
6272ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich            Log.d(TAG, "onDetachedFromWindow");
6282ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        }
6292ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        if (mGLThread != null) {
6302ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich            mGLThread.requestExitAndWait();
6312ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        }
6322ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich        mDetached = true;
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onDetachedFromWindow();
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
638b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich    /**
639b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * An interface used to wrap a GL interface.
640b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>Typically
641b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * used for implementing debugging and tracing on top of the default
642b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * GL interface. You would typically use this by creating your own class
643b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * that implemented all the GL methods by delegating to another GL instance.
644b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * Then you could add your own behavior before or after calling the
645b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * delegate. All the GLWrapper would do was instantiate and return the
646b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * wrapper GL instance:
647b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <pre class="prettyprint">
648b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * class MyGLWrapper implements GLWrapper {
649b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *     GL wrap(GL gl) {
650b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *         return new MyGLImplementation(gl);
651b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *     }
652b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *     static class MyGLImplementation implements GL,GL10,GL11,... {
653b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *         ...
654b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *     }
655b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * }
656b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * </pre>
657b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #setGLWrapper(GLWrapper)
658b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     */
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface GLWrapper {
660b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich        /**
661b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * Wraps a gl interface in another gl interface.
662b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * @param gl a GL interface that is to be wrapped.
663b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * @return either the input argument or another GL object that wraps the input argument.
664b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         */
665b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich        GL wrap(GL gl);
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A generic renderer interface.
670b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
671b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * The renderer is responsible for making OpenGL calls to render a frame.
672b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
673b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * GLSurfaceView clients typically create their own classes that implement
674b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * this interface, and then call {@link GLSurfaceView#setRenderer} to
675b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * register the renderer with the GLSurfaceView.
676b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
67761fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez     *
67861fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez     * <div class="special reference">
67961fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez     * <h3>Developer Guides</h3>
68061fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez     * <p>For more information about how to use OpenGL, read the
68161fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez     * <a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a> developer guide.</p>
68261fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez     * </div>
68361fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez     *
684b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <h3>Threading</h3>
685b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * The renderer will be called on a separate thread, so that rendering
686b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * performance is decoupled from the UI thread. Clients typically need to
687b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * communicate with the renderer from the UI thread, because that's where
688b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * input events are received. Clients can communicate using any of the
689b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * standard Java techniques for cross-thread communication, or they can
690b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * use the {@link GLSurfaceView#queueEvent(Runnable)} convenience method.
691b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
692b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <h3>EGL Context Lost</h3>
693b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * There are situations where the EGL rendering context will be lost. This
694b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * typically happens when device wakes up after going to sleep. When
695b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * the EGL context is lost, all OpenGL resources (such as textures) that are
696b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * associated with that context will be automatically deleted. In order to
697b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * keep rendering correctly, a renderer must recreate any lost resources
698b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * that it still needs. The {@link #onSurfaceCreated(GL10, EGLConfig)} method
699b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * is a convenient place to do this.
700b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *
701b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     *
702b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * @see #setRenderer(Renderer)
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface Renderer {
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
706b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * Called when the surface is created or recreated.
707b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <p>
708b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * Called when the rendering thread
709840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich         * starts and whenever the EGL context is lost. The EGL context will typically
710b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * be lost when the Android device awakes after going to sleep.
711b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <p>
712b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * Since this method is called at the beginning of rendering, as well as
713b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * every time the EGL context is lost, this method is a convenient place to put
714b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * code to create resources that need to be created when the rendering
715b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * starts, and that need to be recreated when the EGL context is lost.
716b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * Textures are an example of a resource that you might want to create
717b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * here.
718b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <p>
719b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * Note that when the EGL context is lost, all OpenGL resources associated
720b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * with that context will be automatically deleted. You do not need to call
721b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * the corresponding "glDelete" methods such as glDeleteTextures to
722b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * manually delete these lost resources.
723b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <p>
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param gl the GL interface. Use <code>instanceof</code> to
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * test if the interface supports GL11 or higher interfaces.
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param config the EGLConfig of the created surface. Can be used
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * to create matching pbuffers.
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void onSurfaceCreated(GL10 gl, EGLConfig config);
730b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
732b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * Called when the surface changed size.
733b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <p>
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Called after the surface is created and whenever
735b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * the OpenGL ES surface size changes.
736b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <p>
737b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * Typically you will set your viewport here. If your camera
738b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * is fixed then you could also set your projection matrix here:
739b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <pre class="prettyprint">
740b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * void onSurfaceChanged(GL10 gl, int width, int height) {
741b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         *     gl.glViewport(0, 0, width, height);
742b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         *     // for a fixed camera, set the projection too
743b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         *     float ratio = (float) width / height;
744b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         *     gl.glMatrixMode(GL10.GL_PROJECTION);
745b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         *     gl.glLoadIdentity();
746b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         *     gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
747b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * }
748b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * </pre>
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param gl the GL interface. Use <code>instanceof</code> to
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * test if the interface supports GL11 or higher interfaces.
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param width
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param height
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void onSurfaceChanged(GL10 gl, int width, int height);
755b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
757b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * Called to draw the current frame.
758b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <p>
759b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * This method is responsible for drawing the current frame.
760b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <p>
761b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * The implementation of this method typically looks like this:
762b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * <pre class="prettyprint">
763b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * void onDrawFrame(GL10 gl) {
764b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         *     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
765b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         *     //... other gl calls to render the scene ...
766b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * }
767b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * </pre>
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param gl the GL interface. Use <code>instanceof</code> to
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * test if the interface supports GL11 or higher interfaces.
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void onDrawFrame(GL10 gl);
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
77515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * An interface for customizing the eglCreateContext and eglDestroyContext calls.
77615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * <p>
77715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * This interface must be implemented by clients wishing to call
77815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)}
77915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     */
78015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    public interface EGLContextFactory {
78115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
78215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
78315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    }
78415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
78557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private static class DefaultContextFactory implements EGLContextFactory {
78657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private final int mEGLContextClientVersion;
78757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
78857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public DefaultContextFactory(int version) {
78957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mEGLContextClientVersion = version;
79057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
79115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
79215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
79357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            int[] attrib_list = {EGL14.EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
7946ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich                    EGL10.EGL_NONE };
7956ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich
7966ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich            return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
7976ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich                    mEGLContextClientVersion != 0 ? attrib_list : null);
79815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        }
79915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
80015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        public void destroyContext(EGL10 egl, EGLDisplay display,
80115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich                EGLContext context) {
80207353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (!egl.eglDestroyContext(display, context)) {
80357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.e(TAG, "display:" + display + " context: " + context);
80407353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich                if (LOG_THREADS) {
80557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    Log.d(TAG, "tid=" + Thread.currentThread().getId());
80607353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich                }
8077d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich                EglHelper.throwEglException("eglDestroyContex", egl.eglGetError());
80807353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
80915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        }
81015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    }
81115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
81215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    /**
81315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.
81415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * <p>
81515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     * This interface must be implemented by clients wishing to call
816d40dfbbbff81219258ca36b762a89ff503154345Jack Palevich     * {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
81715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich     */
81815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    public interface EGLWindowSurfaceFactory {
819a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich        /**
820a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich         *  @return null if the surface cannot be constructed.
821a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich         */
82215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
82315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich                Object nativeWindow);
82415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
82515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    }
82615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
82715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
82815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
82915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
83015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich                EGLConfig config, Object nativeWindow) {
831a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich            EGLSurface result = null;
832a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich            try {
833a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich                result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
834a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich            } catch (IllegalArgumentException e) {
83557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // This exception indicates that the surfaceflinger surface
83657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // is not valid. This can happen if the surfaceflinger surface has
837a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich                // been torn down, but the application has not yet been
838a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich                // notified via SurfaceHolder.Callback.surfaceDestroyed.
839a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich                // In theory the application should be notified first,
840a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich                // but in practice sometimes it is not. See b/4588890
841a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich                Log.e(TAG, "eglCreateWindowSurface", e);
842a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich            }
843a35c120d8fafa7dded606a25bc100b13f48ab9e3Jack Palevich            return result;
84415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        }
84515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
84615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        public void destroySurface(EGL10 egl, EGLDisplay display,
84715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich                EGLSurface surface) {
84815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich            egl.eglDestroySurface(display, surface);
84915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        }
85015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    }
85115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich
85215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    /**
853b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * An interface for choosing an EGLConfig configuration from a list of
854a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     * potential configurations.
855b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * <p>
856b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * This interface must be implemented by clients wishing to call
857b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich     * {@link GLSurfaceView#setEGLConfigChooser(EGLConfigChooser)}
858a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     */
859a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    public interface EGLConfigChooser {
860a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        /**
861a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich         * Choose a configuration from the list. Implementors typically
862a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich         * implement this method by calling
863b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the
864b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich         * EGL specification available from The Khronos Group to learn how to call eglChooseConfig.
865a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich         * @param egl the EGL10 for the current display.
866a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich         * @param display the current display.
867a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich         * @return the chosen configuration.
868a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich         */
869a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
870a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    }
871a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
87257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private static abstract class BaseConfigChooser
873a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            implements EGLConfigChooser {
87457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
87557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public BaseConfigChooser(int[] configSpec, int version) {
87657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mConfigSpec = filterConfigSpec(configSpec, version);
877a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        }
8786ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich
879a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
880a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            int[] num_config = new int[1];
88128023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich            if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
88228023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich                    num_config)) {
88328023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich                throw new IllegalArgumentException("eglChooseConfig failed");
88428023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich            }
885a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
886a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            int numConfigs = num_config[0];
887a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
888a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            if (numConfigs <= 0) {
889a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                throw new IllegalArgumentException(
890a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                        "No configs match configSpec");
891a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            }
892a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
893a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            EGLConfig[] configs = new EGLConfig[numConfigs];
89428023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich            if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
89528023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich                    num_config)) {
89628023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich                throw new IllegalArgumentException("eglChooseConfig#2 failed");
89728023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich            }
898a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            EGLConfig config = chooseConfig(egl, display, configs);
899a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            if (config == null) {
900a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                throw new IllegalArgumentException("No config chosen");
901a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            }
902a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            return config;
903a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        }
904a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
905a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
906a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                EGLConfig[] configs);
907a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
908a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        protected int[] mConfigSpec;
9096ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich
91057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private int[] filterConfigSpec(int[] configSpec, int version) {
91157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (version != 2) {
9126ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich                return configSpec;
9136ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich            }
9146ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich            /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
9156ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich             * And we know the configSpec is well formed.
9166ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich             */
9176ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich            int len = configSpec.length;
9186ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich            int[] newConfigSpec = new int[len + 2];
9196ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich            System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
9206ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich            newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
92157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT;
9226ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich            newConfigSpec[len+1] = EGL10.EGL_NONE;
9236ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich            return newConfigSpec;
9246ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich        }
925a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    }
926a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
92783835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich    /**
92883835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * Choose a configuration with exactly the specified r,g,b,a sizes,
92983835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * and at least the specified depth and stencil sizes.
93083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     */
93157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private static class ComponentSizeChooser extends BaseConfigChooser {
932a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
93357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                int alphaSize, int depthSize, int stencilSize, int version) {
934a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            super(new int[] {
935a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                    EGL10.EGL_RED_SIZE, redSize,
936a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                    EGL10.EGL_GREEN_SIZE, greenSize,
937a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                    EGL10.EGL_BLUE_SIZE, blueSize,
938a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                    EGL10.EGL_ALPHA_SIZE, alphaSize,
939a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                    EGL10.EGL_DEPTH_SIZE, depthSize,
940a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                    EGL10.EGL_STENCIL_SIZE, stencilSize,
94157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    EGL10.EGL_NONE}, version);
942a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            mValue = new int[1];
943a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            mRedSize = redSize;
944a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            mGreenSize = greenSize;
945a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            mBlueSize = blueSize;
946a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            mAlphaSize = alphaSize;
947a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            mDepthSize = depthSize;
948a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            mStencilSize = stencilSize;
94957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
950a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
951a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        @Override
952a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
953a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                EGLConfig[] configs) {
95483835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich            for (EGLConfig config : configs) {
955a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                int d = findConfigAttrib(egl, display, config,
956a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                        EGL10.EGL_DEPTH_SIZE, 0);
957a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                int s = findConfigAttrib(egl, display, config,
958a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                        EGL10.EGL_STENCIL_SIZE, 0);
95983835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich                if ((d >= mDepthSize) && (s >= mStencilSize)) {
96057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
96157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
96257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
96357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
96483835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich                    if ((r == mRedSize) && (g == mGreenSize)
96583835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich                            && (b == mBlueSize) && (a == mAlphaSize)) {
96683835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich                        return config;
96782fd4fce16b9bbde25d044acc86ddf7306ebdd10Mathias Agopian                    }
968a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                }
969a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            }
97083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich            return null;
971a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        }
972a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
973a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        private int findConfigAttrib(EGL10 egl, EGLDisplay display,
974a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                EGLConfig config, int attribute, int defaultValue) {
975a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
976a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
977a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich                return mValue[0];
978a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            }
979a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich            return defaultValue;
980a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        }
981a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
982a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        private int[] mValue;
983a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        // Subclasses can adjust these values:
984a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        protected int mRedSize;
985a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        protected int mGreenSize;
986a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        protected int mBlueSize;
987a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        protected int mAlphaSize;
988a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        protected int mDepthSize;
989a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        protected int mStencilSize;
99057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    }
991a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
992a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    /**
99329e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian     * This class will choose a RGB_888 surface with
99483835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich     * or without a depth buffer.
995a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     *
996a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich     */
99757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    private static class SimpleEGLConfigChooser extends ComponentSizeChooser {
99857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public SimpleEGLConfigChooser(boolean withDepthBuffer, int version) {
99957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0, version);
1000a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich        }
1001a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    }
1002a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich
1003a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich    /**
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * An EGL helper class.
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
100780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich    private static class EglHelper {
100880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich        public EglHelper(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
100980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Initialize EGL for a given configuration spec.
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param configSpec
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
101657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void initialize() {
101707353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (LOG_EGL) {
101857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.d(TAG, "initialize() tid=" + Thread.currentThread().getId());
101907353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Get an EGL instance
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEgl = (EGL10) EGLContext.getEGL();
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Get to the default display.
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
103028023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich            if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
103128023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich                throw new RuntimeException("eglGetDisplay failed");
103228023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich            }
103328023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * We can now initialize EGL for that display
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] version = new int[2];
103828023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich            if(!mEgl.eglInitialize(mEglDisplay, version)) {
103928023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich                throw new RuntimeException("eglInitialize failed");
104028023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich            }
104180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
104280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            if (view == null) {
104380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                mEglConfig = null;
104480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                mEglContext = null;
104580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            } else {
104680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
104880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                /*
104980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                * Create an EGL context. We want to do this as rarely as we can, because an
105080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                * EGL context is a somewhat heavy object.
105180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                */
105280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
105380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            }
10542e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich            if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
105507353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich                mEglContext = null;
10569bb4dbae91df0971038e955ef49c5d9a64d4a428Jack Palevich                throwEglException("createContext");
10572e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich            }
105807353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (LOG_EGL) {
105957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.d(TAG, "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
106007353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEglSurface = null;
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1065b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich        /**
1066b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich         * Create an egl surface for the current SurfaceHolder surface. If a surface
1067b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich         * already exists, destroy it before creating the new surface.
1068b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich         *
1069b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich         * @return true if the surface was created successfully.
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
107180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich        public boolean createSurface() {
107207353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (LOG_EGL) {
107357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.d(TAG, "createSurface()  tid=" + Thread.currentThread().getId());
107407353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
107507353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            /*
107607353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich             * Check preconditions.
107707353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich             */
107807353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (mEgl == null) {
107907353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich                throw new RuntimeException("egl not initialized");
108007353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
108107353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (mEglDisplay == null) {
108207353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich                throw new RuntimeException("eglDisplay not initialized");
108307353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
108407353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (mEglConfig == null) {
108507353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich                throw new RuntimeException("mEglConfig not initialized");
108607353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
108780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *  The window size has changed, so we need to create a new
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *  surface.
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
109280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            destroySurfaceImp();
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Create an EGL surface we can render into.
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
109780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
109880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            if (view != null) {
109980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
110080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                        mEglDisplay, mEglConfig, view.getHolder());
110180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            } else {
110280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                mEglSurface = null;
110380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            }
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11052e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich            if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
11060e4aa37872810e46775374596e0beb11f7123727Jack Palevich                int error = mEgl.eglGetError();
11070e4aa37872810e46775374596e0beb11f7123727Jack Palevich                if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
110857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    Log.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
11090e4aa37872810e46775374596e0beb11f7123727Jack Palevich                }
1110b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich                return false;
11112e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich            }
11122e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Before we can issue GL commands, we need to make sure
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * the context is current and bound to a surface.
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
11172e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
11187d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich                /*
11197d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich                 * Could not make the context current, probably because the underlying
11207d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich                 * SurfaceView surface has been destroyed.
11217d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich                 */
112257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                logEglErrorAsWarning(TAG, "eglMakeCurrent", mEgl.eglGetError());
112357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // we fall-through to "true" here because we do have a
112457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // valid EGLSurface at this point.
11252e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich            }
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1127b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich            return true;
1128b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich        }
1129b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich
1130b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich        /**
1131b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich         * Create a GL object for the current EGL context.
1132b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich         * @return
1133b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich         */
113457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public GL createGL() {
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            GL gl = mEglContext.getGL();
113680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
113780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            if (view != null) {
113880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                if (view.mGLWrapper != null) {
113980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    gl = view.mGLWrapper.wrap(gl);
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
114180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich
114280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                if ((view.mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) {
114380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    int configFlags = 0;
114480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    Writer log = null;
114580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    if ((view.mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) {
114680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                        configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR;
114780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    }
114880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    if ((view.mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) {
114980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                        log = new LogWriter();
115080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    }
115180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    gl = GLDebugHelper.wrap(gl, configFlags, log);
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return gl;
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Display the current render surface.
1159db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich         * @return the EGL error code from eglSwapBuffers.
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1161db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich        public int swap() {
116204b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich            if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
11637d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich                return mEgl.eglGetError();
116404b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich            }
1165db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich            return EGL10.EGL_SUCCESS;
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11681bd888ba2e0976a179258cfa65ef07be31602a0aJack Palevich        public void destroySurface() {
116907353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (LOG_EGL) {
117057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.d(TAG, "destroySurface()  tid=" + Thread.currentThread().getId());
117107353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
117280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            destroySurfaceImp();
117380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich        }
117480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich
117580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich        private void destroySurfaceImp() {
11762e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich            if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        EGL10.EGL_NO_SURFACE,
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        EGL10.EGL_NO_CONTEXT);
118080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
118180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                if (view != null) {
118280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
118380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                }
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mEglSurface = null;
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11861bd888ba2e0976a179258cfa65ef07be31602a0aJack Palevich        }
11871bd888ba2e0976a179258cfa65ef07be31602a0aJack Palevich
118857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void terminate() {
118907353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (LOG_EGL) {
119057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.d(TAG, "terminate() tid=" + Thread.currentThread().getId());
119107353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mEglContext != null) {
119380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
119480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                if (view != null) {
119580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                    view.mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
119680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich                }
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mEglContext = null;
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mEglDisplay != null) {
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mEgl.eglTerminate(mEglDisplay);
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mEglDisplay = null;
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12055aa3adcf304ec3767b3c22128acb23240d8d0babJack Palevich        private void throwEglException(String function) {
120604b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich            throwEglException(function, mEgl.eglGetError());
120704b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich        }
120804b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich
12097d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich        public static void throwEglException(String function, int error) {
12107d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich            String message = formatEglError(function, error);
121107353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            if (LOG_THREADS) {
121257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.e(TAG, "throwEglException tid=" + Thread.currentThread().getId() + " "
12137d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich                        + message);
121407353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            }
121507353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich            throw new RuntimeException(message);
12165aa3adcf304ec3767b3c22128acb23240d8d0babJack Palevich        }
12175aa3adcf304ec3767b3c22128acb23240d8d0babJack Palevich
12187d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich        public static void logEglErrorAsWarning(String tag, String function, int error) {
12197d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich            Log.w(tag, formatEglError(function, error));
12207d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich        }
12217d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich
12227d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich        public static String formatEglError(String function, int error) {
12237d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich            return function + " failed: " + EGLLogWrapper.getErrorString(error);
12247d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich        }
12257d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich
122680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich        private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        EGL10 mEgl;
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        EGLDisplay mEglDisplay;
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        EGLSurface mEglSurface;
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        EGLConfig mEglConfig;
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        EGLContext mEglContext;
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A generic GL Thread. Takes care of initializing EGL and GL. Delegates
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to a Renderer instance to do the actual drawing. Can be configured to
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * render continuously or on request.
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
123957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
124057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    static class GLThread extends HandlerThread {
124157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // only accessed from GLThread
124257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private GL10 mGLContext;
124357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private int mWidth;
124457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private int mHeight;
124557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private boolean mSizeChanged;
124657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // current render mode
124757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private int mRenderMode;
124857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // the EGLSurface exists but isn't working for some reason
124957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private boolean mEglSurfaceIsBad;
125057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // we have an EGLContext
125157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private boolean mHaveEglContext;
125257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // we have an EGLSurface
125357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private boolean mHaveEglSurface;
125457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // we have a Surface (i.e.: EGLNativeWindowType)
125557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private boolean mHasSurface;
125657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // activity is paused
125757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private boolean mPaused;
125857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
125957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // constants
126057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private EglHelper mEglHelper;
126157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private Handler mGLHandler;
126257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private Choreographer mChoreographer;
126357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
126457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        /*
126557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         * Set once at thread construction time, nulled out when the parent view is garbage
126657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         * called. This weak reference allows the GLSurfaceView to be garbage collected while
126757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         * the GLThread is still alive.
126857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         */
126957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private final WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
127057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
127157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private final Runnable mExecuteDrawAction = new Runnable() {
127257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            private int mTraceVsyncCounter = 0;
127357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            @Override
127457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            public void run() {
127557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (TRACE_ENABLED) {
127657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    Trace.traceCounter(Trace.TRACE_TAG_GRAPHICS,
127757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                            "GLSurfaceView VSYNC counter", (mTraceVsyncCounter++) & 0xf);
127857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
127957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                executeDraw();
128057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }
128157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        };
128257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
128357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
128457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            super("GLThread", android.os.Process.THREAD_PRIORITY_DISPLAY);
128557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (LOG_THREADS) {
128657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.d(TAG, "*** Starting GLThread ***");
128757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mWidth = 0;
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHeight = 0;
12903e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich            mRenderMode = RENDERMODE_CONTINUOUSLY;
129180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich            mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
129457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void readyToRun() {
129557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mChoreographer = Choreographer.getInstance();
129657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
129757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
129857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
130057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void start() {
130157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            super.start();
130257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            // getLooper() blocks until the thread is running
130357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            Looper looper = getLooper();
130457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLHandler = new Handler(looper);
130557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            // don't return until the GLThread state has been initialized
130657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLHandler.runWithScissors(new Runnable() {
130757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                @Override
130857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                public void run() {
130957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    readyToRun();
131057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
131157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }, 0);
131257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
13138b2c9c9ecb08d25244fa97fb42c2c315ae3cf03dJack Palevich
131457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        @Override
131557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void run() {
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
131757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                super.run();
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
131957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // by definition the GLThread is not running anymore here
132057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                stopEglContext();
132157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                stopEglSurface();
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
132557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // only call from the GLThread
132657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void stopEglSurface() {
1327840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich            if (mHaveEglSurface) {
132857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (LOG_SURFACE) {
132957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    Log.d(TAG, "releasing EGL surface because paused tid=" + getId());
133057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
1331840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich                mHaveEglSurface = false;
133232d416518473f3bf5323d660e5910ca5633ffed6Jack Palevich                mEglHelper.destroySurface();
133332d416518473f3bf5323d660e5910ca5633ffed6Jack Palevich            }
133432d416518473f3bf5323d660e5910ca5633ffed6Jack Palevich        }
133532d416518473f3bf5323d660e5910ca5633ffed6Jack Palevich
133657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        // only call from the GLThread
133757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void stopEglContext() {
1338840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich            if (mHaveEglContext) {
133957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                mEglHelper.terminate();
1340840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich                mHaveEglContext = false;
134157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (LOG_SURFACE) {
134257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    Log.d(TAG, "releasing EGL context because paused tid=" + getId());
134357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
1344840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich            }
1345840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich        }
1346840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich
134757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void updateState() {
134857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            final boolean wasAbleToDraw = isAbleToDraw();
134957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (!isReadyToDraw()) {
135057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                return;
135157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }
135267dcd6c2392caf3ff98f35a3d1ec550d229c167bJack Palevich
135357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (!mHaveEglSurface || mSizeChanged) {
135457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // create EGL context if needed
135557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                boolean reportSurfaceCreated = false;
135657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (!mHaveEglContext) {
135757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    mEglHelper.initialize();
135857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    mHaveEglContext = true;
135957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    reportSurfaceCreated = true;
136057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
136167dcd6c2392caf3ff98f35a3d1ec550d229c167bJack Palevich
136257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // get the GL interface for the active EGLContext
136357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                mGLContext = (GL10)mEglHelper.createGL();
136421799450ec751fd3c41c7e66e69fefb094b3050bJack Palevich
136557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // create EGL Surface
136657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                mHaveEglSurface = mEglHelper.createSurface();
136757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                mEglSurfaceIsBad = !mHaveEglSurface;
136857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                mSizeChanged = false;
136967dcd6c2392caf3ff98f35a3d1ec550d229c167bJack Palevich
137057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // notify use of surface size change
137157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
137257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (view != null) {
137357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    if (reportSurfaceCreated) {
137457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        if (LOG_RENDERER) {
137557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                            Log.d(TAG, "onSurfaceCreated");
137615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich                        }
137757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        view.mRenderer.onSurfaceCreated(mGLContext, mEglHelper.mEglConfig);
13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
137967dcd6c2392caf3ff98f35a3d1ec550d229c167bJack Palevich
138057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    if (LOG_RENDERER) {
138157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        Log.d(TAG, "onSurfaceChanged(" + mWidth + ", " + mHeight + ")");
138215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich                    }
138357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    view.mRenderer.onSurfaceChanged(mGLContext, mWidth, mHeight);
138457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
138557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }
1386a08d46d8aaabb53eef4d5dc47272565d50f23c19Jack Palevich
138757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            // see if we should kick the rendering loop
138857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (!wasAbleToDraw && isAbleToDraw()) {
138957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // we're now able to draw
139057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
139157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    requestRender();
139257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
139357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }
1394b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich
139557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            // By design, this is the only place in a GLThread thread where we wait().
139657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (LOG_THREADS) {
139757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.d(TAG, "waiting tid=" + getId()
139857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        + " mHaveEglContext: " + mHaveEglContext
139957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        + " mHaveEglSurface: " + mHaveEglSurface
140057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        + " mPaused: " + mPaused
140157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        + " mHasSurface: " + mHasSurface
140257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        + " mSurfaceIsBad: " + mEglSurfaceIsBad
140357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        + " mWidth: " + mWidth
140457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        + " mHeight: " + mHeight
140557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        + " mRenderMode: " + mRenderMode);
140657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }
140757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
1408b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich
140957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void executeDraw() {
141057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (TRACE_ENABLED) {
141157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "executeDraw");
141257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }
1413840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich
141457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (isAbleToDraw()) {
141557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
141657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    requestRender();
141757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
1418a08d46d8aaabb53eef4d5dc47272565d50f23c19Jack Palevich
141957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (LOG_RENDERER_DRAW_FRAME) {
142057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    Log.d(TAG, "onDrawFrame tid=" + getId());
142157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
142257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
142357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
142457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (view != null) {
142557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    view.mRenderer.onDrawFrame(mGLContext);
1426db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                    int swapError = mEglHelper.swap();
1427db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                    switch (swapError) {
1428db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                        case EGL10.EGL_SUCCESS:
1429db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                            break;
1430db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                        case EGL11.EGL_CONTEXT_LOST:
1431db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                            if (LOG_SURFACE) {
143257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                                Log.d(TAG, "egl context lost tid=" + getId());
1433db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                            }
143457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                            stopEglSurface();
143557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                            stopEglContext();
1436db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                            break;
1437db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                        default:
1438db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                            // Other errors typically mean that the current surface is bad,
14397d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich                            // probably because the SurfaceView surface has been destroyed,
1440db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                            // but we haven't been notified yet.
1441db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                            // Log the error to help developers understand why rendering stopped.
144257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                            EglHelper.logEglErrorAsWarning(TAG, "eglSwapBuffers", swapError);
144357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                            mEglSurfaceIsBad = true;
1444db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich                            break;
144515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich                    }
1446a08d46d8aaabb53eef4d5dc47272565d50f23c19Jack Palevich                }
144757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }
1448840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich
144957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (TRACE_ENABLED) {
145057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
145115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich            }
14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
145457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private boolean isAbleToDraw() {
145557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            return mHaveEglContext && mHaveEglSurface && isReadyToDraw();
14561b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich        }
14571b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich
145857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private boolean isReadyToDraw() {
145957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            return (!mPaused) && mHasSurface && (!mEglSurfaceIsBad)
146057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                && (mWidth > 0) && (mHeight > 0);
14611b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich        }
14621b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich
146357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private boolean isEglContextReleasedWhenPausing() {
146457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
146557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            return (view != null) ? !view.mPreserveEGLContextOnPause : false;
146657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
146757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
146857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void queueEvent(Runnable r) {
146957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (r == null) {
147057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                throw new IllegalArgumentException("Runnable r must not be null");
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
147257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLHandler.post(r);
147357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
147457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
147557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        /*
147657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         * the call-backs below all run on the GLThread and implement state
147757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         * changes of the GLSurfaceView and Activity life cycle.
147857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         */
147957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
148057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void doSurfaceCreated() {
148157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mHasSurface = true;
148257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            updateState();
148357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
148457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
148557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void doSurfaceDestroyed() {
148657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (mHasSurface) {
148757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (LOG_SURFACE) {
148857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    Log.d(TAG, "noticed surfaceView surface lost tid=" + getId());
148957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
149057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                stopEglSurface();
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
149257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mHasSurface = false;
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
149557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void doPause() {
149657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (mPaused == false) {
149757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                mPaused = true;
149857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                stopEglSurface();
149957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                // When pausing, optionally release the EGL Context:
150057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (mHaveEglContext && isEglContextReleasedWhenPausing()) {
150157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    stopEglContext();
150257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
150657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void doResume() {
150757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mPaused = false;
150857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            updateState();
150957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (mRenderMode == RENDERMODE_WHEN_DIRTY) {
151057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                executeDraw();
15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
151457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void doWindowResize(final int width, final int height) {
151557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            // we were not drawing yet. Update the window size and
151657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            // state and attempt to draw a frame.
151757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mSizeChanged = (mWidth != width || mHeight != height);
151857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mWidth = width;
151957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mHeight = height;
152057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            updateState();
152157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            // we always (attempt to) draw a frame before returning
152257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            executeDraw();
152357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
152457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
152557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        private void doSetRenderMode(final int renderMode) {
152657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mRenderMode = renderMode;
152757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            requestRender();
152857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        }
152957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
153057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        /*
153157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         * the call-backs below run on the main UI thread, they just
153257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         * wait while executing work on the GLThread.
153357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         */
153457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void surfaceCreated() {
153657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLHandler.runWithScissors(new Runnable() {
153757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                @Override
153857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                public void run() {
153957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    doSurfaceCreated();
15408b2c9c9ecb08d25244fa97fb42c2c315ae3cf03dJack Palevich                }
154157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }, 0);
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void surfaceDestroyed() {
154557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLHandler.runWithScissors(new Runnable() {
154657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                @Override
154757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                public void run() {
154857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    doSurfaceDestroyed();
15498b2c9c9ecb08d25244fa97fb42c2c315ae3cf03dJack Palevich                }
155057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }, 0);
15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onPause() {
155457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLHandler.runWithScissors(new Runnable() {
155557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                @Override
155657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                public void run() {
155757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    doPause();
1558451a224c46c297bd6b25e3570b45f5053b4788beJack Palevich                }
155957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }, 0);
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onResume() {
156357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLHandler.runWithScissors(new Runnable() {
156457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                @Override
156557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                public void run() {
156657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    doResume();
1567451a224c46c297bd6b25e3570b45f5053b4788beJack Palevich                }
156857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }, 0);
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onWindowResize(int w, int h) {
157257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            final int width = w;
157357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            final int height = h;
157457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLHandler.runWithScissors(new Runnable() {
157557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                @Override
157657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                public void run() {
157757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    doWindowResize(width, height);
157821799450ec751fd3c41c7e66e69fefb094b3050bJack Palevich                }
157957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }, 0);
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
158257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        /*
158357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         * the methods below can be called from any thread
158457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian         */
158557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian
158657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void requestRender() {
158757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
158857d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
158957d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                        mExecuteDrawAction, null);
159057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            } else {
159157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                /*
159257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                 * in RENDERMODE_WHEN_DIRTY we schedule the draw callback
159357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                 * immediately because the developer is manager her
159457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                 * timing loop manually -- in particular she could be
159557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                 * using the Choreographer already.
159657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                 */
159757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                mGLHandler.post(mExecuteDrawAction);
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
160157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void setRenderMode(final int renderMode) {
160257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            mGLHandler.runWithScissors(new Runnable() {
160357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                @Override
160457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                public void run() {
160557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                    doSetRenderMode(renderMode);
160657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                }
160757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            }, 0);
16081b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich        }
16091b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich
161057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void requestExitAndWait() {
161157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            getLooper().quit();
161257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            try {
161357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                this.join();
161457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            } catch (InterruptedException e) {
16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
161757d019e222abc0de3f8876e682617d42872230c6Mathias Agopian    } // class GLThread
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static class LogWriter extends Writer {
162057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        @Override
162157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void close() {
16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flushBuilder();
16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
162557d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        @Override
162657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void flush() {
16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flushBuilder();
16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
163057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        @Override
163157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian        public void write(char[] buf, int offset, int count) {
163257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian            for (int i = 0; i < count; i++) {
16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                char c = buf[offset + i];
163457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                if (c == '\n') {
16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    flushBuilder();
163657d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                } else {
16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mBuilder.append(c);
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void flushBuilder() {
16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mBuilder.length() > 0) {
164457d019e222abc0de3f8876e682617d42872230c6Mathias Agopian                Log.v(TAG, mBuilder.toString());
16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBuilder.delete(0, mBuilder.length());
16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private StringBuilder mBuilder = new StringBuilder();
16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
165215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    private void checkRenderThreadState() {
165315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        if (mGLThread != null) {
165415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich            throw new IllegalStateException(
165515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich                    "setRenderer has already been called for this instance.");
165615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich        }
165715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich    }
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1659