Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2010 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 #ifndef ANDROID_HWUI_OPENGL_RENDERER_H
     18 #define ANDROID_HWUI_OPENGL_RENDERER_H
     19 
     20 #include <GLES2/gl2.h>
     21 #include <GLES2/gl2ext.h>
     22 
     23 #include <SkBitmap.h>
     24 #include <SkMatrix.h>
     25 #include <SkPaint.h>
     26 #include <SkRegion.h>
     27 #include <SkShader.h>
     28 #include <SkXfermode.h>
     29 
     30 #include <utils/Functor.h>
     31 #include <utils/RefBase.h>
     32 #include <utils/Vector.h>
     33 
     34 #include <cutils/compiler.h>
     35 
     36 #include "Debug.h"
     37 #include "Extensions.h"
     38 #include "Matrix.h"
     39 #include "Program.h"
     40 #include "Rect.h"
     41 #include "Snapshot.h"
     42 #include "Vertex.h"
     43 #include "SkiaShader.h"
     44 #include "SkiaColorFilter.h"
     45 #include "Caches.h"
     46 
     47 namespace android {
     48 namespace uirenderer {
     49 
     50 ///////////////////////////////////////////////////////////////////////////////
     51 // Renderer
     52 ///////////////////////////////////////////////////////////////////////////////
     53 
     54 class DisplayList;
     55 
     56 /**
     57  * OpenGL renderer used to draw accelerated 2D graphics. The API is a
     58  * simplified version of Skia's Canvas API.
     59  */
     60 class OpenGLRenderer {
     61 public:
     62     ANDROID_API OpenGLRenderer();
     63     virtual ~OpenGLRenderer();
     64 
     65     virtual void setViewport(int width, int height);
     66 
     67     ANDROID_API void prepare(bool opaque);
     68     virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
     69     virtual void finish();
     70 
     71     // These two calls must not be recorded in display lists
     72     virtual void interrupt();
     73     virtual void resume();
     74 
     75     virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
     76 
     77     ANDROID_API int getSaveCount() const;
     78     virtual int save(int flags);
     79     virtual void restore();
     80     virtual void restoreToCount(int saveCount);
     81 
     82     virtual int saveLayer(float left, float top, float right, float bottom,
     83             SkPaint* p, int flags);
     84     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
     85             int alpha, int flags);
     86 
     87     virtual void translate(float dx, float dy);
     88     virtual void rotate(float degrees);
     89     virtual void scale(float sx, float sy);
     90     virtual void skew(float sx, float sy);
     91 
     92     ANDROID_API void getMatrix(SkMatrix* matrix);
     93     virtual void setMatrix(SkMatrix* matrix);
     94     virtual void concatMatrix(SkMatrix* matrix);
     95 
     96     ANDROID_API const Rect& getClipBounds();
     97     ANDROID_API bool quickReject(float left, float top, float right, float bottom);
     98     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
     99 
    100     virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
    101             Rect& dirty, uint32_t level = 0);
    102     virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
    103     virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
    104     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
    105     virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
    106     virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
    107             float srcRight, float srcBottom, float dstLeft, float dstTop,
    108             float dstRight, float dstBottom, SkPaint* paint);
    109     virtual void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
    110             float* vertices, int* colors, SkPaint* paint);
    111     virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
    112             const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
    113             float left, float top, float right, float bottom, SkPaint* paint);
    114     virtual void drawColor(int color, SkXfermode::Mode mode);
    115     virtual void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
    116     virtual void drawRoundRect(float left, float top, float right, float bottom,
    117             float rx, float ry, SkPaint* paint);
    118     virtual void drawCircle(float x, float y, float radius, SkPaint* paint);
    119     virtual void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
    120     virtual void drawArc(float left, float top, float right, float bottom,
    121             float startAngle, float sweepAngle, bool useCenter, SkPaint* paint);
    122     virtual void drawPath(SkPath* path, SkPaint* paint);
    123     virtual void drawLines(float* points, int count, SkPaint* paint);
    124     virtual void drawPoints(float* points, int count, SkPaint* paint);
    125     virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
    126             SkPaint* paint);
    127 
    128     virtual void resetShader();
    129     virtual void setupShader(SkiaShader* shader);
    130 
    131     virtual void resetColorFilter();
    132     virtual void setupColorFilter(SkiaColorFilter* filter);
    133 
    134     virtual void resetShadow();
    135     virtual void setupShadow(float radius, float dx, float dy, int color);
    136 
    137 protected:
    138     /**
    139      * Compose the layer defined in the current snapshot with the layer
    140      * defined by the previous snapshot.
    141      *
    142      * The current snapshot *must* be a layer (flag kFlagIsLayer set.)
    143      *
    144      * @param curent The current snapshot containing the layer to compose
    145      * @param previous The previous snapshot to compose the current layer with
    146      */
    147     virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
    148 
    149     /**
    150      * Marks the specified region as dirty at the specified bounds.
    151      */
    152     void dirtyLayerUnchecked(Rect& bounds, Region* region);
    153 
    154     /**
    155      * Returns the current snapshot.
    156      */
    157     sp<Snapshot> getSnapshot() {
    158         return mSnapshot;
    159     }
    160 
    161     /**
    162      * Returns the region of the current layer.
    163      */
    164     virtual Region* getRegion() {
    165         return mSnapshot->region;
    166     }
    167 
    168     /**
    169      * Indicates whether rendering is currently targeted at a layer.
    170      */
    171     virtual bool hasLayer() {
    172         return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
    173     }
    174 
    175     /**
    176      * Returns the name of the FBO this renderer is rendering into.
    177      */
    178     virtual GLint getTargetFbo() {
    179         return 0;
    180     }
    181 
    182     /**
    183      * Renders the specified layer as a textured quad.
    184      *
    185      * @param layer The layer to render
    186      * @param rect The bounds of the layer
    187      */
    188     void drawTextureLayer(Layer* layer, const Rect& rect);
    189 
    190 private:
    191     /**
    192      * Saves the current state of the renderer as a new snapshot.
    193      * The new snapshot is saved in mSnapshot and the previous snapshot
    194      * is linked from mSnapshot->previous.
    195      *
    196      * @param flags The save flags; see SkCanvas for more information
    197      *
    198      * @return The new save count. This value can be passed to #restoreToCount()
    199      */
    200     int saveSnapshot(int flags);
    201 
    202     /**
    203      * Restores the current snapshot; mSnapshot becomes mSnapshot->previous.
    204      *
    205      * @return True if the clip was modified.
    206      */
    207     bool restoreSnapshot();
    208 
    209     /**
    210      * Sets the clipping rectangle using glScissor. The clip is defined by
    211      * the current snapshot's clipRect member.
    212      */
    213     void setScissorFromClip();
    214 
    215     /**
    216      * Creates a new layer stored in the specified snapshot.
    217      *
    218      * @param snapshot The snapshot associated with the new layer
    219      * @param left The left coordinate of the layer
    220      * @param top The top coordinate of the layer
    221      * @param right The right coordinate of the layer
    222      * @param bottom The bottom coordinate of the layer
    223      * @param alpha The translucency of the layer
    224      * @param mode The blending mode of the layer
    225      * @param flags The layer save flags
    226      * @param previousFbo The name of the current framebuffer
    227      *
    228      * @return True if the layer was successfully created, false otherwise
    229      */
    230     bool createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom,
    231             int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo);
    232 
    233     /**
    234      * Creates a new layer stored in the specified snapshot as an FBO.
    235      *
    236      * @param layer The layer to store as an FBO
    237      * @param snapshot The snapshot associated with the new layer
    238      * @param bounds The bounds of the layer
    239      * @param previousFbo The name of the current framebuffer
    240      */
    241     bool createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
    242             GLuint previousFbo);
    243 
    244     /**
    245      * Compose the specified layer as a region.
    246      *
    247      * @param layer The layer to compose
    248      * @param rect The layer's bounds
    249      */
    250     void composeLayerRegion(Layer* layer, const Rect& rect);
    251 
    252     /**
    253      * Compose the specified layer as a simple rectangle.
    254      *
    255      * @param layer The layer to compose
    256      * @param rect The layer's bounds
    257      * @param swap If true, the source and destination are swapped
    258      */
    259     void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false);
    260 
    261     /**
    262      * Clears all the regions corresponding to the current list of layers.
    263      * This method MUST be invoked before any drawing operation.
    264      */
    265     void clearLayerRegions();
    266 
    267     /**
    268      * Mark the layer as dirty at the specified coordinates. The coordinates
    269      * are transformed with the supplied matrix.
    270      */
    271     void dirtyLayer(const float left, const float top,
    272             const float right, const float bottom, const mat4 transform);
    273 
    274     /**
    275      * Mark the layer as dirty at the specified coordinates.
    276      */
    277     void dirtyLayer(const float left, const float top,
    278             const float right, const float bottom);
    279 
    280     /**
    281      * Draws a colored rectangle with the specified color. The specified coordinates
    282      * are transformed by the current snapshot's transform matrix.
    283      *
    284      * @param left The left coordinate of the rectangle
    285      * @param top The top coordinate of the rectangle
    286      * @param right The right coordinate of the rectangle
    287      * @param bottom The bottom coordinate of the rectangle
    288      * @param color The rectangle's ARGB color, defined as a packed 32 bits word
    289      * @param mode The Skia xfermode to use
    290      * @param ignoreTransform True if the current transform should be ignored
    291      * @param ignoreBlending True if the blending is set by the caller
    292      */
    293     void drawColorRect(float left, float top, float right, float bottom,
    294             int color, SkXfermode::Mode mode, bool ignoreTransform = false);
    295 
    296     /**
    297      * Draws the shape represented by the specified path texture.
    298      * This method invokes drawPathTexture() but takes into account
    299      * the extra left/top offset and the texture offset to correctly
    300      * position the final shape.
    301      *
    302      * @param left The left coordinate of the shape to render
    303      * @param top The top coordinate of the shape to render
    304      * @param texture The texture reprsenting the shape
    305      * @param paint The paint to draw the shape with
    306      */
    307     void drawShape(float left, float top, const PathTexture* texture, SkPaint* paint);
    308 
    309     /**
    310      * Renders the rect defined by the specified bounds as a shape.
    311      * This will render the rect using a path texture, which is used to render
    312      * rects with stroke effects.
    313      *
    314      * @param left The left coordinate of the rect to draw
    315      * @param top The top coordinate of the rect to draw
    316      * @param right The right coordinate of the rect to draw
    317      * @param bottom The bottom coordinate of the rect to draw
    318      * @param p The paint to draw the rect with
    319      */
    320     void drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p);
    321 
    322     /**
    323      * Draws the specified texture as an alpha bitmap. Alpha bitmaps obey
    324      * different compositing rules.
    325      *
    326      * @param texture The texture to draw with
    327      * @param left The x coordinate of the bitmap
    328      * @param top The y coordinate of the bitmap
    329      * @param paint The paint to render with
    330      */
    331     void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint);
    332 
    333     /**
    334      * Renders the rect defined by the specified bounds as an anti-aliased rect.
    335      *
    336      * @param left The left coordinate of the rect to draw
    337      * @param top The top coordinate of the rect to draw
    338      * @param right The right coordinate of the rect to draw
    339      * @param bottom The bottom coordinate of the rect to draw
    340      * @param color The color of the rect
    341      * @param mode The blending mode to draw the rect
    342      */
    343     void drawAARect(float left, float top, float right, float bottom,
    344             int color, SkXfermode::Mode mode);
    345 
    346     /**
    347      * Draws a textured rectangle with the specified texture. The specified coordinates
    348      * are transformed by the current snapshot's transform matrix.
    349      *
    350      * @param left The left coordinate of the rectangle
    351      * @param top The top coordinate of the rectangle
    352      * @param right The right coordinate of the rectangle
    353      * @param bottom The bottom coordinate of the rectangle
    354      * @param texture The texture name to map onto the rectangle
    355      * @param alpha An additional translucency parameter, between 0.0f and 1.0f
    356      * @param mode The blending mode
    357      * @param blend True if the texture contains an alpha channel
    358      */
    359     void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
    360             float alpha, SkXfermode::Mode mode, bool blend);
    361 
    362     /**
    363      * Draws a textured rectangle with the specified texture. The specified coordinates
    364      * are transformed by the current snapshot's transform matrix.
    365      *
    366      * @param left The left coordinate of the rectangle
    367      * @param top The top coordinate of the rectangle
    368      * @param right The right coordinate of the rectangle
    369      * @param bottom The bottom coordinate of the rectangle
    370      * @param texture The texture to use
    371      * @param paint The paint containing the alpha, blending mode, etc.
    372      */
    373     void drawTextureRect(float left, float top, float right, float bottom,
    374             Texture* texture, SkPaint* paint);
    375 
    376     /**
    377      * Draws a textured mesh with the specified texture. If the indices are omitted,
    378      * the mesh is drawn as a simple quad. The mesh pointers become offsets when a
    379      * VBO is bound.
    380      *
    381      * @param left The left coordinate of the rectangle
    382      * @param top The top coordinate of the rectangle
    383      * @param right The right coordinate of the rectangle
    384      * @param bottom The bottom coordinate of the rectangle
    385      * @param texture The texture name to map onto the rectangle
    386      * @param alpha An additional translucency parameter, between 0.0f and 1.0f
    387      * @param mode The blending mode
    388      * @param blend True if the texture contains an alpha channel
    389      * @param vertices The vertices that define the mesh
    390      * @param texCoords The texture coordinates of each vertex
    391      * @param elementsCount The number of elements in the mesh, required by indices
    392      * @param swapSrcDst Whether or not the src and dst blending operations should be swapped
    393      * @param ignoreTransform True if the current transform should be ignored
    394      * @param vbo The VBO used to draw the mesh
    395      * @param ignoreScale True if the model view matrix should not be scaled
    396      * @param dirty True if calling this method should dirty the current layer
    397      */
    398     void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
    399             float alpha, SkXfermode::Mode mode, bool blend,
    400             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
    401             bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
    402             bool ignoreScale = false, bool dirty = true);
    403 
    404     /**
    405      * Draws text underline and strike-through if needed.
    406      *
    407      * @param text The text to decor
    408      * @param bytesCount The number of bytes in the text
    409      * @param length The length in pixels of the text, can be <= 0.0f to force a measurement
    410      * @param x The x coordinate where the text will be drawn
    411      * @param y The y coordinate where the text will be drawn
    412      * @param paint The paint to draw the text with
    413      */
    414     void drawTextDecorations(const char* text, int bytesCount, float length,
    415             float x, float y, SkPaint* paint);
    416 
    417     /**
    418      * Draws a path texture. Path textures are alpha8 bitmaps that need special
    419      * compositing to apply colors/filters/etc.
    420      *
    421      * @param texture The texture to render
    422      * @param x The x coordinate where the texture will be drawn
    423      * @param y The y coordinate where the texture will be drawn
    424      * @param paint The paint to draw the texture with
    425      */
    426     void drawPathTexture(const PathTexture* texture, float x, float y, SkPaint* paint);
    427 
    428     /**
    429      * Resets the texture coordinates stored in mMeshVertices. Setting the values
    430      * back to default is achieved by calling:
    431      *
    432      * resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
    433      *
    434      * @param u1 The left coordinate of the texture
    435      * @param v1 The bottom coordinate of the texture
    436      * @param u2 The right coordinate of the texture
    437      * @param v2 The top coordinate of the texture
    438      */
    439     void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2);
    440 
    441     /**
    442      * Gets the alpha and xfermode out of a paint object. If the paint is null
    443      * alpha will be 255 and the xfermode will be SRC_OVER.
    444      *
    445      * @param paint The paint to extract values from
    446      * @param alpha Where to store the resulting alpha
    447      * @param mode Where to store the resulting xfermode
    448      */
    449     inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
    450 
    451     /**
    452      * Binds the specified texture. The texture unit must have been selected
    453      * prior to calling this method.
    454      */
    455     inline void bindTexture(GLuint texture) {
    456         glBindTexture(GL_TEXTURE_2D, texture);
    457     }
    458 
    459     /**
    460      * Binds the specified EGLImage texture. The texture unit must have been selected
    461      * prior to calling this method.
    462      */
    463     inline void bindExternalTexture(GLuint texture) {
    464         glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
    465     }
    466 
    467     /**
    468      * Enable or disable blending as necessary. This function sets the appropriate
    469      * blend function based on the specified xfermode.
    470      */
    471     inline void chooseBlending(bool blend, SkXfermode::Mode mode, ProgramDescription& description,
    472             bool swapSrcDst = false);
    473 
    474     /**
    475      * Safely retrieves the mode from the specified xfermode. If the specified
    476      * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode.
    477      */
    478     inline SkXfermode::Mode getXfermode(SkXfermode* mode);
    479 
    480     /**
    481      * Use the specified program with the current GL context. If the program is already
    482      * in use, it will not be bound again. If it is not in use, the current program is
    483      * marked unused and the specified program becomes used and becomes the new
    484      * current program.
    485      *
    486      * @param program The program to use
    487      *
    488      * @return true If the specified program was already in use, false otherwise.
    489      */
    490     inline bool useProgram(Program* program);
    491 
    492     /**
    493      * Invoked before any drawing operation. This sets required state.
    494      */
    495     void setupDraw(bool clear = true);
    496     /**
    497      * Various methods to setup OpenGL rendering.
    498      */
    499     void setupDrawWithTexture(bool isAlpha8 = false);
    500     void setupDrawWithExternalTexture();
    501     void setupDrawAALine();
    502     void setupDrawPoint(float pointSize);
    503     void setupDrawColor(int color);
    504     void setupDrawColor(int color, int alpha);
    505     void setupDrawColor(float r, float g, float b, float a);
    506     void setupDrawAlpha8Color(int color, int alpha);
    507     void setupDrawAlpha8Color(float r, float g, float b, float a);
    508     void setupDrawShader();
    509     void setupDrawColorFilter();
    510     void setupDrawBlending(SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode,
    511             bool swapSrcDst = false);
    512     void setupDrawBlending(bool blend = true, SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode,
    513             bool swapSrcDst = false);
    514     void setupDrawProgram();
    515     void setupDrawDirtyRegionsDisabled();
    516     void setupDrawModelViewIdentity(bool offset = false);
    517     void setupDrawModelView(float left, float top, float right, float bottom,
    518             bool ignoreTransform = false, bool ignoreModelView = false);
    519     void setupDrawModelViewTranslate(float left, float top, float right, float bottom,
    520             bool ignoreTransform = false);
    521     void setupDrawPointUniforms();
    522     void setupDrawColorUniforms();
    523     void setupDrawPureColorUniforms();
    524     void setupDrawShaderIdentityUniforms();
    525     void setupDrawShaderUniforms(bool ignoreTransform = false);
    526     void setupDrawColorFilterUniforms();
    527     void setupDrawSimpleMesh();
    528     void setupDrawTexture(GLuint texture);
    529     void setupDrawExternalTexture(GLuint texture);
    530     void setupDrawTextureTransform();
    531     void setupDrawTextureTransformUniforms(mat4& transform);
    532     void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
    533     void setupDrawVertices(GLvoid* vertices);
    534     void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords,
    535             float strokeWidth);
    536     void finishDrawTexture();
    537     void accountForClear(SkXfermode::Mode mode);
    538 
    539     void drawRegionRects(const Region& region);
    540 
    541     /**
    542      * Should be invoked every time the glScissor is modified.
    543      */
    544     inline void dirtyClip() {
    545         mDirtyClip = true;
    546     }
    547 
    548     // Dimensions of the drawing surface
    549     int mWidth, mHeight;
    550 
    551     // Matrix used for ortho projection in shaders
    552     mat4 mOrthoMatrix;
    553 
    554     // Model-view matrix used to position/size objects
    555     mat4 mModelView;
    556 
    557     // Number of saved states
    558     int mSaveCount;
    559     // Base state
    560     sp<Snapshot> mFirstSnapshot;
    561     // Current state
    562     sp<Snapshot> mSnapshot;
    563 
    564     // Shaders
    565     SkiaShader* mShader;
    566 
    567     // Color filters
    568     SkiaColorFilter* mColorFilter;
    569 
    570     // Used to draw textured quads
    571     TextureVertex mMeshVertices[4];
    572 
    573     // Drop shadow
    574     bool mHasShadow;
    575     float mShadowRadius;
    576     float mShadowDx;
    577     float mShadowDy;
    578     int mShadowColor;
    579 
    580     // Various caches
    581     Caches& mCaches;
    582 
    583     // List of rectagnles to clear after saveLayer() is invoked
    584     Vector<Rect*> mLayers;
    585 
    586     // Indentity matrix
    587     const mat4 mIdentity;
    588 
    589     // Indicates whether the clip must be restored
    590     bool mDirtyClip;
    591 
    592     // The following fields are used to setup drawing
    593     // Used to describe the shaders to generate
    594     ProgramDescription mDescription;
    595     // Color description
    596     bool mColorSet;
    597     float mColorA, mColorR, mColorG, mColorB;
    598     // Indicates that the shader should get a color
    599     bool mSetShaderColor;
    600     // Current texture unit
    601     GLuint mTextureUnit;
    602     // Track dirty regions, true by default
    603     bool mTrackDirtyRegions;
    604     // Texture coordinates slot
    605     int mTexCoordsSlot;
    606 
    607     friend class DisplayListRenderer;
    608 
    609 }; // class OpenGLRenderer
    610 
    611 }; // namespace uirenderer
    612 }; // namespace android
    613 
    614 #endif // ANDROID_HWUI_OPENGL_RENDERER_H
    615