Advertisement
arberg

Original Android -15 GlSurfaceView formatted

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