am 10c0aa24: Merge "Implement support for drawBitmapMesh\'s colors array"

# Via Android (Google) Code Review (1) and Romain Guy (1)
* commit '10c0aa246d9b2633c6cb4e5b714abb0031a4f4cd':
  Implement support for drawBitmapMesh's colors array
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index ec7c65a..06e7116 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -901,9 +901,9 @@
         final int count = (meshWidth + 1) * (meshHeight + 1);
         checkRange(verts.length, vertOffset, count * 2);
 
-        // TODO: Colors are ignored for now
-        colors = null;
-        colorOffset = 0;
+        if (colors != null) {
+            checkRange(colors.length, colorOffset, count);
+        }
 
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         try {
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 74201d1..88f1d83 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -365,11 +365,12 @@
     }
 }
 
-void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices) {
-    if (force || vertices != mCurrentTexCoordsPointer) {
+void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
+    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
         GLuint slot = currentProgram->texCoords;
-        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices);
+        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
         mCurrentTexCoordsPointer = vertices;
+        mCurrentTexCoordsStride = stride;
     }
 }
 
@@ -390,7 +391,7 @@
     }
 }
 
-void Caches::disbaleTexCoordsVertexArray() {
+void Caches::disableTexCoordsVertexArray() {
     if (mTexCoordsArrayEnabled) {
         glDisableVertexAttribArray(Program::kBindingTexCoords);
         mTexCoordsArrayEnabled = false;
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index d70c0e3..0ca2ffd 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -183,7 +183,7 @@
      * Binds an attrib to the specified float vertex pointer.
      * Assumes a stride of gMeshStride and a size of 2.
      */
-    void bindTexCoordsVertexPointer(bool force, GLvoid* vertices);
+    void bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride = gMeshStride);
 
     /**
      * Resets the vertex pointers.
@@ -192,7 +192,7 @@
     void resetTexCoordsVertexPointer();
 
     void enableTexCoordsVertexArray();
-    void disbaleTexCoordsVertexArray();
+    void disableTexCoordsVertexArray();
 
     /**
      * Activate the specified texture unit. The texture unit must
@@ -299,6 +299,7 @@
     void* mCurrentPositionPointer;
     GLsizei mCurrentPositionStride;
     void* mCurrentTexCoordsPointer;
+    GLsizei mCurrentTexCoordsStride;
 
     bool mTexCoordsArrayEnabled;
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2431e54..f0d25e1 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -317,7 +317,7 @@
     mCaches.unbindMeshBuffer();
     mCaches.unbindIndicesBuffer();
     mCaches.resetVertexPointers();
-    mCaches.disbaleTexCoordsVertexArray();
+    mCaches.disableTexCoordsVertexArray();
     debugOverdraw(false, false);
 }
 
@@ -1469,12 +1469,18 @@
     mDescription.hasAlpha8Texture = isAlpha8;
 }
 
+void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
+    mDescription.hasTexture = true;
+    mDescription.hasColors = true;
+    mDescription.hasAlpha8Texture = isAlpha8;
+}
+
 void OpenGLRenderer::setupDrawWithExternalTexture() {
     mDescription.hasExternalTexture = true;
 }
 
 void OpenGLRenderer::setupDrawNoTexture() {
-    mCaches.disbaleTexCoordsVertexArray();
+    mCaches.disableTexCoordsVertexArray();
 }
 
 void OpenGLRenderer::setupDrawAA() {
@@ -1682,6 +1688,23 @@
     mCaches.unbindIndicesBuffer();
 }
 
+void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors) {
+    bool force = mCaches.unbindMeshBuffer();
+    GLsizei stride = sizeof(ColorTextureVertex);
+
+    mCaches.bindPositionVertexPointer(force, vertices, stride);
+    if (mCaches.currentProgram->texCoords >= 0) {
+        mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
+    }
+    int slot = mCaches.currentProgram->getAttrib("colors");
+    if (slot >= 0) {
+        glEnableVertexAttribArray(slot);
+        glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
+    }
+
+    mCaches.unbindIndicesBuffer();
+}
+
 void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) {
     bool force = mCaches.unbindMeshBuffer();
     mCaches.bindPositionVertexPointer(force, vertices);
@@ -1833,9 +1856,16 @@
 
     const uint32_t count = meshWidth * meshHeight * 6;
 
-    // TODO: Support the colors array
-    TextureVertex mesh[count];
-    TextureVertex* vertex = mesh;
+    ColorTextureVertex mesh[count];
+    ColorTextureVertex* vertex = mesh;
+
+    bool cleanupColors = false;
+    if (!colors) {
+        uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
+        colors = new int[colorsCount];
+        memset(colors, 0xff, colorsCount * sizeof(int));
+        cleanupColors = true;
+    }
 
     for (int32_t y = 0; y < meshHeight; y++) {
         for (int32_t x = 0; x < meshWidth; x++) {
@@ -1855,13 +1885,13 @@
             int dx = i + (meshWidth + 1) * 2 + 2;
             int dy = dx + 1;
 
-            TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2);
-            TextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1);
-            TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
+            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
+            ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
+            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
 
-            TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2);
-            TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
-            TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2);
+            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
+            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
+            ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
 
             left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
             top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
@@ -1871,12 +1901,16 @@
     }
 
     if (quickReject(left, top, right, bottom)) {
+        if (cleanupColors) delete[] colors;
         return DrawGlInfo::kStatusDone;
     }
 
     mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
-    if (!texture) return DrawGlInfo::kStatusDone;
+    if (!texture) {
+        if (cleanupColors) delete[] colors;
+        return DrawGlInfo::kStatusDone;
+    }
     const AutoTexture autoCleanup(texture);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
@@ -1886,13 +1920,35 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
+    float a = alpha / 255.0f;
+
     if (hasLayer()) {
         dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
     }
 
-    drawTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f,
-            mode, texture->blend, &mesh[0].position[0], &mesh[0].texture[0],
-            GL_TRIANGLES, count, false, false, 0, false, false);
+    setupDraw();
+    setupDrawWithTextureAndColor();
+    setupDrawColor(a, a, a, a);
+    setupDrawColorFilter();
+    setupDrawBlending(true, mode, false);
+    setupDrawProgram();
+    setupDrawDirtyRegionsDisabled();
+    setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, false);
+    setupDrawTexture(texture->id);
+    setupDrawPureColorUniforms();
+    setupDrawColorFilterUniforms();
+    setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0], &mesh[0].color[0]);
+
+    glDrawArrays(GL_TRIANGLES, 0, count);
+
+    finishDrawTexture();
+
+    int slot = mCaches.currentProgram->getAttrib("colors");
+    if (slot >= 0) {
+        glDisableVertexAttribArray(slot);
+    }
+
+    if (cleanupColors) delete[] colors;
 
     return DrawGlInfo::kStatusDrew;
 }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 0ad81c1..ad80d36 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -777,6 +777,7 @@
      * Various methods to setup OpenGL rendering.
      */
     void setupDrawWithTexture(bool isAlpha8 = false);
+    void setupDrawWithTextureAndColor(bool isAlpha8 = false);
     void setupDrawWithExternalTexture();
     void setupDrawNoTexture();
     void setupDrawAA();
@@ -811,6 +812,7 @@
     void setupDrawTextureTransformUniforms(mat4& transform);
     void setupDrawTextGammaUniforms();
     void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
+    void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors);
     void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords);
     void setupDrawVertices(GLvoid* vertices);
     void finishDrawTexture();
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index b1df980..7b67b3c 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -81,6 +81,8 @@
 
 #define PROGRAM_IS_SIMPLE_GRADIENT 41
 
