Keep shaders to render properly

I don't know who's to blame, SGX or Tegra2 but one of those two GPUs is not
following the OpenGL ES 2.0 spec.

Change-Id: I2624e0efbc9c57d571c55c8b440a5e43f08a54f2
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e2d9ea3..3f940bb 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -233,7 +233,6 @@
             layer->getTexture(), 0);
 
     glDisable(GL_SCISSOR_TEST);
-    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     glClear(GL_COLOR_BUFFER_BIT);
     glEnable(GL_SCISSOR_TEST);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1d7b99d..fa17aad 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -133,8 +133,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::setViewport(int width, int height) {
-    glDisable(GL_DITHER);
-    glViewport(0, 0, width, height);
     mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
 
     mWidth = width;
@@ -144,6 +142,13 @@
     mFirstSnapshot->viewport.set(0, 0, width, height);
 
     mDirtyClip = false;
+
+    glDisable(GL_DITHER);
+    glViewport(0, 0, width, height);
+
+    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+    glEnableVertexAttribArray(Program::kBindingPosition);
 }
 
 void OpenGLRenderer::prepare(bool opaque) {
@@ -159,14 +164,11 @@
 
     mSaveCount = 1;
 
-    glViewport(0, 0, mWidth, mHeight);
-
     glEnable(GL_SCISSOR_TEST);
     glScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
     mSnapshot->setClip(left, top, right, bottom);
 
     if (!opaque) {
-        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
         glClear(GL_COLOR_BUFFER_BIT);
     }
 }
@@ -207,6 +209,8 @@
 
     glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
 
+    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
     glEnable(GL_SCISSOR_TEST);
     dirtyClip();
 
@@ -215,6 +219,8 @@
     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 
+    glEnableVertexAttribArray(Program::kBindingPosition);
+
     mCaches.blend = true;
     glEnable(GL_BLEND);
     glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
@@ -556,7 +562,6 @@
     // 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,
             clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
-    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     glClear(GL_COLOR_BUFFER_BIT);
 
     dirtyClip();
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 4aff23e..db610b0 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -25,21 +25,24 @@
 // Base program
 ///////////////////////////////////////////////////////////////////////////////
 
+// TODO: Program instance should be created from a factory method
 Program::Program(const char* vertex, const char* fragment) {
     mInitialized = false;
     mHasColorUniform = false;
+    mUse = false;
 
     // No need to cache compiled shaders, rely instead on Android's
     // persistent shaders cache
-    GLuint vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
-    if (vertexShader) {
-
-        GLuint fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
-        if (fragmentShader) {
-
+    mVertexShader = buildShader(vertex, GL_VERTEX_SHADER);
+    if (mVertexShader) {
+        mFragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+        if (mFragmentShader) {
             mProgramId = glCreateProgram();
-            glAttachShader(mProgramId, vertexShader);
-            glAttachShader(mProgramId, fragmentShader);
+
+            glAttachShader(mProgramId, mVertexShader);
+            glAttachShader(mProgramId, mFragmentShader);
+
+            position = bindAttrib("position", kBindingPosition);
             glLinkProgram(mProgramId);
 
             GLint status;
@@ -53,34 +56,35 @@
                     glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]);
                     LOGE("%s", log);
                 }
+
+                glDetachShader(mProgramId, mVertexShader);
+                glDetachShader(mProgramId, mFragmentShader);
+
+                glDeleteShader(mVertexShader);
+                glDeleteShader(mFragmentShader);
+
+                glDeleteProgram(mProgramId);
             } else {
                 mInitialized = true;
             }
-
-            glDetachShader(mProgramId, vertexShader);
-            glDetachShader(mProgramId, fragmentShader);
-
-            glDeleteShader(vertexShader);
-            glDeleteShader(fragmentShader);
-
-            if (!mInitialized) {
-                glDeleteProgram(mProgramId);
-            }
         } else {
-            glDeleteShader(vertexShader);
+            glDeleteShader(mVertexShader);
         }
     }
 
-    mUse = false;
-
     if (mInitialized) {
-        position = addAttrib("position");
         transform = addUniform("transform");
     }
 }
 
 Program::~Program() {
     if (mInitialized) {
+        glDetachShader(mProgramId, mVertexShader);
+        glDetachShader(mProgramId, mFragmentShader);
+
+        glDeleteShader(mVertexShader);
+        glDeleteShader(mFragmentShader);
+
         glDeleteProgram(mProgramId);
     }
 }
@@ -91,6 +95,17 @@
     return slot;
 }
 
+int Program::bindAttrib(const char* name, ShaderBindings bindingSlot) {
+    glBindAttribLocation(mProgramId, bindingSlot, name);
+    GLenum status = GL_NO_ERROR;
+    while ((status = glGetError()) != GL_NO_ERROR) {
+        LOGD("Program::GL error from OpenGLRenderer: 0x%x", status);
+    }
+
+    mAttributes.add(name, bindingSlot);
+    return bindingSlot;
+}
+
 int Program::getAttrib(const char* name) {
     ssize_t index = mAttributes.indexOfKey(name);
     if (index >= 0) {
@@ -161,14 +176,10 @@
 void Program::use() {
     glUseProgram(mProgramId);
     mUse = true;
-    glEnableVertexAttribArray(position);
 }
 
 void Program::remove() {
     mUse = false;
-    // 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 edd1209..9e59621 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -33,6 +33,11 @@
  */
 class Program {
 public:
+    enum ShaderBindings {
+        kBindingPosition,
+        kBindingTexCoords
+    };
+
     /**
      * Creates a new program with the specified vertex and fragment
      * shaders sources.
@@ -107,6 +112,11 @@
     int addAttrib(const char* name);
 
     /**
+     * Binds the specified attribute name to the specified slot.
+     */
+    int bindAttrib(const char* name, ShaderBindings bindingSlot);
+
+    /**
      * Adds a uniform with the specified name.
      *
      * @return The OpenGL name of the uniform.
@@ -121,8 +131,10 @@
      */
     GLuint buildShader(const char* source, GLenum type);
 
-    // Name of the OpenGL program
+    // Name of the OpenGL program and shaders
     GLuint mProgramId;
+    GLuint mVertexShader;
+    GLuint mFragmentShader;
 
     // Keeps track of attributes and uniforms slots
     KeyedVector<const char*, int> mAttributes;