Skip eglSwapBuffers() call when we do not draw to GL

The fix is to track when we issue GL drawing commands, and to skip the
call to eglSwapBuffers() when a DisplayList does not result in
any actual rendering calls to GL.

Issue #6364143 QuickMuni list items and buttons flicker instead of fade

Change-Id: I60a02c61a58c32d92481a1e814b4c8a49c6a37a3
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2a8b32c..2dc9726 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -336,7 +336,7 @@
     info.height = getSnapshot()->height;
     getSnapshot()->transform->copyTo(&info.transform[0]);
 
-    status_t result = (*functor)(DrawGlInfo::kModeDraw, &info);
+    status_t result = (*functor)(DrawGlInfo::kModeDraw, &info) | DrawGlInfo::kStatusDrew;
 
     if (result != DrawGlInfo::kStatusDone) {
         Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
@@ -1472,17 +1472,17 @@
     finishDrawTexture();
 }
 
-void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
+status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
     const float right = left + bitmap->width();
     const float bottom = top + bitmap->height();
 
     if (quickReject(left, top, right, bottom)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
-    if (!texture) return;
+    if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
 
     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
@@ -1490,20 +1490,22 @@
     } else {
         drawTextureRect(left, top, right, bottom, texture, paint);
     }
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
+status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
     Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
     const mat4 transform(*matrix);
     transform.mapRect(r);
 
     if (quickReject(r.left, r.top, r.right, r.bottom)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
-    if (!texture) return;
+    if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
 
     // This could be done in a cheaper way, all we need is pass the matrix
@@ -1512,14 +1514,16 @@
     concatMatrix(matrix);
     drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
     restore();
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
+status_t OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
     const float right = left + bitmap->width();
     const float bottom = top + bitmap->height();
 
     if (quickReject(left, top, right, bottom)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     mCaches.activeTexture(0);
@@ -1527,18 +1531,20 @@
     const AutoTexture autoCleanup(texture);
 
     drawTextureRect(left, top, right, bottom, texture, paint);
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
+status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
         float* vertices, int* colors, SkPaint* paint) {
     // TODO: Do a quickReject
     if (!vertices || mSnapshot->isIgnored()) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
-    if (!texture) return;
+    if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
@@ -1611,19 +1617,21 @@
     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);
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
+status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
          float srcLeft, float srcTop, float srcRight, float srcBottom,
          float dstLeft, float dstTop, float dstRight, float dstBottom,
          SkPaint* paint) {
     if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
-    if (!texture) return;
+    if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
 
     const float width = texture->width;
@@ -1666,18 +1674,20 @@
     }
 
     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
         const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
         float left, float top, float right, float bottom, SkPaint* paint) {
     if (quickReject(left, top, right, bottom)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
-    if (!texture) return;
+    if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
     texture->setFilter(GL_LINEAR, true);
@@ -1726,6 +1736,8 @@
                     true, !mesh->hasEmptyQuads);
         }
     }
+
+    return DrawGlInfo::kStatusDrew;
 }
 
 /**
@@ -1826,8 +1838,8 @@
  * 'inside' the line area being filled opaquely and the other pixels being filled according to
  * how far into the boundary region they are, which is determined by shader interpolation.
  */
-void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
+status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
     const bool isAA = paint->isAntiAlias();
     // We use half the stroke width here because we're going to position the quad
@@ -2083,10 +2095,12 @@
     if (isAA) {
         finishDrawAALine(widthSlot, lengthSlot);
     }
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
+status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
     // TODO: The paint's cap style defines whether the points are square or circular
     // TODO: Handle AA for round points
@@ -2138,86 +2152,92 @@
     }
 
     glDrawArrays(GL_POINTS, 0, generatedVerticesCount);
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
+status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
     // No need to check against the clip, we fill the clip region
