Optimize away unnecessary state changes

Change-Id: I0f6816f9f6234853575ecee5033186ad19e76380
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index a8ae5c6..ee6ef1a 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -147,12 +147,12 @@
         this->renderTarget = renderTarget;
     }
 
-    void setWrap(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false) {
-        texture.setWrap(wrapS, wrapT, bindTexture, force, renderTarget);
+    void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) {
+        texture.setWrap(wrap, bindTexture, force, renderTarget);
     }
 
-    void setFilter(GLenum min, GLenum mag, bool bindTexture = false, bool force = false) {
-        texture.setFilter(min, mag,bindTexture, force, renderTarget);
+    void setFilter(GLenum filter, bool bindTexture = false, bool force = false) {
+        texture.setFilter(filter, bindTexture, force, renderTarget);
     }
 
     inline bool isCacheable() {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e38b479..6bf6004 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -294,8 +294,8 @@
         if (renderTarget != layer->getRenderTarget()) {
             layer->setRenderTarget(renderTarget);
             layer->bindTexture();
-            layer->setFilter(GL_NEAREST, GL_NEAREST, false, true);
-            layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, false, true);
+            layer->setFilter(GL_NEAREST, false, true);
+            layer->setWrap(GL_CLAMP_TO_EDGE, false, true);
         }
     }
 }
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 718c131..3c838fc 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -47,6 +47,8 @@
 // TODO: This should be set in properties
 #define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH)
 
+#define FILTER(paint) (paint && paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST)
+
 ///////////////////////////////////////////////////////////////////////////////
 // Globals
 ///////////////////////////////////////////////////////////////////////////////
@@ -665,10 +667,10 @@
         const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
         const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
 
-        layer->setFilter(GL_NEAREST, GL_NEAREST);
+        layer->setFilter(GL_NEAREST);
         setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
     } else {
-        layer->setFilter(GL_LINEAR, GL_LINEAR);
+        layer->setFilter(GL_LINEAR);
         setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
     }
     setupDrawTextureTransformUniforms(layer->getTexTransform());
@@ -702,9 +704,9 @@
                 y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
             }
 
-            layer->setFilter(GL_NEAREST, GL_NEAREST, true);
+            layer->setFilter(GL_NEAREST, true);
         } else {
-            layer->setFilter(GL_LINEAR, GL_LINEAR, true);
+            layer->setFilter(GL_LINEAR, true);
         }
 
         drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
@@ -760,10 +762,10 @@
             const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
             const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
 
-            layer->setFilter(GL_NEAREST, GL_NEAREST);
+            layer->setFilter(GL_NEAREST);
             setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
         } else {
-            layer->setFilter(GL_LINEAR, GL_LINEAR);
+            layer->setFilter(GL_LINEAR);
             setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
         }
         setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]);
@@ -1320,6 +1322,8 @@
         y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
         ignoreTransform = true;
         filter = GL_NEAREST;
+    } else {
+        filter = FILTER(paint);
     }
 
     setupDraw();
@@ -1334,8 +1338,8 @@
     setupDrawModelView(x, y, x + texture->width, y + texture->height, ignoreTransform);
 
     setupDrawTexture(texture->id);
-    texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
-    texture->setFilter(filter, filter);
+    texture->setWrap(GL_CLAMP_TO_EDGE);
+    texture->setFilter(filter);
 
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
@@ -1401,8 +1405,8 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(GL_LINEAR, GL_LINEAR, true);
+    texture->setWrap(GL_CLAMP_TO_EDGE, true);
+    texture->setFilter(FILTER(paint), true);
 
     int alpha;
     SkXfermode::Mode mode;
@@ -1485,7 +1489,6 @@
     Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
-    texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true);
 
     const float width = texture->width;
     const float height = texture->height;
@@ -1502,6 +1505,8 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
+    texture->setWrap(GL_CLAMP_TO_EDGE, true);
+
     if (mSnapshot->transform->isPureTranslate()) {
         const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f);
         const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f);
@@ -1509,17 +1514,16 @@
         GLenum filter = GL_NEAREST;
         // Enable linear filtering if the source rectangle is scaled
         if (srcRight - srcLeft != dstRight - dstLeft || srcBottom - srcTop != dstBottom - dstTop) {
-            filter = GL_LINEAR;
+            filter = FILTER(paint);
         }
-        texture->setFilter(filter, filter, true);
 
+        texture->setFilter(filter, true);
         drawTextureMesh(x, y, x + (dstRight - dstLeft), y + (dstBottom - dstTop),
                 texture->id, alpha / 255.0f, mode, texture->blend,
                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
                 GL_TRIANGLE_STRIP, gMeshCount, false, true);
     } else {
-        texture->setFilter(GL_LINEAR, GL_LINEAR, true);
-
+        texture->setFilter(FILTER(paint), true);
         drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f,
                 mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
                 GL_TRIANGLE_STRIP, gMeshCount);
