Don't render degenerate triangles in 9patches.
Bug #3251983

Change-Id: Ib0b38a7b8111542372f4c4c106b6321c26fe4ad4
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index feaba25..ddbfa5e 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -34,6 +34,9 @@
 
 // Turn on to display debug infor about 9patch objects
 #define DEBUG_PATCHES 0
+// Turn on to display vertex and tex coords data about 9patch objects
+// This flag requires DEBUG_PATCHES to be turned on
+#define DEBUG_PATCHES_VERTICES 0
 
 // Turn on to display debug info about paths
 #define DEBUG_PATHS 0
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 60343e0..f3e5b16 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -936,7 +936,8 @@
     const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
             right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
 
-    if (mesh) {
+    if (mesh && mesh->verticesCount > 0) {
+#if RENDER_LAYERS_AS_REGIONS
         // Mark the current layer dirty where we are going to draw the patch
         if ((mSnapshot->flags & Snapshot::kFlagFboTarget) &&
                 mSnapshot->region && mesh->hasEmptyQuads) {
@@ -947,14 +948,12 @@
                         *mSnapshot->transform);
             }
         }
+#endif
 
         drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
                 mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
                 GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
                 true, !mesh->hasEmptyQuads);
-    } else {
-        PATCH_LOGD("Invisible 9patch, ignoring (%.2f, %.2f, %.2f, %.2f)",
-                left, top, right, bottom);
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 94d96a5..a942dde 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -45,13 +45,6 @@
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
-
-// If turned on, layers drawn inside FBOs are optimized with regions
-#define RENDER_LAYERS_AS_REGIONS 0
-
-///////////////////////////////////////////////////////////////////////////////
 // Renderer
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index ebffd34..17b1d86 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -22,6 +22,7 @@
 
 #include "Patch.h"
 #include "Caches.h"
+#include "Properties.h"
 
 namespace android {
 namespace uirenderer {
@@ -31,19 +32,22 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads):
-        mXCount(xCount), mYCount(yCount) {
+        mXCount(xCount), mYCount(yCount), mEmptyQuads(emptyQuads) {
+    // Initialized with the maximum number of vertices we will need
     // 2 triangles per patch, 3 vertices per triangle
-    verticesCount = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
-    mVertices = new TextureVertex[verticesCount];
-    hasEmptyQuads = emptyQuads > 0;
+    const int maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
+    mVertices = new TextureVertex[maxVertices];
     mUploaded = false;
 
+    verticesCount = 0;
+    hasEmptyQuads = emptyQuads > 0;
+
     mColorKey = 0;
     mXDivs = new int32_t[mXCount];
     mYDivs = new int32_t[mYCount];
 
-    PATCH_LOGD("    patch: xCount = %d, yCount = %d, emptyQuads = %d, vertices = %d",
-            xCount, yCount, emptyQuads, verticesCount);
+    PATCH_LOGD("    patch: xCount = %d, yCount = %d, emptyQuads = %d, max vertices = %d",
+            xCount, yCount, emptyQuads, maxVertices);
 
     glGenBuffers(1, &meshBuffer);
 }
@@ -104,7 +108,13 @@
 
 void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
         float left, float top, float right, float bottom) {
+#if RENDER_LAYERS_AS_REGIONS
     if (hasEmptyQuads) quads.clear();
+#endif
+
+    // Reset the vertices count here, we will count exactly how many
+    // vertices we actually need when generating the quads
+    verticesCount = 0;
 
     const uint32_t xStretchCount = (mXCount + 1) >> 1;
     const uint32_t yStretchCount = (mYCount + 1) >> 1;
@@ -167,15 +177,19 @@
     generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left,
             bitmapWidth, quadCount);
 
-    Caches::getInstance().bindMeshBuffer(meshBuffer);
-    if (!mUploaded) {
-        glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
-                mVertices, GL_DYNAMIC_DRAW);
-        mUploaded = true;
-    } else {
-        glBufferSubData(GL_ARRAY_BUFFER, 0,
-                sizeof(TextureVertex) * verticesCount, mVertices);
+    if (verticesCount > 0) {
+        Caches::getInstance().bindMeshBuffer(meshBuffer);
+        if (!mUploaded) {
+            glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
+                    mVertices, GL_DYNAMIC_DRAW);
+            mUploaded = true;
+        } else {
+            glBufferSubData(GL_ARRAY_BUFFER, 0,
+                    sizeof(TextureVertex) * verticesCount, mVertices);
+        }
     }
+
+    PATCH_LOGD("    patch: new vertices count = %d", verticesCount);
 }
 
 void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
@@ -211,22 +225,24 @@
 
 void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
             float u1, float v1, float u2, float v2, uint32_t& quadCount) {
-    uint32_t oldQuadCount = quadCount;
-
-    // Degenerate quads are an artifact of our implementation and should not
-    // be taken into account when checking for transparent quads
-    if (x2 - x1 > 0.999f && y2 - y1 > 0.999f) {
+    const uint32_t oldQuadCount = quadCount;
+    const bool valid = fabs(x2 - x1) > 0.9999f && fabs(y2 - y1) > 0.9999f;
+    if (valid) {
         quadCount++;
     }
 
-    if (((mColorKey >> oldQuadCount) & 0x1) == 1) {
+    // Skip degenerate and transparent (empty) quads
+    if (!valid || ((mColorKey >> oldQuadCount) & 0x1) == 1) {
         return;
     }
 
+#if RENDER_LAYERS_AS_REGIONS
+    // Record all non empty quads
     if (hasEmptyQuads) {
         Rect bounds(x1, y1, x2, y2);
         quads.add(bounds);
     }
+#endif
 
     // Left triangle
     TextureVertex::set(vertex++, x1, y1, u1, v1);
@@ -237,6 +253,15 @@
     TextureVertex::set(vertex++, x1, y2, u1, v2);
     TextureVertex::set(vertex++, x2, y1, u2, v1);
     TextureVertex::set(vertex++, x2, y2, u2, v2);
+
+    // A quad is made of 2 triangles, 6 vertices
+    verticesCount += 6;
+
+#if DEBUG_PATCHES_VERTICES
+    PATCH_LOGD("    quad %d", oldQuadCount);
+    PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.2f, %.2f", x1, y1, u1, v1);
+    PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.2f, %.2f", x2, y2, u2, v2);
+#endif
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 2cb8ecb..16ad86d 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -51,19 +51,23 @@
 
     GLuint meshBuffer;
     uint32_t verticesCount;
-    Vector<Rect> quads;
     bool hasEmptyQuads;
+#if RENDER_LAYERS_AS_REGIONS
+    Vector<Rect> quads;
+#endif
 
 private:
     TextureVertex* mVertices;
     bool mUploaded;
 
-    uint32_t mXCount;
     int32_t* mXDivs;
-    uint32_t mYCount;
     int32_t* mYDivs;
     uint32_t mColorKey;
 
+    uint32_t mXCount;
+    uint32_t mYCount;
+    int8_t mEmptyQuads;
+
     void copy(const int32_t* yDivs);
 
     void generateRow(TextureVertex*& vertex, float y1, float y2,
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 96d8b69..ac91769 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -25,6 +25,9 @@
  * the OpenGLRenderer.
  */
 
+// If turned on, layers drawn inside FBOs are optimized with regions
+#define RENDER_LAYERS_AS_REGIONS 0
+
 /**
  * Debug level for app developers.
  */