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 19cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reckimport android.content.Context; 20cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reckimport android.os.Trace; 21cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reckimport android.util.AttributeSet; 22cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reckimport android.util.Log; 23cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reckimport android.view.SurfaceHolder; 24cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reckimport android.view.SurfaceView; 25cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.Writer; 2780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevichimport java.lang.ref.WeakReference; 28f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brownimport java.util.ArrayList; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGL10; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGL11; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGLConfig; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGLContext; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGLDisplay; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.egl.EGLSurface; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.opengles.GL; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.microedition.khronos.opengles.GL10; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An implementation of SurfaceView that uses the dedicated surface for 41b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * displaying OpenGL rendering. 42b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 43b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * A GLSurfaceView provides the following features: 44b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 45b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <ul> 46b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Manages a surface, which is a special piece of memory that can be 47b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * composited into the Android view system. 48b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Manages an EGL display, which enables OpenGL to render into a surface. 49b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Accepts a user-provided Renderer object that does the actual rendering. 50b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Renders on a dedicated thread to decouple rendering performance from the 51b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * UI thread. 52b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Supports both on-demand and continuous rendering. 53b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>Optionally wraps, traces, and/or error-checks the renderer's OpenGL calls. 54b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </ul> 55b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 5661fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <div class="special reference"> 5761fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <h3>Developer Guides</h3> 5861fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <p>For more information about how to use OpenGL, read the 5961fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a> developer guide.</p> 6061fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * </div> 6161fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * 62b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Using GLSurfaceView</h3> 63b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 64b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Typically you use GLSurfaceView by subclassing it and overriding one or more of the 65b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * View system input event methods. If your application does not need to override event 66b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * methods then GLSurfaceView can be used as-is. For the most part 67b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * GLSurfaceView behavior is customized by calling "set" methods rather than by subclassing. 68b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * For example, unlike a regular View, drawing is delegated to a separate Renderer object which 69b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * is registered with the GLSurfaceView 70b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * using the {@link #setRenderer(Renderer)} call. 71b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 72b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Initializing GLSurfaceView</h3> 73b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * All you have to do to initialize a GLSurfaceView is call {@link #setRenderer(Renderer)}. 74b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * However, if desired, you can modify the default behavior of GLSurfaceView by calling one or 75b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * more of these methods before calling setRenderer: 76b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <ul> 77b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setDebugFlags(int)} 78b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setEGLConfigChooser(boolean)} 79b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setEGLConfigChooser(EGLConfigChooser)} 80b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)} 81b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setGLWrapper(GLWrapper)} 82b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </ul> 83b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 8483835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * <h4>Specifying the android.view.Surface</h4> 8529e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian * By default GLSurfaceView will create a PixelFormat.RGB_888 format surface. If a translucent 8683835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * surface is required, call getHolder().setFormat(PixelFormat.TRANSLUCENT). 8783835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * The exact format of a TRANSLUCENT surface is device dependent, but it will be 8883835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * a 32-bit-per-pixel surface with 8 bits per component. 8983835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * <p> 90b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h4>Choosing an EGL Configuration</h4> 9183835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * A given Android device may support multiple EGLConfig rendering configurations. 9235ff3b3e9dfd99fda201776591d254b54174678fAurimas Liutikas * The available configurations may differ in how many channels of data are present, as 93b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * well as how many bits are allocated to each channel. Therefore, the first thing 9483835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * GLSurfaceView has to do when starting to render is choose what EGLConfig to use. 9583835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * <p> 9629e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian * By default GLSurfaceView chooses a EGLConfig that has an RGB_888 pixel format, 9783835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * with at least a 16-bit depth buffer and no stencil. 98b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 9983835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * If you would prefer a different EGLConfig 10083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * you can override the default behavior by calling one of the 101b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * setEGLConfigChooser methods. 102b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 103b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h4>Debug Behavior</h4> 104b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * You can optionally modify the behavior of GLSurfaceView by calling 105b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * one or more of the debugging methods {@link #setDebugFlags(int)}, 106b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * and {@link #setGLWrapper}. These methods may be called before and/or after setRenderer, but 107b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * typically they are called before setRenderer so that they take effect immediately. 108b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 109b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h4>Setting a Renderer</h4> 110b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Finally, you must call {@link #setRenderer} to register a {@link Renderer}. 111b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * The renderer is 112b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * responsible for doing the actual OpenGL rendering. 113b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 114b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Rendering Mode</h3> 115b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Once the renderer is set, you can control whether the renderer draws 116b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * continuously or on-demand by calling 117b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * {@link #setRenderMode}. The default is continuous rendering. 118b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 119b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Activity Life-cycle</h3> 120cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * A GLSurfaceView must be notified when to pause and resume rendering. GLSurfaceView clients 121cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * are required to call {@link #onPause()} when the activity stops and 122cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * {@link #onResume()} when the activity starts. These calls allow GLSurfaceView to 123b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate 124b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * the OpenGL display. 125b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 126b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Handling events</h3> 127b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 128b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * To handle an event you will typically subclass GLSurfaceView and override the 129b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * appropriate method, just as you would with any other View. However, when handling 130b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * the event, you may need to communicate with the Renderer object 131b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * that's running in the rendering thread. You can do this using any 132b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * standard Java cross-thread communication mechanism. In addition, 133b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * one relatively easy way to communicate with your renderer is 134b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * to call 135b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * {@link #queueEvent(Runnable)}. For example: 136b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <pre class="prettyprint"> 137b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * class MyGLSurfaceView extends GLSurfaceView { 138b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 139b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * private MyRenderer mMyRenderer; 140b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 141b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * public void start() { 142b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * mMyRenderer = ...; 143b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * setRenderer(mMyRenderer); 144b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * } 145b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 146b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * public boolean onKeyDown(int keyCode, KeyEvent event) { 147b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { 148b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * queueEvent(new Runnable() { 149b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * // This method will be called on the rendering 150b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * // thread: 151b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * public void run() { 152b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * mMyRenderer.handleDpadCenter(); 153b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * }}); 154b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * return true; 155b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * } 156b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * return super.onKeyDown(keyCode, event); 157b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * } 158b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * } 159b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </pre> 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1622b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carrpublic class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2 { 1632ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich private final static String TAG = "GLSurfaceView"; 1642ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich private final static boolean LOG_ATTACH_DETACH = false; 16557c6a46bd0c84c4b349d49f8df12f30a8cfcdaa2Jack Palevich private final static boolean LOG_THREADS = false; 166f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private final static boolean LOG_PAUSE_RESUME = false; 1674a65900cd69b79e6e47d275575eaeb5bb2487f9fJack Palevich private final static boolean LOG_SURFACE = false; 1684a65900cd69b79e6e47d275575eaeb5bb2487f9fJack Palevich private final static boolean LOG_RENDERER = false; 1694a2221ec4a929976be570ad096252c8dea326e19Jack Palevich private final static boolean LOG_RENDERER_DRAW_FRAME = false; 1704a65900cd69b79e6e47d275575eaeb5bb2487f9fJack Palevich private final static boolean LOG_EGL = false; 171b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 172b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * The renderer only renders 173b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * when the surface is created, or when {@link #requestRender} is called. 174b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 175b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #getRenderMode() 176b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #setRenderMode(int) 177840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich * @see #requestRender() 178b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final static int RENDERMODE_WHEN_DIRTY = 0; 180b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 181b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * The renderer is called 182b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * continuously to re-render the scene. 183b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 184b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #getRenderMode() 185b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #setRenderMode(int) 186b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 1873e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich public final static int RENDERMODE_CONTINUOUSLY = 1; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 190b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Check glError() after every GL call and throw an exception if glError indicates 191b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * that an error has occurred. This can be used to help track down which OpenGL ES call 192b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * is causing an error. 193b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 194b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #getDebugFlags 195b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #setDebugFlags 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final static int DEBUG_CHECK_GL_ERROR = 1; 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView". 201b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 202b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #getDebugFlags 203b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #setDebugFlags 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final static int DEBUG_LOG_GL_CALLS = 2; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 207b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 208b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Standard View constructor. In order to render something, you 209b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * must call {@link #setRenderer} to register a renderer. 210b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public GLSurfaceView(Context context) { 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context); 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project init(); 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 216b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 217b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Standard View constructor. In order to render something, you 218b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * must call {@link #setRenderer} to register a renderer. 219b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public GLSurfaceView(Context context, AttributeSet attrs) { 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project init(); 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich @Override 22680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich protected void finalize() throws Throwable { 22780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich try { 22880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if (mGLThread != null) { 22980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich // GLThread may still be running if this view was never 23080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich // attached to a window. 231f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mGLThread.requestExitAndWait(); 23280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 23380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } finally { 23480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich super.finalize(); 23580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 23680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 23780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void init() { 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Install a SurfaceHolder.Callback so we get notified when the 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // underlying surface is created and destroyed 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SurfaceHolder holder = getHolder(); 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project holder.addCallback(this); 243f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // setFormat is done by SurfaceView in SDK 2.3 and newer. Uncomment 244f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // this statement if back-porting to 2.2 or older: 245f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // holder.setFormat(PixelFormat.RGB_565); 246f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // 247f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // setType is not needed for SDK 2.0 or newer. Uncomment this 248f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // statement if back-porting this code to older SDKs. 249f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 253b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Set the glWrapper. If the glWrapper is not null, its 254b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * {@link GLWrapper#wrap(GL)} method is called 255b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * whenever a surface is created. A GLWrapper can be used to wrap 256b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * the GL object that's passed to the renderer. Wrapping a GL 257b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * object enables examining and modifying the behavior of the 258b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * GL calls made by the renderer. 259b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 260b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Wrapping is typically used for debugging purposes. 261b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 262b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * The default value is null. 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param glWrapper the new GLWrapper 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setGLWrapper(GLWrapper glWrapper) { 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLWrapper = glWrapper; 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 270b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Set the debug flags to a new value. The value is 271b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * constructed by OR-together zero or more 272b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * of the DEBUG_CHECK_* constants. The debug flags take effect 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * whenever a surface is created. The default value is zero. 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param debugFlags the new debug flags 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #DEBUG_CHECK_GL_ERROR 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #DEBUG_LOG_GL_CALLS 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setDebugFlags(int debugFlags) { 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDebugFlags = debugFlags; 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 282b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 283b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Get the current value of the debug flags. 284b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @return the current value of the debug flags. 285b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getDebugFlags() { 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDebugFlags; 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2918432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * Control whether the EGL context is preserved when the GLSurfaceView is paused and 2928432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * resumed. 2938432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * <p> 2948432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * If set to true, then the EGL context may be preserved when the GLSurfaceView is paused. 295cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * <p> 296cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * Prior to API level 11, whether the EGL context is actually preserved or not 297cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * depends upon whether the Android device can support an arbitrary number of 298cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * EGL contexts or not. Devices that can only support a limited number of EGL 299cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * contexts must release the EGL context in order to allow multiple applications 300cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * to share the GPU. 3018432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * <p> 3028432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * If set to false, the EGL context will be released when the GLSurfaceView is paused, 3038432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * and recreated when the GLSurfaceView is resumed. 3048432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * <p> 3058432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * 3068432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * The default is false. 3078432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * 3088432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * @param preserveOnPause preserve the EGL context when paused 3098432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich */ 3108432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich public void setPreserveEGLContextOnPause(boolean preserveOnPause) { 3118432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich mPreserveEGLContextOnPause = preserveOnPause; 3128432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich } 3138432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich 3148432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich /** 3158432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich * @return true if the EGL context will be preserved when paused 3168432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich */ 3178432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich public boolean getPreserveEGLContextOnPause() { 3188432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich return mPreserveEGLContextOnPause; 3198432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich } 3208432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich 3218432b3f98a22d5cdfcc0183d134770597e44d412Jack Palevich /** 322b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Set the renderer associated with this view. Also starts the thread that 323b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * will call the renderer, which in turn causes the rendering to start. 324b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>This method should be called once and only once in the life-cycle of 325b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * a GLSurfaceView. 326b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>The following GLSurfaceView methods can only be called <em>before</em> 327b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * setRenderer is called: 328b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <ul> 329b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setEGLConfigChooser(boolean)} 330b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setEGLConfigChooser(EGLConfigChooser)} 331b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)} 332b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </ul> 333b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 334b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * The following GLSurfaceView methods can only be called <em>after</em> 335b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * setRenderer is called: 336b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <ul> 337b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #getRenderMode()} 338b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #onPause()} 339b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #onResume()} 340b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #queueEvent(Runnable)} 341b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #requestRender()} 342b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <li>{@link #setRenderMode(int)} 343b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </ul> 344b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 345b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @param renderer the renderer to use to perform OpenGL drawing. 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setRenderer(Renderer renderer) { 34815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich checkRenderThreadState(); 349a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich if (mEGLConfigChooser == null) { 350f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mEGLConfigChooser = new SimpleEGLConfigChooser(true); 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 35215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich if (mEGLContextFactory == null) { 353f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mEGLContextFactory = new DefaultContextFactory(); 35415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 35515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich if (mEGLWindowSurfaceFactory == null) { 35615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory(); 35715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 3582ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich mRenderer = renderer; 35980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mGLThread = new GLThread(mThisWeakRef); 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLThread.start(); 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 36415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * Install a custom EGLContextFactory. 36515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * <p>If this method is 36615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * called, it must be called before {@link #setRenderer(Renderer)} 36715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * is called. 36815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * <p> 36915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * If this method is not called, then by default 37015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * a context will be created with no shared context and 37115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * with a null attribute list. 37215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich */ 373a8fecb87c5eaaefc9ca6272e3b59ef88d293dd6dJack Palevich public void setEGLContextFactory(EGLContextFactory factory) { 37415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich checkRenderThreadState(); 37515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich mEGLContextFactory = factory; 37615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 37715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich 37815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich /** 37915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * Install a custom EGLWindowSurfaceFactory. 38015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * <p>If this method is 38115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * called, it must be called before {@link #setRenderer(Renderer)} 38215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * is called. 38315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * <p> 38415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * If this method is not called, then by default 38515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * a window surface will be created with a null attribute list. 38615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich */ 387a8fecb87c5eaaefc9ca6272e3b59ef88d293dd6dJack Palevich public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) { 38815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich checkRenderThreadState(); 38915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich mEGLWindowSurfaceFactory = factory; 39015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 39115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich 39215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich /** 393b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Install a custom EGLConfigChooser. 394b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>If this method is 395b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * called, it must be called before {@link #setRenderer(Renderer)} 396a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * is called. 397a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * <p> 398b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * If no setEGLConfigChooser method is called, then by default the 39983835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * view will choose an EGLConfig that is compatible with the current 40083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * android.view.Surface, with a depth buffer depth of 40183835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * at least 16 bits. 402a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * @param configChooser 403a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich */ 404a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich public void setEGLConfigChooser(EGLConfigChooser configChooser) { 40515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich checkRenderThreadState(); 406a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich mEGLConfigChooser = configChooser; 407a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 408a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 409a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich /** 410b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Install a config chooser which will choose a config 411a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * as close to 16-bit RGB as possible, with or without an optional depth 412a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * buffer as close to 16-bits as possible. 413b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>If this method is 414b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * called, it must be called before {@link #setRenderer(Renderer)} 415b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * is called. 416a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * <p> 41783835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * If no setEGLConfigChooser method is called, then by default the 41829e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian * view will choose an RGB_888 surface with a depth buffer depth of 41983835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * at least 16 bits. 420a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * 421a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * @param needDepth 422a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich */ 423a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich public void setEGLConfigChooser(boolean needDepth) { 424f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth)); 425a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 426a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 427a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich /** 428b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Install a config chooser which will choose a config 42983835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * with at least the specified depthSize and stencilSize, 43083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * and exactly the specified redSize, greenSize, blueSize and alphaSize. 431b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>If this method is 432a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * called, it must be called before {@link #setRenderer(Renderer)} 433a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * is called. 434a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * <p> 435b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * If no setEGLConfigChooser method is called, then by default the 43629e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian * view will choose an RGB_888 surface with a depth buffer depth of 43783835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * at least 16 bits. 438a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * 439a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich */ 440a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, 441a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich int alphaSize, int depthSize, int stencilSize) { 442a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize, 443f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown blueSize, alphaSize, depthSize, stencilSize)); 444a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 4456ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich 4466ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich /** 4476ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * Inform the default EGLContextFactory and default EGLConfigChooser 4486ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * which EGLContext client version to pick. 4496ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * <p>Use this method to create an OpenGL ES 2.0-compatible context. 4506ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * Example: 4516ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * <pre class="prettyprint"> 4526ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * public MyView(Context context) { 4536ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * super(context); 4546ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * setEGLContextClientVersion(2); // Pick an OpenGL ES 2.0 context. 4556ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * setRenderer(new MyRenderer()); 4566ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * } 4576ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * </pre> 4586ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * <p>Note: Activities which require OpenGL ES 2.0 should indicate this by 4596ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * setting @lt;uses-feature android:glEsVersion="0x00020000" /> in the activity's 4606ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * AndroidManifest.xml file. 4616ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * <p>If this method is called, it must be called before {@link #setRenderer(Renderer)} 4626ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * is called. 4636ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * <p>This method only affects the behavior of the default EGLContexFactory and the 4646ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * default EGLConfigChooser. If 4656ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then the supplied 4666ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * EGLContextFactory is responsible for creating an OpenGL ES 2.0-compatible context. 4676ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * If 4686ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * {@link #setEGLConfigChooser(EGLConfigChooser)} has been called, then the supplied 4696ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible config. 4706ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * @param version The EGLContext client version to choose. Use 2 for OpenGL ES 2.0 4716ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich */ 4726ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich public void setEGLContextClientVersion(int version) { 4736ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich checkRenderThreadState(); 4746ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich mEGLContextClientVersion = version; 4756ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich } 4766ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich 477a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich /** 478b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Set the rendering mode. When renderMode is 4793e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich * RENDERMODE_CONTINUOUSLY, the renderer is called 480b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * repeatedly to re-render the scene. When renderMode 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface 4823e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY. 483b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 484b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance 485b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * by allowing the GPU and CPU to idle when the view does not need to be updated. 486b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 487b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * This method can only be called after {@link #setRenderer(Renderer)} 488b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param renderMode one of the RENDERMODE_X constants 4903e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich * @see #RENDERMODE_CONTINUOUSLY 491b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #RENDERMODE_WHEN_DIRTY 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setRenderMode(int renderMode) { 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLThread.setRenderMode(renderMode); 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the current rendering mode. May be called 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * from any thread. Must not be called before a renderer has been set. 500b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @return the current rendering mode. 5013e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich * @see #RENDERMODE_CONTINUOUSLY 502b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #RENDERMODE_WHEN_DIRTY 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getRenderMode() { 50578bc2033129507f1cf4acb2e3007f89cb2b3f224Mathias Agopian return mGLThread.getRenderMode(); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 509b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Request that the renderer render a frame. 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method is typically used when the render mode has been set to 511b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand. 512b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * May be called 513b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * from any thread. Must not be called before a renderer has been set. 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void requestRender() { 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLThread.requestRender(); 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 519b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 520b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * This method is part of the SurfaceHolder.Callback interface, and is 521b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * not normally called or subclassed by clients of GLSurfaceView. 522b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceCreated(SurfaceHolder holder) { 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLThread.surfaceCreated(); 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 527b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 528b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * This method is part of the SurfaceHolder.Callback interface, and is 529b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * not normally called or subclassed by clients of GLSurfaceView. 530b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceDestroyed(SurfaceHolder holder) { 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Surface will be destroyed when we return 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLThread.surfaceDestroyed(); 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 536b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 537b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * This method is part of the SurfaceHolder.Callback interface, and is 538b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * not normally called or subclassed by clients of GLSurfaceView. 539b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLThread.onWindowResize(w, h); 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 54525cfa134835e3791bdb6572f5e25cf4599015678Robert Carr * This method is part of the SurfaceHolder.Callback2 interface, and is 5462b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr * not normally called or subclassed by clients of GLSurfaceView. 5472b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr */ 5482b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr @Override 54925cfa134835e3791bdb6572f5e25cf4599015678Robert Carr public void surfaceRedrawNeededAsync(SurfaceHolder holder, Runnable finishDrawing) { 550fd3cee138e24f6fa84db89a936eb7381a8673fe9John Reck if (mGLThread != null) { 55125cfa134835e3791bdb6572f5e25cf4599015678Robert Carr mGLThread.requestRenderAndNotify(finishDrawing); 552fd3cee138e24f6fa84db89a936eb7381a8673fe9John Reck } 5532b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr } 5542b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr 55525cfa134835e3791bdb6572f5e25cf4599015678Robert Carr /** 55625cfa134835e3791bdb6572f5e25cf4599015678Robert Carr * This method is part of the SurfaceHolder.Callback2 interface, and is 55725cfa134835e3791bdb6572f5e25cf4599015678Robert Carr * not normally called or subclassed by clients of GLSurfaceView. 55825cfa134835e3791bdb6572f5e25cf4599015678Robert Carr */ 55925cfa134835e3791bdb6572f5e25cf4599015678Robert Carr @Deprecated 56025cfa134835e3791bdb6572f5e25cf4599015678Robert Carr @Override 56125cfa134835e3791bdb6572f5e25cf4599015678Robert Carr public void surfaceRedrawNeeded(SurfaceHolder holder) { 56225cfa134835e3791bdb6572f5e25cf4599015678Robert Carr // Since we are part of the framework we know only surfaceRedrawNeededAsync 56325cfa134835e3791bdb6572f5e25cf4599015678Robert Carr // will be called. 56425cfa134835e3791bdb6572f5e25cf4599015678Robert Carr } 56525cfa134835e3791bdb6572f5e25cf4599015678Robert Carr 5662b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr 5672b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr /** 568cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * Pause the rendering thread, optionally tearing down the EGL context 569cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * depending upon the value of {@link #setPreserveEGLContextOnPause(boolean)}. 570cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * 571cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * This method should be called when it is no longer desirable for the 572cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * GLSurfaceView to continue rendering, such as in response to 573cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * {@link android.app.Activity#onStop Activity.onStop}. 574cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * 575b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Must not be called before a renderer has been set. 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onPause() { 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLThread.onPause(); 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 582cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * Resumes the rendering thread, re-creating the OpenGL context if necessary. It 583cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * is the counterpart to {@link #onPause()}. 584cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * 585cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * This method should typically be called in 586cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * {@link android.app.Activity#onStart Activity.onStart}. 587cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck * 588b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Must not be called before a renderer has been set. 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onResume() { 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLThread.onResume(); 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 595b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Queue a runnable to be run on the GL rendering thread. This can be used 596b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * to communicate with the Renderer on the rendering thread. 597b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Must not be called before a renderer has been set. 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param r the runnable to be run on the GL rendering thread. 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void queueEvent(Runnable r) { 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGLThread.queueEvent(r); 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 604b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 605b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * This method is used as part of the View class and is not normally 606b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * called or subclassed by clients of GLSurfaceView. 6072ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich */ 6082ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich @Override 6092ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich protected void onAttachedToWindow() { 6102ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich super.onAttachedToWindow(); 6112ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich if (LOG_ATTACH_DETACH) { 6122ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich Log.d(TAG, "onAttachedToWindow reattach =" + mDetached); 6132ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich } 6142ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich if (mDetached && (mRenderer != null)) { 615f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown int renderMode = RENDERMODE_CONTINUOUSLY; 616f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mGLThread != null) { 617f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown renderMode = mGLThread.getRenderMode(); 618f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 61980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mGLThread = new GLThread(mThisWeakRef); 620f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (renderMode != RENDERMODE_CONTINUOUSLY) { 621f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mGLThread.setRenderMode(renderMode); 622f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 6232ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich mGLThread.start(); 6242ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich } 6252ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich mDetached = false; 6262ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich } 6272ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 62977e4a5250fc6df451999efe508f57968a44b603fJohn Reck protected void onDetachedFromWindow() { 6302ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich if (LOG_ATTACH_DETACH) { 6312ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich Log.d(TAG, "onDetachedFromWindow"); 6322ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich } 6332ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich if (mGLThread != null) { 634f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mGLThread.requestExitAndWait(); 6352ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich } 6362ff6a824619ac6849ba9f36d97590acf74f62518Jack Palevich mDetached = true; 63777e4a5250fc6df451999efe508f57968a44b603fJohn Reck super.onDetachedFromWindow(); 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ---------------------------------------------------------------------- 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 642b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 643b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * An interface used to wrap a GL interface. 644b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p>Typically 645b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * used for implementing debugging and tracing on top of the default 646b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * GL interface. You would typically use this by creating your own class 647b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * that implemented all the GL methods by delegating to another GL instance. 648b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Then you could add your own behavior before or after calling the 649b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * delegate. All the GLWrapper would do was instantiate and return the 650b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * wrapper GL instance: 651b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <pre class="prettyprint"> 652b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * class MyGLWrapper implements GLWrapper { 653b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * GL wrap(GL gl) { 654b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * return new MyGLImplementation(gl); 655b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * } 656b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * static class MyGLImplementation implements GL,GL10,GL11,... { 657b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * ... 658b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * } 659b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * } 660b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </pre> 661b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #setGLWrapper(GLWrapper) 662b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public interface GLWrapper { 664b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich /** 665b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Wraps a gl interface in another gl interface. 666b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @param gl a GL interface that is to be wrapped. 667b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @return either the input argument or another GL object that wraps the input argument. 668b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich */ 669b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich GL wrap(GL gl); 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A generic renderer interface. 674b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 675b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * The renderer is responsible for making OpenGL calls to render a frame. 676b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 677b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * GLSurfaceView clients typically create their own classes that implement 678b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * this interface, and then call {@link GLSurfaceView#setRenderer} to 679b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * register the renderer with the GLSurfaceView. 680b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 68161fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * 68261fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <div class="special reference"> 68361fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <h3>Developer Guides</h3> 68461fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <p>For more information about how to use OpenGL, read the 68561fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a> developer guide.</p> 68661fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * </div> 68761fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * 688b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>Threading</h3> 689b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * The renderer will be called on a separate thread, so that rendering 690b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * performance is decoupled from the UI thread. Clients typically need to 691b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * communicate with the renderer from the UI thread, because that's where 692b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * input events are received. Clients can communicate using any of the 693b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * standard Java techniques for cross-thread communication, or they can 694b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * use the {@link GLSurfaceView#queueEvent(Runnable)} convenience method. 695b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 696b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <h3>EGL Context Lost</h3> 697b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * There are situations where the EGL rendering context will be lost. This 698b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * typically happens when device wakes up after going to sleep. When 699b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * the EGL context is lost, all OpenGL resources (such as textures) that are 700b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * associated with that context will be automatically deleted. In order to 701b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * keep rendering correctly, a renderer must recreate any lost resources 702b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * that it still needs. The {@link #onSurfaceCreated(GL10, EGLConfig)} method 703b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * is a convenient place to do this. 704b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 705b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * 706b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * @see #setRenderer(Renderer) 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public interface Renderer { 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 710b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Called when the surface is created or recreated. 711b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 712b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Called when the rendering thread 713840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich * starts and whenever the EGL context is lost. The EGL context will typically 714b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * be lost when the Android device awakes after going to sleep. 715b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 716b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Since this method is called at the beginning of rendering, as well as 717b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * every time the EGL context is lost, this method is a convenient place to put 718b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * code to create resources that need to be created when the rendering 719b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * starts, and that need to be recreated when the EGL context is lost. 720b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Textures are an example of a resource that you might want to create 721b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * here. 722b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 723b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Note that when the EGL context is lost, all OpenGL resources associated 724b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * with that context will be automatically deleted. You do not need to call 725b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * the corresponding "glDelete" methods such as glDeleteTextures to 726b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * manually delete these lost resources. 727b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param gl the GL interface. Use <code>instanceof</code> to 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * test if the interface supports GL11 or higher interfaces. 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param config the EGLConfig of the created surface. Can be used 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to create matching pbuffers. 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onSurfaceCreated(GL10 gl, EGLConfig config); 734b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 736b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Called when the surface changed size. 737b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called after the surface is created and whenever 739b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * the OpenGL ES surface size changes. 740b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 741b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Typically you will set your viewport here. If your camera 742b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * is fixed then you could also set your projection matrix here: 743b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <pre class="prettyprint"> 744b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * void onSurfaceChanged(GL10 gl, int width, int height) { 745b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * gl.glViewport(0, 0, width, height); 746b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * // for a fixed camera, set the projection too 747b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * float ratio = (float) width / height; 748b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * gl.glMatrixMode(GL10.GL_PROJECTION); 749b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * gl.glLoadIdentity(); 750b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); 751b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * } 752b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </pre> 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param gl the GL interface. Use <code>instanceof</code> to 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * test if the interface supports GL11 or higher interfaces. 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param width 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param height 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onSurfaceChanged(GL10 gl, int width, int height); 759b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 761b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * Called to draw the current frame. 762b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 763b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * This method is responsible for drawing the current frame. 764b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <p> 765b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * The implementation of this method typically looks like this: 766b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * <pre class="prettyprint"> 767b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * void onDrawFrame(GL10 gl) { 768b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 769b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * //... other gl calls to render the scene ... 770b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * } 771b47c641fe8330fc68dbed91163ff07015068d0ceJack Palevich * </pre> 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param gl the GL interface. Use <code>instanceof</code> to 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * test if the interface supports GL11 or higher interfaces. 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onDrawFrame(GL10 gl); 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 77915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * An interface for customizing the eglCreateContext and eglDestroyContext calls. 78015e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * <p> 78115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * This interface must be implemented by clients wishing to call 78215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich * {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)} 78315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich */ 78415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich public interface EGLContextFactory { 78515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig); 78615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context); 78715e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 78815e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich 789f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private class DefaultContextFactory implements EGLContextFactory { 790f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 79115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich 79215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) { 793f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown int[] attrib_list = {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)) { 803f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.e("DefaultContextFactory", "display:" + display + " context: " + context); 80407353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (LOG_THREADS) { 805f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("DefaultContextFactory", "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) { 835f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // This exception indicates that the surface flinger surface 836f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // is not valid. This can happen if the surface flinger 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 872f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private abstract class BaseConfigChooser 873a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich implements EGLConfigChooser { 874f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public BaseConfigChooser(int[] configSpec) { 875f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mConfigSpec = filterConfigSpec(configSpec); 876a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 8776ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich 878a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 879a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich int[] num_config = new int[1]; 88028023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, 88128023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich num_config)) { 88228023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich throw new IllegalArgumentException("eglChooseConfig failed"); 88328023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich } 884a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 885a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich int numConfigs = num_config[0]; 886a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 887a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich if (numConfigs <= 0) { 888a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich throw new IllegalArgumentException( 889a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich "No configs match configSpec"); 890a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 891a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 892a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGLConfig[] configs = new EGLConfig[numConfigs]; 89328023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, 89428023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich num_config)) { 89528023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich throw new IllegalArgumentException("eglChooseConfig#2 failed"); 89628023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich } 897a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGLConfig config = chooseConfig(egl, display, configs); 898a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich if (config == null) { 899a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich throw new IllegalArgumentException("No config chosen"); 900a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 901a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich return config; 902a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 903a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 904a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, 905a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGLConfig[] configs); 906a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 907a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich protected int[] mConfigSpec; 9086ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich 909f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private int[] filterConfigSpec(int[] configSpec) { 91028a5c593577d6aef03d874b42ec0215c88f62bf4Jin Zhebin if (mEGLContextClientVersion != 2 && mEGLContextClientVersion != 3) { 9116ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich return configSpec; 9126ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich } 9136ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich /* We know none of the subclasses define EGL_RENDERABLE_TYPE. 9146ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich * And we know the configSpec is well formed. 9156ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich */ 9166ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich int len = configSpec.length; 9176ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich int[] newConfigSpec = new int[len + 2]; 9186ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1); 9196ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE; 92028a5c593577d6aef03d874b42ec0215c88f62bf4Jin Zhebin if (mEGLContextClientVersion == 2) { 92128a5c593577d6aef03d874b42ec0215c88f62bf4Jin Zhebin newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT; /* EGL_OPENGL_ES2_BIT */ 92228a5c593577d6aef03d874b42ec0215c88f62bf4Jin Zhebin } else { 92328a5c593577d6aef03d874b42ec0215c88f62bf4Jin Zhebin newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR; /* EGL_OPENGL_ES3_BIT_KHR */ 92428a5c593577d6aef03d874b42ec0215c88f62bf4Jin Zhebin } 9256ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich newConfigSpec[len+1] = EGL10.EGL_NONE; 9266ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich return newConfigSpec; 9276ae4da75422bbb31c3e0a09f616cdaee1d465946Jack Palevich } 928a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 929a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 93083835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich /** 93183835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * Choose a configuration with exactly the specified r,g,b,a sizes, 93283835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * and at least the specified depth and stencil sizes. 93383835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich */ 934f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private class ComponentSizeChooser extends BaseConfigChooser { 935a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich public ComponentSizeChooser(int redSize, int greenSize, int blueSize, 936f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown int alphaSize, int depthSize, int stencilSize) { 937a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich super(new int[] { 938a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGL10.EGL_RED_SIZE, redSize, 939a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGL10.EGL_GREEN_SIZE, greenSize, 940a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGL10.EGL_BLUE_SIZE, blueSize, 941a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGL10.EGL_ALPHA_SIZE, alphaSize, 942a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGL10.EGL_DEPTH_SIZE, depthSize, 943a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGL10.EGL_STENCIL_SIZE, stencilSize, 944f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown EGL10.EGL_NONE}); 945a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich mValue = new int[1]; 946a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich mRedSize = redSize; 947a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich mGreenSize = greenSize; 948a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich mBlueSize = blueSize; 949a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich mAlphaSize = alphaSize; 950a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich mDepthSize = depthSize; 951a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich mStencilSize = stencilSize; 952f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 953a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 954a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich @Override 955a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, 956a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGLConfig[] configs) { 95783835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich for (EGLConfig config : configs) { 958a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich int d = findConfigAttrib(egl, display, config, 959a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGL10.EGL_DEPTH_SIZE, 0); 960a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich int s = findConfigAttrib(egl, display, config, 961a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGL10.EGL_STENCIL_SIZE, 0); 96283835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich if ((d >= mDepthSize) && (s >= mStencilSize)) { 963f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown int r = findConfigAttrib(egl, display, config, 964f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown EGL10.EGL_RED_SIZE, 0); 965f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown int g = findConfigAttrib(egl, display, config, 966f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown EGL10.EGL_GREEN_SIZE, 0); 967f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown int b = findConfigAttrib(egl, display, config, 968f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown EGL10.EGL_BLUE_SIZE, 0); 969f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown int a = findConfigAttrib(egl, display, config, 970f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown EGL10.EGL_ALPHA_SIZE, 0); 97183835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich if ((r == mRedSize) && (g == mGreenSize) 97283835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich && (b == mBlueSize) && (a == mAlphaSize)) { 97383835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich return config; 97482fd4fce16b9bbde25d044acc86ddf7306ebdd10Mathias Agopian } 975a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 976a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 97783835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich return null; 978a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 979a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 980a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich private int findConfigAttrib(EGL10 egl, EGLDisplay display, 981a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich EGLConfig config, int attribute, int defaultValue) { 982a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 983a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { 984a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich return mValue[0]; 985a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 986a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich return defaultValue; 987a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 988a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 989a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich private int[] mValue; 990a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich // Subclasses can adjust these values: 991a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich protected int mRedSize; 992a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich protected int mGreenSize; 993a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich protected int mBlueSize; 994a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich protected int mAlphaSize; 995a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich protected int mDepthSize; 996a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich protected int mStencilSize; 997f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 998a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 999a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich /** 100029e0bd2f5a80fdfe0e5b482a1df86363afcecbfaMathias Agopian * This class will choose a RGB_888 surface with 100183835359e51ddb8be37cea9bf4bb32f9390d82b7Jack Palevich * or without a depth buffer. 1002a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich * 1003a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich */ 1004f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private class SimpleEGLConfigChooser extends ComponentSizeChooser { 1005f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public SimpleEGLConfigChooser(boolean withDepthBuffer) { 1006f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0); 1007a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 1008a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich } 1009a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich 1010a605a51e63de2e7dc99ed085639a6f12b7f85af7Jack Palevich /** 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An EGL helper class. 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 101480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich private static class EglHelper { 101580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich public EglHelper(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) { 101680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mGLSurfaceViewWeakRef = glSurfaceViewWeakRef; 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Initialize EGL for a given configuration spec. 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param configSpec 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1023f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public void start() { 102407353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (LOG_EGL) { 1025f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId()); 102607353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich } 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get an EGL instance 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEgl = (EGL10) EGLContext.getEGL(); 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get to the default display. 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 103728023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { 103828023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich throw new RuntimeException("eglGetDisplay failed"); 103928023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich } 104028023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * We can now initialize EGL for that display 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] version = new int[2]; 104528023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich if(!mEgl.eglInitialize(mEglDisplay, version)) { 104628023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich throw new RuntimeException("eglInitialize failed"); 104728023911a4b572f0ca640e7a3e3f9a0dd6f535e9Jack Palevich } 104880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich GLSurfaceView view = mGLSurfaceViewWeakRef.get(); 104980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if (view == null) { 105080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mEglConfig = null; 105180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mEglContext = null; 105280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } else { 105380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay); 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 105580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich /* 105680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich * Create an EGL context. We want to do this as rarely as we can, because an 105780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich * EGL context is a somewhat heavy object. 105880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich */ 105980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig); 106080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 10612e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) { 106207353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich mEglContext = null; 10639bb4dbae91df0971038e955ef49c5d9a64d4a428Jack Palevich throwEglException("createContext"); 10642e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich } 106507353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (LOG_EGL) { 1066f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId()); 106707353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich } 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEglSurface = null; 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1072b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich /** 1073b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich * Create an egl surface for the current SurfaceHolder surface. If a surface 1074b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich * already exists, destroy it before creating the new surface. 1075b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich * 1076b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich * @return true if the surface was created successfully. 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 107880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich public boolean createSurface() { 107907353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (LOG_EGL) { 1080f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.w("EglHelper", "createSurface() tid=" + Thread.currentThread().getId()); 108107353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich } 108207353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich /* 108307353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich * Check preconditions. 108407353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich */ 108507353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (mEgl == null) { 108607353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich throw new RuntimeException("egl not initialized"); 108707353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich } 108807353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (mEglDisplay == null) { 108907353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich throw new RuntimeException("eglDisplay not initialized"); 109007353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich } 109107353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (mEglConfig == null) { 109207353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich throw new RuntimeException("mEglConfig not initialized"); 109307353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich } 109480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The window size has changed, so we need to create a new 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * surface. 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 109980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich destroySurfaceImp(); 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create an EGL surface we can render into. 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 110480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich GLSurfaceView view = mGLSurfaceViewWeakRef.get(); 110580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if (view != null) { 110680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl, 110780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mEglDisplay, mEglConfig, view.getHolder()); 110880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } else { 110980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mEglSurface = null; 111080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11122e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { 11130e4aa37872810e46775374596e0beb11f7123727Jack Palevich int error = mEgl.eglGetError(); 11140e4aa37872810e46775374596e0beb11f7123727Jack Palevich if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { 1115f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 11160e4aa37872810e46775374596e0beb11f7123727Jack Palevich } 1117b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich return false; 11182e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich } 11192e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Before we can issue GL commands, we need to make sure 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the context is current and bound to a surface. 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11242e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 11257d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich /* 11267d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich * Could not make the context current, probably because the underlying 11277d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich * SurfaceView surface has been destroyed. 11287d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich */ 1129f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError()); 1130f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown return false; 11312e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich } 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1133b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich return true; 1134b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich } 1135b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich 1136b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich /** 1137b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich * Create a GL object for the current EGL context. 1138b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich * @return 1139b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich */ 1140f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown GL createGL() { 1141f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GL gl = mEglContext.getGL(); 114380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich GLSurfaceView view = mGLSurfaceViewWeakRef.get(); 114480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if (view != null) { 114580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if (view.mGLWrapper != null) { 114680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich gl = view.mGLWrapper.wrap(gl); 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 114880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich 114980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if ((view.mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) { 115080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich int configFlags = 0; 115180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich Writer log = null; 115280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if ((view.mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { 115380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; 115480b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 115580b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if ((view.mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { 115680b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich log = new LogWriter(); 115780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 115880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich gl = GLDebugHelper.wrap(gl, configFlags, log); 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return gl; 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Display the current render surface. 1166db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich * @return the EGL error code from eglSwapBuffers. 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1168db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich public int swap() { 116904b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { 11707d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich return mEgl.eglGetError(); 117104b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich } 1172db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich return EGL10.EGL_SUCCESS; 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11751bd888ba2e0976a179258cfa65ef07be31602a0aJack Palevich public void destroySurface() { 117607353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (LOG_EGL) { 1177f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.w("EglHelper", "destroySurface() tid=" + Thread.currentThread().getId()); 117807353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich } 117980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich destroySurfaceImp(); 118080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 118180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich 118280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich private void destroySurfaceImp() { 11832e26fc08aa1939c19e939d983bd608cdec050024Jack Palevich if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EGL10.EGL_NO_SURFACE, 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EGL10.EGL_NO_CONTEXT); 118780b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich GLSurfaceView view = mGLSurfaceViewWeakRef.get(); 118880b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if (view != null) { 118980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface); 119080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEglSurface = null; 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11931bd888ba2e0976a179258cfa65ef07be31602a0aJack Palevich } 11941bd888ba2e0976a179258cfa65ef07be31602a0aJack Palevich 1195f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public void finish() { 119607353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (LOG_EGL) { 1197f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.w("EglHelper", "finish() tid=" + Thread.currentThread().getId()); 119807353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich } 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEglContext != null) { 120080b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich GLSurfaceView view = mGLSurfaceViewWeakRef.get(); 120180b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich if (view != null) { 120280b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich view.mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext); 120380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich } 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEglContext = null; 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEglDisplay != null) { 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEgl.eglTerminate(mEglDisplay); 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEglDisplay = null; 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12125aa3adcf304ec3767b3c22128acb23240d8d0babJack Palevich private void throwEglException(String function) { 121304b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich throwEglException(function, mEgl.eglGetError()); 121404b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich } 121504b17ab7b4a17a28f541f746c3d55046c5b87596Jack Palevich 12167d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich public static void throwEglException(String function, int error) { 12177d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich String message = formatEglError(function, error); 121807353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich if (LOG_THREADS) { 1219f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " " 12207d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich + message); 122107353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich } 122207353a1e8598b1e2993b8b6763f630379ae6e8bbJack Palevich throw new RuntimeException(message); 12235aa3adcf304ec3767b3c22128acb23240d8d0babJack Palevich } 12245aa3adcf304ec3767b3c22128acb23240d8d0babJack Palevich 12257d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich public static void logEglErrorAsWarning(String tag, String function, int error) { 12267d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich Log.w(tag, formatEglError(function, error)); 12277d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich } 12287d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich 12297d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich public static String formatEglError(String function, int error) { 12307d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich return function + " failed: " + EGLLogWrapper.getErrorString(error); 12317d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich } 12327d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich 123380b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef; 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EGL10 mEgl; 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EGLDisplay mEglDisplay; 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EGLSurface mEglSurface; 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EGLConfig mEglConfig; 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EGLContext mEglContext; 1239f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A generic GL Thread. Takes care of initializing EGL and GL. Delegates 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to a Renderer instance to do the actual drawing. Can be configured to 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * render continuously or on request. 1246f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * 1247f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * All potentially blocking synchronization is done through the 1248f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * sGLThreadManager object. This avoids multiple-lock ordering issues. 1249f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1251f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown static class GLThread extends Thread { 1252f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) { 1253f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown super(); 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWidth = 0; 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHeight = 0; 1256f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRequestRender = true; 12573e832dbe966c2ca0fde2f4bd87ad9c974a93a7cfJack Palevich mRenderMode = RENDERMODE_CONTINUOUSLY; 12582b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr mWantRenderNotification = false; 125980b3cd6bc608c5929096e3407de2b157be925d3eJack Palevich mGLSurfaceViewWeakRef = glSurfaceViewWeakRef; 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 126257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian @Override 126357d019e222abc0de3f8876e682617d42872230c6Mathias Agopian public void run() { 1264f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown setName("GLThread " + getId()); 1265f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_THREADS) { 1266f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "starting tid=" + getId()); 1267f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1268f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1270f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown guardedRun(); 1271f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } catch (InterruptedException e) { 1272f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // fall thru and exit normally 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 1274f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.threadExiting(this); 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1278f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown /* 1279f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * This private method should only be called inside a 1280f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * synchronized(sGLThreadManager) block. 1281f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown */ 1282f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private void stopEglSurfaceLocked() { 1283840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich if (mHaveEglSurface) { 1284840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich mHaveEglSurface = false; 128532d416518473f3bf5323d660e5910ca5633ffed6Jack Palevich mEglHelper.destroySurface(); 128632d416518473f3bf5323d660e5910ca5633ffed6Jack Palevich } 128732d416518473f3bf5323d660e5910ca5633ffed6Jack Palevich } 128832d416518473f3bf5323d660e5910ca5633ffed6Jack Palevich 1289f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown /* 1290f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * This private method should only be called inside a 1291f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * synchronized(sGLThreadManager) block. 1292f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown */ 1293f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private void stopEglContextLocked() { 1294840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich if (mHaveEglContext) { 1295f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mEglHelper.finish(); 1296840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich mHaveEglContext = false; 1297f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.releaseEglContextLocked(this); 1298840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich } 1299840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich } 1300f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private void guardedRun() throws InterruptedException { 1301f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mEglHelper = new EglHelper(mGLSurfaceViewWeakRef); 1302f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mHaveEglContext = false; 1303f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mHaveEglSurface = false; 13042b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr mWantRenderNotification = false; 13052b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr 1306f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown try { 1307f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown GL10 gl = null; 1308f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown boolean createEglContext = false; 1309f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown boolean createEglSurface = false; 1310f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown boolean createGlInterface = false; 1311f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown boolean lostEglContext = false; 1312f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown boolean sizeChanged = false; 1313d4393b28978e45f67ace6530338c01ef647fada6Robert Carr boolean wantRenderNotification = false; 1314f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown boolean doRenderNotification = false; 1315f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown boolean askedToReleaseEglContext = false; 1316f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown int w = 0; 1317f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown int h = 0; 1318f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Runnable event = null; 131925cfa134835e3791bdb6572f5e25cf4599015678Robert Carr Runnable finishDrawingRunnable = null; 1320f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1321f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown while (true) { 1322f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized (sGLThreadManager) { 1323f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown while (true) { 1324f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mShouldExit) { 1325f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown return; 1326f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1327840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich 1328f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (! mEventQueue.isEmpty()) { 1329f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown event = mEventQueue.remove(0); 1330f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown break; 1331f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 133267dcd6c2392caf3ff98f35a3d1ec550d229c167bJack Palevich 1333f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // Update the pause state. 1334f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown boolean pausing = false; 1335f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mPaused != mRequestPaused) { 1336f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown pausing = mRequestPaused; 1337f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mPaused = mRequestPaused; 1338f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1339f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_PAUSE_RESUME) { 1340f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId()); 1341f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1342f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 134367dcd6c2392caf3ff98f35a3d1ec550d229c167bJack Palevich 1344f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // Do we need to give up the EGL context? 1345f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mShouldReleaseEglContext) { 1346f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_SURFACE) { 1347f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "releasing EGL context because asked to tid=" + getId()); 1348f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1349f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown stopEglSurfaceLocked(); 1350f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown stopEglContextLocked(); 1351f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mShouldReleaseEglContext = false; 1352f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown askedToReleaseEglContext = true; 1353f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 135421799450ec751fd3c41c7e66e69fefb094b3050bJack Palevich 1355f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // Have we lost the EGL context? 1356f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (lostEglContext) { 1357f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown stopEglSurfaceLocked(); 1358f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown stopEglContextLocked(); 1359f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown lostEglContext = false; 1360f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 136167dcd6c2392caf3ff98f35a3d1ec550d229c167bJack Palevich 1362f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // When pausing, release the EGL surface: 1363f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (pausing && mHaveEglSurface) { 1364f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_SURFACE) { 1365f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "releasing EGL surface because paused tid=" + getId()); 1366f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1367f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown stopEglSurfaceLocked(); 1368f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1369f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1370f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // When pausing, optionally release the EGL Context: 1371f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (pausing && mHaveEglContext) { 1372f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown GLSurfaceView view = mGLSurfaceViewWeakRef.get(); 1373f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown boolean preserveEglContextOnPause = view == null ? 1374f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown false : view.mPreserveEGLContextOnPause; 1375cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck if (!preserveEglContextOnPause) { 1376f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown stopEglContextLocked(); 1377f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_SURFACE) { 1378f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "releasing EGL context because paused tid=" + getId()); 1379f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1380f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1381f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1382f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1383f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // Have we lost the SurfaceView surface? 1384f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if ((! mHasSurface) && (! mWaitingForSurface)) { 1385f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_SURFACE) { 1386f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "noticed surfaceView surface lost tid=" + getId()); 1387f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1388f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mHaveEglSurface) { 1389f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown stopEglSurfaceLocked(); 1390f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1391f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mWaitingForSurface = true; 1392f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mSurfaceIsBad = false; 1393f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1394f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1395f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1396f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // Have we acquired the surface view surface? 1397f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mHasSurface && mWaitingForSurface) { 1398f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_SURFACE) { 1399f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "noticed surfaceView surface acquired tid=" + getId()); 1400f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1401f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mWaitingForSurface = false; 1402f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1403f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1404f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1405f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (doRenderNotification) { 1406f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_SURFACE) { 1407f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "sending render notification tid=" + getId()); 1408f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 14092b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr mWantRenderNotification = false; 1410f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown doRenderNotification = false; 1411f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRenderComplete = true; 1412f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1413f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1414f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 141525cfa134835e3791bdb6572f5e25cf4599015678Robert Carr if (mFinishDrawingRunnable != null) { 141625cfa134835e3791bdb6572f5e25cf4599015678Robert Carr finishDrawingRunnable = mFinishDrawingRunnable; 141725cfa134835e3791bdb6572f5e25cf4599015678Robert Carr mFinishDrawingRunnable = null; 141825cfa134835e3791bdb6572f5e25cf4599015678Robert Carr } 141925cfa134835e3791bdb6572f5e25cf4599015678Robert Carr 1420f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // Ready to draw? 1421f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (readyToDraw()) { 1422f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1423f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // If we don't have an EGL context, try to acquire one. 1424f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (! mHaveEglContext) { 1425f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (askedToReleaseEglContext) { 1426f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown askedToReleaseEglContext = false; 1427cf89019e500441d8cb4f7cff7f0b07049515c97aJohn Reck } else { 1428f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown try { 1429f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mEglHelper.start(); 1430f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } catch (RuntimeException t) { 1431f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.releaseEglContextLocked(this); 1432f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown throw t; 1433f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1434f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mHaveEglContext = true; 1435f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown createEglContext = true; 1436f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1437f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1438f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1439f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1440f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1441f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mHaveEglContext && !mHaveEglSurface) { 1442f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mHaveEglSurface = true; 1443f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown createEglSurface = true; 1444f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown createGlInterface = true; 1445f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sizeChanged = true; 1446f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1447f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1448f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mHaveEglSurface) { 1449f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mSizeChanged) { 1450f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sizeChanged = true; 1451f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown w = mWidth; 1452f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown h = mHeight; 14532b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr mWantRenderNotification = true; 1454f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_SURFACE) { 1455f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", 1456f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown "noticing that we want render notification tid=" 1457f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + getId()); 1458f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1459f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1460f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // Destroy and recreate the EGL surface. 1461f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown createEglSurface = true; 1462f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1463f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mSizeChanged = false; 1464f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1465f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRequestRender = false; 1466f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1467d4393b28978e45f67ace6530338c01ef647fada6Robert Carr if (mWantRenderNotification) { 1468d4393b28978e45f67ace6530338c01ef647fada6Robert Carr wantRenderNotification = true; 1469d4393b28978e45f67ace6530338c01ef647fada6Robert Carr } 1470f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown break; 1471f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1472e7f4286c8a9d301a24d408b820aeec436b0f3423John Reck } else { 1473e7f4286c8a9d301a24d408b820aeec436b0f3423John Reck if (finishDrawingRunnable != null) { 1474e7f4286c8a9d301a24d408b820aeec436b0f3423John Reck Log.w(TAG, "Warning, !readyToDraw() but waiting for " + 1475e7f4286c8a9d301a24d408b820aeec436b0f3423John Reck "draw finished! Early reporting draw finished."); 1476e7f4286c8a9d301a24d408b820aeec436b0f3423John Reck finishDrawingRunnable.run(); 1477e7f4286c8a9d301a24d408b820aeec436b0f3423John Reck finishDrawingRunnable = null; 1478e7f4286c8a9d301a24d408b820aeec436b0f3423John Reck } 1479f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1480f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // By design, this is the only place in a GLThread thread where we wait(). 1481f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_THREADS) { 1482f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "waiting tid=" + getId() 1483f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mHaveEglContext: " + mHaveEglContext 1484f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mHaveEglSurface: " + mHaveEglSurface 1485f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mFinishedCreatingEglSurface: " + mFinishedCreatingEglSurface 1486f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mPaused: " + mPaused 1487f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mHasSurface: " + mHasSurface 1488f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mSurfaceIsBad: " + mSurfaceIsBad 1489f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mWaitingForSurface: " + mWaitingForSurface 1490f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mWidth: " + mWidth 1491f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mHeight: " + mHeight 1492f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mRequestRender: " + mRequestRender 1493f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown + " mRenderMode: " + mRenderMode); 1494f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1495f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.wait(); 149615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 1497f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } // end of synchronized(sGLThreadManager) 149867dcd6c2392caf3ff98f35a3d1ec550d229c167bJack Palevich 1499f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (event != null) { 1500f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown event.run(); 1501f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown event = null; 1502f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown continue; 150315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 1504a08d46d8aaabb53eef4d5dc47272565d50f23c19Jack Palevich 1505f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (createEglSurface) { 1506f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_SURFACE) { 1507f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.w("GLThread", "egl createSurface"); 1508f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1509f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (mEglHelper.createSurface()) { 1510f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1511f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mFinishedCreatingEglSurface = true; 1512f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1513f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1514f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } else { 1515f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1516f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mFinishedCreatingEglSurface = true; 1517f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mSurfaceIsBad = true; 1518f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1519f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1520f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown continue; 1521f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1522f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown createEglSurface = false; 1523f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1524b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich 1525f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (createGlInterface) { 1526f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown gl = (GL10) mEglHelper.createGL(); 1527b50e2afd6782e9b877f52844bec106c12ff9a9efJack Palevich 1528f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown createGlInterface = false; 1529f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1530840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich 1531f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (createEglContext) { 1532f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_RENDERER) { 1533f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.w("GLThread", "onSurfaceCreated"); 1534f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1535f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown GLSurfaceView view = mGLSurfaceViewWeakRef.get(); 1536f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (view != null) { 153759b429d10678542756c1a9ba7acf900de3d41871Chris Craik try { 153859b429d10678542756c1a9ba7acf900de3d41871Chris Craik Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceCreated"); 153959b429d10678542756c1a9ba7acf900de3d41871Chris Craik view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig); 154059b429d10678542756c1a9ba7acf900de3d41871Chris Craik } finally { 154159b429d10678542756c1a9ba7acf900de3d41871Chris Craik Trace.traceEnd(Trace.TRACE_TAG_VIEW); 154259b429d10678542756c1a9ba7acf900de3d41871Chris Craik } 1543f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1544f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown createEglContext = false; 1545f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1546a08d46d8aaabb53eef4d5dc47272565d50f23c19Jack Palevich 1547f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (sizeChanged) { 1548f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_RENDERER) { 1549f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")"); 1550f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1551f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown GLSurfaceView view = mGLSurfaceViewWeakRef.get(); 1552f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (view != null) { 155359b429d10678542756c1a9ba7acf900de3d41871Chris Craik try { 155459b429d10678542756c1a9ba7acf900de3d41871Chris Craik Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceChanged"); 155559b429d10678542756c1a9ba7acf900de3d41871Chris Craik view.mRenderer.onSurfaceChanged(gl, w, h); 155659b429d10678542756c1a9ba7acf900de3d41871Chris Craik } finally { 155759b429d10678542756c1a9ba7acf900de3d41871Chris Craik Trace.traceEnd(Trace.TRACE_TAG_VIEW); 155859b429d10678542756c1a9ba7acf900de3d41871Chris Craik } 1559f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1560f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sizeChanged = false; 1561f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 156257d019e222abc0de3f8876e682617d42872230c6Mathias Agopian 1563f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_RENDERER_DRAW_FRAME) { 1564f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.w("GLThread", "onDrawFrame tid=" + getId()); 1565f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1566f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown { 1567f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown GLSurfaceView view = mGLSurfaceViewWeakRef.get(); 1568f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (view != null) { 156959b429d10678542756c1a9ba7acf900de3d41871Chris Craik try { 157059b429d10678542756c1a9ba7acf900de3d41871Chris Craik Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onDrawFrame"); 157159b429d10678542756c1a9ba7acf900de3d41871Chris Craik view.mRenderer.onDrawFrame(gl); 157225cfa134835e3791bdb6572f5e25cf4599015678Robert Carr if (finishDrawingRunnable != null) { 157325cfa134835e3791bdb6572f5e25cf4599015678Robert Carr finishDrawingRunnable.run(); 157425cfa134835e3791bdb6572f5e25cf4599015678Robert Carr finishDrawingRunnable = null; 157525cfa134835e3791bdb6572f5e25cf4599015678Robert Carr } 157659b429d10678542756c1a9ba7acf900de3d41871Chris Craik } finally { 157759b429d10678542756c1a9ba7acf900de3d41871Chris Craik Trace.traceEnd(Trace.TRACE_TAG_VIEW); 157859b429d10678542756c1a9ba7acf900de3d41871Chris Craik } 1579f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1580f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1581db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich int swapError = mEglHelper.swap(); 1582db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich switch (swapError) { 1583db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich case EGL10.EGL_SUCCESS: 1584db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich break; 1585db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich case EGL11.EGL_CONTEXT_LOST: 1586db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich if (LOG_SURFACE) { 1587f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "egl context lost tid=" + getId()); 1588db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich } 1589f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown lostEglContext = true; 1590db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich break; 1591db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich default: 1592db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich // Other errors typically mean that the current surface is bad, 15937d73df83f9a28950f404e957eb2e4ea1e8525c55Jack Palevich // probably because the SurfaceView surface has been destroyed, 1594db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich // but we haven't been notified yet. 1595db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich // Log the error to help developers understand why rendering stopped. 1596f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError); 1597f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1598f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1599f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mSurfaceIsBad = true; 1600f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1601f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1602db6c78b5bdf264abe8f6de97f67ca5e90fb6a05aJack Palevich break; 160315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 1604f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1605d4393b28978e45f67ace6530338c01ef647fada6Robert Carr if (wantRenderNotification) { 1606f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown doRenderNotification = true; 1607d4393b28978e45f67ace6530338c01ef647fada6Robert Carr wantRenderNotification = false; 1608f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1609a08d46d8aaabb53eef4d5dc47272565d50f23c19Jack Palevich } 1610840e958847f31f835dbf17ce539c9f8317251cc9Jack Palevich 1611f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } finally { 1612f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown /* 1613f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * clean-up everything... 1614f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown */ 1615f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized (sGLThreadManager) { 1616f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown stopEglSurfaceLocked(); 1617f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown stopEglContextLocked(); 1618f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 161915e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1622f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public boolean ableToDraw() { 1623f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown return mHaveEglContext && mHaveEglSurface && readyToDraw(); 16241b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich } 16251b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich 1626f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean readyToDraw() { 1627f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown return (!mPaused) && mHasSurface && (!mSurfaceIsBad) 1628f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown && (mWidth > 0) && (mHeight > 0) 1629f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY)); 163057d019e222abc0de3f8876e682617d42872230c6Mathias Agopian } 163157d019e222abc0de3f8876e682617d42872230c6Mathias Agopian 1632f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public void setRenderMode(int renderMode) { 1633f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) { 1634f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown throw new IllegalArgumentException("renderMode"); 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1636f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1637f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRenderMode = renderMode; 1638f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1642f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public int getRenderMode() { 1643f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1644f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown return mRenderMode; 16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1648f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public void requestRender() { 1649f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1650f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRequestRender = true; 1651f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 165525cfa134835e3791bdb6572f5e25cf4599015678Robert Carr public void requestRenderAndNotify(Runnable finishDrawing) { 16562b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr synchronized(sGLThreadManager) { 1657d4393b28978e45f67ace6530338c01ef647fada6Robert Carr // If we are already on the GL thread, this means a client callback 1658d4393b28978e45f67ace6530338c01ef647fada6Robert Carr // has caused reentrancy, for example via updating the SurfaceView parameters. 1659d4393b28978e45f67ace6530338c01ef647fada6Robert Carr // We will return to the client rendering code, so here we don't need to 1660d4393b28978e45f67ace6530338c01ef647fada6Robert Carr // do anything. 1661d4393b28978e45f67ace6530338c01ef647fada6Robert Carr if (Thread.currentThread() == this) { 1662d4393b28978e45f67ace6530338c01ef647fada6Robert Carr return; 1663d4393b28978e45f67ace6530338c01ef647fada6Robert Carr } 1664d4393b28978e45f67ace6530338c01ef647fada6Robert Carr 16652b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr mWantRenderNotification = true; 16662b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr mRequestRender = true; 16672b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr mRenderComplete = false; 166825cfa134835e3791bdb6572f5e25cf4599015678Robert Carr mFinishDrawingRunnable = finishDrawing; 1669d4393b28978e45f67ace6530338c01ef647fada6Robert Carr 16702b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr sGLThreadManager.notifyAll(); 16712b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr } 16722b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr } 16732b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr 16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceCreated() { 1675f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1676f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_THREADS) { 1677f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "surfaceCreated tid=" + getId()); 16788b2c9c9ecb08d25244fa97fb42c2c315ae3cf03dJack Palevich } 1679f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mHasSurface = true; 1680f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mFinishedCreatingEglSurface = false; 1681f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1682f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown while (mWaitingForSurface 1683f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown && !mFinishedCreatingEglSurface 1684f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown && !mExited) { 1685f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown try { 1686f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.wait(); 1687f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } catch (InterruptedException e) { 1688f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Thread.currentThread().interrupt(); 1689f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1690f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1691f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceDestroyed() { 1695f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1696f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_THREADS) { 1697f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "surfaceDestroyed tid=" + getId()); 16988b2c9c9ecb08d25244fa97fb42c2c315ae3cf03dJack Palevich } 1699f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mHasSurface = false; 1700f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1701f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown while((!mWaitingForSurface) && (!mExited)) { 1702f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown try { 1703f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.wait(); 1704f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } catch (InterruptedException e) { 1705f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Thread.currentThread().interrupt(); 1706f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1707f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1708f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onPause() { 1712f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized (sGLThreadManager) { 1713f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_PAUSE_RESUME) { 1714f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "onPause tid=" + getId()); 1715f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1716f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRequestPaused = true; 1717f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1718f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown while ((! mExited) && (! mPaused)) { 1719f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_PAUSE_RESUME) { 1720f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("Main thread", "onPause waiting for mPaused."); 1721f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1722f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown try { 1723f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.wait(); 1724f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } catch (InterruptedException ex) { 1725f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Thread.currentThread().interrupt(); 1726f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1727451a224c46c297bd6b25e3570b45f5053b4788beJack Palevich } 1728f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onResume() { 1732f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized (sGLThreadManager) { 1733f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_PAUSE_RESUME) { 1734f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "onResume tid=" + getId()); 1735f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1736f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRequestPaused = false; 1737f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRequestRender = true; 1738f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRenderComplete = false; 1739f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1740f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown while ((! mExited) && mPaused && (!mRenderComplete)) { 1741f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_PAUSE_RESUME) { 1742f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("Main thread", "onResume waiting for !mPaused."); 1743f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1744f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown try { 1745f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.wait(); 1746f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } catch (InterruptedException ex) { 1747f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Thread.currentThread().interrupt(); 1748f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1749451a224c46c297bd6b25e3570b45f5053b4788beJack Palevich } 1750f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onWindowResize(int w, int h) { 1754f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized (sGLThreadManager) { 1755f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mWidth = w; 1756f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mHeight = h; 1757f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mSizeChanged = true; 1758f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRequestRender = true; 1759f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mRenderComplete = false; 1760d4393b28978e45f67ace6530338c01ef647fada6Robert Carr 1761d4393b28978e45f67ace6530338c01ef647fada6Robert Carr // If we are already on the GL thread, this means a client callback 1762d4393b28978e45f67ace6530338c01ef647fada6Robert Carr // has caused reentrancy, for example via updating the SurfaceView parameters. 1763d4393b28978e45f67ace6530338c01ef647fada6Robert Carr // We need to process the size change eventually though and update our EGLSurface. 1764d4393b28978e45f67ace6530338c01ef647fada6Robert Carr // So we set the parameters and return so they can be processed on our 1765d4393b28978e45f67ace6530338c01ef647fada6Robert Carr // next iteration. 1766d4393b28978e45f67ace6530338c01ef647fada6Robert Carr if (Thread.currentThread() == this) { 1767d4393b28978e45f67ace6530338c01ef647fada6Robert Carr return; 1768d4393b28978e45f67ace6530338c01ef647fada6Robert Carr } 1769d4393b28978e45f67ace6530338c01ef647fada6Robert Carr 1770f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1771f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1772f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // Wait for thread to react to resize and render a frame 1773f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown while (! mExited && !mPaused && !mRenderComplete 1774f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown && ableToDraw()) { 1775f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_SURFACE) { 1776f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + getId()); 1777f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1778f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown try { 1779f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.wait(); 1780f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } catch (InterruptedException ex) { 1781f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Thread.currentThread().interrupt(); 1782f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 178321799450ec751fd3c41c7e66e69fefb094b3050bJack Palevich } 1784f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1787f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public void requestExitAndWait() { 1788f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // don't call this from GLThread thread or it is a guaranteed 1789f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // deadlock! 1790f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1791f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mShouldExit = true; 1792f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1793f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown while (! mExited) { 1794f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown try { 1795f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.wait(); 1796f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } catch (InterruptedException ex) { 1797f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Thread.currentThread().interrupt(); 1798f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1799f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1803f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public void requestReleaseEglContextLocked() { 1804f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mShouldReleaseEglContext = true; 1805f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 18061b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich } 18071b4ecc63c4eceb7c125d4e749fd5f747d99d6ec6Jack Palevich 1808f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown /** 1809f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * Queue an "event" to be run on the GL rendering thread. 1810f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * @param r the runnable to be run on the GL rendering thread. 1811f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown */ 1812f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public void queueEvent(Runnable r) { 1813f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (r == null) { 1814f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown throw new IllegalArgumentException("r must not be null"); 1815f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1816f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown synchronized(sGLThreadManager) { 1817f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown mEventQueue.add(r); 1818f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown sGLThreadManager.notifyAll(); 1819f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 182078bc2033129507f1cf4acb2e3007f89cb2b3f224Mathias Agopian } 1821f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1822f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // Once the thread is started, all accesses to the following member 1823f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // variables are protected by the sGLThreadManager monitor 1824f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mShouldExit; 1825f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mExited; 1826f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mRequestPaused; 1827f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mPaused; 1828f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mHasSurface; 1829f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mSurfaceIsBad; 1830f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mWaitingForSurface; 1831f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mHaveEglContext; 1832f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mHaveEglSurface; 1833f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mFinishedCreatingEglSurface; 1834f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mShouldReleaseEglContext; 1835f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private int mWidth; 1836f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private int mHeight; 1837f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private int mRenderMode; 1838f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mRequestRender; 18392b3bf720bf28584f700ad8ebb5e8e31a0e466f29Robert Carr private boolean mWantRenderNotification; 1840f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mRenderComplete; 1841f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>(); 1842f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mSizeChanged = true; 184325cfa134835e3791bdb6572f5e25cf4599015678Robert Carr private Runnable mFinishDrawingRunnable = null; 1844f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1845f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown // End of member variables protected by the sGLThreadManager monitor. 1846f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1847f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private EglHelper mEglHelper; 1848f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1849f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown /** 1850f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * Set once at thread construction time, nulled out when the parent view is garbage 1851f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * called. This weak reference allows the GLSurfaceView to be garbage collected while 1852f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * the GLThread is still alive. 1853f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown */ 1854f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef; 1855f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1856f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static class LogWriter extends Writer { 1859f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1860f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown @Override public void close() { 18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project flushBuilder(); 18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1864f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown @Override public void flush() { 18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project flushBuilder(); 18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1868f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown @Override public void write(char[] buf, int offset, int count) { 1869f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown for(int i = 0; i < count; i++) { 18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = buf[offset + i]; 1871f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if ( c == '\n') { 18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project flushBuilder(); 1873f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1874f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown else { 18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBuilder.append(c); 18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void flushBuilder() { 18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mBuilder.length() > 0) { 1882f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.v("GLSurfaceView", mBuilder.toString()); 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBuilder.delete(0, mBuilder.length()); 18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private StringBuilder mBuilder = new StringBuilder(); 18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1890f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 189115e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich private void checkRenderThreadState() { 189215e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich if (mGLThread != null) { 189315e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich throw new IllegalStateException( 189415e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich "setRenderer has already been called for this instance."); 189515e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 189615e1c6dc7a778590068b1cad55beea2bc6159509Jack Palevich } 1897f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1898f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private static class GLThreadManager { 1899f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private static String TAG = "GLThreadManager"; 1900f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1901f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public synchronized void threadExiting(GLThread thread) { 1902f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown if (LOG_THREADS) { 1903f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown Log.i("GLThread", "exiting tid=" + thread.getId()); 1904f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1905f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown thread.mExited = true; 1906f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown notifyAll(); 1907f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1908f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1909f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown /* 1910f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * Releases the EGL context. Requires that we are already in the 1911f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown * sGLThreadManager monitor when this is called. 1912f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown */ 1913f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown public void releaseEglContextLocked(GLThread thread) { 1914f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown notifyAll(); 1915f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1916f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown } 1917f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1918f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private static final GLThreadManager sGLThreadManager = new GLThreadManager(); 1919f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown 1920f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private final WeakReference<GLSurfaceView> mThisWeakRef = 1921f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown new WeakReference<GLSurfaceView>(this); 1922f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private GLThread mGLThread; 1923f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private Renderer mRenderer; 1924f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mDetached; 1925f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private EGLConfigChooser mEGLConfigChooser; 1926f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private EGLContextFactory mEGLContextFactory; 1927f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory; 1928f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private GLWrapper mGLWrapper; 1929f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private int mDebugFlags; 1930f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private int mEGLContextClientVersion; 1931f48b03296c715b18ffbb7393d5e71ea96eaae028Jeff Brown private boolean mPreserveEGLContextOnPause; 19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1933