@@ -1539,8 +1543,8 @@
     Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
-    texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(GL_LINEAR, GL_LINEAR, true);
+    texture->setWrap(GL_CLAMP_TO_EDGE, true);
+    texture->setFilter(GL_LINEAR, true);
 
     int alpha;
     SkXfermode::Mode mode;
@@ -2250,11 +2254,11 @@
                 x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
                 y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
 
-                layer->setFilter(GL_NEAREST, GL_NEAREST);
+                layer->setFilter(GL_NEAREST);
                 setupDrawModelViewTranslate(x, y,
                         x + layer->layer.getWidth(), y + layer->layer.getHeight(), true);
             } else {
-                layer->setFilter(GL_LINEAR, GL_LINEAR);
+                layer->setFilter(GL_LINEAR);
                 setupDrawModelViewTranslate(x, y,
                         x + layer->layer.getWidth(), y + layer->layer.getHeight());
             }
@@ -2447,18 +2451,18 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true);
+    texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
     if (mSnapshot->transform->isPureTranslate()) {
         const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
         const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
 
-        texture->setFilter(GL_NEAREST, GL_NEAREST, true);
+        texture->setFilter(GL_NEAREST, true);
         drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
                 alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL,
                 (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true);
     } else {
-        texture->setFilter(GL_LINEAR, GL_LINEAR, true);
+        texture->setFilter(FILTER(paint), true);
         drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
                 texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
                 GL_TRIANGLE_STRIP, gMeshCount);
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index 0660b69..8b88d30 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -584,8 +584,8 @@
     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
             GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels());
 
-    texture->setFilter(GL_LINEAR, GL_LINEAR);
-    texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+    texture->setFilter(GL_LINEAR);
+    texture->setWrap(GL_CLAMP_TO_EDGE);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 2428295..32e7533 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -77,7 +77,7 @@
 
 void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
     glBindTexture(GL_TEXTURE_2D, texture->id);
-    texture->setWrap(wrapS, wrapT);
+    texture->setWrapST(wrapS, wrapT);
 }
 
 void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
@@ -148,7 +148,7 @@
     // ::updateTransforms() but we don't have the texture object
     // available at that point. The optimization is not worth the
     // effort for now.
-    texture->setFilter(GL_LINEAR, GL_LINEAR);
+    texture->setFilter(GL_LINEAR);
 
     glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
     glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 48229b6..a4aed07 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -40,7 +40,12 @@
         firstWrap = true;
     }
 
-    void setWrap(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false,
+    void setWrap(GLenum wrap, bool bindTexture = false, bool force = false,
+                GLenum renderTarget = GL_TEXTURE_2D) {
+        setWrapST(wrap, wrap, bindTexture, force, renderTarget);
+    }
+
+    void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false,
             GLenum renderTarget = GL_TEXTURE_2D) {
 
         if (firstWrap || force || wrapS != this->wrapS || wrapT != this->wrapT) {
@@ -58,7 +63,12 @@
         }
     }
 
-    void setFilter(GLenum min, GLenum mag, bool bindTexture = false, bool force = false,
+    void setFilter(GLenum filter, bool bindTexture = false, bool force = false,
+                GLenum renderTarget = GL_TEXTURE_2D) {
+        setFilterMinMag(filter, filter, bindTexture, force, renderTarget);
+    }
+
+    void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false, bool force = false,
             GLenum renderTarget = GL_TEXTURE_2D) {
 
         if (firstFilter || force || min != minFilter || mag != magFilter) {
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 018ce3e..711277a 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -217,11 +217,15 @@
     texture->height = bitmap->height();
 
     glBindTexture(GL_TEXTURE_2D, texture->id);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
+    if (!regenerate) {
+        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
+    }
 
     switch (bitmap->getConfig()) {
     case SkBitmap::kA8_Config:
-        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        if (!regenerate) {
+            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        }
         uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height,
                 GL_UNSIGNED_BYTE, bitmap->getPixels());
         texture->blend = true;
@@ -248,8 +252,10 @@
         break;
     }
 
-    texture->setFilter(GL_LINEAR, GL_LINEAR);
-    texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+    if (!regenerate) {
+        texture->setFilter(GL_NEAREST);
+        texture->setWrap(GL_CLAMP_TO_EDGE);
+    }
 }
 
 void TextureCache::uploadLoFiTexture(bool resize, SkBitmap* bitmap,