Batch glCopyTexImage() calls to get about 15 fps back on SGX.

Change-Id: I04079e070739c1e46df3e90fc388c335e2a7d2b9
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6c9c0eb..5343a05 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -476,13 +476,8 @@
                         snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
             }
 
-            // Clear the framebuffer where the layer will draw
-            glScissor(bounds.left, mSnapshot->height - bounds.bottom,
-                    bounds.getWidth(), bounds.getHeight());
-            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-            glClear(GL_COLOR_BUFFER_BIT);
-
-            dirtyClip();
+            // Enqueue the buffer coordinates to clear the corresponding region later
+            mLayers.push(new Rect(bounds));
         }
     }
 
@@ -817,6 +812,58 @@
 #endif
 }
 
+void OpenGLRenderer::clearLayerRegions() {
+    const size_t count = mLayers.size();
+    if (count == 0) return;
+
+    if (!mSnapshot->isIgnored()) {
+        // Doing several glScissor/glClear here can negatively impact
+        // GPUs with a tiler architecture, instead we draw quads with
+        // the Clear blending mode
+
+        // The list contains bounds that have already been clipped
+        // against their initial clip rect, and the current clip
+        // is likely different so we need to disable clipping here
+        glDisable(GL_SCISSOR_TEST);
+
+        Vertex mesh[count * 6];
+        Vertex* vertex = mesh;
+
+        for (uint32_t i = 0; i < count; i++) {
+            Rect* bounds = mLayers.itemAt(i);
+
+            Vertex::set(vertex++, bounds->left, bounds->bottom);
+            Vertex::set(vertex++, bounds->left, bounds->top);
+            Vertex::set(vertex++, bounds->right, bounds->top);
+            Vertex::set(vertex++, bounds->left, bounds->bottom);
+            Vertex::set(vertex++, bounds->right, bounds->top);
+            Vertex::set(vertex++, bounds->right, bounds->bottom);
+
+            delete bounds;
+        }
+
+        setupDraw(false);
+        setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
+        setupDrawBlending(true, SkXfermode::kClear_Mode);
+        setupDrawProgram();
+        setupDrawPureColorUniforms();
+        setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
+
+        mCaches.unbindMeshBuffer();
+        glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
+                gVertexStride, &mesh[0].position[0]);
+        glDrawArrays(GL_TRIANGLES, 0, count * 6);
+
+        glEnable(GL_SCISSOR_TEST);
+    } else {
+        for (uint32_t i = 0; i < count; i++) {
+            delete mLayers.itemAt(i);
+        }
+    }
+
+    mLayers.clear();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Transforms
 ///////////////////////////////////////////////////////////////////////////////
@@ -901,7 +948,8 @@
 // Drawing commands
 ///////////////////////////////////////////////////////////////////////////////
 
-void OpenGLRenderer::setupDraw() {
+void OpenGLRenderer::setupDraw(bool clear) {
+    if (clear) clearLayerRegions();
     if (mDirtyClip) {
         setScissorFromClip();
     }
@@ -994,7 +1042,7 @@
     if (mColorSet && mode == SkXfermode::kClear_Mode) {
         mColorA = 1.0f;
         mColorR = mColorG = mColorB = 0.0f;
-        mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA);
+        mSetShaderColor = mDescription.modulate = true;
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 549d6e9..b9e3ddc 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -249,6 +249,18 @@
      */
     void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false);
 
+    /**
+     * Clears all the regions corresponding to the current list of layers.
+     * This method MUST be invoked before any drawing operation.
+     */
+    void clearLayerRegions();
+
+    /**
+     * Renders the specified layer as a textured quad.
+     *
+     * @param layer The layer to render
+     * @param rect The bounds of the layer
+     */
     void drawTextureLayer(Layer* layer, const Rect& rect);
 
     /**
@@ -280,11 +292,53 @@
     void drawColorRect(float left, float top, float right, float bottom,
             int color, SkXfermode::Mode mode, bool ignoreTransform = false);
 
+    /**
+     * Draws the shape represented by the specified path texture.
+     * This method invokes drawPathTexture() but takes into account
+     * the extra left/top offset and the texture offset to correctly
+     * position the final shape.
+     *
+     * @param left The left coordinate of the shape to render
+     * @param top The top coordinate of the shape to render
+     * @param texture The texture reprsenting the shape
+     * @param paint The paint to draw the shape with
+     */
     void drawShape(float left, float top, const PathTexture* texture, SkPaint* paint);
+
+    /**
+     * Renders the rect defined by the specified bounds as a shape.
+     * This will render the rect using a path texture, which is used to render
+     * rects with stroke effects.
+     *
+     * @param left The left coordinate of the rect to draw
+     * @param top The top coordinate of the rect to draw
+     * @param right The right coordinate of the rect to draw
+     * @param bottom The bottom coordinate of the rect to draw
+     * @param p The paint to draw the rect with
+     */
     void drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p);
 
+    /**
+     * Draws the specified texture as an alpha bitmap. Alpha bitmaps obey
+     * different compositing rules.
+     *
+     * @param texture The texture to draw with
+     * @param left The x coordinate of the bitmap
+     * @param top The y coordinate of the bitmap
+     * @param paint The paint to render with
+     */
     void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint);
 
+    /**
+     * Renders the rect defined by the specified bounds as an anti-aliased rect.
+     *
+     * @param left The left coordinate of the rect to draw
+     * @param top The top coordinate of the rect to draw
+     * @param right The right coordinate of the rect to draw
+     * @param bottom The bottom coordinate of the rect to draw
+     * @param color The color of the rect
+     * @param mode The blending mode to draw the rect
+     */
     void drawAARect(float left, float top, float right, float bottom,
             int color, SkXfermode::Mode mode);
 
@@ -359,6 +413,15 @@
     void drawTextDecorations(const char* text, int bytesCount, float length,
             float x, float y, SkPaint* paint);
 
+    /**
+     * Draws a path texture. Path textures are alpha8 bitmaps that need special
+     * compositing to apply colors/filters/etc.
+     *
+     * @param texture The texture to render
+     * @param x The x coordinate where the texture will be drawn
+     * @param y The y coordinate where the texture will be drawn
+     * @param paint The paint to draw the texture with
+     */
     void drawPathTexture(const PathTexture* texture, float x, float y, SkPaint* paint);
 
     /**
@@ -434,7 +497,7 @@
     /**
      * Invoked before any drawing operation. This sets required state.
      */
-    void setupDraw();
+    void setupDraw(bool clear = true);
     /**
      * Various methods to setup OpenGL rendering.
      */
@@ -522,6 +585,9 @@
     // Various caches
     Caches& mCaches;
 
+    // List of rectagnles to clear after saveLayer() is invoked
+    Vector<Rect*> mLayers;
+
     // Indentity matrix
     const mat4 mIdentity;