-    if (mSnapshot->isIgnored()) return;
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
     Rect& clip(*mSnapshot->clipRect);
     clip.snapToPixelBoundaries();
 
     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture, SkPaint* paint) {
-    if (!texture) return;
+status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
+        SkPaint* paint) {
+    if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
 
     const float x = left + texture->left - texture->offset;
     const float y = top + texture->top - texture->offset;
 
     drawPathTexture(texture, x, y, paint);
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
+status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
         float rx, float ry, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
     mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
             right - left, bottom - top, rx, ry, paint);
-    drawShape(left, top, texture, paint);
+    return drawShape(left, top, texture, paint);
 }
 
-void OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
+status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
     mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, paint);
-    drawShape(x - radius, y - radius, texture, paint);
+    return drawShape(x - radius, y - radius, texture, paint);
 }
 
-void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
+status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
+        SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
     mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, paint);
-    drawShape(left, top, texture, paint);
+    return drawShape(left, top, texture, paint);
 }
 
-void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
+status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
     if (fabs(sweepAngle) >= 360.0f) {
-        drawOval(left, top, right, bottom, paint);
-        return;
+        return drawOval(left, top, right, bottom, paint);
     }
 
     mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
             startAngle, sweepAngle, useCenter, paint);
-    drawShape(left, top, texture, paint);
+    return drawShape(left, top, texture, paint);
 }
 
-void OpenGLRenderer::drawRectAsShape(float left, float top, float right, float bottom,
+status_t OpenGLRenderer::drawRectAsShape(float left, float top, float right, float bottom,
         SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
     mCaches.activeTexture(0);
     const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, paint);
-    drawShape(left, top, texture, paint);
+    return drawShape(left, top, texture, paint);
 }
 
-void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
+status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
     if (p->getStyle() != SkPaint::kFill_Style) {
-        drawRectAsShape(left, top, right, bottom, p);
-        return;
+        return drawRectAsShape(left, top, right, bottom, p);
     }
 
     if (quickReject(left, top, right, bottom)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     SkXfermode::Mode mode;
@@ -2237,18 +2257,20 @@
     } else {
         drawColorRect(left, top, right, bottom, color, mode);
     }
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
+status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, SkPaint* paint) {
     if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
             (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     // NOTE: Skia does not support perspective transform on drawPosText yet
     if (!mSnapshot->transform->isSimple()) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     float x = 0.0f;
@@ -2308,13 +2330,15 @@
         }
 #endif
     }
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
+status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
         float x, float y, SkPaint* paint, float length) {
     if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
             (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     if (length < 0.0f) length = paint->measureText(text, bytesCount);
@@ -2332,7 +2356,7 @@
     SkPaint::FontMetrics metrics;
     paint->getFontMetrics(&metrics, 0.0f);
     if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     const float oldX = x;
@@ -2432,13 +2456,15 @@
     }
 
     drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
+status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
         float hOffset, float vOffset, SkPaint* paint) {
     if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
             (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
@@ -2482,27 +2508,31 @@
         }
 #endif
     }
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
+status_t OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
 
     mCaches.activeTexture(0);
 
     // TODO: Perform early clip test before we rasterize the path
     const PathTexture* texture = mCaches.pathCache.get(path, paint);
-    if (!texture) return;
+    if (!texture) return DrawGlInfo::kStatusDone;
     const AutoTexture autoCleanup(texture);
 
     const float x = texture->left - texture->offset;
     const float y = texture->top - texture->offset;
 
     drawPathTexture(texture, x, y, paint);
+
+    return DrawGlInfo::kStatusDrew;
 }
 
-void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
+status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
     if (!layer || quickReject(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight())) {
-        return;
+        return DrawGlInfo::kStatusDone;
     }
 
     if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) {
@@ -2575,6 +2605,8 @@
     const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight());
     composeLayerRect(layer, r);
 #endif
+
+    return DrawGlInfo::kStatusDrew;
 }
 
 ///////////////////////////////////////////////////////////////////////////////