Optimize shader binding changes.

This change also cleans up the internal API a little bit by using mat4
everywhere instead of float[16] (for the ortho matrix for instance.)

Change-Id: I35924c7dc17bad17f30307118d5ed437c2ed37e0
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b783d3f..117fccd 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -118,6 +118,7 @@
 
     mDrawColorShader = new DrawColorProgram;
     mDrawTextureShader = new DrawTextureProgram;
+    mCurrentShader = mDrawTextureShader;
 
     memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices));
 }
@@ -136,9 +137,7 @@
 void OpenGLRenderer::setViewport(int width, int height) {
     glViewport(0, 0, width, height);
 
-    mat4 ortho;
-    ortho.loadOrtho(0, width, height, 0, -1, 1);
-    ortho.copyTo(mOrthoMatrix);
+    mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
 
     mWidth = width;
     mHeight = height;
@@ -208,7 +207,7 @@
     sp<Snapshot> previous = mSnapshot->previous;
 
     if (restoreOrtho) {
-        memcpy(mOrthoMatrix, current->orthoMatrix, sizeof(mOrthoMatrix));
+        mOrthoMatrix.load(current->orthoMatrix);
     }
 
     if (restoreLayer) {
@@ -333,12 +332,10 @@
 
     mSnapshot->flags = Snapshot::kFlagDirtyTransform | Snapshot::kFlagDirtyOrtho |
             Snapshot::kFlagClipSet;
-    memcpy(mSnapshot->orthoMatrix, mOrthoMatrix, sizeof(mOrthoMatrix));
+    mSnapshot->orthoMatrix.load(mOrthoMatrix);
 
     // Change the ortho projection
-    mat4 ortho;
-    ortho.loadOrtho(0.0f, right - left, bottom - top, 0.0f, 0.0f, 1.0f);
-    ortho.copyTo(mOrthoMatrix);
+    mOrthoMatrix.loadOrtho(0.0f, right - left, bottom - top, 0.0f, 0.0f, 1.0f);
 
     return true;
 }
@@ -511,7 +508,8 @@
     mModelView.loadTranslate(left, top, 0.0f);
     mModelView.scale(right - left, bottom - top, 1.0f);
 
-    mDrawColorShader->use(&mOrthoMatrix[0], mModelView, mSnapshot->transform);
+    useShader(mDrawColorShader);
+    mDrawColorShader->set(mOrthoMatrix, mModelView, mSnapshot->transform);
 
     const GLvoid* p = &gDrawColorVertices[0].position[0];
 
@@ -548,7 +546,8 @@
     mModelView.loadTranslate(left, top, 0.0f);
     mModelView.scale(right - left, bottom - top, 1.0f);
 
-    mDrawTextureShader->use(&mOrthoMatrix[0], mModelView, mSnapshot->transform);
+    useShader(mDrawTextureShader);
+    mDrawTextureShader->set(mOrthoMatrix, mModelView, mSnapshot->transform);
 
     chooseBlending(blend || alpha < 1.0f, mode, isPremultiplied);
 
@@ -606,6 +605,14 @@
     mBlend = blend;
 }
 
+void OpenGLRenderer::useShader(const sp<Program>& shader) {
+    if (!shader->isInUse()) {
+        mCurrentShader->remove();
+        shader->use();
+        mCurrentShader = shader;
+    }
+}
+
 void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
     TextureVertex* v = &mDrawTextureVertices[0];
     TextureVertex::setUV(v++, u1, v1);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 76d6e06..afb747f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -247,11 +247,19 @@
      */
     inline void chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied);
 
+    /**
+     * Use the specified shader with the current GL context. If the shader is already
+     * in use, it will not be bound again. If it is not in use, the current shader is
+     * marked unused and the specified shader becomes used and becomes the new
+     * current shader.
+     */
+    inline void useShader(const sp<Program>& shader);
+
     // Dimensions of the drawing surface
     int mWidth, mHeight;
 
     // Matrix used for ortho projection in shaders
-    float mOrthoMatrix[16];
+    mat4 mOrthoMatrix;
 
     // Model-view matrix used to position/size objects
     mat4 mModelView;
@@ -264,6 +272,7 @@
     sp<Snapshot> mSnapshot;
 
     // Shaders
+    sp<Program> mCurrentShader;
     sp<DrawColorProgram> mDrawColorShader;
     sp<DrawTextureProgram> mDrawTextureShader;
 
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 98d254c..3b5e5da 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -59,6 +59,8 @@
         }
         glDeleteProgram(id);
     }
+
+    mUse = false;
 }
 
 Program::~Program() {
@@ -69,6 +71,11 @@
 
 void Program::use() {
     glUseProgram(id);
+    mUse = true;
+}
+
+void Program::remove() {
+    mUse = false;
 }
 
 int Program::addAttrib(const char* name) {
@@ -130,13 +137,12 @@
     transform = addUniform("transform");
 }
 
-void DrawColorProgram::use(const float* projectionMatrix, const mat4& modelViewMatrix,
+void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
         const mat4& transformMatrix) {
     mat4 t(projectionMatrix);
     t.multiply(transformMatrix);
     t.multiply(modelViewMatrix);
 
-    Program::use();
     glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
 }
 
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 61d55a9..652befe1 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -46,6 +46,20 @@
      */
     void use();
 
+    /**
+     * Marks this program as unused. This will not unbind
+     * the program from the GL context.
+     */
+    void remove();
+
+    /**
+     * Indicates whether this program is currently in use with
+     * the GL context.
+     */
+    inline bool isInUse() const {
+        return mUse;
+    }
+
 protected:
     /**
      * Adds an attribute with the specified name.
@@ -87,6 +101,8 @@
     // Keeps track of attributes and uniforms slots
     KeyedVector<const char*, int> attributes;
     KeyedVector<const char*, int> uniforms;
+
+    bool mUse;
 }; // class Program
 
 /**
@@ -109,7 +125,7 @@
      * Binds the program with the specified projection, modelView and
      * transform matrices.
      */
-    void use(const float* projectionMatrix, const mat4& modelViewMatrix,
+    void set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
              const mat4& transformMatrix);
 
     /**
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 17ca440..ef9269f 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -130,7 +130,7 @@
     /**
      * Contains the previous ortho matrix.
      */
-    float orthoMatrix[16];
+    mat4 orthoMatrix;
 
 private:
     // Clipping rectangle mapped with the transform