Further reduce the number of GL commands sent to the driver

Change-Id: Id922b2a166ea4573b767c27d3195e11c70320b23
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 27039dd..96e142c 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -79,6 +79,9 @@
 
     mTexCoordsArrayEnabled = false;
 
+    glActiveTexture(gTextureUnits[0]);
+    mTextureUnit = 0;
+
     mRegionMesh = NULL;
 
     blend = false;
@@ -301,6 +304,13 @@
     }
 }
 
+void Caches::activeTexture(GLuint textureUnit) {
+    if (mTextureUnit != textureUnit) {
+        glActiveTexture(gTextureUnits[textureUnit]);
+        mTextureUnit = textureUnit;
+    }
+}
+
 TextureVertex* Caches::getRegionMesh() {
     // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
     if (!mRegionMesh) {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 6143593..edf3a47 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -70,6 +70,12 @@
 static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
 static const GLsizei gMeshCount = 4;
 
+static const GLenum gTextureUnits[] = {
+    GL_TEXTURE0,
+    GL_TEXTURE1,
+    GL_TEXTURE2
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 // Debug
 ///////////////////////////////////////////////////////////////////////////////
@@ -176,6 +182,12 @@
     void disbaleTexCoordsVertexArray();
 
     /**
+     * Activate the specified texture unit. The texture unit must
+     * be specified using an integer number (0 for GL_TEXTURE0 etc.)
+     */
+    void activeTexture(GLuint textureUnit);
+
+    /**
      * Returns the mesh used to draw regions. Calling this method will
      * bind a VBO of type GL_ELEMENT_ARRAY_BUFFER that contains the
      * indices for the region mesh.
@@ -226,6 +238,8 @@
 
     bool mTexCoordsArrayEnabled;
 
+    GLuint mTextureUnit;
+
     // Used to render layers
     TextureVertex* mRegionMesh;
     GLuint mRegionMeshIndices;
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 324765b..d304b37 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -20,6 +20,7 @@
 
 #include <utils/Log.h>
 
+#include "Caches.h"
 #include "Debug.h"
 #include "LayerCache.h"
 #include "Properties.h"
@@ -140,7 +141,7 @@
     uint32_t oldWidth = layer->getWidth();
     uint32_t oldHeight = layer->getHeight();
 
-    glActiveTexture(GL_TEXTURE0);
+    Caches::getInstance().activeTexture(0);
     layer->bindTexture();
     layer->setSize(entry.mWidth, entry.mHeight);
     layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index c30923f..38630b8 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -182,14 +182,15 @@
 Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
     LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
 
-    GLuint fbo = Caches::getInstance().fboCache.get();
+    Caches& caches = Caches::getInstance();
+    GLuint fbo = caches.fboCache.get();
     if (!fbo) {
         LOGW("Could not obtain an FBO");
         return NULL;
     }
 
-    glActiveTexture(GL_TEXTURE0);
-    Layer* layer = Caches::getInstance().layerCache.get(width, height);
+    caches.activeTexture(0);
+    Layer* layer = caches.layerCache.get(width, height);
     if (!layer) {
         LOGW("Could not obtain a layer");
         return NULL;
@@ -220,7 +221,7 @@
                     fbo, width, height);
 
             glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-            Caches::getInstance().fboCache.put(fbo);
+            caches.fboCache.put(fbo);
 
             layer->deleteTexture();
             delete layer;
@@ -274,7 +275,7 @@
     layer->region.clear();
     layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
 
-    glActiveTexture(GL_TEXTURE0);
+    Caches::getInstance().activeTexture(0);
     layer->generateTexture();
 
     return layer;
@@ -406,7 +407,7 @@
         glGenTextures(1, &texture);
         if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
-        glActiveTexture(GL_TEXTURE0);
+        caches.activeTexture(0);
         glBindTexture(GL_TEXTURE_2D, texture);
 
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 59d3fcc..1f5d13b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -103,12 +103,6 @@
     { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
 };
 
-static const GLenum gTextureUnits[] = {
-    GL_TEXTURE0,
-    GL_TEXTURE1,
-    GL_TEXTURE2
-};
-
 ///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
@@ -214,6 +208,7 @@
     glEnable(GL_SCISSOR_TEST);
     dirtyClip();
 
+    mCaches.activeTexture(0);
     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
 
     mCaches.blend = true;
@@ -454,7 +449,7 @@
         return false;
     }
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
     if (!layer) {
         return false;
@@ -596,7 +591,7 @@
 
     mCaches.unbindMeshBuffer();
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
 
     // When the layer is stored in an FBO, we can save a bit of fillrate by
     // drawing only the dirty region
@@ -1377,7 +1372,7 @@
         return;
     }
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
@@ -1398,7 +1393,7 @@
         return;
     }
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
@@ -1418,7 +1413,7 @@
         return;
     }
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
@@ -1503,7 +1498,7 @@
         return;
     }
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
@@ -1557,7 +1552,7 @@
         return;
     }
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
@@ -2008,7 +2003,7 @@
         float rx, float ry, SkPaint* paint) {
     if (mSnapshot->isIgnored()) return;
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
             right - left, bottom - top, rx, ry, paint);
     drawShape(left, top, texture, paint);
@@ -2017,7 +2012,7 @@
 void OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
     if (mSnapshot->isIgnored()) return;
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, paint);
     drawShape(x - radius, y - radius, texture, paint);
 }
@@ -2025,7 +2020,7 @@
 void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, SkPaint* paint) {
     if (mSnapshot->isIgnored()) return;
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, paint);
     drawShape(left, top, texture, paint);
 }
@@ -2039,7 +2034,7 @@
         return;
     }
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
             startAngle, sweepAngle, useCenter, paint);
     drawShape(left, top, texture, paint);
@@ -2049,7 +2044,7 @@
         SkPaint* paint) {
     if (mSnapshot->isIgnored()) return;
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, paint);
     drawShape(left, top, texture, paint);
 }
@@ -2147,7 +2142,7 @@
             shadowColor = 0xffffffff;
         }
 
-        glActiveTexture(gTextureUnits[0]);
+        mCaches.activeTexture(0);
         setupDraw();
         setupDrawWithTexture(true);
         setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
@@ -2177,7 +2172,7 @@
         linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
     }
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
     setupDraw();
     setupDrawDirtyRegionsDisabled();
     setupDrawWithTexture(true);
@@ -2219,7 +2214,7 @@
 void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
     if (mSnapshot->isIgnored()) return;
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
 
     const PathTexture* texture = mCaches.pathCache.get(path, paint);
     if (!texture) return;
@@ -2236,7 +2231,7 @@
         return;
     }
 
-    glActiveTexture(gTextureUnits[0]);
+    mCaches.activeTexture(0);
 
     int alpha;
     SkXfermode::Mode mode;
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index edc90e1..adf019b 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -29,17 +29,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class Rect {
-    static inline float min(float a, float b) { return (a<b) ? a : b; }
-    static inline float max(float a, float b) { return (a>b) ? a : b; }
-    Rect intersectWith(float l, float t, float r, float b) const {
-        Rect tmp;
-        tmp.left    = max(left, l);
-        tmp.top     = max(top, t);
-        tmp.right   = min(right, r);
-        tmp.bottom  = min(bottom, b);
-        return tmp;
-    }
-
 public:
     float left;
     float top;
@@ -115,7 +104,7 @@
     }
 
     bool intersects(float l, float t, float r, float b) const {
-        return !intersectWith(l,t,r,b).isEmpty();
+        return !intersectWith(l, t, r, b).isEmpty();
     }
 
     bool intersects(const Rect& r) const {
@@ -123,7 +112,7 @@
     }
 
     bool intersect(float l, float t, float r, float b) {
-        Rect tmp(intersectWith(l,t,r,b));
+        Rect tmp(intersectWith(l, t, r, b));
         if (!tmp.isEmpty()) {
             set(tmp);
             return true;
@@ -172,6 +161,19 @@
         LOGD("Rect[l=%f t=%f r=%f b=%f]", left, top, right, bottom);
     }
 
+private:
+    static inline float min(float a, float b) { return (a < b) ? a : b; }
+    static inline float max(float a, float b) { return (a > b) ? a : b; }
+
+    Rect intersectWith(float l, float t, float r, float b) const {
+        Rect tmp;
+        tmp.left = max(left, l);
+        tmp.top = max(top, t);
+        tmp.right = min(right, r);
+        tmp.bottom = min(bottom, b);
+        return tmp;
+    }
+
 }; // class Rect
 
 }; // namespace uirenderer
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 32e7533..66993a4 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -20,6 +20,7 @@
 
 #include <SkMatrix.h>
 
+#include "Caches.h"
 #include "SkiaShader.h"
 #include "Texture.h"
 #include "Matrix.h"
@@ -31,12 +32,6 @@
 // Support
 ///////////////////////////////////////////////////////////////////////////////
 
-static const GLenum gTextureUnitsMap[] = {
-        GL_TEXTURE0,
-        GL_TEXTURE1,
-        GL_TEXTURE2
-};
-
 static const GLint gTileModes[] = {
         GL_CLAMP_TO_EDGE,   // == SkShader::kClamp_TileMode
         GL_REPEAT,          // == SkShader::kRepeat_Mode
@@ -129,7 +124,7 @@
 void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
         const Snapshot& snapshot, GLuint* textureUnit) {
     GLuint textureSlot = (*textureUnit)++;
-    glActiveTexture(gTextureUnitsMap[textureSlot]);
+    Caches::getInstance().activeTexture(textureSlot);
 
     Texture* texture = mTexture;
     mTexture = NULL;
@@ -223,7 +218,7 @@
 void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
         const Snapshot& snapshot, GLuint* textureUnit) {
     GLuint textureSlot = (*textureUnit)++;
-    glActiveTexture(gTextureUnitsMap[textureSlot]);
+    Caches::getInstance().activeTexture(textureSlot);
 
     Texture* texture = mGradientCache->get(mColors, mPositions, mCount, mTileX);
 
@@ -335,7 +330,7 @@
 void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
         const Snapshot& snapshot, GLuint* textureUnit) {
     GLuint textureSlot = (*textureUnit)++;
-    glActiveTexture(gTextureUnitsMap[textureSlot]);
+    Caches::getInstance().activeTexture(textureSlot);
 
     Texture* texture = mGradientCache->get(mColors, mPositions, mCount);