Free up resources by deleting shaders early on

Change-Id: I29a39775732c0a48d3e6823f7afa3e741cae8541
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 972dd87..516546f 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -27,35 +27,45 @@
 
 Program::Program(const char* vertex, const char* fragment) {
     mInitialized = false;
+    mHasColorUniform = false;
 
-    vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
+    GLuint vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
     if (vertexShader) {
 
-        fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+        GLuint fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
         if (fragmentShader) {
 
-            id = glCreateProgram();
-            glAttachShader(id, vertexShader);
-            glAttachShader(id, fragmentShader);
-            glLinkProgram(id);
+            mProgramId = glCreateProgram();
+            glAttachShader(mProgramId, vertexShader);
+            glAttachShader(mProgramId, fragmentShader);
+            glLinkProgram(mProgramId);
 
             GLint status;
-            glGetProgramiv(id, GL_LINK_STATUS, &status);
+            glGetProgramiv(mProgramId, GL_LINK_STATUS, &status);
             if (status != GL_TRUE) {
                 LOGE("Error while linking shaders:");
                 GLint infoLen = 0;
-                glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
+                glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen);
                 if (infoLen > 1) {
                     GLchar log[infoLen];
-                    glGetProgramInfoLog(id, infoLen, 0, &log[0]);
+                    glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]);
                     LOGE("%s", log);
                 }
-                glDeleteShader(vertexShader);
-                glDeleteShader(fragmentShader);
-                glDeleteProgram(id);
             } else {
                 mInitialized = true;
             }
+
+            glDetachShader(mProgramId, vertexShader);
+            glDetachShader(mProgramId, fragmentShader);
+
+            glDeleteShader(vertexShader);
+            glDeleteShader(fragmentShader);
+
+            if (!mInitialized) {
+                glDeleteProgram(mProgramId);
+            }
+        } else {
+            glDeleteShader(vertexShader);
         }
     }
 
@@ -69,36 +79,34 @@
 
 Program::~Program() {
     if (mInitialized) {
-        glDeleteShader(vertexShader);
-        glDeleteShader(fragmentShader);
-        glDeleteProgram(id);
+        glDeleteProgram(mProgramId);
     }
 }
 
 int Program::addAttrib(const char* name) {
-    int slot = glGetAttribLocation(id, name);
-    attributes.add(name, slot);
+    int slot = glGetAttribLocation(mProgramId, name);
+    mAttributes.add(name, slot);
     return slot;
 }
 
 int Program::getAttrib(const char* name) {
-    ssize_t index = attributes.indexOfKey(name);
+    ssize_t index = mAttributes.indexOfKey(name);
     if (index >= 0) {
-        return attributes.valueAt(index);
+        return mAttributes.valueAt(index);
     }
     return addAttrib(name);
 }
 
 int Program::addUniform(const char* name) {
-    int slot = glGetUniformLocation(id, name);
-    uniforms.add(name, slot);
+    int slot = glGetUniformLocation(mProgramId, name);
+    mUniforms.add(name, slot);
     return slot;
 }
 
 int Program::getUniform(const char* name) {
-    ssize_t index = uniforms.indexOfKey(name);
+    ssize_t index = mUniforms.indexOfKey(name);
     if (index >= 0) {
-        return uniforms.valueAt(index);
+        return mUniforms.valueAt(index);
     }
     return addUniform(name);
 }
@@ -140,20 +148,24 @@
 }
 
 void Program::setColor(const float r, const float g, const float b, const float a) {
-    glUniform4f(getUniform("color"), r, g, b, a);
+    if (!mHasColorUniform) {
+        mColorUniform = getUniform("color");
+        mHasColorUniform = false;
+    }
+    glUniform4f(mColorUniform, r, g, b, a);
 }
 
 void Program::use() {
-    glUseProgram(id);
+    glUseProgram(mProgramId);
     mUse = true;
-
     glEnableVertexAttribArray(position);
 }
 
 void Program::remove() {
     mUse = false;
-
-    glDisableVertexAttribArray(position);
+    // TODO: Is this necessary? It should not be since all of our shaders
+    //       use slot 0 for the position attrib
+    // glDisableVertexAttribArray(position);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 764cb05..edd1209 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -122,18 +122,17 @@
     GLuint buildShader(const char* source, GLenum type);
 
     // Name of the OpenGL program
-    GLuint id;
-
-    // Name of the shaders
-    GLuint vertexShader;
-    GLuint fragmentShader;
+    GLuint mProgramId;
 
     // Keeps track of attributes and uniforms slots
-    KeyedVector<const char*, int> attributes;
-    KeyedVector<const char*, int> uniforms;
+    KeyedVector<const char*, int> mAttributes;
+    KeyedVector<const char*, int> mUniforms;
 
     bool mUse;
     bool mInitialized;
+
+    bool mHasColorUniform;
+    int mColorUniform;
 }; // class Program
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 8c01e3a..47484d0 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -74,7 +74,7 @@
 #define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "ro.text_gamma.white_threshold"
 
 // Converts a number of mega-bytes into bytes
-#define MB(s) s * 1024 * 1024
+#define MB(s) (s * 1024 * 1024)
 
 #define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
 #define DEFAULT_LAYER_CACHE_SIZE 16.0f