Generate even fewer GL commands

Change-Id: I0f4dcacb03ef5ee7f6ebd501df98bfead5f0a7f8
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index c3bac5d..f2205f6 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -79,6 +79,8 @@
 
     mTexCoordsArrayEnabled = false;
 
+    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
+
     glActiveTexture(gTextureUnits[0]);
     mTextureUnit = 0;
 
@@ -312,6 +314,17 @@
     }
 }
 
+void Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
+    if (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight) {
+        glScissor(x, y, width, height);
+
+        mScissorX = x;
+        mScissorY = y;
+        mScissorWidth = width;
+        mScissorHeight = height;
+    }
+}
+
 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 edf3a47..d264971 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -188,6 +188,11 @@
     void activeTexture(GLuint textureUnit);
 
     /**
+     * Sets the scissor for the current surface.
+     */
+    void setScissor(GLint x, GLint y, GLint width, GLint height);
+
+    /**
      * 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.
@@ -240,6 +245,11 @@
 
     GLuint mTextureUnit;
 
+    GLint mScissorX;
+    GLint mScissorY;
+    GLint mScissorWidth;
+    GLint mScissorHeight;
+
     // Used to render layers
     TextureVertex* mRegionMesh;
     GLuint mRegionMeshIndices;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cbfd778..75c6d0a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -155,7 +155,7 @@
     mSaveCount = 1;
 
     glViewport(0, 0, mWidth, mHeight);
-    glScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
+    mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
 
     mSnapshot->setClip(left, top, right, bottom);
     mDirtyClip = false;
@@ -550,7 +550,7 @@
 #endif
 
     // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
-    glScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
+    mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
             clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
     glClear(GL_COLOR_BUFFER_BIT);
 
@@ -965,7 +965,10 @@
 void OpenGLRenderer::setScissorFromClip() {
     Rect clip(*mSnapshot->clipRect);
     clip.snapToPixelBoundaries();
-    glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight());
+
+    mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom,
+            clip.getWidth(), clip.getHeight());
+
     mDirtyClip = false;
 }
 
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index fb76717..fff9f6c 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -112,7 +112,8 @@
     }
 
     bool intersect(float l, float t, float r, float b) {
-        Rect tmp(intersectWith(l, t, r, b));
+        Rect tmp(l, t, r, b);
+        intersectWith(tmp);
         if (!tmp.isEmpty()) {
             set(tmp);
             return true;
@@ -173,6 +174,13 @@
     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; }
 
+    void intersectWith(Rect& tmp) const {
+        tmp.left = max(left, tmp.left);
+        tmp.top = max(top, tmp.top);
+        tmp.right = min(right, tmp.right);
+        tmp.bottom = min(bottom, tmp.bottom);
+    }
+
     Rect intersectWith(float l, float t, float r, float b) const {
         Rect tmp;
         tmp.left = max(left, l);