GLSurfaceView.java revision 3c1e67e433728684b5f228c5d4f3e5b1457bb271
1cfd74d65d832137e20e193c960802afba73b5d38sm/* 23c1e67e433728684b5f228c5d4f3e5b1457bb271sm * Copyright (C) 2010 The Android Open Source Project 3cfd74d65d832137e20e193c960802afba73b5d38sm * 4cfd74d65d832137e20e193c960802afba73b5d38sm * Licensed under the Apache License, Version 2.0 (the "License"); 5cfd74d65d832137e20e193c960802afba73b5d38sm * you may not use this file except in compliance with the License. 6cfd74d65d832137e20e193c960802afba73b5d38sm * You may obtain a copy of the License at 7cfd74d65d832137e20e193c960802afba73b5d38sm * 8cfd74d65d832137e20e193c960802afba73b5d38sm * http://www.apache.org/licenses/LICENSE-2.0 9cfd74d65d832137e20e193c960802afba73b5d38sm * 10cfd74d65d832137e20e193c960802afba73b5d38sm * Unless required by applicable law or agreed to in writing, software 11cfd74d65d832137e20e193c960802afba73b5d38sm * distributed under the License is distributed on an "AS IS" BASIS, 12cfd74d65d832137e20e193c960802afba73b5d38sm * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cfd74d65d832137e20e193c960802afba73b5d38sm * See the License for the specific language governing permissions and 14cfd74d65d832137e20e193c960802afba73b5d38sm * limitations under the License. 15cfd74d65d832137e20e193c960802afba73b5d38sm */ 16cfd74d65d832137e20e193c960802afba73b5d38sm 17cfd74d65d832137e20e193c960802afba73b5d38smpackage com.replica.replicaisland; 18cfd74d65d832137e20e193c960802afba73b5d38sm 19cfd74d65d832137e20e193c960802afba73b5d38smimport java.io.Writer; 20cfd74d65d832137e20e193c960802afba73b5d38smimport java.util.ArrayList; 21cfd74d65d832137e20e193c960802afba73b5d38sm 22cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.egl.EGL10; 23cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.egl.EGL11; 24cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.egl.EGLConfig; 25cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.egl.EGLContext; 26cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.egl.EGLDisplay; 27cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.egl.EGLSurface; 28cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.opengles.GL; 29cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.opengles.GL10; 30cfd74d65d832137e20e193c960802afba73b5d38sm 31cfd74d65d832137e20e193c960802afba73b5d38smimport android.content.Context; 32cfd74d65d832137e20e193c960802afba73b5d38smimport android.content.pm.ConfigurationInfo; 33cfd74d65d832137e20e193c960802afba73b5d38smimport android.opengl.GLDebugHelper; 34cfd74d65d832137e20e193c960802afba73b5d38smimport android.util.AttributeSet; 35cfd74d65d832137e20e193c960802afba73b5d38smimport android.view.SurfaceHolder; 36cfd74d65d832137e20e193c960802afba73b5d38smimport android.view.SurfaceView; 37cfd74d65d832137e20e193c960802afba73b5d38sm 38cfd74d65d832137e20e193c960802afba73b5d38sm/** 39cfd74d65d832137e20e193c960802afba73b5d38sm * An implementation of SurfaceView that uses the dedicated surface for 40cfd74d65d832137e20e193c960802afba73b5d38sm * displaying OpenGL rendering. 41cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 42cfd74d65d832137e20e193c960802afba73b5d38sm * A GLSurfaceView provides the following features: 43cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 44cfd74d65d832137e20e193c960802afba73b5d38sm * <ul> 45cfd74d65d832137e20e193c960802afba73b5d38sm * <li>Manages a surface, which is a special piece of memory that can be 46cfd74d65d832137e20e193c960802afba73b5d38sm * composited into the Android view system. 47cfd74d65d832137e20e193c960802afba73b5d38sm * <li>Manages an EGL display, which enables OpenGL to render into a surface. 48cfd74d65d832137e20e193c960802afba73b5d38sm * <li>Accepts a user-provided Renderer object that does the actual rendering. 49cfd74d65d832137e20e193c960802afba73b5d38sm * <li>Renders on a dedicated thread to decouple rendering performance from the 50cfd74d65d832137e20e193c960802afba73b5d38sm * UI thread. 51cfd74d65d832137e20e193c960802afba73b5d38sm * <li>Supports both on-demand and continuous rendering. 52cfd74d65d832137e20e193c960802afba73b5d38sm * <li>Optionally wraps, traces, and/or error-checks the renderer's OpenGL calls. 53cfd74d65d832137e20e193c960802afba73b5d38sm * </ul> 54cfd74d65d832137e20e193c960802afba73b5d38sm * 55cfd74d65d832137e20e193c960802afba73b5d38sm * <h3>Using GLSurfaceView</h3> 56cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 57cfd74d65d832137e20e193c960802afba73b5d38sm * Typically you use GLSurfaceView by subclassing it and overriding one or more of the 58cfd74d65d832137e20e193c960802afba73b5d38sm * View system input event methods. If your application does not need to override event 59cfd74d65d832137e20e193c960802afba73b5d38sm * methods then GLSurfaceView can be used as-is. For the most part 60cfd74d65d832137e20e193c960802afba73b5d38sm * GLSurfaceView behavior is customized by calling "set" methods rather than by subclassing. 61cfd74d65d832137e20e193c960802afba73b5d38sm * For example, unlike a regular View, drawing is delegated to a separate Renderer object which 62cfd74d65d832137e20e193c960802afba73b5d38sm * is registered with the GLSurfaceView 63cfd74d65d832137e20e193c960802afba73b5d38sm * using the {@link #setRenderer(Renderer)} call. 64cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 65cfd74d65d832137e20e193c960802afba73b5d38sm * <h3>Initializing GLSurfaceView</h3> 66cfd74d65d832137e20e193c960802afba73b5d38sm * All you have to do to initialize a GLSurfaceView is call {@link #setRenderer(Renderer)}. 67cfd74d65d832137e20e193c960802afba73b5d38sm * However, if desired, you can modify the default behavior of GLSurfaceView by calling one or 68cfd74d65d832137e20e193c960802afba73b5d38sm * more of these methods before calling setRenderer: 69cfd74d65d832137e20e193c960802afba73b5d38sm * <ul> 70cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #setDebugFlags(int)} 71cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #setEGLConfigChooser(boolean)} 72cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #setEGLConfigChooser(EGLConfigChooser)} 73cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)} 74cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #setGLWrapper(GLWrapper)} 75cfd74d65d832137e20e193c960802afba73b5d38sm * </ul> 76cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 77cfd74d65d832137e20e193c960802afba73b5d38sm * <h4>Choosing an EGL Configuration</h4> 78cfd74d65d832137e20e193c960802afba73b5d38sm * A given Android device may support multiple possible types of drawing surfaces. 79cfd74d65d832137e20e193c960802afba73b5d38sm * The available surfaces may differ in how may channels of data are present, as 80cfd74d65d832137e20e193c960802afba73b5d38sm * well as how many bits are allocated to each channel. Therefore, the first thing 81cfd74d65d832137e20e193c960802afba73b5d38sm * GLSurfaceView has to do when starting to render is choose what type of surface to use. 82cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 83cfd74d65d832137e20e193c960802afba73b5d38sm * By default GLSurfaceView chooses an available surface that's closest to a 16-bit R5G6B5 surface 84cfd74d65d832137e20e193c960802afba73b5d38sm * with a 16-bit depth buffer and no stencil. If you would prefer a different surface (for example, 85cfd74d65d832137e20e193c960802afba73b5d38sm * if you do not need a depth buffer) you can override the default behavior by calling one of the 86cfd74d65d832137e20e193c960802afba73b5d38sm * setEGLConfigChooser methods. 87cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 88cfd74d65d832137e20e193c960802afba73b5d38sm * <h4>Debug Behavior</h4> 89cfd74d65d832137e20e193c960802afba73b5d38sm * You can optionally modify the behavior of GLSurfaceView by calling 90cfd74d65d832137e20e193c960802afba73b5d38sm * one or more of the debugging methods {@link #setDebugFlags(int)}, 91cfd74d65d832137e20e193c960802afba73b5d38sm * and {@link #setGLWrapper}. These methods may be called before and/or after setRenderer, but 92cfd74d65d832137e20e193c960802afba73b5d38sm * typically they are called before setRenderer so that they take effect immediately. 93cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 94cfd74d65d832137e20e193c960802afba73b5d38sm * <h4>Setting a Renderer</h4> 95cfd74d65d832137e20e193c960802afba73b5d38sm * Finally, you must call {@link #setRenderer} to register a {@link Renderer}. 96cfd74d65d832137e20e193c960802afba73b5d38sm * The renderer is 97cfd74d65d832137e20e193c960802afba73b5d38sm * responsible for doing the actual OpenGL rendering. 98cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 99cfd74d65d832137e20e193c960802afba73b5d38sm * <h3>Rendering Mode</h3> 100cfd74d65d832137e20e193c960802afba73b5d38sm * Once the renderer is set, you can control whether the renderer draws 101cfd74d65d832137e20e193c960802afba73b5d38sm * continuously or on-demand by calling 102cfd74d65d832137e20e193c960802afba73b5d38sm * {@link #setRenderMode}. The default is continuous rendering. 103cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 104cfd74d65d832137e20e193c960802afba73b5d38sm * <h3>Activity Life-cycle</h3> 105cfd74d65d832137e20e193c960802afba73b5d38sm * A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView clients 106cfd74d65d832137e20e193c960802afba73b5d38sm * are required to call {@link #onPause()} when the activity pauses and 107cfd74d65d832137e20e193c960802afba73b5d38sm * {@link #onResume()} when the activity resumes. These calls allow GLSurfaceView to 108cfd74d65d832137e20e193c960802afba73b5d38sm * pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate 109cfd74d65d832137e20e193c960802afba73b5d38sm * the OpenGL display. 110cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 111cfd74d65d832137e20e193c960802afba73b5d38sm * <h3>Handling events</h3> 112cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 113cfd74d65d832137e20e193c960802afba73b5d38sm * To handle an event you will typically subclass GLSurfaceView and override the 114cfd74d65d832137e20e193c960802afba73b5d38sm * appropriate method, just as you would with any other View. However, when handling 115cfd74d65d832137e20e193c960802afba73b5d38sm * the event, you may need to communicate with the Renderer object 116cfd74d65d832137e20e193c960802afba73b5d38sm * that's running in the rendering thread. You can do this using any 117cfd74d65d832137e20e193c960802afba73b5d38sm * standard Java cross-thread communication mechanism. In addition, 118cfd74d65d832137e20e193c960802afba73b5d38sm * one relatively easy way to communicate with your renderer is 119cfd74d65d832137e20e193c960802afba73b5d38sm * to call 120cfd74d65d832137e20e193c960802afba73b5d38sm * {@link #queueEvent(Runnable)}. For example: 121cfd74d65d832137e20e193c960802afba73b5d38sm * <pre class="prettyprint"> 122cfd74d65d832137e20e193c960802afba73b5d38sm * class MyGLSurfaceView extends GLSurfaceView { 123cfd74d65d832137e20e193c960802afba73b5d38sm * 124cfd74d65d832137e20e193c960802afba73b5d38sm * private MyRenderer mMyRenderer; 125cfd74d65d832137e20e193c960802afba73b5d38sm * 126cfd74d65d832137e20e193c960802afba73b5d38sm * public void start() { 127cfd74d65d832137e20e193c960802afba73b5d38sm * mMyRenderer = ...; 128cfd74d65d832137e20e193c960802afba73b5d38sm * setRenderer(mMyRenderer); 129cfd74d65d832137e20e193c960802afba73b5d38sm * } 130cfd74d65d832137e20e193c960802afba73b5d38sm * 131cfd74d65d832137e20e193c960802afba73b5d38sm * public boolean onKeyDown(int keyCode, KeyEvent event) { 132cfd74d65d832137e20e193c960802afba73b5d38sm * if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { 133cfd74d65d832137e20e193c960802afba73b5d38sm * queueEvent(new Runnable() { 134cfd74d65d832137e20e193c960802afba73b5d38sm * // This method will be called on the rendering 135cfd74d65d832137e20e193c960802afba73b5d38sm * // thread: 136cfd74d65d832137e20e193c960802afba73b5d38sm * public void run() { 137cfd74d65d832137e20e193c960802afba73b5d38sm * mMyRenderer.handleDpadCenter(); 138cfd74d65d832137e20e193c960802afba73b5d38sm * }}); 139cfd74d65d832137e20e193c960802afba73b5d38sm * return true; 140cfd74d65d832137e20e193c960802afba73b5d38sm * } 141cfd74d65d832137e20e193c960802afba73b5d38sm * return super.onKeyDown(keyCode, event); 142cfd74d65d832137e20e193c960802afba73b5d38sm * } 143cfd74d65d832137e20e193c960802afba73b5d38sm * } 144cfd74d65d832137e20e193c960802afba73b5d38sm * </pre> 145cfd74d65d832137e20e193c960802afba73b5d38sm * 146cfd74d65d832137e20e193c960802afba73b5d38sm */ 147cfd74d65d832137e20e193c960802afba73b5d38smpublic class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback { 148cfd74d65d832137e20e193c960802afba73b5d38sm private final static boolean LOG_THREADS = false; 149cfd74d65d832137e20e193c960802afba73b5d38sm private final static boolean LOG_SURFACE = true; 150cfd74d65d832137e20e193c960802afba73b5d38sm private final static boolean LOG_RENDERER = false; 151cfd74d65d832137e20e193c960802afba73b5d38sm // Work-around for bug 2263168 152cfd74d65d832137e20e193c960802afba73b5d38sm private final static boolean DRAW_TWICE_AFTER_SIZE_CHANGED = true; 153cfd74d65d832137e20e193c960802afba73b5d38sm /** 154cfd74d65d832137e20e193c960802afba73b5d38sm * The renderer only renders 155cfd74d65d832137e20e193c960802afba73b5d38sm * when the surface is created, or when {@link #requestRender} is called. 156cfd74d65d832137e20e193c960802afba73b5d38sm * 157cfd74d65d832137e20e193c960802afba73b5d38sm * @see #getRenderMode() 158cfd74d65d832137e20e193c960802afba73b5d38sm * @see #setRenderMode(int) 159cfd74d65d832137e20e193c960802afba73b5d38sm */ 160cfd74d65d832137e20e193c960802afba73b5d38sm public final static int RENDERMODE_WHEN_DIRTY = 0; 161cfd74d65d832137e20e193c960802afba73b5d38sm /** 162cfd74d65d832137e20e193c960802afba73b5d38sm * The renderer is called 163cfd74d65d832137e20e193c960802afba73b5d38sm * continuously to re-render the scene. 164cfd74d65d832137e20e193c960802afba73b5d38sm * 165cfd74d65d832137e20e193c960802afba73b5d38sm * @see #getRenderMode() 166cfd74d65d832137e20e193c960802afba73b5d38sm * @see #setRenderMode(int) 167cfd74d65d832137e20e193c960802afba73b5d38sm * @see #requestRender() 168cfd74d65d832137e20e193c960802afba73b5d38sm */ 169cfd74d65d832137e20e193c960802afba73b5d38sm public final static int RENDERMODE_CONTINUOUSLY = 1; 170cfd74d65d832137e20e193c960802afba73b5d38sm 171cfd74d65d832137e20e193c960802afba73b5d38sm /** 172cfd74d65d832137e20e193c960802afba73b5d38sm * Check glError() after every GL call and throw an exception if glError indicates 173cfd74d65d832137e20e193c960802afba73b5d38sm * that an error has occurred. This can be used to help track down which OpenGL ES call 174cfd74d65d832137e20e193c960802afba73b5d38sm * is causing an error. 175cfd74d65d832137e20e193c960802afba73b5d38sm * 176cfd74d65d832137e20e193c960802afba73b5d38sm * @see #getDebugFlags 177cfd74d65d832137e20e193c960802afba73b5d38sm * @see #setDebugFlags 178cfd74d65d832137e20e193c960802afba73b5d38sm */ 179cfd74d65d832137e20e193c960802afba73b5d38sm public final static int DEBUG_CHECK_GL_ERROR = 1; 180cfd74d65d832137e20e193c960802afba73b5d38sm 181cfd74d65d832137e20e193c960802afba73b5d38sm /** 182cfd74d65d832137e20e193c960802afba73b5d38sm * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView". 183cfd74d65d832137e20e193c960802afba73b5d38sm * 184cfd74d65d832137e20e193c960802afba73b5d38sm * @see #getDebugFlags 185cfd74d65d832137e20e193c960802afba73b5d38sm * @see #setDebugFlags 186cfd74d65d832137e20e193c960802afba73b5d38sm */ 187cfd74d65d832137e20e193c960802afba73b5d38sm public final static int DEBUG_LOG_GL_CALLS = 2; 188cfd74d65d832137e20e193c960802afba73b5d38sm 189cfd74d65d832137e20e193c960802afba73b5d38sm /** 190cfd74d65d832137e20e193c960802afba73b5d38sm * Standard View constructor. In order to render something, you 191cfd74d65d832137e20e193c960802afba73b5d38sm * must call {@link #setRenderer} to register a renderer. 192cfd74d65d832137e20e193c960802afba73b5d38sm */ 193cfd74d65d832137e20e193c960802afba73b5d38sm public GLSurfaceView(Context context) { 194cfd74d65d832137e20e193c960802afba73b5d38sm super(context); 195cfd74d65d832137e20e193c960802afba73b5d38sm init(); 196cfd74d65d832137e20e193c960802afba73b5d38sm } 197cfd74d65d832137e20e193c960802afba73b5d38sm 198cfd74d65d832137e20e193c960802afba73b5d38sm /** 199cfd74d65d832137e20e193c960802afba73b5d38sm * Standard View constructor. In order to render something, you 200cfd74d65d832137e20e193c960802afba73b5d38sm * must call {@link #setRenderer} to register a renderer. 201cfd74d65d832137e20e193c960802afba73b5d38sm */ 202cfd74d65d832137e20e193c960802afba73b5d38sm public GLSurfaceView(Context context, AttributeSet attrs) { 203cfd74d65d832137e20e193c960802afba73b5d38sm super(context, attrs); 204cfd74d65d832137e20e193c960802afba73b5d38sm init(); 205cfd74d65d832137e20e193c960802afba73b5d38sm } 206cfd74d65d832137e20e193c960802afba73b5d38sm 207cfd74d65d832137e20e193c960802afba73b5d38sm private void init() { 208cfd74d65d832137e20e193c960802afba73b5d38sm // Install a SurfaceHolder.Callback so we get notified when the 209cfd74d65d832137e20e193c960802afba73b5d38sm // underlying surface is created and destroyed 210cfd74d65d832137e20e193c960802afba73b5d38sm SurfaceHolder holder = getHolder(); 211cfd74d65d832137e20e193c960802afba73b5d38sm holder.addCallback(this); 212cfd74d65d832137e20e193c960802afba73b5d38sm holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); 213cfd74d65d832137e20e193c960802afba73b5d38sm 214cfd74d65d832137e20e193c960802afba73b5d38sm } 215cfd74d65d832137e20e193c960802afba73b5d38sm 216cfd74d65d832137e20e193c960802afba73b5d38sm /** 217cfd74d65d832137e20e193c960802afba73b5d38sm * Set the glWrapper. If the glWrapper is not null, its 218cfd74d65d832137e20e193c960802afba73b5d38sm * {@link GLWrapper#wrap(GL)} method is called 219cfd74d65d832137e20e193c960802afba73b5d38sm * whenever a surface is created. A GLWrapper can be used to wrap 220cfd74d65d832137e20e193c960802afba73b5d38sm * the GL object that's passed to the renderer. Wrapping a GL 221cfd74d65d832137e20e193c960802afba73b5d38sm * object enables examining and modifying the behavior of the 222cfd74d65d832137e20e193c960802afba73b5d38sm * GL calls made by the renderer. 223cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 224cfd74d65d832137e20e193c960802afba73b5d38sm * Wrapping is typically used for debugging purposes. 225cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 226cfd74d65d832137e20e193c960802afba73b5d38sm * The default value is null. 227cfd74d65d832137e20e193c960802afba73b5d38sm * @param glWrapper the new GLWrapper 228cfd74d65d832137e20e193c960802afba73b5d38sm */ 229cfd74d65d832137e20e193c960802afba73b5d38sm public void setGLWrapper(GLWrapper glWrapper) { 230cfd74d65d832137e20e193c960802afba73b5d38sm mGLWrapper = glWrapper; 231cfd74d65d832137e20e193c960802afba73b5d38sm } 232cfd74d65d832137e20e193c960802afba73b5d38sm 233cfd74d65d832137e20e193c960802afba73b5d38sm /** 234cfd74d65d832137e20e193c960802afba73b5d38sm * Set the debug flags to a new value. The value is 235cfd74d65d832137e20e193c960802afba73b5d38sm * constructed by OR-together zero or more 236cfd74d65d832137e20e193c960802afba73b5d38sm * of the DEBUG_CHECK_* constants. The debug flags take effect 237cfd74d65d832137e20e193c960802afba73b5d38sm * whenever a surface is created. The default value is zero. 238cfd74d65d832137e20e193c960802afba73b5d38sm * @param debugFlags the new debug flags 239cfd74d65d832137e20e193c960802afba73b5d38sm * @see #DEBUG_CHECK_GL_ERROR 240cfd74d65d832137e20e193c960802afba73b5d38sm * @see #DEBUG_LOG_GL_CALLS 241cfd74d65d832137e20e193c960802afba73b5d38sm */ 242cfd74d65d832137e20e193c960802afba73b5d38sm public void setDebugFlags(int debugFlags) { 243cfd74d65d832137e20e193c960802afba73b5d38sm mDebugFlags = debugFlags; 244cfd74d65d832137e20e193c960802afba73b5d38sm } 245cfd74d65d832137e20e193c960802afba73b5d38sm 246cfd74d65d832137e20e193c960802afba73b5d38sm /** 247cfd74d65d832137e20e193c960802afba73b5d38sm * Get the current value of the debug flags. 248cfd74d65d832137e20e193c960802afba73b5d38sm * @return the current value of the debug flags. 249cfd74d65d832137e20e193c960802afba73b5d38sm */ 250cfd74d65d832137e20e193c960802afba73b5d38sm public int getDebugFlags() { 251cfd74d65d832137e20e193c960802afba73b5d38sm return mDebugFlags; 252cfd74d65d832137e20e193c960802afba73b5d38sm } 253cfd74d65d832137e20e193c960802afba73b5d38sm 254cfd74d65d832137e20e193c960802afba73b5d38sm /** 255cfd74d65d832137e20e193c960802afba73b5d38sm * Set the renderer associated with this view. Also starts the thread that 256cfd74d65d832137e20e193c960802afba73b5d38sm * will call the renderer, which in turn causes the rendering to start. 257cfd74d65d832137e20e193c960802afba73b5d38sm * <p>This method should be called once and only once in the life-cycle of 258cfd74d65d832137e20e193c960802afba73b5d38sm * a GLSurfaceView. 259cfd74d65d832137e20e193c960802afba73b5d38sm * <p>The following GLSurfaceView methods can only be called <em>before</em> 260cfd74d65d832137e20e193c960802afba73b5d38sm * setRenderer is called: 261cfd74d65d832137e20e193c960802afba73b5d38sm * <ul> 262cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #setEGLConfigChooser(boolean)} 263cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #setEGLConfigChooser(EGLConfigChooser)} 264cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)} 265cfd74d65d832137e20e193c960802afba73b5d38sm * </ul> 266cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 267cfd74d65d832137e20e193c960802afba73b5d38sm * The following GLSurfaceView methods can only be called <em>after</em> 268cfd74d65d832137e20e193c960802afba73b5d38sm * setRenderer is called: 269cfd74d65d832137e20e193c960802afba73b5d38sm * <ul> 270cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #getRenderMode()} 271cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #onPause()} 272cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #onResume()} 273cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #queueEvent(Runnable)} 274cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #requestRender()} 275cfd74d65d832137e20e193c960802afba73b5d38sm * <li>{@link #setRenderMode(int)} 276cfd74d65d832137e20e193c960802afba73b5d38sm * </ul> 277cfd74d65d832137e20e193c960802afba73b5d38sm * 278cfd74d65d832137e20e193c960802afba73b5d38sm * @param renderer the renderer to use to perform OpenGL drawing. 279cfd74d65d832137e20e193c960802afba73b5d38sm */ 280cfd74d65d832137e20e193c960802afba73b5d38sm public void setRenderer(Renderer renderer) { 281cfd74d65d832137e20e193c960802afba73b5d38sm checkRenderThreadState(); 282cfd74d65d832137e20e193c960802afba73b5d38sm if (mEGLConfigChooser == null) { 283cfd74d65d832137e20e193c960802afba73b5d38sm mEGLConfigChooser = new SimpleEGLConfigChooser(true); 284cfd74d65d832137e20e193c960802afba73b5d38sm } 285cfd74d65d832137e20e193c960802afba73b5d38sm if (mEGLContextFactory == null) { 286cfd74d65d832137e20e193c960802afba73b5d38sm mEGLContextFactory = new DefaultContextFactory(); 287cfd74d65d832137e20e193c960802afba73b5d38sm } 288cfd74d65d832137e20e193c960802afba73b5d38sm if (mEGLWindowSurfaceFactory == null) { 289cfd74d65d832137e20e193c960802afba73b5d38sm mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory(); 290cfd74d65d832137e20e193c960802afba73b5d38sm } 291cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread = new GLThread(renderer); 292cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.start(); 293cfd74d65d832137e20e193c960802afba73b5d38sm } 294cfd74d65d832137e20e193c960802afba73b5d38sm 295cfd74d65d832137e20e193c960802afba73b5d38sm /** 296cfd74d65d832137e20e193c960802afba73b5d38sm * Install a custom EGLContextFactory. 297cfd74d65d832137e20e193c960802afba73b5d38sm * <p>If this method is 298cfd74d65d832137e20e193c960802afba73b5d38sm * called, it must be called before {@link #setRenderer(Renderer)} 299cfd74d65d832137e20e193c960802afba73b5d38sm * is called. 300cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 301cfd74d65d832137e20e193c960802afba73b5d38sm * If this method is not called, then by default 302cfd74d65d832137e20e193c960802afba73b5d38sm * a context will be created with no shared context and 303cfd74d65d832137e20e193c960802afba73b5d38sm * with a null attribute list. 304cfd74d65d832137e20e193c960802afba73b5d38sm */ 305cfd74d65d832137e20e193c960802afba73b5d38sm public void setEGLContextFactory(EGLContextFactory factory) { 306cfd74d65d832137e20e193c960802afba73b5d38sm checkRenderThreadState(); 307cfd74d65d832137e20e193c960802afba73b5d38sm mEGLContextFactory = factory; 308cfd74d65d832137e20e193c960802afba73b5d38sm } 309cfd74d65d832137e20e193c960802afba73b5d38sm 310cfd74d65d832137e20e193c960802afba73b5d38sm /** 311cfd74d65d832137e20e193c960802afba73b5d38sm * Install a custom EGLWindowSurfaceFactory. 312cfd74d65d832137e20e193c960802afba73b5d38sm * <p>If this method is 313cfd74d65d832137e20e193c960802afba73b5d38sm * called, it must be called before {@link #setRenderer(Renderer)} 314cfd74d65d832137e20e193c960802afba73b5d38sm * is called. 315cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 316cfd74d65d832137e20e193c960802afba73b5d38sm * If this method is not called, then by default 317cfd74d65d832137e20e193c960802afba73b5d38sm * a window surface will be created with a null attribute list. 318cfd74d65d832137e20e193c960802afba73b5d38sm */ 319cfd74d65d832137e20e193c960802afba73b5d38sm public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) { 320cfd74d65d832137e20e193c960802afba73b5d38sm checkRenderThreadState(); 321cfd74d65d832137e20e193c960802afba73b5d38sm mEGLWindowSurfaceFactory = factory; 322cfd74d65d832137e20e193c960802afba73b5d38sm } 323cfd74d65d832137e20e193c960802afba73b5d38sm 324cfd74d65d832137e20e193c960802afba73b5d38sm /** 325cfd74d65d832137e20e193c960802afba73b5d38sm * Install a custom EGLConfigChooser. 326cfd74d65d832137e20e193c960802afba73b5d38sm * <p>If this method is 327cfd74d65d832137e20e193c960802afba73b5d38sm * called, it must be called before {@link #setRenderer(Renderer)} 328cfd74d65d832137e20e193c960802afba73b5d38sm * is called. 329cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 330cfd74d65d832137e20e193c960802afba73b5d38sm * If no setEGLConfigChooser method is called, then by default the 331cfd74d65d832137e20e193c960802afba73b5d38sm * view will choose a config as close to 16-bit RGB as possible, with 332cfd74d65d832137e20e193c960802afba73b5d38sm * a depth buffer as close to 16 bits as possible. 333cfd74d65d832137e20e193c960802afba73b5d38sm * @param configChooser 334cfd74d65d832137e20e193c960802afba73b5d38sm */ 335cfd74d65d832137e20e193c960802afba73b5d38sm public void setEGLConfigChooser(EGLConfigChooser configChooser) { 336cfd74d65d832137e20e193c960802afba73b5d38sm checkRenderThreadState(); 337cfd74d65d832137e20e193c960802afba73b5d38sm mEGLConfigChooser = configChooser; 338cfd74d65d832137e20e193c960802afba73b5d38sm } 339cfd74d65d832137e20e193c960802afba73b5d38sm 340cfd74d65d832137e20e193c960802afba73b5d38sm /** 341cfd74d65d832137e20e193c960802afba73b5d38sm * Install a config chooser which will choose a config 342cfd74d65d832137e20e193c960802afba73b5d38sm * as close to 16-bit RGB as possible, with or without an optional depth 343cfd74d65d832137e20e193c960802afba73b5d38sm * buffer as close to 16-bits as possible. 344cfd74d65d832137e20e193c960802afba73b5d38sm * <p>If this method is 345cfd74d65d832137e20e193c960802afba73b5d38sm * called, it must be called before {@link #setRenderer(Renderer)} 346cfd74d65d832137e20e193c960802afba73b5d38sm * is called. 347cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 348cfd74d65d832137e20e193c960802afba73b5d38sm * If no setEGLConfigChooser method is called, then by default the 349cfd74d65d832137e20e193c960802afba73b5d38sm * view will choose a config as close to 16-bit RGB as possible, with 350cfd74d65d832137e20e193c960802afba73b5d38sm * a depth buffer as close to 16 bits as possible. 351cfd74d65d832137e20e193c960802afba73b5d38sm * 352cfd74d65d832137e20e193c960802afba73b5d38sm * @param needDepth 353cfd74d65d832137e20e193c960802afba73b5d38sm */ 354cfd74d65d832137e20e193c960802afba73b5d38sm public void setEGLConfigChooser(boolean needDepth) { 355cfd74d65d832137e20e193c960802afba73b5d38sm setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth)); 356cfd74d65d832137e20e193c960802afba73b5d38sm } 357cfd74d65d832137e20e193c960802afba73b5d38sm 358cfd74d65d832137e20e193c960802afba73b5d38sm /** 359cfd74d65d832137e20e193c960802afba73b5d38sm * Install a config chooser which will choose a config 360cfd74d65d832137e20e193c960802afba73b5d38sm * with at least the specified component sizes, and as close 361cfd74d65d832137e20e193c960802afba73b5d38sm * to the specified component sizes as possible. 362cfd74d65d832137e20e193c960802afba73b5d38sm * <p>If this method is 363cfd74d65d832137e20e193c960802afba73b5d38sm * called, it must be called before {@link #setRenderer(Renderer)} 364cfd74d65d832137e20e193c960802afba73b5d38sm * is called. 365cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 366cfd74d65d832137e20e193c960802afba73b5d38sm * If no setEGLConfigChooser method is called, then by default the 367cfd74d65d832137e20e193c960802afba73b5d38sm * view will choose a config as close to 16-bit RGB as possible, with 368cfd74d65d832137e20e193c960802afba73b5d38sm * a depth buffer as close to 16 bits as possible. 369cfd74d65d832137e20e193c960802afba73b5d38sm * 370cfd74d65d832137e20e193c960802afba73b5d38sm */ 371cfd74d65d832137e20e193c960802afba73b5d38sm public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, 372cfd74d65d832137e20e193c960802afba73b5d38sm int alphaSize, int depthSize, int stencilSize) { 373cfd74d65d832137e20e193c960802afba73b5d38sm setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize, 374cfd74d65d832137e20e193c960802afba73b5d38sm blueSize, alphaSize, depthSize, stencilSize)); 375cfd74d65d832137e20e193c960802afba73b5d38sm } 376cfd74d65d832137e20e193c960802afba73b5d38sm 377cfd74d65d832137e20e193c960802afba73b5d38sm /** 378cfd74d65d832137e20e193c960802afba73b5d38sm * Inform the default EGLContextFactory and default EGLConfigChooser 379cfd74d65d832137e20e193c960802afba73b5d38sm * which EGLContext client version to pick. 380cfd74d65d832137e20e193c960802afba73b5d38sm * <p>Use this method to create an OpenGL ES 2.0-compatible context. 381cfd74d65d832137e20e193c960802afba73b5d38sm * Example: 382cfd74d65d832137e20e193c960802afba73b5d38sm * <pre class="prettyprint"> 383cfd74d65d832137e20e193c960802afba73b5d38sm * public MyView(Context context) { 384cfd74d65d832137e20e193c960802afba73b5d38sm * super(context); 385cfd74d65d832137e20e193c960802afba73b5d38sm * setEGLContextClientVersion(2); // Pick an OpenGL ES 2.0 context. 386cfd74d65d832137e20e193c960802afba73b5d38sm * setRenderer(new MyRenderer()); 387cfd74d65d832137e20e193c960802afba73b5d38sm * } 388cfd74d65d832137e20e193c960802afba73b5d38sm * </pre> 389cfd74d65d832137e20e193c960802afba73b5d38sm * <p>Note: Activities which require OpenGL ES 2.0 should indicate this by 390cfd74d65d832137e20e193c960802afba73b5d38sm * setting @lt;uses-feature android:glEsVersion="0x00020000" /> in the activity's 391cfd74d65d832137e20e193c960802afba73b5d38sm * AndroidManifest.xml file. 392cfd74d65d832137e20e193c960802afba73b5d38sm * <p>If this method is called, it must be called before {@link #setRenderer(Renderer)} 393cfd74d65d832137e20e193c960802afba73b5d38sm * is called. 394cfd74d65d832137e20e193c960802afba73b5d38sm * <p>This method only affects the behavior of the default EGLContexFactory and the 395cfd74d65d832137e20e193c960802afba73b5d38sm * default EGLConfigChooser. If 396cfd74d65d832137e20e193c960802afba73b5d38sm * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then the supplied 397cfd74d65d832137e20e193c960802afba73b5d38sm * EGLContextFactory is responsible for creating an OpenGL ES 2.0-compatible context. 398cfd74d65d832137e20e193c960802afba73b5d38sm * If 399cfd74d65d832137e20e193c960802afba73b5d38sm * {@link #setEGLConfigChooser(EGLConfigChooser)} has been called, then the supplied 400cfd74d65d832137e20e193c960802afba73b5d38sm * EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible config. 401cfd74d65d832137e20e193c960802afba73b5d38sm * @param version The EGLContext client version to choose. Use 2 for OpenGL ES 2.0 402cfd74d65d832137e20e193c960802afba73b5d38sm */ 403cfd74d65d832137e20e193c960802afba73b5d38sm public void setEGLContextClientVersion(int version) { 404cfd74d65d832137e20e193c960802afba73b5d38sm checkRenderThreadState(); 405cfd74d65d832137e20e193c960802afba73b5d38sm mEGLContextClientVersion = version; 406cfd74d65d832137e20e193c960802afba73b5d38sm } 407cfd74d65d832137e20e193c960802afba73b5d38sm 408cfd74d65d832137e20e193c960802afba73b5d38sm /** 409cfd74d65d832137e20e193c960802afba73b5d38sm * Set the rendering mode. When renderMode is 410cfd74d65d832137e20e193c960802afba73b5d38sm * RENDERMODE_CONTINUOUSLY, the renderer is called 411cfd74d65d832137e20e193c960802afba73b5d38sm * repeatedly to re-render the scene. When renderMode 412cfd74d65d832137e20e193c960802afba73b5d38sm * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface 413cfd74d65d832137e20e193c960802afba73b5d38sm * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY. 414cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 415cfd74d65d832137e20e193c960802afba73b5d38sm * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance 416cfd74d65d832137e20e193c960802afba73b5d38sm * by allowing the GPU and CPU to idle when the view does not need to be updated. 417cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 418cfd74d65d832137e20e193c960802afba73b5d38sm * This method can only be called after {@link #setRenderer(Renderer)} 419cfd74d65d832137e20e193c960802afba73b5d38sm * 420cfd74d65d832137e20e193c960802afba73b5d38sm * @param renderMode one of the RENDERMODE_X constants 421cfd74d65d832137e20e193c960802afba73b5d38sm * @see #RENDERMODE_CONTINUOUSLY 422cfd74d65d832137e20e193c960802afba73b5d38sm * @see #RENDERMODE_WHEN_DIRTY 423cfd74d65d832137e20e193c960802afba73b5d38sm */ 424cfd74d65d832137e20e193c960802afba73b5d38sm public void setRenderMode(int renderMode) { 425cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.setRenderMode(renderMode); 426cfd74d65d832137e20e193c960802afba73b5d38sm } 427cfd74d65d832137e20e193c960802afba73b5d38sm 428cfd74d65d832137e20e193c960802afba73b5d38sm /** 429cfd74d65d832137e20e193c960802afba73b5d38sm * Get the current rendering mode. May be called 430cfd74d65d832137e20e193c960802afba73b5d38sm * from any thread. Must not be called before a renderer has been set. 431cfd74d65d832137e20e193c960802afba73b5d38sm * @return the current rendering mode. 432cfd74d65d832137e20e193c960802afba73b5d38sm * @see #RENDERMODE_CONTINUOUSLY 433cfd74d65d832137e20e193c960802afba73b5d38sm * @see #RENDERMODE_WHEN_DIRTY 434cfd74d65d832137e20e193c960802afba73b5d38sm */ 435cfd74d65d832137e20e193c960802afba73b5d38sm public int getRenderMode() { 436cfd74d65d832137e20e193c960802afba73b5d38sm return mGLThread.getRenderMode(); 437cfd74d65d832137e20e193c960802afba73b5d38sm } 438cfd74d65d832137e20e193c960802afba73b5d38sm 439cfd74d65d832137e20e193c960802afba73b5d38sm /** 440cfd74d65d832137e20e193c960802afba73b5d38sm * Request that the renderer render a frame. 441cfd74d65d832137e20e193c960802afba73b5d38sm * This method is typically used when the render mode has been set to 442cfd74d65d832137e20e193c960802afba73b5d38sm * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand. 443cfd74d65d832137e20e193c960802afba73b5d38sm * May be called 444cfd74d65d832137e20e193c960802afba73b5d38sm * from any thread. Must not be called before a renderer has been set. 445cfd74d65d832137e20e193c960802afba73b5d38sm */ 446cfd74d65d832137e20e193c960802afba73b5d38sm public void requestRender() { 447cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.requestRender(); 448cfd74d65d832137e20e193c960802afba73b5d38sm } 449cfd74d65d832137e20e193c960802afba73b5d38sm 450cfd74d65d832137e20e193c960802afba73b5d38sm /** 451cfd74d65d832137e20e193c960802afba73b5d38sm * This method is part of the SurfaceHolder.Callback interface, and is 452cfd74d65d832137e20e193c960802afba73b5d38sm * not normally called or subclassed by clients of GLSurfaceView. 453cfd74d65d832137e20e193c960802afba73b5d38sm */ 454cfd74d65d832137e20e193c960802afba73b5d38sm public void surfaceCreated(SurfaceHolder holder) { 455cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.surfaceCreated(); 456cfd74d65d832137e20e193c960802afba73b5d38sm } 457cfd74d65d832137e20e193c960802afba73b5d38sm 458cfd74d65d832137e20e193c960802afba73b5d38sm /** 459cfd74d65d832137e20e193c960802afba73b5d38sm * This method is part of the SurfaceHolder.Callback interface, and is 460cfd74d65d832137e20e193c960802afba73b5d38sm * not normally called or subclassed by clients of GLSurfaceView. 461cfd74d65d832137e20e193c960802afba73b5d38sm */ 462cfd74d65d832137e20e193c960802afba73b5d38sm public void surfaceDestroyed(SurfaceHolder holder) { 463cfd74d65d832137e20e193c960802afba73b5d38sm // Surface will be destroyed when we return 464cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.surfaceDestroyed(); 465cfd74d65d832137e20e193c960802afba73b5d38sm } 466cfd74d65d832137e20e193c960802afba73b5d38sm 467cfd74d65d832137e20e193c960802afba73b5d38sm /** 468cfd74d65d832137e20e193c960802afba73b5d38sm * This method is part of the SurfaceHolder.Callback interface, and is 469cfd74d65d832137e20e193c960802afba73b5d38sm * not normally called or subclassed by clients of GLSurfaceView. 470cfd74d65d832137e20e193c960802afba73b5d38sm */ 471cfd74d65d832137e20e193c960802afba73b5d38sm public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 472cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.onWindowResize(w, h); 473cfd74d65d832137e20e193c960802afba73b5d38sm } 474cfd74d65d832137e20e193c960802afba73b5d38sm 475cfd74d65d832137e20e193c960802afba73b5d38sm /** 476cfd74d65d832137e20e193c960802afba73b5d38sm * Inform the view that the activity is paused. The owner of this view must 477cfd74d65d832137e20e193c960802afba73b5d38sm * call this method when the activity is paused. Calling this method will 478cfd74d65d832137e20e193c960802afba73b5d38sm * pause the rendering thread. 479cfd74d65d832137e20e193c960802afba73b5d38sm * Must not be called before a renderer has been set. 480cfd74d65d832137e20e193c960802afba73b5d38sm */ 481cfd74d65d832137e20e193c960802afba73b5d38sm public void onPause() { 482cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.onPause(); 483cfd74d65d832137e20e193c960802afba73b5d38sm } 484cfd74d65d832137e20e193c960802afba73b5d38sm 485cfd74d65d832137e20e193c960802afba73b5d38sm /** 486cfd74d65d832137e20e193c960802afba73b5d38sm * Inform the view that the activity is resumed. The owner of this view must 487cfd74d65d832137e20e193c960802afba73b5d38sm * call this method when the activity is resumed. Calling this method will 488cfd74d65d832137e20e193c960802afba73b5d38sm * recreate the OpenGL display and resume the rendering 489cfd74d65d832137e20e193c960802afba73b5d38sm * thread. 490cfd74d65d832137e20e193c960802afba73b5d38sm * Must not be called before a renderer has been set. 491cfd74d65d832137e20e193c960802afba73b5d38sm */ 492cfd74d65d832137e20e193c960802afba73b5d38sm public void onResume() { 493cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.onResume(); 494cfd74d65d832137e20e193c960802afba73b5d38sm } 495cfd74d65d832137e20e193c960802afba73b5d38sm 496cfd74d65d832137e20e193c960802afba73b5d38sm public void flushTextures(TextureLibrary library) { 497cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.flushTextures(library); 498cfd74d65d832137e20e193c960802afba73b5d38sm } 499cfd74d65d832137e20e193c960802afba73b5d38sm 500cfd74d65d832137e20e193c960802afba73b5d38sm public void loadTextures(TextureLibrary library) { 501cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.loadTextures(library); 502cfd74d65d832137e20e193c960802afba73b5d38sm } 503cfd74d65d832137e20e193c960802afba73b5d38sm 504cfd74d65d832137e20e193c960802afba73b5d38sm public void flushBuffers(BufferLibrary library) { 505cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.flushBuffers(library); 506cfd74d65d832137e20e193c960802afba73b5d38sm } 507cfd74d65d832137e20e193c960802afba73b5d38sm 508cfd74d65d832137e20e193c960802afba73b5d38sm public void loadBuffers(BufferLibrary library) { 509cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.loadBuffers(library); 510cfd74d65d832137e20e193c960802afba73b5d38sm } 511cfd74d65d832137e20e193c960802afba73b5d38sm 512cfd74d65d832137e20e193c960802afba73b5d38sm /** 513cfd74d65d832137e20e193c960802afba73b5d38sm * Queue a runnable to be run on the GL rendering thread. This can be used 514cfd74d65d832137e20e193c960802afba73b5d38sm * to communicate with the Renderer on the rendering thread. 515cfd74d65d832137e20e193c960802afba73b5d38sm * Must not be called before a renderer has been set. 516cfd74d65d832137e20e193c960802afba73b5d38sm * @param r the runnable to be run on the GL rendering thread. 517cfd74d65d832137e20e193c960802afba73b5d38sm */ 518cfd74d65d832137e20e193c960802afba73b5d38sm public void queueEvent(Runnable r) { 519cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.queueEvent(r); 520cfd74d65d832137e20e193c960802afba73b5d38sm } 521cfd74d65d832137e20e193c960802afba73b5d38sm 522cfd74d65d832137e20e193c960802afba73b5d38sm /** 523cfd74d65d832137e20e193c960802afba73b5d38sm * Inform the view that the window focus has changed. 524cfd74d65d832137e20e193c960802afba73b5d38sm */ 525cfd74d65d832137e20e193c960802afba73b5d38sm @Override 526cfd74d65d832137e20e193c960802afba73b5d38sm public void onWindowFocusChanged(boolean hasFocus) { 527cfd74d65d832137e20e193c960802afba73b5d38sm super.onWindowFocusChanged(hasFocus); 528cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.onWindowFocusChanged(hasFocus); 529cfd74d65d832137e20e193c960802afba73b5d38sm } 530cfd74d65d832137e20e193c960802afba73b5d38sm 531cfd74d65d832137e20e193c960802afba73b5d38sm /** 532cfd74d65d832137e20e193c960802afba73b5d38sm * This method is used as part of the View class and is not normally 533cfd74d65d832137e20e193c960802afba73b5d38sm * called or subclassed by clients of GLSurfaceView. 534cfd74d65d832137e20e193c960802afba73b5d38sm * Must not be called before a renderer has been set. 535cfd74d65d832137e20e193c960802afba73b5d38sm */ 536cfd74d65d832137e20e193c960802afba73b5d38sm @Override 537cfd74d65d832137e20e193c960802afba73b5d38sm protected void onDetachedFromWindow() { 538cfd74d65d832137e20e193c960802afba73b5d38sm super.onDetachedFromWindow(); 539cfd74d65d832137e20e193c960802afba73b5d38sm mGLThread.requestExitAndWait(); 540cfd74d65d832137e20e193c960802afba73b5d38sm } 541cfd74d65d832137e20e193c960802afba73b5d38sm 542cfd74d65d832137e20e193c960802afba73b5d38sm // ---------------------------------------------------------------------- 543cfd74d65d832137e20e193c960802afba73b5d38sm 544cfd74d65d832137e20e193c960802afba73b5d38sm /** 545cfd74d65d832137e20e193c960802afba73b5d38sm * An interface used to wrap a GL interface. 546cfd74d65d832137e20e193c960802afba73b5d38sm * <p>Typically 547cfd74d65d832137e20e193c960802afba73b5d38sm * used for implementing debugging and tracing on top of the default 548cfd74d65d832137e20e193c960802afba73b5d38sm * GL interface. You would typically use this by creating your own class 549cfd74d65d832137e20e193c960802afba73b5d38sm * that implemented all the GL methods by delegating to another GL instance. 550cfd74d65d832137e20e193c960802afba73b5d38sm * Then you could add your own behavior before or after calling the 551cfd74d65d832137e20e193c960802afba73b5d38sm * delegate. All the GLWrapper would do was instantiate and return the 552cfd74d65d832137e20e193c960802afba73b5d38sm * wrapper GL instance: 553cfd74d65d832137e20e193c960802afba73b5d38sm * <pre class="prettyprint"> 554cfd74d65d832137e20e193c960802afba73b5d38sm * class MyGLWrapper implements GLWrapper { 555cfd74d65d832137e20e193c960802afba73b5d38sm * GL wrap(GL gl) { 556cfd74d65d832137e20e193c960802afba73b5d38sm * return new MyGLImplementation(gl); 557cfd74d65d832137e20e193c960802afba73b5d38sm * } 558cfd74d65d832137e20e193c960802afba73b5d38sm * static class MyGLImplementation implements GL,GL10,GL11,... { 559cfd74d65d832137e20e193c960802afba73b5d38sm * ... 560cfd74d65d832137e20e193c960802afba73b5d38sm * } 561cfd74d65d832137e20e193c960802afba73b5d38sm * } 562cfd74d65d832137e20e193c960802afba73b5d38sm * </pre> 563cfd74d65d832137e20e193c960802afba73b5d38sm * @see #setGLWrapper(GLWrapper) 564cfd74d65d832137e20e193c960802afba73b5d38sm */ 565cfd74d65d832137e20e193c960802afba73b5d38sm public interface GLWrapper { 566cfd74d65d832137e20e193c960802afba73b5d38sm /** 567cfd74d65d832137e20e193c960802afba73b5d38sm * Wraps a gl interface in another gl interface. 568cfd74d65d832137e20e193c960802afba73b5d38sm * @param gl a GL interface that is to be wrapped. 569cfd74d65d832137e20e193c960802afba73b5d38sm * @return either the input argument or another GL object that wraps the input argument. 570cfd74d65d832137e20e193c960802afba73b5d38sm */ 571cfd74d65d832137e20e193c960802afba73b5d38sm GL wrap(GL gl); 572cfd74d65d832137e20e193c960802afba73b5d38sm } 573cfd74d65d832137e20e193c960802afba73b5d38sm 574cfd74d65d832137e20e193c960802afba73b5d38sm /** 575cfd74d65d832137e20e193c960802afba73b5d38sm * A generic renderer interface. 576cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 577cfd74d65d832137e20e193c960802afba73b5d38sm * The renderer is responsible for making OpenGL calls to render a frame. 578cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 579cfd74d65d832137e20e193c960802afba73b5d38sm * GLSurfaceView clients typically create their own classes that implement 580cfd74d65d832137e20e193c960802afba73b5d38sm * this interface, and then call {@link GLSurfaceView#setRenderer} to 581cfd74d65d832137e20e193c960802afba73b5d38sm * register the renderer with the GLSurfaceView. 582cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 583cfd74d65d832137e20e193c960802afba73b5d38sm * <h3>Threading</h3> 584cfd74d65d832137e20e193c960802afba73b5d38sm * The renderer will be called on a separate thread, so that rendering 585cfd74d65d832137e20e193c960802afba73b5d38sm * performance is decoupled from the UI thread. Clients typically need to 586cfd74d65d832137e20e193c960802afba73b5d38sm * communicate with the renderer from the UI thread, because that's where 587cfd74d65d832137e20e193c960802afba73b5d38sm * input events are received. Clients can communicate using any of the 588cfd74d65d832137e20e193c960802afba73b5d38sm * standard Java techniques for cross-thread communication, or they can 589cfd74d65d832137e20e193c960802afba73b5d38sm * use the {@link GLSurfaceView#queueEvent(Runnable)} convenience method. 590cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 591cfd74d65d832137e20e193c960802afba73b5d38sm * <h3>EGL Context Lost</h3> 592cfd74d65d832137e20e193c960802afba73b5d38sm * There are situations where the EGL rendering context will be lost. This 593cfd74d65d832137e20e193c960802afba73b5d38sm * typically happens when device wakes up after going to sleep. When 594cfd74d65d832137e20e193c960802afba73b5d38sm * the EGL context is lost, all OpenGL resources (such as textures) that are 595cfd74d65d832137e20e193c960802afba73b5d38sm * associated with that context will be automatically deleted. In order to 596cfd74d65d832137e20e193c960802afba73b5d38sm * keep rendering correctly, a renderer must recreate any lost resources 597cfd74d65d832137e20e193c960802afba73b5d38sm * that it still needs. The {@link #onSurfaceCreated(GL10, EGLConfig)} method 598cfd74d65d832137e20e193c960802afba73b5d38sm * is a convenient place to do this. 599cfd74d65d832137e20e193c960802afba73b5d38sm * 600cfd74d65d832137e20e193c960802afba73b5d38sm * 601cfd74d65d832137e20e193c960802afba73b5d38sm * @see #setRenderer(Renderer) 602cfd74d65d832137e20e193c960802afba73b5d38sm */ 603cfd74d65d832137e20e193c960802afba73b5d38sm public interface Renderer { 604cfd74d65d832137e20e193c960802afba73b5d38sm /** 605cfd74d65d832137e20e193c960802afba73b5d38sm * Called when the surface is created or recreated. 606cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 607cfd74d65d832137e20e193c960802afba73b5d38sm * Called when the rendering thread 608cfd74d65d832137e20e193c960802afba73b5d38sm * starts and whenever the EGL context is lost. The context will typically 609cfd74d65d832137e20e193c960802afba73b5d38sm * be lost when the Android device awakes after going to sleep. 610cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 611cfd74d65d832137e20e193c960802afba73b5d38sm * Since this method is called at the beginning of rendering, as well as 612cfd74d65d832137e20e193c960802afba73b5d38sm * every time the EGL context is lost, this method is a convenient place to put 613cfd74d65d832137e20e193c960802afba73b5d38sm * code to create resources that need to be created when the rendering 614cfd74d65d832137e20e193c960802afba73b5d38sm * starts, and that need to be recreated when the EGL context is lost. 615cfd74d65d832137e20e193c960802afba73b5d38sm * Textures are an example of a resource that you might want to create 616cfd74d65d832137e20e193c960802afba73b5d38sm * here. 617cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 618cfd74d65d832137e20e193c960802afba73b5d38sm * Note that when the EGL context is lost, all OpenGL resources associated 619cfd74d65d832137e20e193c960802afba73b5d38sm * with that context will be automatically deleted. You do not need to call 620cfd74d65d832137e20e193c960802afba73b5d38sm * the corresponding "glDelete" methods such as glDeleteTextures to 621cfd74d65d832137e20e193c960802afba73b5d38sm * manually delete these lost resources. 622cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 623cfd74d65d832137e20e193c960802afba73b5d38sm * @param gl the GL interface. Use <code>instanceof</code> to 624cfd74d65d832137e20e193c960802afba73b5d38sm * test if the interface supports GL11 or higher interfaces. 625cfd74d65d832137e20e193c960802afba73b5d38sm * @param config the EGLConfig of the created surface. Can be used 626cfd74d65d832137e20e193c960802afba73b5d38sm * to create matching pbuffers. 627cfd74d65d832137e20e193c960802afba73b5d38sm */ 628cfd74d65d832137e20e193c960802afba73b5d38sm void onSurfaceCreated(GL10 gl, EGLConfig config); 629cfd74d65d832137e20e193c960802afba73b5d38sm 630cfd74d65d832137e20e193c960802afba73b5d38sm /** 631cfd74d65d832137e20e193c960802afba73b5d38sm * Called when the surface changed size. 632cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 633cfd74d65d832137e20e193c960802afba73b5d38sm * Called after the surface is created and whenever 634cfd74d65d832137e20e193c960802afba73b5d38sm * the OpenGL ES surface size changes. 635cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 636cfd74d65d832137e20e193c960802afba73b5d38sm * Typically you will set your viewport here. If your camera 637cfd74d65d832137e20e193c960802afba73b5d38sm * is fixed then you could also set your projection matrix here: 638cfd74d65d832137e20e193c960802afba73b5d38sm * <pre class="prettyprint"> 639cfd74d65d832137e20e193c960802afba73b5d38sm * void onSurfaceChanged(GL10 gl, int width, int height) { 640cfd74d65d832137e20e193c960802afba73b5d38sm * gl.glViewport(0, 0, width, height); 641cfd74d65d832137e20e193c960802afba73b5d38sm * // for a fixed camera, set the projection too 642cfd74d65d832137e20e193c960802afba73b5d38sm * float ratio = (float) width / height; 643cfd74d65d832137e20e193c960802afba73b5d38sm * gl.glMatrixMode(GL10.GL_PROJECTION); 644cfd74d65d832137e20e193c960802afba73b5d38sm * gl.glLoadIdentity(); 645cfd74d65d832137e20e193c960802afba73b5d38sm * gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); 646cfd74d65d832137e20e193c960802afba73b5d38sm * } 647cfd74d65d832137e20e193c960802afba73b5d38sm * </pre> 648cfd74d65d832137e20e193c960802afba73b5d38sm * @param gl the GL interface. Use <code>instanceof</code> to 649cfd74d65d832137e20e193c960802afba73b5d38sm * test if the interface supports GL11 or higher interfaces. 650cfd74d65d832137e20e193c960802afba73b5d38sm * @param width 651cfd74d65d832137e20e193c960802afba73b5d38sm * @param height 652cfd74d65d832137e20e193c960802afba73b5d38sm */ 653cfd74d65d832137e20e193c960802afba73b5d38sm void onSurfaceChanged(GL10 gl, int width, int height); 654cfd74d65d832137e20e193c960802afba73b5d38sm 655cfd74d65d832137e20e193c960802afba73b5d38sm /** 656cfd74d65d832137e20e193c960802afba73b5d38sm * Called when the OpenGL context has been lost is about 657cfd74d65d832137e20e193c960802afba73b5d38sm * to be recreated. onSurfaceCreated() will be called after 658cfd74d65d832137e20e193c960802afba73b5d38sm * onSurfaceLost(). 659cfd74d65d832137e20e193c960802afba73b5d38sm * */ 660cfd74d65d832137e20e193c960802afba73b5d38sm void onSurfaceLost(); 661cfd74d65d832137e20e193c960802afba73b5d38sm 662cfd74d65d832137e20e193c960802afba73b5d38sm /** 663cfd74d65d832137e20e193c960802afba73b5d38sm * Called to draw the current frame. 664cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 665cfd74d65d832137e20e193c960802afba73b5d38sm * This method is responsible for drawing the current frame. 666cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 667cfd74d65d832137e20e193c960802afba73b5d38sm * The implementation of this method typically looks like this: 668cfd74d65d832137e20e193c960802afba73b5d38sm * <pre class="prettyprint"> 669cfd74d65d832137e20e193c960802afba73b5d38sm * void onDrawFrame(GL10 gl) { 670cfd74d65d832137e20e193c960802afba73b5d38sm * gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 671cfd74d65d832137e20e193c960802afba73b5d38sm * //... other gl calls to render the scene ... 672cfd74d65d832137e20e193c960802afba73b5d38sm * } 673cfd74d65d832137e20e193c960802afba73b5d38sm * </pre> 674cfd74d65d832137e20e193c960802afba73b5d38sm * @param gl the GL interface. Use <code>instanceof</code> to 675cfd74d65d832137e20e193c960802afba73b5d38sm * test if the interface supports GL11 or higher interfaces. 676cfd74d65d832137e20e193c960802afba73b5d38sm */ 677cfd74d65d832137e20e193c960802afba73b5d38sm void onDrawFrame(GL10 gl); 678cfd74d65d832137e20e193c960802afba73b5d38sm 679cfd74d65d832137e20e193c960802afba73b5d38sm void loadTextures(GL10 gl, TextureLibrary library); 680cfd74d65d832137e20e193c960802afba73b5d38sm void flushTextures(GL10 gl, TextureLibrary library); 681cfd74d65d832137e20e193c960802afba73b5d38sm void loadBuffers(GL10 gl, BufferLibrary library); 682cfd74d65d832137e20e193c960802afba73b5d38sm void flushBuffers(GL10 gl, BufferLibrary library); 683cfd74d65d832137e20e193c960802afba73b5d38sm 684cfd74d65d832137e20e193c960802afba73b5d38sm 685cfd74d65d832137e20e193c960802afba73b5d38sm 686cfd74d65d832137e20e193c960802afba73b5d38sm } 687cfd74d65d832137e20e193c960802afba73b5d38sm 688cfd74d65d832137e20e193c960802afba73b5d38sm /** 689cfd74d65d832137e20e193c960802afba73b5d38sm * An interface for customizing the eglCreateContext and eglDestroyContext calls. 690cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 691cfd74d65d832137e20e193c960802afba73b5d38sm * This interface must be implemented by clients wishing to call 692cfd74d65d832137e20e193c960802afba73b5d38sm * {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)} 693cfd74d65d832137e20e193c960802afba73b5d38sm */ 694cfd74d65d832137e20e193c960802afba73b5d38sm public interface EGLContextFactory { 695cfd74d65d832137e20e193c960802afba73b5d38sm EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig); 696cfd74d65d832137e20e193c960802afba73b5d38sm void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context); 697cfd74d65d832137e20e193c960802afba73b5d38sm } 698cfd74d65d832137e20e193c960802afba73b5d38sm 699cfd74d65d832137e20e193c960802afba73b5d38sm private class DefaultContextFactory implements EGLContextFactory { 700cfd74d65d832137e20e193c960802afba73b5d38sm private int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 701cfd74d65d832137e20e193c960802afba73b5d38sm 702cfd74d65d832137e20e193c960802afba73b5d38sm public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) { 703cfd74d65d832137e20e193c960802afba73b5d38sm int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion, 704cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_NONE }; 705cfd74d65d832137e20e193c960802afba73b5d38sm 706cfd74d65d832137e20e193c960802afba73b5d38sm return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, 707cfd74d65d832137e20e193c960802afba73b5d38sm mEGLContextClientVersion != 0 ? attrib_list : null); 708cfd74d65d832137e20e193c960802afba73b5d38sm } 709cfd74d65d832137e20e193c960802afba73b5d38sm 710cfd74d65d832137e20e193c960802afba73b5d38sm public void destroyContext(EGL10 egl, EGLDisplay display, 711cfd74d65d832137e20e193c960802afba73b5d38sm EGLContext context) { 712cfd74d65d832137e20e193c960802afba73b5d38sm egl.eglDestroyContext(display, context); 713cfd74d65d832137e20e193c960802afba73b5d38sm } 714cfd74d65d832137e20e193c960802afba73b5d38sm } 715cfd74d65d832137e20e193c960802afba73b5d38sm 716cfd74d65d832137e20e193c960802afba73b5d38sm /** 717cfd74d65d832137e20e193c960802afba73b5d38sm * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls. 718cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 719cfd74d65d832137e20e193c960802afba73b5d38sm * This interface must be implemented by clients wishing to call 720cfd74d65d832137e20e193c960802afba73b5d38sm * {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)} 721cfd74d65d832137e20e193c960802afba73b5d38sm */ 722cfd74d65d832137e20e193c960802afba73b5d38sm public interface EGLWindowSurfaceFactory { 723cfd74d65d832137e20e193c960802afba73b5d38sm EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, 724cfd74d65d832137e20e193c960802afba73b5d38sm Object nativeWindow); 725cfd74d65d832137e20e193c960802afba73b5d38sm void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface); 726cfd74d65d832137e20e193c960802afba73b5d38sm } 727cfd74d65d832137e20e193c960802afba73b5d38sm 728cfd74d65d832137e20e193c960802afba73b5d38sm private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory { 729cfd74d65d832137e20e193c960802afba73b5d38sm 730cfd74d65d832137e20e193c960802afba73b5d38sm public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, 731cfd74d65d832137e20e193c960802afba73b5d38sm EGLConfig config, Object nativeWindow) { 732cfd74d65d832137e20e193c960802afba73b5d38sm return egl.eglCreateWindowSurface(display, config, nativeWindow, null); 733cfd74d65d832137e20e193c960802afba73b5d38sm } 734cfd74d65d832137e20e193c960802afba73b5d38sm 735cfd74d65d832137e20e193c960802afba73b5d38sm public void destroySurface(EGL10 egl, EGLDisplay display, 736cfd74d65d832137e20e193c960802afba73b5d38sm EGLSurface surface) { 737cfd74d65d832137e20e193c960802afba73b5d38sm egl.eglDestroySurface(display, surface); 738cfd74d65d832137e20e193c960802afba73b5d38sm } 739cfd74d65d832137e20e193c960802afba73b5d38sm } 740cfd74d65d832137e20e193c960802afba73b5d38sm 741cfd74d65d832137e20e193c960802afba73b5d38sm /** 742cfd74d65d832137e20e193c960802afba73b5d38sm * An interface for choosing an EGLConfig configuration from a list of 743cfd74d65d832137e20e193c960802afba73b5d38sm * potential configurations. 744cfd74d65d832137e20e193c960802afba73b5d38sm * <p> 745cfd74d65d832137e20e193c960802afba73b5d38sm * This interface must be implemented by clients wishing to call 746cfd74d65d832137e20e193c960802afba73b5d38sm * {@link GLSurfaceView#setEGLConfigChooser(EGLConfigChooser)} 747cfd74d65d832137e20e193c960802afba73b5d38sm */ 748cfd74d65d832137e20e193c960802afba73b5d38sm public interface EGLConfigChooser { 749cfd74d65d832137e20e193c960802afba73b5d38sm /** 750cfd74d65d832137e20e193c960802afba73b5d38sm * Choose a configuration from the list. Implementors typically 751cfd74d65d832137e20e193c960802afba73b5d38sm * implement this method by calling 752cfd74d65d832137e20e193c960802afba73b5d38sm * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the 753cfd74d65d832137e20e193c960802afba73b5d38sm * EGL specification available from The Khronos Group to learn how to call eglChooseConfig. 754cfd74d65d832137e20e193c960802afba73b5d38sm * @param egl the EGL10 for the current display. 755cfd74d65d832137e20e193c960802afba73b5d38sm * @param display the current display. 756cfd74d65d832137e20e193c960802afba73b5d38sm * @return the chosen configuration. 757cfd74d65d832137e20e193c960802afba73b5d38sm */ 758cfd74d65d832137e20e193c960802afba73b5d38sm EGLConfig chooseConfig(EGL10 egl, EGLDisplay display); 759cfd74d65d832137e20e193c960802afba73b5d38sm } 760cfd74d65d832137e20e193c960802afba73b5d38sm 761cfd74d65d832137e20e193c960802afba73b5d38sm private abstract class BaseConfigChooser 762cfd74d65d832137e20e193c960802afba73b5d38sm implements EGLConfigChooser { 763cfd74d65d832137e20e193c960802afba73b5d38sm public BaseConfigChooser(int[] configSpec) { 764cfd74d65d832137e20e193c960802afba73b5d38sm mConfigSpec = filterConfigSpec(configSpec); 765cfd74d65d832137e20e193c960802afba73b5d38sm } 766cfd74d65d832137e20e193c960802afba73b5d38sm 767cfd74d65d832137e20e193c960802afba73b5d38sm public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 768cfd74d65d832137e20e193c960802afba73b5d38sm int[] num_config = new int[1]; 769cfd74d65d832137e20e193c960802afba73b5d38sm if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, 770cfd74d65d832137e20e193c960802afba73b5d38sm num_config)) { 771cfd74d65d832137e20e193c960802afba73b5d38sm throw new IllegalArgumentException("eglChooseConfig failed"); 772cfd74d65d832137e20e193c960802afba73b5d38sm } 773cfd74d65d832137e20e193c960802afba73b5d38sm 774cfd74d65d832137e20e193c960802afba73b5d38sm int numConfigs = num_config[0]; 775cfd74d65d832137e20e193c960802afba73b5d38sm 776cfd74d65d832137e20e193c960802afba73b5d38sm if (numConfigs <= 0) { 777cfd74d65d832137e20e193c960802afba73b5d38sm throw new IllegalArgumentException( 778cfd74d65d832137e20e193c960802afba73b5d38sm "No configs match configSpec"); 779cfd74d65d832137e20e193c960802afba73b5d38sm } 780cfd74d65d832137e20e193c960802afba73b5d38sm 781cfd74d65d832137e20e193c960802afba73b5d38sm EGLConfig[] configs = new EGLConfig[numConfigs]; 782cfd74d65d832137e20e193c960802afba73b5d38sm if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, 783cfd74d65d832137e20e193c960802afba73b5d38sm num_config)) { 784cfd74d65d832137e20e193c960802afba73b5d38sm throw new IllegalArgumentException("eglChooseConfig#2 failed"); 785cfd74d65d832137e20e193c960802afba73b5d38sm } 786cfd74d65d832137e20e193c960802afba73b5d38sm EGLConfig config = chooseConfig(egl, display, configs); 787cfd74d65d832137e20e193c960802afba73b5d38sm if (config == null) { 788cfd74d65d832137e20e193c960802afba73b5d38sm throw new IllegalArgumentException("No config chosen"); 789cfd74d65d832137e20e193c960802afba73b5d38sm } 790cfd74d65d832137e20e193c960802afba73b5d38sm return config; 791cfd74d65d832137e20e193c960802afba73b5d38sm } 792cfd74d65d832137e20e193c960802afba73b5d38sm 793cfd74d65d832137e20e193c960802afba73b5d38sm abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, 794cfd74d65d832137e20e193c960802afba73b5d38sm EGLConfig[] configs); 795cfd74d65d832137e20e193c960802afba73b5d38sm 796cfd74d65d832137e20e193c960802afba73b5d38sm protected int[] mConfigSpec; 797cfd74d65d832137e20e193c960802afba73b5d38sm 798cfd74d65d832137e20e193c960802afba73b5d38sm private int[] filterConfigSpec(int[] configSpec) { 799cfd74d65d832137e20e193c960802afba73b5d38sm if (mEGLContextClientVersion != 2) { 800cfd74d65d832137e20e193c960802afba73b5d38sm return configSpec; 801cfd74d65d832137e20e193c960802afba73b5d38sm } 802cfd74d65d832137e20e193c960802afba73b5d38sm /* We know none of the subclasses define EGL_RENDERABLE_TYPE. 803cfd74d65d832137e20e193c960802afba73b5d38sm * And we know the configSpec is well formed. 804cfd74d65d832137e20e193c960802afba73b5d38sm */ 805cfd74d65d832137e20e193c960802afba73b5d38sm int len = configSpec.length; 806cfd74d65d832137e20e193c960802afba73b5d38sm int[] newConfigSpec = new int[len + 2]; 807cfd74d65d832137e20e193c960802afba73b5d38sm System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1); 808cfd74d65d832137e20e193c960802afba73b5d38sm newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE; 809cfd74d65d832137e20e193c960802afba73b5d38sm newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */ 810cfd74d65d832137e20e193c960802afba73b5d38sm newConfigSpec[len+1] = EGL10.EGL_NONE; 811cfd74d65d832137e20e193c960802afba73b5d38sm return newConfigSpec; 812cfd74d65d832137e20e193c960802afba73b5d38sm } 813cfd74d65d832137e20e193c960802afba73b5d38sm } 814cfd74d65d832137e20e193c960802afba73b5d38sm 815cfd74d65d832137e20e193c960802afba73b5d38sm private class ComponentSizeChooser extends BaseConfigChooser { 816cfd74d65d832137e20e193c960802afba73b5d38sm public ComponentSizeChooser(int redSize, int greenSize, int blueSize, 817cfd74d65d832137e20e193c960802afba73b5d38sm int alphaSize, int depthSize, int stencilSize) { 818cfd74d65d832137e20e193c960802afba73b5d38sm super(new int[] { 819cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_RED_SIZE, redSize, 820cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_GREEN_SIZE, greenSize, 821cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_BLUE_SIZE, blueSize, 822cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_ALPHA_SIZE, alphaSize, 823cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_DEPTH_SIZE, depthSize, 824cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_STENCIL_SIZE, stencilSize, 825cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_NONE}); 826cfd74d65d832137e20e193c960802afba73b5d38sm mValue = new int[1]; 827cfd74d65d832137e20e193c960802afba73b5d38sm mRedSize = redSize; 828cfd74d65d832137e20e193c960802afba73b5d38sm mGreenSize = greenSize; 829cfd74d65d832137e20e193c960802afba73b5d38sm mBlueSize = blueSize; 830cfd74d65d832137e20e193c960802afba73b5d38sm mAlphaSize = alphaSize; 831cfd74d65d832137e20e193c960802afba73b5d38sm mDepthSize = depthSize; 832cfd74d65d832137e20e193c960802afba73b5d38sm mStencilSize = stencilSize; 833cfd74d65d832137e20e193c960802afba73b5d38sm } 834cfd74d65d832137e20e193c960802afba73b5d38sm 835cfd74d65d832137e20e193c960802afba73b5d38sm @Override 836cfd74d65d832137e20e193c960802afba73b5d38sm public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, 837cfd74d65d832137e20e193c960802afba73b5d38sm EGLConfig[] configs) { 838cfd74d65d832137e20e193c960802afba73b5d38sm EGLConfig closestConfig = null; 839cfd74d65d832137e20e193c960802afba73b5d38sm int closestDistance = 1000; 840cfd74d65d832137e20e193c960802afba73b5d38sm for(EGLConfig config : configs) { 841cfd74d65d832137e20e193c960802afba73b5d38sm int d = findConfigAttrib(egl, display, config, 842cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_DEPTH_SIZE, 0); 843cfd74d65d832137e20e193c960802afba73b5d38sm int s = findConfigAttrib(egl, display, config, 844cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_STENCIL_SIZE, 0); 845cfd74d65d832137e20e193c960802afba73b5d38sm if (d >= mDepthSize && s>= mStencilSize) { 846cfd74d65d832137e20e193c960802afba73b5d38sm int r = findConfigAttrib(egl, display, config, 847cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_RED_SIZE, 0); 848cfd74d65d832137e20e193c960802afba73b5d38sm int g = findConfigAttrib(egl, display, config, 849cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_GREEN_SIZE, 0); 850cfd74d65d832137e20e193c960802afba73b5d38sm int b = findConfigAttrib(egl, display, config, 851cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_BLUE_SIZE, 0); 852cfd74d65d832137e20e193c960802afba73b5d38sm int a = findConfigAttrib(egl, display, config, 853cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_ALPHA_SIZE, 0); 854cfd74d65d832137e20e193c960802afba73b5d38sm int distance = Math.abs(r - mRedSize) 855cfd74d65d832137e20e193c960802afba73b5d38sm + Math.abs(g - mGreenSize) 856cfd74d65d832137e20e193c960802afba73b5d38sm + Math.abs(b - mBlueSize) 857cfd74d65d832137e20e193c960802afba73b5d38sm + Math.abs(a - mAlphaSize); 858cfd74d65d832137e20e193c960802afba73b5d38sm if (distance < closestDistance) { 859cfd74d65d832137e20e193c960802afba73b5d38sm closestDistance = distance; 860cfd74d65d832137e20e193c960802afba73b5d38sm closestConfig = config; 861cfd74d65d832137e20e193c960802afba73b5d38sm } 862cfd74d65d832137e20e193c960802afba73b5d38sm } 863cfd74d65d832137e20e193c960802afba73b5d38sm } 864cfd74d65d832137e20e193c960802afba73b5d38sm return closestConfig; 865cfd74d65d832137e20e193c960802afba73b5d38sm } 866cfd74d65d832137e20e193c960802afba73b5d38sm 867cfd74d65d832137e20e193c960802afba73b5d38sm private int findConfigAttrib(EGL10 egl, EGLDisplay display, 868cfd74d65d832137e20e193c960802afba73b5d38sm EGLConfig config, int attribute, int defaultValue) { 869cfd74d65d832137e20e193c960802afba73b5d38sm 870cfd74d65d832137e20e193c960802afba73b5d38sm if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { 871cfd74d65d832137e20e193c960802afba73b5d38sm return mValue[0]; 872cfd74d65d832137e20e193c960802afba73b5d38sm } 873cfd74d65d832137e20e193c960802afba73b5d38sm return defaultValue; 874cfd74d65d832137e20e193c960802afba73b5d38sm } 875cfd74d65d832137e20e193c960802afba73b5d38sm 876cfd74d65d832137e20e193c960802afba73b5d38sm private int[] mValue; 877cfd74d65d832137e20e193c960802afba73b5d38sm // Subclasses can adjust these values: 878cfd74d65d832137e20e193c960802afba73b5d38sm protected int mRedSize; 879cfd74d65d832137e20e193c960802afba73b5d38sm protected int mGreenSize; 880cfd74d65d832137e20e193c960802afba73b5d38sm protected int mBlueSize; 881cfd74d65d832137e20e193c960802afba73b5d38sm protected int mAlphaSize; 882cfd74d65d832137e20e193c960802afba73b5d38sm protected int mDepthSize; 883cfd74d65d832137e20e193c960802afba73b5d38sm protected int mStencilSize; 884cfd74d65d832137e20e193c960802afba73b5d38sm } 885cfd74d65d832137e20e193c960802afba73b5d38sm 886cfd74d65d832137e20e193c960802afba73b5d38sm /** 887cfd74d65d832137e20e193c960802afba73b5d38sm * This class will choose a supported surface as close to 888cfd74d65d832137e20e193c960802afba73b5d38sm * RGB565 as possible, with or without a depth buffer. 889cfd74d65d832137e20e193c960802afba73b5d38sm * 890cfd74d65d832137e20e193c960802afba73b5d38sm */ 891cfd74d65d832137e20e193c960802afba73b5d38sm private class SimpleEGLConfigChooser extends ComponentSizeChooser { 892cfd74d65d832137e20e193c960802afba73b5d38sm public SimpleEGLConfigChooser(boolean withDepthBuffer) { 893cfd74d65d832137e20e193c960802afba73b5d38sm super(4, 4, 4, 0, withDepthBuffer ? 16 : 0, 0); 894cfd74d65d832137e20e193c960802afba73b5d38sm // Adjust target values. This way we'll accept a 4444 or 895cfd74d65d832137e20e193c960802afba73b5d38sm // 555 buffer if there's no 565 buffer available. 896cfd74d65d832137e20e193c960802afba73b5d38sm mRedSize = 5; 897cfd74d65d832137e20e193c960802afba73b5d38sm mGreenSize = 6; 898cfd74d65d832137e20e193c960802afba73b5d38sm mBlueSize = 5; 899cfd74d65d832137e20e193c960802afba73b5d38sm } 900cfd74d65d832137e20e193c960802afba73b5d38sm } 901cfd74d65d832137e20e193c960802afba73b5d38sm 902cfd74d65d832137e20e193c960802afba73b5d38sm /** 903cfd74d65d832137e20e193c960802afba73b5d38sm * An EGL helper class. 904cfd74d65d832137e20e193c960802afba73b5d38sm */ 905cfd74d65d832137e20e193c960802afba73b5d38sm 906cfd74d65d832137e20e193c960802afba73b5d38sm private class EglHelper { 907cfd74d65d832137e20e193c960802afba73b5d38sm public EglHelper() { 908cfd74d65d832137e20e193c960802afba73b5d38sm 909cfd74d65d832137e20e193c960802afba73b5d38sm } 910cfd74d65d832137e20e193c960802afba73b5d38sm 911cfd74d65d832137e20e193c960802afba73b5d38sm /** 912cfd74d65d832137e20e193c960802afba73b5d38sm * Initialize EGL for a given configuration spec. 913cfd74d65d832137e20e193c960802afba73b5d38sm * @param configSpec 914cfd74d65d832137e20e193c960802afba73b5d38sm */ 915cfd74d65d832137e20e193c960802afba73b5d38sm public void start(){ 916cfd74d65d832137e20e193c960802afba73b5d38sm /* 917cfd74d65d832137e20e193c960802afba73b5d38sm * Get an EGL instance 918cfd74d65d832137e20e193c960802afba73b5d38sm */ 919cfd74d65d832137e20e193c960802afba73b5d38sm mEgl = (EGL10) EGLContext.getEGL(); 920cfd74d65d832137e20e193c960802afba73b5d38sm 921cfd74d65d832137e20e193c960802afba73b5d38sm /* 922cfd74d65d832137e20e193c960802afba73b5d38sm * Get to the default display. 923cfd74d65d832137e20e193c960802afba73b5d38sm */ 924cfd74d65d832137e20e193c960802afba73b5d38sm mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 925cfd74d65d832137e20e193c960802afba73b5d38sm 926cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { 927cfd74d65d832137e20e193c960802afba73b5d38sm throw new RuntimeException("eglGetDisplay failed"); 928cfd74d65d832137e20e193c960802afba73b5d38sm } 929cfd74d65d832137e20e193c960802afba73b5d38sm 930cfd74d65d832137e20e193c960802afba73b5d38sm /* 931cfd74d65d832137e20e193c960802afba73b5d38sm * We can now initialize EGL for that display 932cfd74d65d832137e20e193c960802afba73b5d38sm */ 933cfd74d65d832137e20e193c960802afba73b5d38sm int[] version = new int[2]; 934cfd74d65d832137e20e193c960802afba73b5d38sm if(!mEgl.eglInitialize(mEglDisplay, version)) { 935cfd74d65d832137e20e193c960802afba73b5d38sm throw new RuntimeException("eglInitialize failed"); 936cfd74d65d832137e20e193c960802afba73b5d38sm } 937cfd74d65d832137e20e193c960802afba73b5d38sm mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay); 938cfd74d65d832137e20e193c960802afba73b5d38sm 939cfd74d65d832137e20e193c960802afba73b5d38sm /* 940cfd74d65d832137e20e193c960802afba73b5d38sm * Create an OpenGL ES context. This must be done only once, an 941cfd74d65d832137e20e193c960802afba73b5d38sm * OpenGL context is a somewhat heavy object. 942cfd74d65d832137e20e193c960802afba73b5d38sm */ 943cfd74d65d832137e20e193c960802afba73b5d38sm mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig); 944cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) { 945cfd74d65d832137e20e193c960802afba73b5d38sm throwEglException("createContext"); 946cfd74d65d832137e20e193c960802afba73b5d38sm } 947cfd74d65d832137e20e193c960802afba73b5d38sm 948cfd74d65d832137e20e193c960802afba73b5d38sm mEglSurface = null; 949cfd74d65d832137e20e193c960802afba73b5d38sm } 950cfd74d65d832137e20e193c960802afba73b5d38sm 951cfd74d65d832137e20e193c960802afba73b5d38sm /* 952cfd74d65d832137e20e193c960802afba73b5d38sm * React to the creation of a new surface by creating and returning an 953cfd74d65d832137e20e193c960802afba73b5d38sm * OpenGL interface that renders to that surface. 954cfd74d65d832137e20e193c960802afba73b5d38sm */ 955cfd74d65d832137e20e193c960802afba73b5d38sm public GL createSurface(SurfaceHolder holder) { 956cfd74d65d832137e20e193c960802afba73b5d38sm /* 957cfd74d65d832137e20e193c960802afba73b5d38sm * The window size has changed, so we need to create a new 958cfd74d65d832137e20e193c960802afba73b5d38sm * surface. 959cfd74d65d832137e20e193c960802afba73b5d38sm */ 960cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { 961cfd74d65d832137e20e193c960802afba73b5d38sm 962cfd74d65d832137e20e193c960802afba73b5d38sm /* 963cfd74d65d832137e20e193c960802afba73b5d38sm * Unbind and destroy the old EGL surface, if 964cfd74d65d832137e20e193c960802afba73b5d38sm * there is one. 965cfd74d65d832137e20e193c960802afba73b5d38sm */ 966cfd74d65d832137e20e193c960802afba73b5d38sm mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, 967cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); 968cfd74d65d832137e20e193c960802afba73b5d38sm mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface); 969cfd74d65d832137e20e193c960802afba73b5d38sm } 970cfd74d65d832137e20e193c960802afba73b5d38sm 971cfd74d65d832137e20e193c960802afba73b5d38sm /* 972cfd74d65d832137e20e193c960802afba73b5d38sm * Create an EGL surface we can render into. 973cfd74d65d832137e20e193c960802afba73b5d38sm */ 974cfd74d65d832137e20e193c960802afba73b5d38sm mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl, 975cfd74d65d832137e20e193c960802afba73b5d38sm mEglDisplay, mEglConfig, holder); 976cfd74d65d832137e20e193c960802afba73b5d38sm 977cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { 978cfd74d65d832137e20e193c960802afba73b5d38sm throwEglException("createWindowSurface"); 979cfd74d65d832137e20e193c960802afba73b5d38sm } 980cfd74d65d832137e20e193c960802afba73b5d38sm 981cfd74d65d832137e20e193c960802afba73b5d38sm /* 982cfd74d65d832137e20e193c960802afba73b5d38sm * Before we can issue GL commands, we need to make sure 983cfd74d65d832137e20e193c960802afba73b5d38sm * the context is current and bound to a surface. 984cfd74d65d832137e20e193c960802afba73b5d38sm */ 985cfd74d65d832137e20e193c960802afba73b5d38sm if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 986cfd74d65d832137e20e193c960802afba73b5d38sm throwEglException("eglMakeCurrent"); 987cfd74d65d832137e20e193c960802afba73b5d38sm } 988cfd74d65d832137e20e193c960802afba73b5d38sm 989cfd74d65d832137e20e193c960802afba73b5d38sm GL gl = mEglContext.getGL(); 990cfd74d65d832137e20e193c960802afba73b5d38sm if (mGLWrapper != null) { 991cfd74d65d832137e20e193c960802afba73b5d38sm gl = mGLWrapper.wrap(gl); 992cfd74d65d832137e20e193c960802afba73b5d38sm } 993cfd74d65d832137e20e193c960802afba73b5d38sm 994cfd74d65d832137e20e193c960802afba73b5d38sm if ((mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) { 995cfd74d65d832137e20e193c960802afba73b5d38sm int configFlags = 0; 996cfd74d65d832137e20e193c960802afba73b5d38sm Writer log = null; 997cfd74d65d832137e20e193c960802afba73b5d38sm if ((mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { 998cfd74d65d832137e20e193c960802afba73b5d38sm configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; 999cfd74d65d832137e20e193c960802afba73b5d38sm } 1000cfd74d65d832137e20e193c960802afba73b5d38sm if ((mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { 1001cfd74d65d832137e20e193c960802afba73b5d38sm log = new LogWriter(); 1002cfd74d65d832137e20e193c960802afba73b5d38sm } 1003cfd74d65d832137e20e193c960802afba73b5d38sm gl = GLDebugHelper.wrap(gl, configFlags, log); 1004cfd74d65d832137e20e193c960802afba73b5d38sm } 1005cfd74d65d832137e20e193c960802afba73b5d38sm return gl; 1006cfd74d65d832137e20e193c960802afba73b5d38sm } 1007cfd74d65d832137e20e193c960802afba73b5d38sm 1008cfd74d65d832137e20e193c960802afba73b5d38sm /** 1009cfd74d65d832137e20e193c960802afba73b5d38sm * Display the current render surface. 1010cfd74d65d832137e20e193c960802afba73b5d38sm * @return false if the context has been lost. 1011cfd74d65d832137e20e193c960802afba73b5d38sm */ 1012cfd74d65d832137e20e193c960802afba73b5d38sm public boolean swap() { 1013cfd74d65d832137e20e193c960802afba73b5d38sm mEgl.eglSwapBuffers(mEglDisplay, mEglSurface); 1014cfd74d65d832137e20e193c960802afba73b5d38sm 1015cfd74d65d832137e20e193c960802afba73b5d38sm /* 1016cfd74d65d832137e20e193c960802afba73b5d38sm * Always check for EGL_CONTEXT_LOST, which means the context 1017cfd74d65d832137e20e193c960802afba73b5d38sm * and all associated data were lost (For instance because 1018cfd74d65d832137e20e193c960802afba73b5d38sm * the device went to sleep). We need to sleep until we 1019cfd74d65d832137e20e193c960802afba73b5d38sm * get a new surface. 1020cfd74d65d832137e20e193c960802afba73b5d38sm */ 1021cfd74d65d832137e20e193c960802afba73b5d38sm return mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST; 1022cfd74d65d832137e20e193c960802afba73b5d38sm } 1023cfd74d65d832137e20e193c960802afba73b5d38sm 1024cfd74d65d832137e20e193c960802afba73b5d38sm public void destroySurface() { 1025cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { 1026cfd74d65d832137e20e193c960802afba73b5d38sm mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, 1027cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_NO_SURFACE, 1028cfd74d65d832137e20e193c960802afba73b5d38sm EGL10.EGL_NO_CONTEXT); 1029cfd74d65d832137e20e193c960802afba73b5d38sm mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface); 1030cfd74d65d832137e20e193c960802afba73b5d38sm mEglSurface = null; 1031cfd74d65d832137e20e193c960802afba73b5d38sm } 1032cfd74d65d832137e20e193c960802afba73b5d38sm } 1033cfd74d65d832137e20e193c960802afba73b5d38sm 1034cfd74d65d832137e20e193c960802afba73b5d38sm public void finish() { 1035cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglContext != null) { 1036cfd74d65d832137e20e193c960802afba73b5d38sm mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext); 1037cfd74d65d832137e20e193c960802afba73b5d38sm mEglContext = null; 1038cfd74d65d832137e20e193c960802afba73b5d38sm } 1039cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglDisplay != null) { 1040cfd74d65d832137e20e193c960802afba73b5d38sm mEgl.eglTerminate(mEglDisplay); 1041cfd74d65d832137e20e193c960802afba73b5d38sm mEglDisplay = null; 1042cfd74d65d832137e20e193c960802afba73b5d38sm } 1043cfd74d65d832137e20e193c960802afba73b5d38sm } 1044cfd74d65d832137e20e193c960802afba73b5d38sm 1045cfd74d65d832137e20e193c960802afba73b5d38sm private void throwEglException(String function) { 1046cfd74d65d832137e20e193c960802afba73b5d38sm throw new RuntimeException(function + " failed: " + mEgl.eglGetError()); 1047cfd74d65d832137e20e193c960802afba73b5d38sm } 1048cfd74d65d832137e20e193c960802afba73b5d38sm 1049cfd74d65d832137e20e193c960802afba73b5d38sm /** Checks to see if the current context is valid. **/ 1050cfd74d65d832137e20e193c960802afba73b5d38sm public boolean verifyContext() { 1051cfd74d65d832137e20e193c960802afba73b5d38sm EGLContext currentContext = mEgl.eglGetCurrentContext(); 1052cfd74d65d832137e20e193c960802afba73b5d38sm return currentContext != EGL10.EGL_NO_CONTEXT && mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST; 1053cfd74d65d832137e20e193c960802afba73b5d38sm } 1054cfd74d65d832137e20e193c960802afba73b5d38sm 1055cfd74d65d832137e20e193c960802afba73b5d38sm EGL10 mEgl; 1056cfd74d65d832137e20e193c960802afba73b5d38sm EGLDisplay mEglDisplay; 1057cfd74d65d832137e20e193c960802afba73b5d38sm EGLSurface mEglSurface; 1058cfd74d65d832137e20e193c960802afba73b5d38sm EGLConfig mEglConfig; 1059cfd74d65d832137e20e193c960802afba73b5d38sm EGLContext mEglContext; 1060cfd74d65d832137e20e193c960802afba73b5d38sm 1061cfd74d65d832137e20e193c960802afba73b5d38sm } 1062cfd74d65d832137e20e193c960802afba73b5d38sm 1063cfd74d65d832137e20e193c960802afba73b5d38sm /** 1064cfd74d65d832137e20e193c960802afba73b5d38sm * A generic GL Thread. Takes care of initializing EGL and GL. Delegates 1065cfd74d65d832137e20e193c960802afba73b5d38sm * to a Renderer instance to do the actual drawing. Can be configured to 1066cfd74d65d832137e20e193c960802afba73b5d38sm * render continuously or on request. 1067cfd74d65d832137e20e193c960802afba73b5d38sm * 1068cfd74d65d832137e20e193c960802afba73b5d38sm * All potentially blocking synchronization is done through the 1069cfd74d65d832137e20e193c960802afba73b5d38sm * sGLThreadManager object. This avoids multiple-lock ordering issues. 1070cfd74d65d832137e20e193c960802afba73b5d38sm * 1071cfd74d65d832137e20e193c960802afba73b5d38sm */ 1072cfd74d65d832137e20e193c960802afba73b5d38sm private class GLThread extends Thread { 1073cfd74d65d832137e20e193c960802afba73b5d38sm public GLThread(Renderer renderer) { 1074cfd74d65d832137e20e193c960802afba73b5d38sm super(); 1075cfd74d65d832137e20e193c960802afba73b5d38sm mWidth = 0; 1076cfd74d65d832137e20e193c960802afba73b5d38sm mHeight = 0; 1077cfd74d65d832137e20e193c960802afba73b5d38sm mRequestRender = true; 1078cfd74d65d832137e20e193c960802afba73b5d38sm mRenderMode = RENDERMODE_CONTINUOUSLY; 1079cfd74d65d832137e20e193c960802afba73b5d38sm mRenderer = renderer; 1080cfd74d65d832137e20e193c960802afba73b5d38sm } 1081cfd74d65d832137e20e193c960802afba73b5d38sm 1082cfd74d65d832137e20e193c960802afba73b5d38sm 1083cfd74d65d832137e20e193c960802afba73b5d38sm @Override 1084cfd74d65d832137e20e193c960802afba73b5d38sm public void run() { 1085cfd74d65d832137e20e193c960802afba73b5d38sm setName("GLThread " + getId()); 1086cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_THREADS) { 1087cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("GLThread", "starting tid=" + getId()); 1088cfd74d65d832137e20e193c960802afba73b5d38sm } 1089cfd74d65d832137e20e193c960802afba73b5d38sm 1090cfd74d65d832137e20e193c960802afba73b5d38sm try { 1091cfd74d65d832137e20e193c960802afba73b5d38sm guardedRun(); 1092cfd74d65d832137e20e193c960802afba73b5d38sm } catch (InterruptedException e) { 1093cfd74d65d832137e20e193c960802afba73b5d38sm // fall thru and exit normally 1094cfd74d65d832137e20e193c960802afba73b5d38sm } finally { 1095cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.threadExiting(this); 1096cfd74d65d832137e20e193c960802afba73b5d38sm } 1097cfd74d65d832137e20e193c960802afba73b5d38sm } 1098cfd74d65d832137e20e193c960802afba73b5d38sm 1099cfd74d65d832137e20e193c960802afba73b5d38sm /* 1100cfd74d65d832137e20e193c960802afba73b5d38sm * This private method should only be called inside a 1101cfd74d65d832137e20e193c960802afba73b5d38sm * synchronized(sGLThreadManager) block. 1102cfd74d65d832137e20e193c960802afba73b5d38sm */ 1103cfd74d65d832137e20e193c960802afba73b5d38sm private void stopEglLocked() { 1104cfd74d65d832137e20e193c960802afba73b5d38sm if (mHaveEglSurface) { 1105cfd74d65d832137e20e193c960802afba73b5d38sm mHaveEglSurface = false; 1106cfd74d65d832137e20e193c960802afba73b5d38sm mEglHelper.destroySurface(); 1107cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.releaseEglSurfaceLocked(this); 1108cfd74d65d832137e20e193c960802afba73b5d38sm } 1109cfd74d65d832137e20e193c960802afba73b5d38sm } 1110cfd74d65d832137e20e193c960802afba73b5d38sm 1111cfd74d65d832137e20e193c960802afba73b5d38sm private void guardedRun() throws InterruptedException { 1112cfd74d65d832137e20e193c960802afba73b5d38sm mEglHelper = new EglHelper(); 1113cfd74d65d832137e20e193c960802afba73b5d38sm mHaveEglContext = false; 1114cfd74d65d832137e20e193c960802afba73b5d38sm mHaveEglSurface = false; 1115cfd74d65d832137e20e193c960802afba73b5d38sm try { 1116cfd74d65d832137e20e193c960802afba73b5d38sm GL10 gl = null; 1117cfd74d65d832137e20e193c960802afba73b5d38sm boolean createEglSurface = false; 1118cfd74d65d832137e20e193c960802afba73b5d38sm boolean sizeChanged = false; 1119cfd74d65d832137e20e193c960802afba73b5d38sm boolean wantRenderNotification = false; 1120cfd74d65d832137e20e193c960802afba73b5d38sm boolean doRenderNotification = false; 1121cfd74d65d832137e20e193c960802afba73b5d38sm int w = 0; 1122cfd74d65d832137e20e193c960802afba73b5d38sm int h = 0; 1123cfd74d65d832137e20e193c960802afba73b5d38sm Runnable event = null; 1124cfd74d65d832137e20e193c960802afba73b5d38sm 1125cfd74d65d832137e20e193c960802afba73b5d38sm while (true) { 1126cfd74d65d832137e20e193c960802afba73b5d38sm synchronized (sGLThreadManager) { 1127cfd74d65d832137e20e193c960802afba73b5d38sm while (true) { 1128cfd74d65d832137e20e193c960802afba73b5d38sm if (mShouldExit) { 1129cfd74d65d832137e20e193c960802afba73b5d38sm return; 1130cfd74d65d832137e20e193c960802afba73b5d38sm } 1131cfd74d65d832137e20e193c960802afba73b5d38sm 1132cfd74d65d832137e20e193c960802afba73b5d38sm if (! mEventQueue.isEmpty()) { 1133cfd74d65d832137e20e193c960802afba73b5d38sm event = mEventQueue.remove(0); 1134cfd74d65d832137e20e193c960802afba73b5d38sm break; 1135cfd74d65d832137e20e193c960802afba73b5d38sm } 1136cfd74d65d832137e20e193c960802afba73b5d38sm 1137cfd74d65d832137e20e193c960802afba73b5d38sm // Do we need to release the EGL surface? 1138cfd74d65d832137e20e193c960802afba73b5d38sm if (mHaveEglSurface && mPaused) { 1139cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_SURFACE) { 1140cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("GLThread", "releasing EGL surface because paused tid=" + getId()); 1141cfd74d65d832137e20e193c960802afba73b5d38sm } 1142cfd74d65d832137e20e193c960802afba73b5d38sm stopEglLocked(); 1143cfd74d65d832137e20e193c960802afba73b5d38sm } 1144cfd74d65d832137e20e193c960802afba73b5d38sm 1145cfd74d65d832137e20e193c960802afba73b5d38sm // Have we lost the surface view surface? 1146cfd74d65d832137e20e193c960802afba73b5d38sm if ((! mHasSurface) && (! mWaitingForSurface)) { 1147cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_SURFACE) { 1148cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("GLThread", "noticed surfaceView surface lost tid=" + getId()); 1149cfd74d65d832137e20e193c960802afba73b5d38sm } 1150cfd74d65d832137e20e193c960802afba73b5d38sm if (mHaveEglSurface) { 1151cfd74d65d832137e20e193c960802afba73b5d38sm stopEglLocked(); 1152cfd74d65d832137e20e193c960802afba73b5d38sm } 1153cfd74d65d832137e20e193c960802afba73b5d38sm mWaitingForSurface = true; 1154cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1155cfd74d65d832137e20e193c960802afba73b5d38sm } 1156cfd74d65d832137e20e193c960802afba73b5d38sm 1157cfd74d65d832137e20e193c960802afba73b5d38sm // Have we acquired the surface view surface? 1158cfd74d65d832137e20e193c960802afba73b5d38sm if (mHasSurface && mWaitingForSurface) { 1159cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_SURFACE) { 1160cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("GLThread", "noticed surfaceView surface acquired tid=" + getId()); 1161cfd74d65d832137e20e193c960802afba73b5d38sm } 1162cfd74d65d832137e20e193c960802afba73b5d38sm mWaitingForSurface = false; 1163cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1164cfd74d65d832137e20e193c960802afba73b5d38sm } 1165cfd74d65d832137e20e193c960802afba73b5d38sm 1166cfd74d65d832137e20e193c960802afba73b5d38sm if (doRenderNotification) { 1167cfd74d65d832137e20e193c960802afba73b5d38sm wantRenderNotification = false; 1168cfd74d65d832137e20e193c960802afba73b5d38sm doRenderNotification = false; 1169cfd74d65d832137e20e193c960802afba73b5d38sm mRenderComplete = true; 1170cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1171cfd74d65d832137e20e193c960802afba73b5d38sm } 1172cfd74d65d832137e20e193c960802afba73b5d38sm 1173cfd74d65d832137e20e193c960802afba73b5d38sm // Ready to draw? 1174cfd74d65d832137e20e193c960802afba73b5d38sm if ((!mPaused) && mHasSurface 1175cfd74d65d832137e20e193c960802afba73b5d38sm && (mWidth > 0) && (mHeight > 0) 1176cfd74d65d832137e20e193c960802afba73b5d38sm && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) { 1177cfd74d65d832137e20e193c960802afba73b5d38sm 1178cfd74d65d832137e20e193c960802afba73b5d38sm if (mHaveEglContext && !mHaveEglSurface) { 1179cfd74d65d832137e20e193c960802afba73b5d38sm // Let's make sure the context hasn't been lost. 1180cfd74d65d832137e20e193c960802afba73b5d38sm if (!mEglHelper.verifyContext()) { 1181cfd74d65d832137e20e193c960802afba73b5d38sm mEglHelper.finish(); 1182cfd74d65d832137e20e193c960802afba73b5d38sm mRenderer.onSurfaceLost(); 1183cfd74d65d832137e20e193c960802afba73b5d38sm mHaveEglContext = false; 1184cfd74d65d832137e20e193c960802afba73b5d38sm } 1185cfd74d65d832137e20e193c960802afba73b5d38sm } 1186cfd74d65d832137e20e193c960802afba73b5d38sm // If we don't have an egl surface, try to acquire one. 1187cfd74d65d832137e20e193c960802afba73b5d38sm if ((! mHaveEglContext) && sGLThreadManager.tryAcquireEglSurfaceLocked(this)) { 1188cfd74d65d832137e20e193c960802afba73b5d38sm mHaveEglContext = true; 1189cfd74d65d832137e20e193c960802afba73b5d38sm mEglHelper.start(); 1190cfd74d65d832137e20e193c960802afba73b5d38sm 1191cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1192cfd74d65d832137e20e193c960802afba73b5d38sm } 1193cfd74d65d832137e20e193c960802afba73b5d38sm 1194cfd74d65d832137e20e193c960802afba73b5d38sm if (mHaveEglContext && !mHaveEglSurface) { 1195cfd74d65d832137e20e193c960802afba73b5d38sm mHaveEglSurface = true; 1196cfd74d65d832137e20e193c960802afba73b5d38sm createEglSurface = true; 1197cfd74d65d832137e20e193c960802afba73b5d38sm sizeChanged = true; 1198cfd74d65d832137e20e193c960802afba73b5d38sm } 1199cfd74d65d832137e20e193c960802afba73b5d38sm 1200cfd74d65d832137e20e193c960802afba73b5d38sm if (mHaveEglSurface) { 1201cfd74d65d832137e20e193c960802afba73b5d38sm if (mSizeChanged) { 1202cfd74d65d832137e20e193c960802afba73b5d38sm sizeChanged = true; 1203cfd74d65d832137e20e193c960802afba73b5d38sm w = mWidth; 1204cfd74d65d832137e20e193c960802afba73b5d38sm h = mHeight; 1205cfd74d65d832137e20e193c960802afba73b5d38sm wantRenderNotification = true; 1206cfd74d65d832137e20e193c960802afba73b5d38sm 1207cfd74d65d832137e20e193c960802afba73b5d38sm if (DRAW_TWICE_AFTER_SIZE_CHANGED) { 1208cfd74d65d832137e20e193c960802afba73b5d38sm // We keep mRequestRender true so that we draw twice after the size changes. 1209cfd74d65d832137e20e193c960802afba73b5d38sm // (Once because of mSizeChanged, the second time because of mRequestRender.) 1210cfd74d65d832137e20e193c960802afba73b5d38sm // This forces the updated graphics onto the screen. 1211cfd74d65d832137e20e193c960802afba73b5d38sm } else { 1212cfd74d65d832137e20e193c960802afba73b5d38sm mRequestRender = false; 1213cfd74d65d832137e20e193c960802afba73b5d38sm } 1214cfd74d65d832137e20e193c960802afba73b5d38sm mSizeChanged = false; 1215cfd74d65d832137e20e193c960802afba73b5d38sm } else { 1216cfd74d65d832137e20e193c960802afba73b5d38sm mRequestRender = false; 1217cfd74d65d832137e20e193c960802afba73b5d38sm } 1218cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1219cfd74d65d832137e20e193c960802afba73b5d38sm break; 1220cfd74d65d832137e20e193c960802afba73b5d38sm } 1221cfd74d65d832137e20e193c960802afba73b5d38sm } 1222cfd74d65d832137e20e193c960802afba73b5d38sm 1223cfd74d65d832137e20e193c960802afba73b5d38sm // By design, this is the only place in a GLThread thread where we wait(). 1224cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_THREADS) { 1225cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("GLThread", "waiting tid=" + getId()); 1226cfd74d65d832137e20e193c960802afba73b5d38sm } 1227cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.wait(); 1228cfd74d65d832137e20e193c960802afba73b5d38sm } 1229cfd74d65d832137e20e193c960802afba73b5d38sm } // end of synchronized(sGLThreadManager) 1230cfd74d65d832137e20e193c960802afba73b5d38sm 1231cfd74d65d832137e20e193c960802afba73b5d38sm if (event != null) { 1232cfd74d65d832137e20e193c960802afba73b5d38sm event.run(); 1233cfd74d65d832137e20e193c960802afba73b5d38sm event = null; 1234cfd74d65d832137e20e193c960802afba73b5d38sm continue; 1235cfd74d65d832137e20e193c960802afba73b5d38sm } 1236cfd74d65d832137e20e193c960802afba73b5d38sm 1237cfd74d65d832137e20e193c960802afba73b5d38sm if (mHasFocus) { 1238cfd74d65d832137e20e193c960802afba73b5d38sm if (createEglSurface) { 1239cfd74d65d832137e20e193c960802afba73b5d38sm gl = (GL10) mEglHelper.createSurface(getHolder()); 1240cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.checkGLDriver(gl); 1241cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_RENDERER) { 1242cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.w("GLThread", "onSurfaceCreated"); 1243cfd74d65d832137e20e193c960802afba73b5d38sm } 1244cfd74d65d832137e20e193c960802afba73b5d38sm mGL = gl; 1245cfd74d65d832137e20e193c960802afba73b5d38sm mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig); 1246cfd74d65d832137e20e193c960802afba73b5d38sm createEglSurface = false; 1247cfd74d65d832137e20e193c960802afba73b5d38sm } 1248cfd74d65d832137e20e193c960802afba73b5d38sm 1249cfd74d65d832137e20e193c960802afba73b5d38sm 1250cfd74d65d832137e20e193c960802afba73b5d38sm if (sizeChanged) { 1251cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_RENDERER) { 1252cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")"); 1253cfd74d65d832137e20e193c960802afba73b5d38sm } 1254cfd74d65d832137e20e193c960802afba73b5d38sm mRenderer.onSurfaceChanged(gl, w, h); 1255cfd74d65d832137e20e193c960802afba73b5d38sm sizeChanged = false; 1256cfd74d65d832137e20e193c960802afba73b5d38sm } 1257cfd74d65d832137e20e193c960802afba73b5d38sm 1258cfd74d65d832137e20e193c960802afba73b5d38sm 1259cfd74d65d832137e20e193c960802afba73b5d38sm 1260cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_RENDERER) { 1261cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.w("GLThread", "onDrawFrame"); 1262cfd74d65d832137e20e193c960802afba73b5d38sm } 1263cfd74d65d832137e20e193c960802afba73b5d38sm mRenderer.onDrawFrame(gl); 1264cfd74d65d832137e20e193c960802afba73b5d38sm if(!mEglHelper.swap()) { 1265cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_SURFACE) { 1266cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("GLThread", "egl surface lost tid=" + getId()); 1267cfd74d65d832137e20e193c960802afba73b5d38sm } 1268cfd74d65d832137e20e193c960802afba73b5d38sm } 1269cfd74d65d832137e20e193c960802afba73b5d38sm 1270cfd74d65d832137e20e193c960802afba73b5d38sm } 1271cfd74d65d832137e20e193c960802afba73b5d38sm if (wantRenderNotification) { 1272cfd74d65d832137e20e193c960802afba73b5d38sm doRenderNotification = true; 1273cfd74d65d832137e20e193c960802afba73b5d38sm } 1274cfd74d65d832137e20e193c960802afba73b5d38sm } 1275cfd74d65d832137e20e193c960802afba73b5d38sm 1276cfd74d65d832137e20e193c960802afba73b5d38sm } finally { 1277cfd74d65d832137e20e193c960802afba73b5d38sm mGL = null; 1278cfd74d65d832137e20e193c960802afba73b5d38sm /* 1279cfd74d65d832137e20e193c960802afba73b5d38sm * clean-up everything... 1280cfd74d65d832137e20e193c960802afba73b5d38sm */ 1281cfd74d65d832137e20e193c960802afba73b5d38sm synchronized (sGLThreadManager) { 1282cfd74d65d832137e20e193c960802afba73b5d38sm stopEglLocked(); 1283cfd74d65d832137e20e193c960802afba73b5d38sm mEglHelper.finish(); 1284cfd74d65d832137e20e193c960802afba73b5d38sm } 1285cfd74d65d832137e20e193c960802afba73b5d38sm } 1286cfd74d65d832137e20e193c960802afba73b5d38sm } 1287cfd74d65d832137e20e193c960802afba73b5d38sm 1288cfd74d65d832137e20e193c960802afba73b5d38sm public void setRenderMode(int renderMode) { 1289cfd74d65d832137e20e193c960802afba73b5d38sm if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) { 1290cfd74d65d832137e20e193c960802afba73b5d38sm throw new IllegalArgumentException("renderMode"); 1291cfd74d65d832137e20e193c960802afba73b5d38sm } 1292cfd74d65d832137e20e193c960802afba73b5d38sm synchronized(sGLThreadManager) { 1293cfd74d65d832137e20e193c960802afba73b5d38sm mRenderMode = renderMode; 1294cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1295cfd74d65d832137e20e193c960802afba73b5d38sm } 1296cfd74d65d832137e20e193c960802afba73b5d38sm } 1297cfd74d65d832137e20e193c960802afba73b5d38sm 1298cfd74d65d832137e20e193c960802afba73b5d38sm public int getRenderMode() { 1299cfd74d65d832137e20e193c960802afba73b5d38sm synchronized(sGLThreadManager) { 1300cfd74d65d832137e20e193c960802afba73b5d38sm return mRenderMode; 1301cfd74d65d832137e20e193c960802afba73b5d38sm } 1302cfd74d65d832137e20e193c960802afba73b5d38sm } 1303cfd74d65d832137e20e193c960802afba73b5d38sm 1304cfd74d65d832137e20e193c960802afba73b5d38sm public void requestRender() { 1305cfd74d65d832137e20e193c960802afba73b5d38sm synchronized(sGLThreadManager) { 1306cfd74d65d832137e20e193c960802afba73b5d38sm mRequestRender = true; 1307cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1308cfd74d65d832137e20e193c960802afba73b5d38sm } 1309cfd74d65d832137e20e193c960802afba73b5d38sm } 1310cfd74d65d832137e20e193c960802afba73b5d38sm 1311cfd74d65d832137e20e193c960802afba73b5d38sm public void surfaceCreated() { 1312cfd74d65d832137e20e193c960802afba73b5d38sm synchronized(sGLThreadManager) { 1313cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_THREADS) { 1314cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("GLThread", "surfaceCreated tid=" + getId()); 1315cfd74d65d832137e20e193c960802afba73b5d38sm } 1316cfd74d65d832137e20e193c960802afba73b5d38sm mHasSurface = true; 1317cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1318cfd74d65d832137e20e193c960802afba73b5d38sm } 1319cfd74d65d832137e20e193c960802afba73b5d38sm } 1320cfd74d65d832137e20e193c960802afba73b5d38sm 1321cfd74d65d832137e20e193c960802afba73b5d38sm public void surfaceDestroyed() { 1322cfd74d65d832137e20e193c960802afba73b5d38sm synchronized(sGLThreadManager) { 1323cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_THREADS) { 1324cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("GLThread", "surfaceDestroyed tid=" + getId()); 1325cfd74d65d832137e20e193c960802afba73b5d38sm } 1326cfd74d65d832137e20e193c960802afba73b5d38sm mHasSurface = false; 1327cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1328cfd74d65d832137e20e193c960802afba73b5d38sm while((!mWaitingForSurface) && (!mExited)) { 1329cfd74d65d832137e20e193c960802afba73b5d38sm try { 1330cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.wait(); 1331cfd74d65d832137e20e193c960802afba73b5d38sm } catch (InterruptedException e) { 1332cfd74d65d832137e20e193c960802afba73b5d38sm Thread.currentThread().interrupt(); 1333cfd74d65d832137e20e193c960802afba73b5d38sm } 1334cfd74d65d832137e20e193c960802afba73b5d38sm } 1335cfd74d65d832137e20e193c960802afba73b5d38sm } 1336cfd74d65d832137e20e193c960802afba73b5d38sm } 1337cfd74d65d832137e20e193c960802afba73b5d38sm 1338cfd74d65d832137e20e193c960802afba73b5d38sm public void onPause() { 1339cfd74d65d832137e20e193c960802afba73b5d38sm synchronized (sGLThreadManager) { 1340cfd74d65d832137e20e193c960802afba73b5d38sm mPaused = true; 1341cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1342cfd74d65d832137e20e193c960802afba73b5d38sm } 1343cfd74d65d832137e20e193c960802afba73b5d38sm } 1344cfd74d65d832137e20e193c960802afba73b5d38sm 1345cfd74d65d832137e20e193c960802afba73b5d38sm public void onResume() { 1346cfd74d65d832137e20e193c960802afba73b5d38sm synchronized (sGLThreadManager) { 1347cfd74d65d832137e20e193c960802afba73b5d38sm mPaused = false; 1348cfd74d65d832137e20e193c960802afba73b5d38sm mRequestRender = true; 1349cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1350cfd74d65d832137e20e193c960802afba73b5d38sm } 1351cfd74d65d832137e20e193c960802afba73b5d38sm } 1352cfd74d65d832137e20e193c960802afba73b5d38sm 1353cfd74d65d832137e20e193c960802afba73b5d38sm public void onWindowResize(int w, int h) { 1354cfd74d65d832137e20e193c960802afba73b5d38sm synchronized (sGLThreadManager) { 1355cfd74d65d832137e20e193c960802afba73b5d38sm mWidth = w; 1356cfd74d65d832137e20e193c960802afba73b5d38sm mHeight = h; 1357cfd74d65d832137e20e193c960802afba73b5d38sm mSizeChanged = true; 1358cfd74d65d832137e20e193c960802afba73b5d38sm mRequestRender = true; 1359cfd74d65d832137e20e193c960802afba73b5d38sm mRenderComplete = false; 1360cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1361cfd74d65d832137e20e193c960802afba73b5d38sm 1362cfd74d65d832137e20e193c960802afba73b5d38sm // Wait for thread to react to resize and render a frame 1363cfd74d65d832137e20e193c960802afba73b5d38sm while (! mExited && !mPaused && !mRenderComplete ) { 1364cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_SURFACE) { 1365cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("Main thread", "onWindowResize waiting for render complete."); 1366cfd74d65d832137e20e193c960802afba73b5d38sm } 1367cfd74d65d832137e20e193c960802afba73b5d38sm try { 1368cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.wait(); 1369cfd74d65d832137e20e193c960802afba73b5d38sm } catch (InterruptedException ex) { 1370cfd74d65d832137e20e193c960802afba73b5d38sm Thread.currentThread().interrupt(); 1371cfd74d65d832137e20e193c960802afba73b5d38sm } 1372cfd74d65d832137e20e193c960802afba73b5d38sm } 1373cfd74d65d832137e20e193c960802afba73b5d38sm } 1374cfd74d65d832137e20e193c960802afba73b5d38sm } 1375cfd74d65d832137e20e193c960802afba73b5d38sm 1376cfd74d65d832137e20e193c960802afba73b5d38sm public void loadTextures(TextureLibrary library) { 1377cfd74d65d832137e20e193c960802afba73b5d38sm synchronized (this) { 1378cfd74d65d832137e20e193c960802afba73b5d38sm assert mGL != null; 1379cfd74d65d832137e20e193c960802afba73b5d38sm if (mGL != null && mHasSurface) { 1380cfd74d65d832137e20e193c960802afba73b5d38sm mRenderer.loadTextures(mGL, library); 1381cfd74d65d832137e20e193c960802afba73b5d38sm } 1382cfd74d65d832137e20e193c960802afba73b5d38sm } 1383cfd74d65d832137e20e193c960802afba73b5d38sm } 1384cfd74d65d832137e20e193c960802afba73b5d38sm 1385cfd74d65d832137e20e193c960802afba73b5d38sm public void flushTextures(TextureLibrary library) { 1386cfd74d65d832137e20e193c960802afba73b5d38sm synchronized (this) { 1387cfd74d65d832137e20e193c960802afba73b5d38sm assert mGL != null; 1388cfd74d65d832137e20e193c960802afba73b5d38sm if (mGL != null) { 1389cfd74d65d832137e20e193c960802afba73b5d38sm mRenderer.flushTextures(mGL, library); 1390cfd74d65d832137e20e193c960802afba73b5d38sm } 1391cfd74d65d832137e20e193c960802afba73b5d38sm } 1392cfd74d65d832137e20e193c960802afba73b5d38sm } 1393cfd74d65d832137e20e193c960802afba73b5d38sm 1394cfd74d65d832137e20e193c960802afba73b5d38sm public void loadBuffers(BufferLibrary library) { 1395cfd74d65d832137e20e193c960802afba73b5d38sm synchronized (this) { 1396cfd74d65d832137e20e193c960802afba73b5d38sm assert mGL != null; 1397cfd74d65d832137e20e193c960802afba73b5d38sm if (mGL != null) { 1398cfd74d65d832137e20e193c960802afba73b5d38sm mRenderer.loadBuffers(mGL, library); 1399cfd74d65d832137e20e193c960802afba73b5d38sm } 1400cfd74d65d832137e20e193c960802afba73b5d38sm } 1401cfd74d65d832137e20e193c960802afba73b5d38sm } 1402cfd74d65d832137e20e193c960802afba73b5d38sm 1403cfd74d65d832137e20e193c960802afba73b5d38sm public void flushBuffers(BufferLibrary library) { 1404cfd74d65d832137e20e193c960802afba73b5d38sm synchronized (this) { 1405cfd74d65d832137e20e193c960802afba73b5d38sm assert mGL != null; 1406cfd74d65d832137e20e193c960802afba73b5d38sm if (mGL != null) { 1407cfd74d65d832137e20e193c960802afba73b5d38sm mRenderer.flushBuffers(mGL, library); 1408cfd74d65d832137e20e193c960802afba73b5d38sm } 1409cfd74d65d832137e20e193c960802afba73b5d38sm } 1410cfd74d65d832137e20e193c960802afba73b5d38sm } 1411cfd74d65d832137e20e193c960802afba73b5d38sm 1412cfd74d65d832137e20e193c960802afba73b5d38sm // On some Qualcomm devices (such as the HTC Magic running Android 1.6), 1413cfd74d65d832137e20e193c960802afba73b5d38sm // there's a bug in the graphics driver that will cause glViewport() to 1414cfd74d65d832137e20e193c960802afba73b5d38sm // do the wrong thing in a very specific situation. When the screen is 1415cfd74d65d832137e20e193c960802afba73b5d38sm // rotated, if a surface is created in one layout (say, portrait view) 1416cfd74d65d832137e20e193c960802afba73b5d38sm // and then rotated to another, subsequent calls to glViewport are clipped. 1417cfd74d65d832137e20e193c960802afba73b5d38sm // So, if the window is, say, 320x480 when the surface is created, and 1418cfd74d65d832137e20e193c960802afba73b5d38sm // then the rotation occurs and glViewport() is called with the new 1419cfd74d65d832137e20e193c960802afba73b5d38sm // size of 480x320, devices with the buggy driver will clip the viewport 1420cfd74d65d832137e20e193c960802afba73b5d38sm // to the old width (which means 320x320...ugh!). This is fixed in 1421cfd74d65d832137e20e193c960802afba73b5d38sm // Android 2.1 Qualcomm devices (like Nexus One) and doesn't affect 1422cfd74d65d832137e20e193c960802afba73b5d38sm // non-Qualcomm devices (like the Motorola DROID). 1423cfd74d65d832137e20e193c960802afba73b5d38sm // 1424cfd74d65d832137e20e193c960802afba73b5d38sm // Unfortunately, under Android 1.6 this exact case occurs when the 1425cfd74d65d832137e20e193c960802afba73b5d38sm // screen is put to sleep and then wakes up again. The lock screen 1426cfd74d65d832137e20e193c960802afba73b5d38sm // comes up in portrait mode, but at the same time the window surface 1427cfd74d65d832137e20e193c960802afba73b5d38sm // is also created in the backgrounded game. When the lock screen is closed 1428cfd74d65d832137e20e193c960802afba73b5d38sm // and the game comes forward, the window is fixed to the correct size 1429cfd74d65d832137e20e193c960802afba73b5d38sm // which causes the bug to occur. 1430cfd74d65d832137e20e193c960802afba73b5d38sm 1431cfd74d65d832137e20e193c960802afba73b5d38sm // The solution used here is to simply never render when the window surface 1432cfd74d65d832137e20e193c960802afba73b5d38sm // does not have the focus. When the lock screen (or menu) is up, rendering 1433cfd74d65d832137e20e193c960802afba73b5d38sm // will stop. This resolves the driver bug (as the egl surface won't be created 1434cfd74d65d832137e20e193c960802afba73b5d38sm // until after the screen size has been fixed), and is generally good practice 1435cfd74d65d832137e20e193c960802afba73b5d38sm // since you don't want to be doing a lot of CPU intensive work when the lock 1436cfd74d65d832137e20e193c960802afba73b5d38sm // screen is up (to preserve battery life). 1437cfd74d65d832137e20e193c960802afba73b5d38sm 1438cfd74d65d832137e20e193c960802afba73b5d38sm public void onWindowFocusChanged(boolean hasFocus) { 1439cfd74d65d832137e20e193c960802afba73b5d38sm synchronized(sGLThreadManager) { 1440cfd74d65d832137e20e193c960802afba73b5d38sm mHasFocus = hasFocus; 1441cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1442cfd74d65d832137e20e193c960802afba73b5d38sm } 1443cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_SURFACE) { 1444cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("Main thread", "Focus " + (mHasFocus ? "gained" : "lost")); 1445cfd74d65d832137e20e193c960802afba73b5d38sm } 1446cfd74d65d832137e20e193c960802afba73b5d38sm 1447cfd74d65d832137e20e193c960802afba73b5d38sm } 1448cfd74d65d832137e20e193c960802afba73b5d38sm 1449cfd74d65d832137e20e193c960802afba73b5d38sm public void requestExitAndWait() { 1450cfd74d65d832137e20e193c960802afba73b5d38sm // don't call this from GLThread thread or it is a guaranteed 1451cfd74d65d832137e20e193c960802afba73b5d38sm // deadlock! 1452cfd74d65d832137e20e193c960802afba73b5d38sm synchronized(sGLThreadManager) { 1453cfd74d65d832137e20e193c960802afba73b5d38sm mShouldExit = true; 1454cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1455cfd74d65d832137e20e193c960802afba73b5d38sm while (! mExited) { 1456cfd74d65d832137e20e193c960802afba73b5d38sm try { 1457cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.wait(); 1458cfd74d65d832137e20e193c960802afba73b5d38sm } catch (InterruptedException ex) { 1459cfd74d65d832137e20e193c960802afba73b5d38sm Thread.currentThread().interrupt(); 1460cfd74d65d832137e20e193c960802afba73b5d38sm } 1461cfd74d65d832137e20e193c960802afba73b5d38sm } 1462cfd74d65d832137e20e193c960802afba73b5d38sm } 1463cfd74d65d832137e20e193c960802afba73b5d38sm } 1464cfd74d65d832137e20e193c960802afba73b5d38sm 1465cfd74d65d832137e20e193c960802afba73b5d38sm /** 1466cfd74d65d832137e20e193c960802afba73b5d38sm * Queue an "event" to be run on the GL rendering thread. 1467cfd74d65d832137e20e193c960802afba73b5d38sm * @param r the runnable to be run on the GL rendering thread. 1468cfd74d65d832137e20e193c960802afba73b5d38sm */ 1469cfd74d65d832137e20e193c960802afba73b5d38sm public void queueEvent(Runnable r) { 1470cfd74d65d832137e20e193c960802afba73b5d38sm if (r == null) { 1471cfd74d65d832137e20e193c960802afba73b5d38sm throw new IllegalArgumentException("r must not be null"); 1472cfd74d65d832137e20e193c960802afba73b5d38sm } 1473cfd74d65d832137e20e193c960802afba73b5d38sm synchronized(sGLThreadManager) { 1474cfd74d65d832137e20e193c960802afba73b5d38sm mEventQueue.add(r); 1475cfd74d65d832137e20e193c960802afba73b5d38sm sGLThreadManager.notifyAll(); 1476cfd74d65d832137e20e193c960802afba73b5d38sm } 1477cfd74d65d832137e20e193c960802afba73b5d38sm } 1478cfd74d65d832137e20e193c960802afba73b5d38sm 1479cfd74d65d832137e20e193c960802afba73b5d38sm // Once the thread is started, all accesses to the following member 1480cfd74d65d832137e20e193c960802afba73b5d38sm // variables are protected by the sGLThreadManager monitor 1481cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mShouldExit; 1482cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mExited; 1483cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mPaused; 1484cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mHasSurface; 1485cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mWaitingForSurface; 1486cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mHaveEglContext; 1487cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mHaveEglSurface; 1488cfd74d65d832137e20e193c960802afba73b5d38sm private int mWidth; 1489cfd74d65d832137e20e193c960802afba73b5d38sm private int mHeight; 1490cfd74d65d832137e20e193c960802afba73b5d38sm private int mRenderMode; 1491cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mRequestRender; 1492cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mRenderComplete; 1493cfd74d65d832137e20e193c960802afba73b5d38sm private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>(); 1494cfd74d65d832137e20e193c960802afba73b5d38sm private GL10 mGL; 1495cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mHasFocus; 1496cfd74d65d832137e20e193c960802afba73b5d38sm 1497cfd74d65d832137e20e193c960802afba73b5d38sm // End of member variables protected by the sGLThreadManager monitor. 1498cfd74d65d832137e20e193c960802afba73b5d38sm 1499cfd74d65d832137e20e193c960802afba73b5d38sm private Renderer mRenderer; 1500cfd74d65d832137e20e193c960802afba73b5d38sm private EglHelper mEglHelper; 1501cfd74d65d832137e20e193c960802afba73b5d38sm } 1502cfd74d65d832137e20e193c960802afba73b5d38sm 1503cfd74d65d832137e20e193c960802afba73b5d38sm static class LogWriter extends Writer { 1504cfd74d65d832137e20e193c960802afba73b5d38sm 1505cfd74d65d832137e20e193c960802afba73b5d38sm @Override public void close() { 1506cfd74d65d832137e20e193c960802afba73b5d38sm flushBuilder(); 1507cfd74d65d832137e20e193c960802afba73b5d38sm } 1508cfd74d65d832137e20e193c960802afba73b5d38sm 1509cfd74d65d832137e20e193c960802afba73b5d38sm @Override public void flush() { 1510cfd74d65d832137e20e193c960802afba73b5d38sm flushBuilder(); 1511cfd74d65d832137e20e193c960802afba73b5d38sm } 1512cfd74d65d832137e20e193c960802afba73b5d38sm 1513cfd74d65d832137e20e193c960802afba73b5d38sm @Override public void write(char[] buf, int offset, int count) { 1514cfd74d65d832137e20e193c960802afba73b5d38sm for(int i = 0; i < count; i++) { 1515cfd74d65d832137e20e193c960802afba73b5d38sm char c = buf[offset + i]; 1516cfd74d65d832137e20e193c960802afba73b5d38sm if ( c == '\n') { 1517cfd74d65d832137e20e193c960802afba73b5d38sm flushBuilder(); 1518cfd74d65d832137e20e193c960802afba73b5d38sm } 1519cfd74d65d832137e20e193c960802afba73b5d38sm else { 1520cfd74d65d832137e20e193c960802afba73b5d38sm mBuilder.append(c); 1521cfd74d65d832137e20e193c960802afba73b5d38sm } 1522cfd74d65d832137e20e193c960802afba73b5d38sm } 1523cfd74d65d832137e20e193c960802afba73b5d38sm } 1524cfd74d65d832137e20e193c960802afba73b5d38sm 1525cfd74d65d832137e20e193c960802afba73b5d38sm private void flushBuilder() { 1526cfd74d65d832137e20e193c960802afba73b5d38sm if (mBuilder.length() > 0) { 1527cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.v("GLSurfaceView", mBuilder.toString()); 1528cfd74d65d832137e20e193c960802afba73b5d38sm mBuilder.delete(0, mBuilder.length()); 1529cfd74d65d832137e20e193c960802afba73b5d38sm } 1530cfd74d65d832137e20e193c960802afba73b5d38sm } 1531cfd74d65d832137e20e193c960802afba73b5d38sm 1532cfd74d65d832137e20e193c960802afba73b5d38sm private StringBuilder mBuilder = new StringBuilder(); 1533cfd74d65d832137e20e193c960802afba73b5d38sm } 1534cfd74d65d832137e20e193c960802afba73b5d38sm 1535cfd74d65d832137e20e193c960802afba73b5d38sm 1536cfd74d65d832137e20e193c960802afba73b5d38sm private void checkRenderThreadState() { 1537cfd74d65d832137e20e193c960802afba73b5d38sm if (mGLThread != null) { 1538cfd74d65d832137e20e193c960802afba73b5d38sm throw new IllegalStateException( 1539cfd74d65d832137e20e193c960802afba73b5d38sm "setRenderer has already been called for this instance."); 1540cfd74d65d832137e20e193c960802afba73b5d38sm } 1541cfd74d65d832137e20e193c960802afba73b5d38sm } 1542cfd74d65d832137e20e193c960802afba73b5d38sm 1543cfd74d65d832137e20e193c960802afba73b5d38sm private static class GLThreadManager { 1544cfd74d65d832137e20e193c960802afba73b5d38sm 1545cfd74d65d832137e20e193c960802afba73b5d38sm public synchronized void threadExiting(GLThread thread) { 1546cfd74d65d832137e20e193c960802afba73b5d38sm if (LOG_THREADS) { 1547cfd74d65d832137e20e193c960802afba73b5d38sm DebugLog.i("GLThread", "exiting tid=" + thread.getId()); 1548cfd74d65d832137e20e193c960802afba73b5d38sm } 1549cfd74d65d832137e20e193c960802afba73b5d38sm thread.mExited = true; 1550cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglOwner == thread) { 1551cfd74d65d832137e20e193c960802afba73b5d38sm mEglOwner = null; 1552cfd74d65d832137e20e193c960802afba73b5d38sm } 1553cfd74d65d832137e20e193c960802afba73b5d38sm notifyAll(); 1554cfd74d65d832137e20e193c960802afba73b5d38sm } 1555cfd74d65d832137e20e193c960802afba73b5d38sm 1556cfd74d65d832137e20e193c960802afba73b5d38sm /* 1557cfd74d65d832137e20e193c960802afba73b5d38sm * Tries once to acquire the right to use an EGL 1558cfd74d65d832137e20e193c960802afba73b5d38sm * surface. Does not block. Requires that we are already 1559cfd74d65d832137e20e193c960802afba73b5d38sm * in the sGLThreadManager monitor when this is called. 1560cfd74d65d832137e20e193c960802afba73b5d38sm * 1561cfd74d65d832137e20e193c960802afba73b5d38sm * @return true if the right to use an EGL surface was acquired. 1562cfd74d65d832137e20e193c960802afba73b5d38sm */ 1563cfd74d65d832137e20e193c960802afba73b5d38sm public boolean tryAcquireEglSurfaceLocked(GLThread thread) { 1564cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglOwner == thread || mEglOwner == null) { 1565cfd74d65d832137e20e193c960802afba73b5d38sm mEglOwner = thread; 1566cfd74d65d832137e20e193c960802afba73b5d38sm notifyAll(); 1567cfd74d65d832137e20e193c960802afba73b5d38sm return true; 1568cfd74d65d832137e20e193c960802afba73b5d38sm } 1569cfd74d65d832137e20e193c960802afba73b5d38sm checkGLESVersion(); 1570cfd74d65d832137e20e193c960802afba73b5d38sm if (mMultipleGLESContextsAllowed) { 1571cfd74d65d832137e20e193c960802afba73b5d38sm return true; 1572cfd74d65d832137e20e193c960802afba73b5d38sm } 1573cfd74d65d832137e20e193c960802afba73b5d38sm return false; 1574cfd74d65d832137e20e193c960802afba73b5d38sm } 1575cfd74d65d832137e20e193c960802afba73b5d38sm /* 1576cfd74d65d832137e20e193c960802afba73b5d38sm * Releases the EGL surface. Requires that we are already in the 1577cfd74d65d832137e20e193c960802afba73b5d38sm * sGLThreadManager monitor when this is called. 1578cfd74d65d832137e20e193c960802afba73b5d38sm */ 1579cfd74d65d832137e20e193c960802afba73b5d38sm public void releaseEglSurfaceLocked(GLThread thread) { 1580cfd74d65d832137e20e193c960802afba73b5d38sm if (mEglOwner == thread) { 1581cfd74d65d832137e20e193c960802afba73b5d38sm mEglOwner = null; 1582cfd74d65d832137e20e193c960802afba73b5d38sm } 1583cfd74d65d832137e20e193c960802afba73b5d38sm notifyAll(); 1584cfd74d65d832137e20e193c960802afba73b5d38sm } 1585cfd74d65d832137e20e193c960802afba73b5d38sm 1586cfd74d65d832137e20e193c960802afba73b5d38sm public synchronized void checkGLDriver(GL10 gl) { 1587cfd74d65d832137e20e193c960802afba73b5d38sm if (! mGLESDriverCheckComplete) { 1588cfd74d65d832137e20e193c960802afba73b5d38sm checkGLESVersion(); 1589cfd74d65d832137e20e193c960802afba73b5d38sm if (mGLESVersion < kGLES_20) { 1590cfd74d65d832137e20e193c960802afba73b5d38sm String renderer = gl.glGetString(GL10.GL_RENDERER); 1591cfd74d65d832137e20e193c960802afba73b5d38sm mMultipleGLESContextsAllowed = false; 1592cfd74d65d832137e20e193c960802afba73b5d38sm notifyAll(); 1593cfd74d65d832137e20e193c960802afba73b5d38sm } 1594cfd74d65d832137e20e193c960802afba73b5d38sm mGLESDriverCheckComplete = true; 1595cfd74d65d832137e20e193c960802afba73b5d38sm } 1596cfd74d65d832137e20e193c960802afba73b5d38sm } 1597cfd74d65d832137e20e193c960802afba73b5d38sm 1598cfd74d65d832137e20e193c960802afba73b5d38sm private void checkGLESVersion() { 1599cfd74d65d832137e20e193c960802afba73b5d38sm if (! mGLESVersionCheckComplete) { 1600cfd74d65d832137e20e193c960802afba73b5d38sm mGLESVersion = ConfigurationInfo.GL_ES_VERSION_UNDEFINED; 1601cfd74d65d832137e20e193c960802afba73b5d38sm if (mGLESVersion >= kGLES_20) { 1602cfd74d65d832137e20e193c960802afba73b5d38sm mMultipleGLESContextsAllowed = true; 1603cfd74d65d832137e20e193c960802afba73b5d38sm } 1604cfd74d65d832137e20e193c960802afba73b5d38sm mGLESVersionCheckComplete = true; 1605cfd74d65d832137e20e193c960802afba73b5d38sm } 1606cfd74d65d832137e20e193c960802afba73b5d38sm 1607cfd74d65d832137e20e193c960802afba73b5d38sm } 1608cfd74d65d832137e20e193c960802afba73b5d38sm 1609cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mGLESVersionCheckComplete; 1610cfd74d65d832137e20e193c960802afba73b5d38sm private int mGLESVersion; 1611cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mGLESDriverCheckComplete; 1612cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mMultipleGLESContextsAllowed; 1613cfd74d65d832137e20e193c960802afba73b5d38sm private int mGLContextCount; 1614cfd74d65d832137e20e193c960802afba73b5d38sm private static final int kGLES_20 = 0x20000; 1615cfd74d65d832137e20e193c960802afba73b5d38sm private GLThread mEglOwner; 1616cfd74d65d832137e20e193c960802afba73b5d38sm 1617cfd74d65d832137e20e193c960802afba73b5d38sm } 1618cfd74d65d832137e20e193c960802afba73b5d38sm 1619cfd74d65d832137e20e193c960802afba73b5d38sm private static final GLThreadManager sGLThreadManager = new GLThreadManager(); 1620cfd74d65d832137e20e193c960802afba73b5d38sm private boolean mSizeChanged = true; 1621cfd74d65d832137e20e193c960802afba73b5d38sm 1622cfd74d65d832137e20e193c960802afba73b5d38sm private GLThread mGLThread; 1623cfd74d65d832137e20e193c960802afba73b5d38sm private EGLConfigChooser mEGLConfigChooser; 1624cfd74d65d832137e20e193c960802afba73b5d38sm private EGLContextFactory mEGLContextFactory; 1625cfd74d65d832137e20e193c960802afba73b5d38sm private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory; 1626cfd74d65d832137e20e193c960802afba73b5d38sm private GLWrapper mGLWrapper; 1627cfd74d65d832137e20e193c960802afba73b5d38sm private int mDebugFlags; 1628cfd74d65d832137e20e193c960802afba73b5d38sm private int mEGLContextClientVersion; 1629cfd74d65d832137e20e193c960802afba73b5d38sm 1630cfd74d65d832137e20e193c960802afba73b5d38sm 1631cfd74d65d832137e20e193c960802afba73b5d38sm} 1632