Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2013 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.view;
     18 
     19 import android.content.ComponentCallbacks2;
     20 import android.graphics.Paint;
     21 import android.graphics.Rect;
     22 import android.graphics.SurfaceTexture;
     23 import android.opengl.EGL14;
     24 import android.opengl.GLUtils;
     25 import android.opengl.ManagedEGLContext;
     26 import android.os.Handler;
     27 import android.os.Looper;
     28 import android.os.SystemClock;
     29 import android.os.SystemProperties;
     30 import android.os.Trace;
     31 import android.util.DisplayMetrics;
     32 import android.util.Log;
     33 import com.google.android.gles_jni.EGLImpl;
     34 
     35 import javax.microedition.khronos.egl.EGL10;
     36 import javax.microedition.khronos.egl.EGL11;
     37 import javax.microedition.khronos.egl.EGLConfig;
     38 import javax.microedition.khronos.egl.EGLContext;
     39 import javax.microedition.khronos.egl.EGLDisplay;
     40 import javax.microedition.khronos.egl.EGLSurface;
     41 import javax.microedition.khronos.opengles.GL;
     42 
     43 import java.io.File;
     44 import java.io.PrintWriter;
     45 import java.util.Arrays;
     46 import java.util.concurrent.locks.ReentrantLock;
     47 
     48 import static javax.microedition.khronos.egl.EGL10.*;
     49 
     50 /**
     51  * Interface for rendering a view hierarchy using hardware acceleration.
     52  *
     53  * @hide
     54  */
     55 public abstract class HardwareRenderer {
     56     static final String LOG_TAG = "HardwareRenderer";
     57 
     58     /**
     59      * Name of the file that holds the shaders cache.
     60      */
     61     private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
     62 
     63     /**
     64      * Turn on to only refresh the parts of the screen that need updating.
     65      * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
     66      * must also have the value "true".
     67      */
     68     static final boolean RENDER_DIRTY_REGIONS = true;
     69 
     70     /**
     71      * System property used to enable or disable dirty regions invalidation.
     72      * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
     73      * The default value of this property is assumed to be true.
     74      *
     75      * Possible values:
     76      * "true", to enable partial invalidates
     77      * "false", to disable partial invalidates
     78      */
     79     static final String RENDER_DIRTY_REGIONS_PROPERTY = "debug.hwui.render_dirty_regions";
     80 
     81     /**
     82      * System property used to enable or disable hardware rendering profiling.
     83      * The default value of this property is assumed to be false.
     84      *
     85      * When profiling is enabled, the adb shell dumpsys gfxinfo command will
     86      * output extra information about the time taken to execute by the last
     87      * frames.
     88      *
     89      * Possible values:
     90      * "true", to enable profiling
     91      * "visual_bars", to enable profiling and visualize the results on screen
     92      * "visual_lines", to enable profiling and visualize the results on screen
     93      * "false", to disable profiling
     94      *
     95      * @see #PROFILE_PROPERTY_VISUALIZE_BARS
     96      * @see #PROFILE_PROPERTY_VISUALIZE_LINES
     97      *
     98      * @hide
     99      */
    100     public static final String PROFILE_PROPERTY = "debug.hwui.profile";
    101 
    102     /**
    103      * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
    104      * value, profiling data will be visualized on screen as a bar chart.
    105      *
    106      * @hide
    107      */
    108     public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars";
    109 
    110     /**
    111      * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
    112      * value, profiling data will be visualized on screen as a line chart.
    113      *
    114      * @hide
    115      */
    116     public static final String PROFILE_PROPERTY_VISUALIZE_LINES = "visual_lines";
    117 
    118     /**
    119      * System property used to specify the number of frames to be used
    120      * when doing hardware rendering profiling.
    121      * The default value of this property is #PROFILE_MAX_FRAMES.
    122      *
    123      * When profiling is enabled, the adb shell dumpsys gfxinfo command will
    124      * output extra information about the time taken to execute by the last
    125      * frames.
    126      *
    127      * Possible values:
    128      * "60", to set the limit of frames to 60
    129      */
    130     static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes";
    131 
    132     /**
    133      * System property used to debug EGL configuration choice.
    134      *
    135      * Possible values:
    136      * "choice", print the chosen configuration only
    137      * "all", print all possible configurations
    138      */
    139     static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config";
    140 
    141     /**
    142      * Turn on to draw dirty regions every other frame.
    143      *
    144      * Possible values:
    145      * "true", to enable dirty regions debugging
    146      * "false", to disable dirty regions debugging
    147      *
    148      * @hide
    149      */
    150     public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
    151 
    152     /**
    153      * Turn on to flash hardware layers when they update.
    154      *
    155      * Possible values:
    156      * "true", to enable hardware layers updates debugging
    157      * "false", to disable hardware layers updates debugging
    158      *
    159      * @hide
    160      */
    161     public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY =
    162             "debug.hwui.show_layers_updates";
    163 
    164     /**
    165      * Turn on to show overdraw level.
    166      *
    167      * Possible values:
    168      * "true", to enable overdraw debugging
    169      * "false", to disable overdraw debugging
    170      *
    171      * @hide
    172      */
    173     public static final String DEBUG_SHOW_OVERDRAW_PROPERTY = "debug.hwui.show_overdraw";
    174 
    175     /**
    176      * Turn on to debug non-rectangular clip operations.
    177      *
    178      * Possible values:
    179      * "hide", to disable this debug mode
    180      * "highlight", highlight drawing commands tested against a non-rectangular clip
    181      * "stencil", renders the clip region on screen when set
    182      *
    183      * @hide
    184      */
    185     public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY =
    186             "debug.hwui.show_non_rect_clip";
    187 
    188     /**
    189      * A process can set this flag to false to prevent the use of hardware
    190      * rendering.
    191      *
    192      * @hide
    193      */
    194     public static boolean sRendererDisabled = false;
    195 
    196     /**
    197      * Further hardware renderer disabling for the system process.
    198      *
    199      * @hide
    200      */
    201     public static boolean sSystemRendererDisabled = false;
    202 
    203     /**
    204      * Number of frames to profile.
    205      */
    206     private static final int PROFILE_MAX_FRAMES = 128;
    207 
    208     /**
    209      * Number of floats per profiled frame.
    210      */
    211     private static final int PROFILE_FRAME_DATA_COUNT = 3;
    212 
    213     private boolean mEnabled;
    214     private boolean mRequested = true;
    215 
    216     /**
    217      * Invoke this method to disable hardware rendering in the current process.
    218      *
    219      * @hide
    220      */
    221     public static void disable(boolean system) {
    222         sRendererDisabled = true;
    223         if (system) {
    224             sSystemRendererDisabled = true;
    225         }
    226     }
    227 
    228     /**
    229      * Indicates whether hardware acceleration is available under any form for
    230      * the view hierarchy.
    231      *
    232      * @return True if the view hierarchy can potentially be hardware accelerated,
    233      *         false otherwise
    234      */
    235     public static boolean isAvailable() {
    236         return GLES20Canvas.isAvailable();
    237     }
    238 
    239     /**
    240      * Destroys the hardware rendering context.
    241      *
    242      * @param full If true, destroys all associated resources.
    243      */
    244     abstract void destroy(boolean full);
    245 
    246     /**
    247      * Initializes the hardware renderer for the specified surface.
    248      *
    249      * @param surface The surface to hardware accelerate
    250      *
    251      * @return True if the initialization was successful, false otherwise.
    252      */
    253     abstract boolean initialize(Surface surface) throws Surface.OutOfResourcesException;
    254 
    255     /**
    256      * Updates the hardware renderer for the specified surface.
    257      *
    258      * @param surface The surface to hardware accelerate
    259      */
    260     abstract void updateSurface(Surface surface) throws Surface.OutOfResourcesException;
    261 
    262     /**
    263      * Destroys the layers used by the specified view hierarchy.
    264      *
    265      * @param view The root of the view hierarchy
    266      */
    267     abstract void destroyLayers(View view);
    268 
    269     /**
    270      * Destroys all hardware rendering resources associated with the specified
    271      * view hierarchy.
    272      *
    273      * @param view The root of the view hierarchy
    274      */
    275     abstract void destroyHardwareResources(View view);
    276 
    277     /**
    278      * This method should be invoked whenever the current hardware renderer
    279      * context should be reset.
    280      *
    281      * @param surface The surface to hardware accelerate
    282      */
    283     abstract void invalidate(Surface surface);
    284 
    285     /**
    286      * This method should be invoked to ensure the hardware renderer is in
    287      * valid state (for instance, to ensure the correct EGL context is bound
    288      * to the current thread.)
    289      *
    290      * @return true if the renderer is now valid, false otherwise
    291      */
    292     abstract boolean validate();
    293 
    294     /**
    295      * This method ensures the hardware renderer is in a valid state
    296      * before executing the specified action.
    297      *
    298      * This method will attempt to set a valid state even if the window
    299      * the renderer is attached to was destroyed.
    300      *
    301      * @return true if the action was run
    302      */
    303     abstract boolean safelyRun(Runnable action);
    304 
    305     /**
    306      * Setup the hardware renderer for drawing. This is called whenever the
    307      * size of the target surface changes or when the surface is first created.
    308      *
    309      * @param width Width of the drawing surface.
    310      * @param height Height of the drawing surface.
    311      */
    312     abstract void setup(int width, int height);
    313 
    314     /**
    315      * Gets the current width of the surface. This is the width that the surface
    316      * was last set to in a call to {@link #setup(int, int)}.
    317      *
    318      * @return the current width of the surface
    319      */
    320     abstract int getWidth();
    321 
    322     /**
    323      * Gets the current height of the surface. This is the height that the surface
    324      * was last set to in a call to {@link #setup(int, int)}.
    325      *
    326      * @return the current width of the surface
    327      */
    328     abstract int getHeight();
    329 
    330     /**
    331      * Gets the current canvas associated with this HardwareRenderer.
    332      *
    333      * @return the current HardwareCanvas
    334      */
    335     abstract HardwareCanvas getCanvas();
    336 
    337     /**
    338      * Outputs extra debugging information in the specified file descriptor.
    339      * @param pw
    340      */
    341     abstract void dumpGfxInfo(PrintWriter pw);
    342 
    343     /**
    344      * Outputs the total number of frames rendered (used for fps calculations)
    345      *
    346      * @return the number of frames rendered
    347      */
    348     abstract long getFrameCount();
    349 
    350     /**
    351      * Loads system properties used by the renderer. This method is invoked
    352      * whenever system properties are modified. Implementations can use this
    353      * to trigger live updates of the renderer based on properties.
    354      *
    355      * @param surface The surface to update with the new properties.
    356      *                Can be null.
    357      *
    358      * @return True if a property has changed.
    359      */
    360     abstract boolean loadSystemProperties(Surface surface);
    361 
    362     private static native boolean nLoadProperties();
    363 
    364     /**
    365      * Sets the directory to use as a persistent storage for hardware rendering
    366      * resources.
    367      *
    368      * @param cacheDir A directory the current process can write to
    369      *
    370      * @hide
    371      */
    372     public static void setupDiskCache(File cacheDir) {
    373         nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
    374     }
    375 
    376     private static native void nSetupShadersDiskCache(String cacheFile);
    377 
    378     /**
    379      * Notifies EGL that the frame is about to be rendered.
    380      * @param size
    381      */
    382     static void beginFrame(int[] size) {
    383         nBeginFrame(size);
    384     }
    385 
    386     private static native void nBeginFrame(int[] size);
    387 
    388     /**
    389      * Preserves the back buffer of the current surface after a buffer swap.
    390      * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
    391      * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
    392      * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
    393      *
    394      * @return True if the swap behavior was successfully changed,
    395      *         false otherwise.
    396      */
    397     static boolean preserveBackBuffer() {
    398         return nPreserveBackBuffer();
    399     }
    400 
    401     private static native boolean nPreserveBackBuffer();
    402 
    403     /**
    404      * Indicates whether the current surface preserves its back buffer
    405      * after a buffer swap.
    406      *
    407      * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
    408      *         false otherwise
    409      */
    410     static boolean isBackBufferPreserved() {
    411         return nIsBackBufferPreserved();
    412     }
    413 
    414     private static native boolean nIsBackBufferPreserved();
    415 
    416     /**
    417      * Indicates that the specified hardware layer needs to be updated
    418      * as soon as possible.
    419      *
    420      * @param layer The hardware layer that needs an update
    421      */
    422     abstract void pushLayerUpdate(HardwareLayer layer);
    423 
    424     /**
    425      * Interface used to receive callbacks whenever a view is drawn by
    426      * a hardware renderer instance.
    427      */
    428     interface HardwareDrawCallbacks {
    429         /**
    430          * Invoked before a view is drawn by a hardware renderer.
    431          * This method can be used to apply transformations to the
    432          * canvas but no drawing command should be issued.
    433          *
    434          * @param canvas The Canvas used to render the view.
    435          */
    436         void onHardwarePreDraw(HardwareCanvas canvas);
    437 
    438         /**
    439          * Invoked after a view is drawn by a hardware renderer.
    440          * It is safe to invoke drawing commands from this method.
    441          *
    442          * @param canvas The Canvas used to render the view.
    443          */
    444         void onHardwarePostDraw(HardwareCanvas canvas);
    445     }
    446 
    447     /**
    448      * Draws the specified view.
    449      *
    450      * @param view The view to draw.
    451      * @param attachInfo AttachInfo tied to the specified view.
    452      * @param callbacks Callbacks invoked when drawing happens.
    453      * @param dirty The dirty rectangle to update, can be null.
    454      */
    455     abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
    456             Rect dirty);
    457 
    458     /**
    459      * Creates a new display list that can be used to record batches of
    460      * drawing operations.
    461      *
    462      * @param name The name of the display list, used for debugging purpose. May be null.
    463      *
    464      * @return A new display list.
    465      *
    466      * @hide
    467      */
    468     public abstract DisplayList createDisplayList(String name);
    469 
    470     /**
    471      * Creates a new hardware layer. A hardware layer built by calling this
    472      * method will be treated as a texture layer, instead of as a render target.
    473      *
    474      * @param isOpaque Whether the layer should be opaque or not
    475      *
    476      * @return A hardware layer
    477      */
    478     abstract HardwareLayer createHardwareLayer(boolean isOpaque);
    479 
    480     /**
    481      * Creates a new hardware layer.
    482      *
    483      * @param width The minimum width of the layer
    484      * @param height The minimum height of the layer
    485      * @param isOpaque Whether the layer should be opaque or not
    486      *
    487      * @return A hardware layer
    488      */
    489     abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
    490 
    491     /**
    492      * Creates a new {@link SurfaceTexture} that can be used to render into the
    493      * specified hardware layer.
    494      *
    495      * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
    496      *
    497      * @return A {@link SurfaceTexture}
    498      */
    499     abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
    500 
    501     /**
    502      * Sets the {@link android.graphics.SurfaceTexture} that will be used to
    503      * render into the specified hardware layer.
    504      *
    505      * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
    506      * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
    507      */
    508     abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
    509 
    510     /**
    511      * Detaches the specified functor from the current functor execution queue.
    512      *
    513      * @param functor The native functor to remove from the execution queue.
    514      *
    515      * @see HardwareCanvas#callDrawGLFunction(int)
    516      * @see #attachFunctor(android.view.View.AttachInfo, int)
    517      */
    518     abstract void detachFunctor(int functor);
    519 
    520     /**
    521      * Schedules the specified functor in the functors execution queue.
    522      *
    523      * @param attachInfo AttachInfo tied to this renderer.
    524      * @param functor The native functor to insert in the execution queue.
    525      *
    526      * @see HardwareCanvas#callDrawGLFunction(int)
    527      * @see #detachFunctor(int)
    528      *
    529      * @return true if the functor was attached successfully
    530      */
    531     abstract boolean attachFunctor(View.AttachInfo attachInfo, int functor);
    532 
    533     /**
    534      * Initializes the hardware renderer for the specified surface and setup the
    535      * renderer for drawing, if needed. This is invoked when the ViewAncestor has
    536      * potentially lost the hardware renderer. The hardware renderer should be
    537      * reinitialized and setup when the render {@link #isRequested()} and
    538      * {@link #isEnabled()}.
    539      *
    540      * @param width The width of the drawing surface.
    541      * @param height The height of the drawing surface.
    542      * @param surface The surface to hardware accelerate
    543      *
    544      * @return true if the surface was initialized, false otherwise. Returning
    545      *         false might mean that the surface was already initialized.
    546      */
    547     boolean initializeIfNeeded(int width, int height, Surface surface)
    548             throws Surface.OutOfResourcesException {
    549         if (isRequested()) {
    550             // We lost the gl context, so recreate it.
    551             if (!isEnabled()) {
    552                 if (initialize(surface)) {
    553                     setup(width, height);
    554                     return true;
    555                 }
    556             }
    557         }
    558         return false;
    559     }
    560 
    561     /**
    562      * Optional, sets the name of the renderer. Useful for debugging purposes.
    563      *
    564      * @param name The name of this renderer, can be null
    565      */
    566     abstract void setName(String name);
    567 
    568     /**
    569      * Creates a hardware renderer using OpenGL.
    570      *
    571      * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
    572      * @param translucent True if the surface is translucent, false otherwise
    573      *
    574      * @return A hardware renderer backed by OpenGL.
    575      */
    576     static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
    577         switch (glVersion) {
    578             case 2:
    579                 return Gl20Renderer.create(translucent);
    580         }
    581         throw new IllegalArgumentException("Unknown GL version: " + glVersion);
    582     }
    583 
    584     /**
    585      * Invoke this method when the system is running out of memory. This
    586      * method will attempt to recover as much memory as possible, based on
    587      * the specified hint.
    588      *
    589      * @param level Hint about the amount of memory that should be trimmed,
    590      *              see {@link android.content.ComponentCallbacks}
    591      */
    592     static void trimMemory(int level) {
    593         startTrimMemory(level);
    594         endTrimMemory();
    595     }
    596 
    597     /**
    598      * Starts the process of trimming memory. Usually this call will setup
    599      * hardware rendering context and reclaim memory.Extra cleanup might
    600      * be required by calling {@link #endTrimMemory()}.
    601      *
    602      * @param level Hint about the amount of memory that should be trimmed,
    603      *              see {@link android.content.ComponentCallbacks}
    604      */
    605     static void startTrimMemory(int level) {
    606         Gl20Renderer.startTrimMemory(level);
    607     }
    608 
    609     /**
    610      * Finishes the process of trimming memory. This method will usually
    611      * cleanup special resources used by the memory trimming process.
    612      */
    613     static void endTrimMemory() {
    614         Gl20Renderer.endTrimMemory();
    615     }
    616 
    617     /**
    618      * Indicates whether hardware acceleration is currently enabled.
    619      *
    620      * @return True if hardware acceleration is in use, false otherwise.
    621      */
    622     boolean isEnabled() {
    623         return mEnabled;
    624     }
    625 
    626     /**
    627      * Indicates whether hardware acceleration is currently enabled.
    628      *
    629      * @param enabled True if the hardware renderer is in use, false otherwise.
    630      */
    631     void setEnabled(boolean enabled) {
    632         mEnabled = enabled;
    633     }
    634 
    635     /**
    636      * Indicates whether hardware acceleration is currently request but not
    637      * necessarily enabled yet.
    638      *
    639      * @return True if requested, false otherwise.
    640      */
    641     boolean isRequested() {
    642         return mRequested;
    643     }
    644 
    645     /**
    646      * Indicates whether hardware acceleration is currently requested but not
    647      * necessarily enabled yet.
    648      *
    649      * @return True to request hardware acceleration, false otherwise.
    650      */
    651     void setRequested(boolean requested) {
    652         mRequested = requested;
    653     }
    654 
    655     /**
    656      * Describes a series of frames that should be drawn on screen as a graph.
    657      * Each frame is composed of 1 or more elements.
    658      */
    659     abstract class GraphDataProvider {
    660         /**
    661          * Draws the graph as bars. Frame elements are stacked on top of
    662          * each other.
    663          */
    664         public static final int GRAPH_TYPE_BARS = 0;
    665         /**
    666          * Draws the graph as lines. The number of series drawn corresponds
    667          * to the number of elements.
    668          */
    669         public static final int GRAPH_TYPE_LINES = 1;
    670 
    671         /**
    672          * Returns the type of graph to render.
    673          *
    674          * @return {@link #GRAPH_TYPE_BARS} or {@link #GRAPH_TYPE_LINES}
    675          */
    676         abstract int getGraphType();
    677 
    678         /**
    679          * This method is invoked before the graph is drawn. This method
    680          * can be used to compute sizes, etc.
    681          *
    682          * @param metrics The display metrics
    683          */
    684         abstract void prepare(DisplayMetrics metrics);
    685 
    686         /**
    687          * @return The size in pixels of a vertical unit.
    688          */
    689         abstract int getVerticalUnitSize();
    690 
    691         /**
    692          * @return The size in pixels of a horizontal unit.
    693          */
    694         abstract int getHorizontalUnitSize();
    695 
    696         /**
    697          * @return The size in pixels of the margin between horizontal units.
    698          */
    699         abstract int getHorizontaUnitMargin();
    700 
    701         /**
    702          * An optional threshold value.
    703          *
    704          * @return A value >= 0 to draw the threshold, a negative value
    705          *         to ignore it.
    706          */
    707         abstract float getThreshold();
    708 
    709         /**
    710          * The data to draw in the graph. The number of elements in the
    711          * array must be at least {@link #getFrameCount()} * {@link #getElementCount()}.
    712          * If a value is negative the following values will be ignored.
    713          */
    714         abstract float[] getData();
    715 
    716         /**
    717          * Returns the number of frames to render in the graph.
    718          */
    719         abstract int getFrameCount();
    720 
    721         /**
    722          * Returns the number of elements in each frame. This directly affects
    723          * the number of series drawn in the graph.
    724          */
    725         abstract int getElementCount();
    726 
    727         /**
    728          * Returns the current frame, if any. If the returned value is negative
    729          * the current frame is ignored.
    730          */
    731         abstract int getCurrentFrame();
    732 
    733         /**
    734          * Prepares the paint to draw the specified element (or series.)
    735          */
    736         abstract void setupGraphPaint(Paint paint, int elementIndex);
    737 
    738         /**
    739          * Prepares the paint to draw the threshold.
    740          */
    741         abstract void setupThresholdPaint(Paint paint);
    742 
    743         /**
    744          * Prepares the paint to draw the current frame indicator.
    745          */
    746         abstract void setupCurrentFramePaint(Paint paint);
    747     }
    748 
    749     @SuppressWarnings({"deprecation"})
    750     static abstract class GlRenderer extends HardwareRenderer {
    751         static final int SURFACE_STATE_ERROR = 0;
    752         static final int SURFACE_STATE_SUCCESS = 1;
    753         static final int SURFACE_STATE_UPDATED = 2;
    754 
    755         static final int FUNCTOR_PROCESS_DELAY = 4;
    756 
    757         private static final int PROFILE_DRAW_MARGIN = 0;
    758         private static final int PROFILE_DRAW_WIDTH = 3;
    759         private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
    760         private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
    761         private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
    762         private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
    763         private static final int PROFILE_DRAW_DP_PER_MS = 7;
    764 
    765         static EGL10 sEgl;
    766         static EGLDisplay sEglDisplay;
    767         static EGLConfig sEglConfig;
    768         static final Object[] sEglLock = new Object[0];
    769         int mWidth = -1, mHeight = -1;
    770 
    771         static final ThreadLocal<ManagedEGLContext> sEglContextStorage
    772                 = new ThreadLocal<ManagedEGLContext>();
    773 
    774         EGLContext mEglContext;
    775         Thread mEglThread;
    776 
    777         EGLSurface mEglSurface;
    778 
    779         GL mGl;
    780         HardwareCanvas mCanvas;
    781 
    782         String mName;
    783 
    784         long mFrameCount;
    785         Paint mDebugPaint;
    786 
    787         static boolean sDirtyRegions;
    788         static final boolean sDirtyRegionsRequested;
    789         static {
    790             String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
    791             //noinspection PointlessBooleanExpression,ConstantConditions
    792             sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
    793             sDirtyRegionsRequested = sDirtyRegions;
    794         }
    795 
    796         boolean mDirtyRegionsEnabled;
    797         boolean mUpdateDirtyRegions;
    798 
    799         boolean mProfileEnabled;
    800         int mProfileVisualizerType = -1;
    801         float[] mProfileData;
    802         ReentrantLock mProfileLock;
    803         int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
    804 
    805         GraphDataProvider mDebugDataProvider;
    806         float[][] mProfileShapes;
    807         Paint mProfilePaint;
    808 
    809         boolean mDebugDirtyRegions;
    810         boolean mShowOverdraw;
    811 
    812         final int mGlVersion;
    813         final boolean mTranslucent;
    814 
    815         private boolean mDestroyed;
    816 
    817         private final Rect mRedrawClip = new Rect();
    818 
    819         private final int[] mSurfaceSize = new int[2];
    820         private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
    821 
    822         GlRenderer(int glVersion, boolean translucent) {
    823             mGlVersion = glVersion;
    824             mTranslucent = translucent;
    825 
    826             loadSystemProperties(null);
    827         }
    828 
    829         private static final String[] VISUALIZERS = {
    830                 PROFILE_PROPERTY_VISUALIZE_BARS,
    831                 PROFILE_PROPERTY_VISUALIZE_LINES
    832         };
    833 
    834         @Override
    835         boolean loadSystemProperties(Surface surface) {
    836             boolean value;
    837             boolean changed = false;
    838 
    839             String profiling = SystemProperties.get(PROFILE_PROPERTY);
    840             int graphType = Arrays.binarySearch(VISUALIZERS, profiling);
    841             value = graphType >= 0;
    842 
    843             if (graphType != mProfileVisualizerType) {
    844                 changed = true;
    845                 mProfileVisualizerType = graphType;
    846 
    847                 mProfileShapes = null;
    848                 mProfilePaint = null;
    849 
    850                 if (value) {
    851                     mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
    852                 } else {
    853                     mDebugDataProvider = null;
    854                 }
    855             }
    856 
    857             // If on-screen profiling is not enabled, we need to check whether
    858             // console profiling only is enabled
    859             if (!value) {
    860                 value = Boolean.parseBoolean(profiling);
    861             }
    862 
    863             if (value != mProfileEnabled) {
    864                 changed = true;
    865                 mProfileEnabled = value;
    866 
    867                 if (mProfileEnabled) {
    868                     Log.d(LOG_TAG, "Profiling hardware renderer");
    869 
    870                     int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
    871                             PROFILE_MAX_FRAMES);
    872                     mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
    873                     for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
    874                         mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
    875                     }
    876 
    877                     mProfileLock = new ReentrantLock();
    878                 } else {
    879                     mProfileData = null;
    880                     mProfileLock = null;
    881                     mProfileVisualizerType = -1;
    882                 }
    883 
    884                 mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
    885             }
    886 
    887             value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
    888             if (value != mDebugDirtyRegions) {
    889                 changed = true;
    890                 mDebugDirtyRegions = value;
    891 
    892                 if (mDebugDirtyRegions) {
    893                     Log.d(LOG_TAG, "Debugging dirty regions");
    894                 }
    895             }
    896 
    897             value = SystemProperties.getBoolean(
    898                     HardwareRenderer.DEBUG_SHOW_OVERDRAW_PROPERTY, false);
    899             if (value != mShowOverdraw) {
    900                 changed = true;
    901                 mShowOverdraw = value;
    902             }
    903 
    904             if (nLoadProperties()) {
    905                 changed = true;
    906             }
    907 
    908             return changed;
    909         }
    910 
    911         @Override
    912         void dumpGfxInfo(PrintWriter pw) {
    913             if (mProfileEnabled) {
    914                 pw.printf("\n\tDraw\tProcess\tExecute\n");
    915 
    916                 mProfileLock.lock();
    917                 try {
    918                     for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
    919                         if (mProfileData[i] < 0) {
    920                             break;
    921                         }
    922                         pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
    923                                 mProfileData[i + 2]);
    924                         mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
    925                     }
    926                     mProfileCurrentFrame = mProfileData.length;
    927                 } finally {
    928                     mProfileLock.unlock();
    929                 }
    930             }
    931         }
    932 
    933         @Override
    934         long getFrameCount() {
    935             return mFrameCount;
    936         }
    937 
    938         /**
    939          * Indicates whether this renderer instance can track and update dirty regions.
    940          */
    941         boolean hasDirtyRegions() {
    942             return mDirtyRegionsEnabled;
    943         }
    944 
    945         /**
    946          * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
    947          * is invoked and the requested flag is turned off. The error code is
    948          * also logged as a warning.
    949          */
    950         void checkEglErrors() {
    951             if (isEnabled()) {
    952                 checkEglErrorsForced();
    953             }
    954         }
    955 
    956         private void checkEglErrorsForced() {
    957             int error = sEgl.eglGetError();
    958             if (error != EGL_SUCCESS) {
    959                 // something bad has happened revert to
    960                 // normal rendering.
    961                 Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
    962                 fallback(error != EGL11.EGL_CONTEXT_LOST);
    963             }
    964         }
    965 
    966         private void fallback(boolean fallback) {
    967             destroy(true);
    968             if (fallback) {
    969                 // we'll try again if it was context lost
    970                 setRequested(false);
    971                 Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
    972                         + "Switching back to software rendering.");
    973             }
    974         }
    975 
    976         @Override
    977         boolean initialize(Surface surface) throws Surface.OutOfResourcesException {
    978             if (isRequested() && !isEnabled()) {
    979                 initializeEgl();
    980                 mGl = createEglSurface(surface);
    981                 mDestroyed = false;
    982 
    983                 if (mGl != null) {
    984                     int err = sEgl.eglGetError();
    985                     if (err != EGL_SUCCESS) {
    986                         destroy(true);
    987                         setRequested(false);
    988                     } else {
    989                         if (mCanvas == null) {
    990                             mCanvas = createCanvas();
    991                             mCanvas.setName(mName);
    992                         }
    993                         setEnabled(true);
    994                     }
    995 
    996                     return mCanvas != null;
    997                 }
    998             }
    999             return false;
   1000         }
   1001 
   1002         @Override
   1003         void updateSurface(Surface surface) throws Surface.OutOfResourcesException {
   1004             if (isRequested() && isEnabled()) {
   1005                 createEglSurface(surface);
   1006             }
   1007         }
   1008 
   1009         abstract HardwareCanvas createCanvas();
   1010 
   1011         abstract int[] getConfig(boolean dirtyRegions);
   1012 
   1013         void initializeEgl() {
   1014             synchronized (sEglLock) {
   1015                 if (sEgl == null && sEglConfig == null) {
   1016                     sEgl = (EGL10) EGLContext.getEGL();
   1017 
   1018                     // Get to the default display.
   1019                     sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
   1020 
   1021                     if (sEglDisplay == EGL_NO_DISPLAY) {
   1022                         throw new RuntimeException("eglGetDisplay failed "
   1023                                 + GLUtils.getEGLErrorString(sEgl.eglGetError()));
   1024                     }
   1025 
   1026                     // We can now initialize EGL for that display
   1027                     int[] version = new int[2];
   1028                     if (!sEgl.eglInitialize(sEglDisplay, version)) {
   1029                         throw new RuntimeException("eglInitialize failed " +
   1030                                 GLUtils.getEGLErrorString(sEgl.eglGetError()));
   1031                     }
   1032 
   1033                     checkEglErrorsForced();
   1034 
   1035                     sEglConfig = loadEglConfig();
   1036                 }
   1037             }
   1038 
   1039             ManagedEGLContext managedContext = sEglContextStorage.get();
   1040             mEglContext = managedContext != null ? managedContext.getContext() : null;
   1041             mEglThread = Thread.currentThread();
   1042 
   1043             if (mEglContext == null) {
   1044                 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
   1045                 sEglContextStorage.set(createManagedContext(mEglContext));
   1046             }
   1047         }
   1048 
   1049         private EGLConfig loadEglConfig() {
   1050             EGLConfig eglConfig = chooseEglConfig();
   1051             if (eglConfig == null) {
   1052                 // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
   1053                 if (sDirtyRegions) {
   1054                     sDirtyRegions = false;
   1055                     eglConfig = chooseEglConfig();
   1056                     if (eglConfig == null) {
   1057                         throw new RuntimeException("eglConfig not initialized");
   1058                     }
   1059                 } else {
   1060                     throw new RuntimeException("eglConfig not initialized");
   1061                 }
   1062             }
   1063             return eglConfig;
   1064         }
   1065 
   1066         abstract ManagedEGLContext createManagedContext(EGLContext eglContext);
   1067 
   1068         private EGLConfig chooseEglConfig() {
   1069             EGLConfig[] configs = new EGLConfig[1];
   1070             int[] configsCount = new int[1];
   1071             int[] configSpec = getConfig(sDirtyRegions);
   1072 
   1073             // Debug
   1074             final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
   1075             if ("all".equalsIgnoreCase(debug)) {
   1076                 sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
   1077 
   1078                 EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
   1079                 sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
   1080                         configsCount[0], configsCount);
   1081 
   1082                 for (EGLConfig config : debugConfigs) {
   1083                     printConfig(config);
   1084                 }
   1085             }
   1086 
   1087             if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
   1088                 throw new IllegalArgumentException("eglChooseConfig failed " +
   1089                         GLUtils.getEGLErrorString(sEgl.eglGetError()));
   1090             } else if (configsCount[0] > 0) {
   1091                 if ("choice".equalsIgnoreCase(debug)) {
   1092                     printConfig(configs[0]);
   1093                 }
   1094                 return configs[0];
   1095             }
   1096 
   1097             return null;
   1098         }
   1099 
   1100         private static void printConfig(EGLConfig config) {
   1101             int[] value = new int[1];
   1102 
   1103             Log.d(LOG_TAG, "EGL configuration " + config + ":");
   1104 
   1105             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
   1106             Log.d(LOG_TAG, "  RED_SIZE = " + value[0]);
   1107 
   1108             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
   1109             Log.d(LOG_TAG, "  GREEN_SIZE = " + value[0]);
   1110 
   1111             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
   1112             Log.d(LOG_TAG, "  BLUE_SIZE = " + value[0]);
   1113 
   1114             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
   1115             Log.d(LOG_TAG, "  ALPHA_SIZE = " + value[0]);
   1116 
   1117             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
   1118             Log.d(LOG_TAG, "  DEPTH_SIZE = " + value[0]);
   1119 
   1120             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
   1121             Log.d(LOG_TAG, "  STENCIL_SIZE = " + value[0]);
   1122 
   1123             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
   1124             Log.d(LOG_TAG, "  SAMPLE_BUFFERS = " + value[0]);
   1125 
   1126             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
   1127             Log.d(LOG_TAG, "  SAMPLES = " + value[0]);
   1128 
   1129             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
   1130             Log.d(LOG_TAG, "  SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
   1131 
   1132             sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
   1133             Log.d(LOG_TAG, "  CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
   1134         }
   1135 
   1136         GL createEglSurface(Surface surface) throws Surface.OutOfResourcesException {
   1137             // Check preconditions.
   1138             if (sEgl == null) {
   1139                 throw new RuntimeException("egl not initialized");
   1140             }
   1141             if (sEglDisplay == null) {
   1142                 throw new RuntimeException("eglDisplay not initialized");
   1143             }
   1144             if (sEglConfig == null) {
   1145                 throw new RuntimeException("eglConfig not initialized");
   1146             }
   1147             if (Thread.currentThread() != mEglThread) {
   1148                 throw new IllegalStateException("HardwareRenderer cannot be used "
   1149                         + "from multiple threads");
   1150             }
   1151 
   1152             // In case we need to destroy an existing surface
   1153             destroySurface();
   1154 
   1155             // Create an EGL surface we can render into.
   1156             if (!createSurface(surface)) {
   1157                 return null;
   1158             }
   1159 
   1160             initCaches();
   1161 
   1162             return mEglContext.getGL();
   1163         }
   1164 
   1165         private void enableDirtyRegions() {
   1166             // If mDirtyRegions is set, this means we have an EGL configuration
   1167             // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
   1168             if (sDirtyRegions) {
   1169                 if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
   1170                     Log.w(LOG_TAG, "Backbuffer cannot be preserved");
   1171                 }
   1172             } else if (sDirtyRegionsRequested) {
   1173                 // If mDirtyRegions is not set, our EGL configuration does not
   1174                 // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
   1175                 // swap behavior might be EGL_BUFFER_PRESERVED, which means we
   1176                 // want to set mDirtyRegions. We try to do this only if dirty
   1177                 // regions were initially requested as part of the device
   1178                 // configuration (see RENDER_DIRTY_REGIONS)
   1179                 mDirtyRegionsEnabled = isBackBufferPreserved();
   1180             }
   1181         }
   1182 
   1183         abstract void initCaches();
   1184 
   1185         EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
   1186             int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
   1187 
   1188             EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
   1189                     mGlVersion != 0 ? attribs : null);
   1190             if (context == null || context == EGL_NO_CONTEXT) {
   1191                 //noinspection ConstantConditions
   1192                 throw new IllegalStateException(
   1193                         "Could not create an EGL context. eglCreateContext failed with error: " +
   1194                         GLUtils.getEGLErrorString(sEgl.eglGetError()));
   1195             }
   1196             return context;
   1197         }
   1198 
   1199         @Override
   1200         void destroy(boolean full) {
   1201             if (full && mCanvas != null) {
   1202                 mCanvas = null;
   1203             }
   1204 
   1205             if (!isEnabled() || mDestroyed) {
   1206                 setEnabled(false);
   1207                 return;
   1208             }
   1209 
   1210             destroySurface();
   1211             setEnabled(false);
   1212 
   1213             mDestroyed = true;
   1214             mGl = null;
   1215         }
   1216 
   1217         void destroySurface() {
   1218             if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
   1219                 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   1220                 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
   1221                 mEglSurface = null;
   1222             }
   1223         }
   1224 
   1225         @Override
   1226         void invalidate(Surface surface) {
   1227             // Cancels any existing buffer to ensure we'll get a buffer
   1228             // of the right size before we call eglSwapBuffers
   1229             sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   1230 
   1231             if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
   1232                 sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
   1233                 mEglSurface = null;
   1234                 setEnabled(false);
   1235             }
   1236 
   1237             if (surface.isValid()) {
   1238                 if (!createSurface(surface)) {
   1239                     return;
   1240                 }
   1241 
   1242                 mUpdateDirtyRegions = true;
   1243 
   1244                 if (mCanvas != null) {
   1245                     setEnabled(true);
   1246                 }
   1247             }
   1248         }
   1249 
   1250         private boolean createSurface(Surface surface) {
   1251             mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
   1252 
   1253             if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
   1254                 int error = sEgl.eglGetError();
   1255                 if (error == EGL_BAD_NATIVE_WINDOW) {
   1256                     Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
   1257                     return false;
   1258                 }
   1259                 throw new RuntimeException("createWindowSurface failed "
   1260                         + GLUtils.getEGLErrorString(error));
   1261             }
   1262 
   1263             if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
   1264                 throw new IllegalStateException("eglMakeCurrent failed " +
   1265                         GLUtils.getEGLErrorString(sEgl.eglGetError()));
   1266             }
   1267 
   1268             enableDirtyRegions();
   1269 
   1270             return true;
   1271         }
   1272 
   1273         @Override
   1274         boolean validate() {
   1275             return checkCurrent() != SURFACE_STATE_ERROR;
   1276         }
   1277 
   1278         @Override
   1279         void setup(int width, int height) {
   1280             if (validate()) {
   1281                 mCanvas.setViewport(width, height);
   1282                 mWidth = width;
   1283                 mHeight = height;
   1284             }
   1285         }
   1286 
   1287         @Override
   1288         int getWidth() {
   1289             return mWidth;
   1290         }
   1291 
   1292         @Override
   1293         int getHeight() {
   1294             return mHeight;
   1295         }
   1296 
   1297         @Override
   1298         HardwareCanvas getCanvas() {
   1299             return mCanvas;
   1300         }
   1301 
   1302         @Override
   1303         void setName(String name) {
   1304             mName = name;
   1305         }
   1306 
   1307         boolean canDraw() {
   1308             return mGl != null && mCanvas != null;
   1309         }
   1310 
   1311         int onPreDraw(Rect dirty) {
   1312             return DisplayList.STATUS_DONE;
   1313         }
   1314 
   1315         void onPostDraw() {
   1316         }
   1317 
   1318         class FunctorsRunnable implements Runnable {
   1319             View.AttachInfo attachInfo;
   1320 
   1321             @Override
   1322             public void run() {
   1323                 final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
   1324                 if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
   1325                     return;
   1326                 }
   1327 
   1328                 final int surfaceState = checkCurrent();
   1329                 if (surfaceState != SURFACE_STATE_ERROR) {
   1330                     int status = mCanvas.invokeFunctors(mRedrawClip);
   1331                     handleFunctorStatus(attachInfo, status);
   1332                 }
   1333             }
   1334         }
   1335 
   1336         @Override
   1337         void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
   1338                 Rect dirty) {
   1339             if (canDraw()) {
   1340                 if (!hasDirtyRegions()) {
   1341                     dirty = null;
   1342                 }
   1343                 attachInfo.mIgnoreDirtyState = true;
   1344                 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
   1345 
   1346                 view.mPrivateFlags |= View.PFLAG_DRAWN;
   1347 
   1348                 final int surfaceState = checkCurrent();
   1349                 if (surfaceState != SURFACE_STATE_ERROR) {
   1350                     HardwareCanvas canvas = mCanvas;
   1351                     attachInfo.mHardwareCanvas = canvas;
   1352 
   1353                     if (mProfileEnabled) {
   1354                         mProfileLock.lock();
   1355                     }
   1356 
   1357                     dirty = beginFrame(canvas, dirty, surfaceState);
   1358 
   1359                     DisplayList displayList = buildDisplayList(view, canvas);
   1360 
   1361                     int saveCount = 0;
   1362                     int status = DisplayList.STATUS_DONE;
   1363 
   1364                     try {
   1365                         status = prepareFrame(dirty);
   1366 
   1367                         saveCount = canvas.save();
   1368                         callbacks.onHardwarePreDraw(canvas);
   1369 
   1370                         if (displayList != null) {
   1371                             status |= drawDisplayList(attachInfo, canvas, displayList, status);
   1372                         } else {
   1373                             // Shouldn't reach here
   1374                             view.draw(canvas);
   1375                         }
   1376                     } catch (Exception e) {
   1377                         Log.e(LOG_TAG, "An error has occurred while drawing:", e);
   1378                     } finally {
   1379                         callbacks.onHardwarePostDraw(canvas);
   1380                         canvas.restoreToCount(saveCount);
   1381                         view.mRecreateDisplayList = false;
   1382 
   1383                         mFrameCount++;
   1384 
   1385                         debugDirtyRegions(dirty, canvas);
   1386                         drawProfileData(attachInfo);
   1387                     }
   1388 
   1389                     onPostDraw();
   1390 
   1391                     swapBuffers(status);
   1392 
   1393                     if (mProfileEnabled) {
   1394                         mProfileLock.unlock();
   1395                     }
   1396 
   1397                     attachInfo.mIgnoreDirtyState = false;
   1398                 }
   1399             }
   1400         }
   1401 
   1402         private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
   1403             view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
   1404                     == View.PFLAG_INVALIDATED;
   1405             view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
   1406 
   1407             long buildDisplayListStartTime = startBuildDisplayListProfiling();
   1408             canvas.clearLayerUpdates();
   1409 
   1410             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
   1411             DisplayList displayList = view.getDisplayList();
   1412             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   1413 
   1414             endBuildDisplayListProfiling(buildDisplayListStartTime);
   1415 
   1416             return displayList;
   1417         }
   1418 
   1419         abstract void drawProfileData(View.AttachInfo attachInfo);
   1420 
   1421         private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
   1422             // We had to change the current surface and/or context, redraw everything
   1423             if (surfaceState == SURFACE_STATE_UPDATED) {
   1424                 dirty = null;
   1425                 beginFrame(null);
   1426             } else {
   1427                 int[] size = mSurfaceSize;
   1428                 beginFrame(size);
   1429 
   1430                 if (size[1] != mHeight || size[0] != mWidth) {
   1431                     mWidth = size[0];
   1432                     mHeight = size[1];
   1433 
   1434                     canvas.setViewport(mWidth, mHeight);
   1435 
   1436                     dirty = null;
   1437                 }
   1438             }
   1439 
   1440             if (mDebugDataProvider != null) dirty = null;
   1441 
   1442             return dirty;
   1443         }
   1444 
   1445         private long startBuildDisplayListProfiling() {
   1446             if (mProfileEnabled) {
   1447                 mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
   1448                 if (mProfileCurrentFrame >= mProfileData.length) {
   1449                     mProfileCurrentFrame = 0;
   1450                 }
   1451 
   1452                 return System.nanoTime();
   1453             }
   1454             return 0;
   1455         }
   1456 
   1457         private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
   1458             if (mProfileEnabled) {
   1459                 long now = System.nanoTime();
   1460                 float total = (now - getDisplayListStartTime) * 0.000001f;
   1461                 //noinspection PointlessArithmeticExpression
   1462                 mProfileData[mProfileCurrentFrame] = total;
   1463             }
   1464         }
   1465 
   1466         private int prepareFrame(Rect dirty) {
   1467             int status;
   1468             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
   1469             try {
   1470                 status = onPreDraw(dirty);
   1471             } finally {
   1472                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   1473             }
   1474             return status;
   1475         }
   1476 
   1477         private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
   1478                 DisplayList displayList, int status) {
   1479 
   1480             long drawDisplayListStartTime = 0;
   1481             if (mProfileEnabled) {
   1482                 drawDisplayListStartTime = System.nanoTime();
   1483             }
   1484 
   1485             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
   1486             try {
   1487                 status |= canvas.drawDisplayList(displayList, mRedrawClip,
   1488                         DisplayList.FLAG_CLIP_CHILDREN);
   1489             } finally {
   1490                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   1491             }
   1492 
   1493             if (mProfileEnabled) {
   1494                 long now = System.nanoTime();
   1495                 float total = (now - drawDisplayListStartTime) * 0.000001f;
   1496                 mProfileData[mProfileCurrentFrame + 1] = total;
   1497             }
   1498 
   1499             handleFunctorStatus(attachInfo, status);
   1500             return status;
   1501         }
   1502 
   1503         private void swapBuffers(int status) {
   1504             if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
   1505                 long eglSwapBuffersStartTime = 0;
   1506                 if (mProfileEnabled) {
   1507                     eglSwapBuffersStartTime = System.nanoTime();
   1508                 }
   1509 
   1510                 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
   1511 
   1512                 if (mProfileEnabled) {
   1513                     long now = System.nanoTime();
   1514                     float total = (now - eglSwapBuffersStartTime) * 0.000001f;
   1515                     mProfileData[mProfileCurrentFrame + 2] = total;
   1516                 }
   1517 
   1518                 checkEglErrors();
   1519             }
   1520         }
   1521 
   1522         private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
   1523             if (mDebugDirtyRegions) {
   1524                 if (mDebugPaint == null) {
   1525                     mDebugPaint = new Paint();
   1526                     mDebugPaint.setColor(0x7fff0000);
   1527                 }
   1528 
   1529                 if (dirty != null && (mFrameCount & 1) == 0) {
   1530                     canvas.drawRect(dirty, mDebugPaint);
   1531                 }
   1532             }
   1533         }
   1534 
   1535         private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
   1536             // If the draw flag is set, functors will be invoked while executing
   1537             // the tree of display lists
   1538             if ((status & DisplayList.STATUS_DRAW) != 0) {
   1539                 if (mRedrawClip.isEmpty()) {
   1540                     attachInfo.mViewRootImpl.invalidate();
   1541                 } else {
   1542                     attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
   1543                     mRedrawClip.setEmpty();
   1544                 }
   1545             }
   1546 
   1547             if ((status & DisplayList.STATUS_INVOKE) != 0 ||
   1548                     attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
   1549                 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
   1550                 mFunctorsRunnable.attachInfo = attachInfo;
   1551                 attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
   1552             }
   1553         }
   1554 
   1555         @Override
   1556         void detachFunctor(int functor) {
   1557             if (mCanvas != null) {
   1558                 mCanvas.detachFunctor(functor);
   1559             }
   1560         }
   1561 
   1562         @Override
   1563         boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
   1564             if (mCanvas != null) {
   1565                 mCanvas.attachFunctor(functor);
   1566                 mFunctorsRunnable.attachInfo = attachInfo;
   1567                 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
   1568                 attachInfo.mHandler.postDelayed(mFunctorsRunnable,  0);
   1569                 return true;
   1570             }
   1571             return false;
   1572         }
   1573 
   1574         /**
   1575          * Ensures the current EGL context is the one we expect.
   1576          *
   1577          * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
   1578          *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
   1579          *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
   1580          */
   1581         int checkCurrent() {
   1582             if (mEglThread != Thread.currentThread()) {
   1583                 throw new IllegalStateException("Hardware acceleration can only be used with a " +
   1584                         "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
   1585                         "Current thread: " + Thread.currentThread());
   1586             }
   1587 
   1588             if (!mEglContext.equals(sEgl.eglGetCurrentContext()) ||
   1589                     !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
   1590                 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
   1591                     Log.e(LOG_TAG, "eglMakeCurrent failed " +
   1592                             GLUtils.getEGLErrorString(sEgl.eglGetError()));
   1593                     fallback(true);
   1594                     return SURFACE_STATE_ERROR;
   1595                 } else {
   1596                     if (mUpdateDirtyRegions) {
   1597                         enableDirtyRegions();
   1598                         mUpdateDirtyRegions = false;
   1599                     }
   1600                     return SURFACE_STATE_UPDATED;
   1601                 }
   1602             }
   1603             return SURFACE_STATE_SUCCESS;
   1604         }
   1605 
   1606         private static int dpToPx(int dp, float density) {
   1607             return (int) (dp * density + 0.5f);
   1608         }
   1609 
   1610         class DrawPerformanceDataProvider extends GraphDataProvider {
   1611             private final int mGraphType;
   1612 
   1613             private int mVerticalUnit;
   1614             private int mHorizontalUnit;
   1615             private int mHorizontalMargin;
   1616             private int mThresholdStroke;
   1617 
   1618             DrawPerformanceDataProvider(int graphType) {
   1619                 mGraphType = graphType;
   1620             }
   1621 
   1622             @Override
   1623             void prepare(DisplayMetrics metrics) {
   1624                 final float density = metrics.density;
   1625 
   1626                 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
   1627                 mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
   1628                 mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
   1629                 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
   1630             }
   1631 
   1632             @Override
   1633             int getGraphType() {
   1634                 return mGraphType;
   1635             }
   1636 
   1637             @Override
   1638             int getVerticalUnitSize() {
   1639                 return mVerticalUnit;
   1640             }
   1641 
   1642             @Override
   1643             int getHorizontalUnitSize() {
   1644                 return mHorizontalUnit;
   1645             }
   1646 
   1647             @Override
   1648             int getHorizontaUnitMargin() {
   1649                 return mHorizontalMargin;
   1650             }
   1651 
   1652             @Override
   1653             float[] getData() {
   1654                 return mProfileData;
   1655             }
   1656 
   1657             @Override
   1658             float getThreshold() {
   1659                 return 16;
   1660             }
   1661 
   1662             @Override
   1663             int getFrameCount() {
   1664                 return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
   1665             }
   1666 
   1667             @Override
   1668             int getElementCount() {
   1669                 return PROFILE_FRAME_DATA_COUNT;
   1670             }
   1671 
   1672             @Override
   1673             int getCurrentFrame() {
   1674                 return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
   1675             }
   1676 
   1677             @Override
   1678             void setupGraphPaint(Paint paint, int elementIndex) {
   1679                 paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
   1680                 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
   1681             }
   1682 
   1683             @Override
   1684             void setupThresholdPaint(Paint paint) {
   1685                 paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
   1686                 paint.setStrokeWidth(mThresholdStroke);
   1687             }
   1688 
   1689             @Override
   1690             void setupCurrentFramePaint(Paint paint) {
   1691                 paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
   1692                 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
   1693             }
   1694         }
   1695     }
   1696 
   1697     /**
   1698      * Hardware renderer using OpenGL ES 2.0.
   1699      */
   1700     static class Gl20Renderer extends GlRenderer {
   1701         private GLES20Canvas mGlCanvas;
   1702 
   1703         private DisplayMetrics mDisplayMetrics;
   1704 
   1705         private static EGLSurface sPbuffer;
   1706         private static final Object[] sPbufferLock = new Object[0];
   1707 
   1708         static class Gl20RendererEglContext extends ManagedEGLContext {
   1709             final Handler mHandler = new Handler();
   1710 
   1711             public Gl20RendererEglContext(EGLContext context) {
   1712                 super(context);
   1713             }
   1714 
   1715             @Override
   1716             public void onTerminate(final EGLContext eglContext) {
   1717                 // Make sure we do this on the correct thread.
   1718                 if (mHandler.getLooper() != Looper.myLooper()) {
   1719                     mHandler.post(new Runnable() {
   1720                         @Override
   1721                         public void run() {
   1722                             onTerminate(eglContext);
   1723                         }
   1724                     });
   1725                     return;
   1726                 }
   1727 
   1728                 synchronized (sEglLock) {
   1729                     if (sEgl == null) return;
   1730 
   1731                     if (EGLImpl.getInitCount(sEglDisplay) == 1) {
   1732                         usePbufferSurface(eglContext);
   1733                         GLES20Canvas.terminateCaches();
   1734 
   1735                         sEgl.eglDestroyContext(sEglDisplay, eglContext);
   1736                         sEglContextStorage.set(null);
   1737                         sEglContextStorage.remove();
   1738 
   1739                         sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
   1740                         sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
   1741                                 EGL_NO_SURFACE, EGL_NO_CONTEXT);
   1742 
   1743                         sEgl.eglReleaseThread();
   1744                         sEgl.eglTerminate(sEglDisplay);
   1745 
   1746                         sEgl = null;
   1747                         sEglDisplay = null;
   1748                         sEglConfig = null;
   1749                         sPbuffer = null;
   1750                     }
   1751                 }
   1752             }
   1753         }
   1754 
   1755         Gl20Renderer(boolean translucent) {
   1756             super(2, translucent);
   1757         }
   1758 
   1759         @Override
   1760         HardwareCanvas createCanvas() {
   1761             return mGlCanvas = new GLES20Canvas(mTranslucent);
   1762         }
   1763 
   1764         @Override
   1765         ManagedEGLContext createManagedContext(EGLContext eglContext) {
   1766             return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
   1767         }
   1768 
   1769         @Override
   1770         int[] getConfig(boolean dirtyRegions) {
   1771             //noinspection PointlessBooleanExpression,ConstantConditions
   1772             final int stencilSize = GLES20Canvas.getStencilSize();
   1773             final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
   1774 
   1775             return new int[] {
   1776                     EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
   1777                     EGL_RED_SIZE, 8,
   1778                     EGL_GREEN_SIZE, 8,
   1779                     EGL_BLUE_SIZE, 8,
   1780                     EGL_ALPHA_SIZE, 8,
   1781                     EGL_DEPTH_SIZE, 0,
   1782                     EGL_CONFIG_CAVEAT, EGL_NONE,
   1783                     EGL_STENCIL_SIZE, stencilSize,
   1784                     EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
   1785                     EGL_NONE
   1786             };
   1787         }
   1788 
   1789         @Override
   1790         void initCaches() {
   1791             GLES20Canvas.initCaches();
   1792         }
   1793 
   1794         @Override
   1795         boolean canDraw() {
   1796             return super.canDraw() && mGlCanvas != null;
   1797         }
   1798 
   1799         @Override
   1800         int onPreDraw(Rect dirty) {
   1801             return mGlCanvas.onPreDraw(dirty);
   1802         }
   1803 
   1804         @Override
   1805         void onPostDraw() {
   1806             mGlCanvas.onPostDraw();
   1807         }
   1808 
   1809         @Override
   1810         void drawProfileData(View.AttachInfo attachInfo) {
   1811             if (mDebugDataProvider != null) {
   1812                 final GraphDataProvider provider = mDebugDataProvider;
   1813                 initProfileDrawData(attachInfo, provider);
   1814 
   1815                 final int height = provider.getVerticalUnitSize();
   1816                 final int margin = provider.getHorizontaUnitMargin();
   1817                 final int width = provider.getHorizontalUnitSize();
   1818 
   1819                 int x = 0;
   1820                 int count = 0;
   1821                 int current = 0;
   1822 
   1823                 final float[] data = provider.getData();
   1824                 final int elementCount = provider.getElementCount();
   1825                 final int graphType = provider.getGraphType();
   1826 
   1827                 int totalCount = provider.getFrameCount() * elementCount;
   1828                 if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
   1829                     totalCount -= elementCount;
   1830                 }
   1831 
   1832                 for (int i = 0; i < totalCount; i += elementCount) {
   1833                     if (data[i] < 0.0f) break;
   1834 
   1835                     int index = count * 4;
   1836                     if (i == provider.getCurrentFrame() * elementCount) current = index;
   1837 
   1838                     x += margin;
   1839                     int x2 = x + width;
   1840 
   1841                     int y2 = mHeight;
   1842                     int y1 = (int) (y2 - data[i] * height);
   1843 
   1844                     switch (graphType) {
   1845                         case GraphDataProvider.GRAPH_TYPE_BARS: {
   1846                             for (int j = 0; j < elementCount; j++) {
   1847                                 //noinspection MismatchedReadAndWriteOfArray
   1848                                 final float[] r = mProfileShapes[j];
   1849                                 r[index] = x;
   1850                                 r[index + 1] = y1;
   1851                                 r[index + 2] = x2;
   1852                                 r[index + 3] = y2;
   1853 
   1854                                 y2 = y1;
   1855                                 if (j < elementCount - 1) {
   1856                                     y1 = (int) (y2 - data[i + j + 1] * height);
   1857                                 }
   1858                             }
   1859                         } break;
   1860                         case GraphDataProvider.GRAPH_TYPE_LINES: {
   1861                             for (int j = 0; j < elementCount; j++) {
   1862                                 //noinspection MismatchedReadAndWriteOfArray
   1863                                 final float[] r = mProfileShapes[j];
   1864                                 r[index] = (x + x2) * 0.5f;
   1865                                 r[index + 1] = index == 0 ? y1 : r[index - 1];
   1866                                 r[index + 2] = r[index] + width;
   1867                                 r[index + 3] = y1;
   1868 
   1869                                 y2 = y1;
   1870                                 if (j < elementCount - 1) {
   1871                                     y1 = (int) (y2 - data[i + j + 1] * height);
   1872                                 }
   1873                             }
   1874                         } break;
   1875                     }
   1876 
   1877 
   1878                     x += width;
   1879                     count++;
   1880                 }
   1881 
   1882                 x += margin;
   1883 
   1884                 drawGraph(graphType, count);
   1885                 drawCurrentFrame(graphType, current);
   1886                 drawThreshold(x, height);
   1887             }
   1888         }
   1889 
   1890         private void drawGraph(int graphType, int count) {
   1891             for (int i = 0; i < mProfileShapes.length; i++) {
   1892                 mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
   1893                 switch (graphType) {
   1894                     case GraphDataProvider.GRAPH_TYPE_BARS:
   1895                         mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
   1896                         break;
   1897                     case GraphDataProvider.GRAPH_TYPE_LINES:
   1898                         mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
   1899                         break;
   1900                 }
   1901             }
   1902         }
   1903 
   1904         private void drawCurrentFrame(int graphType, int index) {
   1905             if (index >= 0) {
   1906                 mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
   1907                 switch (graphType) {
   1908                     case GraphDataProvider.GRAPH_TYPE_BARS:
   1909                         mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
   1910                                 mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
   1911                                 mProfilePaint);
   1912                         break;
   1913                     case GraphDataProvider.GRAPH_TYPE_LINES:
   1914                         mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
   1915                                 mProfileShapes[2][index], mHeight, mProfilePaint);
   1916                         break;
   1917                 }
   1918             }
   1919         }
   1920 
   1921         private void drawThreshold(int x, int height) {
   1922             float threshold = mDebugDataProvider.getThreshold();
   1923             if (threshold > 0.0f) {
   1924                 mDebugDataProvider.setupThresholdPaint(mProfilePaint);
   1925                 int y = (int) (mHeight - threshold * height);
   1926                 mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
   1927             }
   1928         }
   1929 
   1930         private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
   1931             if (mProfileShapes == null) {
   1932                 final int elementCount = provider.getElementCount();
   1933                 final int frameCount = provider.getFrameCount();
   1934 
   1935                 mProfileShapes = new float[elementCount][];
   1936                 for (int i = 0; i < elementCount; i++) {
   1937                     mProfileShapes[i] = new float[frameCount * 4];
   1938                 }
   1939 
   1940                 mProfilePaint = new Paint();
   1941             }
   1942 
   1943             mProfilePaint.reset();
   1944             if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
   1945                 mProfilePaint.setAntiAlias(true);
   1946             }
   1947 
   1948             if (mDisplayMetrics == null) {
   1949                 mDisplayMetrics = new DisplayMetrics();
   1950             }
   1951 
   1952             attachInfo.mDisplay.getMetrics(mDisplayMetrics);
   1953             provider.prepare(mDisplayMetrics);
   1954         }
   1955 
   1956         @Override
   1957         void destroy(boolean full) {
   1958             try {
   1959                 super.destroy(full);
   1960             } finally {
   1961                 if (full && mGlCanvas != null) {
   1962                     mGlCanvas = null;
   1963                 }
   1964             }
   1965         }
   1966 
   1967         @Override
   1968         void pushLayerUpdate(HardwareLayer layer) {
   1969             mGlCanvas.pushLayerUpdate(layer);
   1970         }
   1971 
   1972         @Override
   1973         public DisplayList createDisplayList(String name) {
   1974             return new GLES20DisplayList(name);
   1975         }
   1976 
   1977         @Override
   1978         HardwareLayer createHardwareLayer(boolean isOpaque) {
   1979             return new GLES20TextureLayer(isOpaque);
   1980         }
   1981 
   1982         @Override
   1983         public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
   1984             return new GLES20RenderLayer(width, height, isOpaque);
   1985         }
   1986 
   1987         @Override
   1988         public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
   1989             return ((GLES20TextureLayer) layer).getSurfaceTexture();
   1990         }
   1991 
   1992         @Override
   1993         void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
   1994             ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
   1995         }
   1996 
   1997         @Override
   1998         boolean safelyRun(Runnable action) {
   1999             boolean needsContext = true;
   2000             if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false;
   2001 
   2002             if (needsContext) {
   2003                 Gl20RendererEglContext managedContext =
   2004                         (Gl20RendererEglContext) sEglContextStorage.get();
   2005                 if (managedContext == null) return false;
   2006                 usePbufferSurface(managedContext.getContext());
   2007             }
   2008 
   2009             try {
   2010                 action.run();
   2011             } finally {
   2012                 if (needsContext) {
   2013                     sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
   2014                             EGL_NO_SURFACE, EGL_NO_CONTEXT);
   2015                 }
   2016             }
   2017 
   2018             return true;
   2019         }
   2020 
   2021         @Override
   2022         void destroyLayers(final View view) {
   2023             if (view != null) {
   2024                 safelyRun(new Runnable() {
   2025                     @Override
   2026                     public void run() {
   2027                         if (mCanvas != null) {
   2028                             mCanvas.clearLayerUpdates();
   2029                         }
   2030                         destroyHardwareLayer(view);
   2031                         GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
   2032                     }
   2033                 });
   2034             }
   2035         }
   2036 
   2037         private static void destroyHardwareLayer(View view) {
   2038             view.destroyLayer(true);
   2039 
   2040             if (view instanceof ViewGroup) {
   2041                 ViewGroup group = (ViewGroup) view;
   2042 
   2043                 int count = group.getChildCount();
   2044                 for (int i = 0; i < count; i++) {
   2045                     destroyHardwareLayer(group.getChildAt(i));
   2046                 }
   2047             }
   2048         }
   2049 
   2050         @Override
   2051         void destroyHardwareResources(final View view) {
   2052             if (view != null) {
   2053                 safelyRun(new Runnable() {
   2054                     @Override
   2055                     public void run() {
   2056                         if (mCanvas != null) {
   2057                             mCanvas.clearLayerUpdates();
   2058                         }
   2059                         destroyResources(view);
   2060                         GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
   2061                     }
   2062                 });
   2063             }
   2064         }
   2065 
   2066         private static void destroyResources(View view) {
   2067             view.destroyHardwareResources();
   2068 
   2069             if (view instanceof ViewGroup) {
   2070                 ViewGroup group = (ViewGroup) view;
   2071 
   2072                 int count = group.getChildCount();
   2073                 for (int i = 0; i < count; i++) {
   2074                     destroyResources(group.getChildAt(i));
   2075                 }
   2076             }
   2077         }
   2078 
   2079         static HardwareRenderer create(boolean translucent) {
   2080             if (GLES20Canvas.isAvailable()) {
   2081                 return new Gl20Renderer(translucent);
   2082             }
   2083             return null;
   2084         }
   2085 
   2086         static void startTrimMemory(int level) {
   2087             if (sEgl == null || sEglConfig == null) return;
   2088 
   2089             Gl20RendererEglContext managedContext =
   2090                     (Gl20RendererEglContext) sEglContextStorage.get();
   2091             // We do not have OpenGL objects
   2092             if (managedContext == null) {
   2093                 return;
   2094             } else {
   2095                 usePbufferSurface(managedContext.getContext());
   2096             }
   2097 
   2098             if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
   2099                 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
   2100             } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
   2101                 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
   2102             }
   2103         }
   2104 
   2105         static void endTrimMemory() {
   2106             if (sEgl != null && sEglDisplay != null) {
   2107                 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   2108             }
   2109         }
   2110 
   2111         private static void usePbufferSurface(EGLContext eglContext) {
   2112             synchronized (sPbufferLock) {
   2113                 // Create a temporary 1x1 pbuffer so we have a context
   2114                 // to clear our OpenGL objects
   2115                 if (sPbuffer == null) {
   2116                     sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
   2117                             EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
   2118                     });
   2119                 }
   2120             }
   2121             sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
   2122         }
   2123     }
   2124 }
   2125