+#define PROGRAM_HAS_COLORS 42
+
 ///////////////////////////////////////////////////////////////////////////////
 // Types
 ///////////////////////////////////////////////////////////////////////////////
@@ -120,6 +122,9 @@
     bool hasExternalTexture;
     bool hasTextureTransform;
 
+    // Color attribute
+    bool hasColors;
+
     // Modulate, this should only be set when setColor() return true
     bool modulate;
 
@@ -164,6 +169,8 @@
         hasExternalTexture = false;
         hasTextureTransform = false;
 
+        hasColors = false;
+
         isAA = false;
 
         modulate = false;
@@ -259,6 +266,7 @@
         if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
         if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
         if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT;
+        if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS;
         return key;
     }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index fb00335..74d598d 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -40,6 +40,8 @@
         "attribute vec4 position;\n";
 const char* gVS_Header_Attributes_TexCoords =
         "attribute vec2 texCoords;\n";
+const char* gVS_Header_Attributes_Colors =
+        "attribute vec4 colors;\n";
 const char* gVS_Header_Attributes_AAVertexShapeParameters =
         "attribute float vtxAlpha;\n";
 const char* gVS_Header_Uniforms_TextureTransform =
@@ -65,6 +67,8 @@
         "uniform mediump vec2 textureDimension;\n";
 const char* gVS_Header_Varyings_HasTexture =
         "varying vec2 outTexCoords;\n";
