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