+const char* gVS_Header_Varyings_HasColors =
+        "varying vec4 outColors;\n";
 const char* gVS_Header_Varyings_IsAAVertexShape =
         "varying float alpha;\n";
 const char* gVS_Header_Varyings_HasBitmap =
@@ -94,6 +98,8 @@
         "\nvoid main(void) {\n";
 const char* gVS_Main_OutTexCoords =
         "    outTexCoords = texCoords;\n";
+const char* gVS_Main_OutColors =
+        "    outColors = colors;\n";
 const char* gVS_Main_OutTransformedTexCoords =
         "    outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
 const char* gVS_Main_OutGradient[6] = {
@@ -325,6 +331,8 @@
     };
 const char* gFS_Main_FragColor =
         "    gl_FragColor = fragColor;\n";
+const char* gFS_Main_FragColor_HasColors =
+        "    gl_FragColor *= outColors;\n";
 const char* gFS_Main_FragColor_Blend =
         "    gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
 const char* gFS_Main_FragColor_Blend_Swap =
@@ -459,6 +467,9 @@
     if (description.isAA) {
         shader.append(gVS_Header_Attributes_AAVertexShapeParameters);
     }
+    if (description.hasColors) {
+        shader.append(gVS_Header_Attributes_Colors);
+    }
     // Uniforms
     shader.append(gVS_Header_Uniforms);
     if (description.hasTextureTransform) {
@@ -480,6 +491,9 @@
     if (description.isAA) {
         shader.append(gVS_Header_Varyings_IsAAVertexShape);
     }
+    if (description.hasColors) {
+        shader.append(gVS_Header_Varyings_HasColors);
+    }
     if (description.hasGradient) {
         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
     }
@@ -499,6 +513,9 @@
         if (description.isAA) {
             shader.append(gVS_Main_AAVertexShape);
         }
+        if (description.hasColors) {
+            shader.append(gVS_Main_OutColors);
+        }
         if (description.hasBitmap) {
             shader.append(description.isPoint ?
                     gVS_Main_OutPointBitmapTexCoords :
@@ -549,6 +566,9 @@
     if (description.isAA) {
         shader.append(gVS_Header_Varyings_IsAAVertexShape);
     }
+    if (description.hasColors) {
+        shader.append(gVS_Header_Varyings_HasColors);
+    }
     if (description.hasGradient) {
         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
     }
@@ -583,7 +603,7 @@
     }
 
     // Optimization for common cases
-    if (!description.isAA && !blendFramebuffer &&
+    if (!description.isAA && !blendFramebuffer && !description.hasColors &&
             description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
         bool fast = false;
 
@@ -729,6 +749,9 @@
             shader.append(!description.swapSrcDst ?
                     gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
         }
+        if (description.hasColors) {
+            shader.append(gFS_Main_FragColor_HasColors);
+        }
     }
     // End the shader
     shader.append(gFS_Footer);
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index c120428..523120e 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -33,7 +33,7 @@
 }; // struct Vertex
 
 /**
- * Simple structure to describe a vertex with a position and a texture.
+ * Simple structure to describe a vertex with a position and texture UV.
  */
 struct TextureVertex {
     float position[2];
@@ -53,6 +53,24 @@
 }; // struct TextureVertex
 
 /**
+ * Simple structure to describe a vertex with a position, texture UV and ARGB color.
+ */
+struct ColorTextureVertex : TextureVertex {
+    float color[4];
+
+    static inline void set(ColorTextureVertex* vertex, float x, float y,
+            float u, float v, int color) {
+        TextureVertex::set(vertex, x, y, u, v);
+
+        const float a = ((color >> 24) & 0xff) / 255.0f;
+        vertex[0].color[0] = a * ((color >> 16) & 0xff) / 255.0f;
+        vertex[0].color[1] = a * ((color >>  8) & 0xff) / 255.0f;
+        vertex[0].color[2] = a * ((color      ) & 0xff) / 255.0f;
+        vertex[0].color[3] = a;
+    }
+}; // struct ColorTextureVertex
+
+/**
  * Simple structure to describe a vertex with a position and an alpha value.
  */
 struct AlphaVertex : Vertex {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
index 854dd69..69d34a5 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
@@ -54,7 +54,7 @@
                 0.0f, height * 2, width, height * 2, width * 2, height * 2, width * 3, height * 2,
                 0.0f, height * 4, width, height * 4, width * 2, height * 4, width * 4, height * 4,
             };
-            
+
             mColors = new int[] {
                 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffff0000,
                 0xff0000ff, 0xffff0000, 0xff00ff00, 0xff00ff00,