Add new debug tool to track hardware layers updates

You can setprop debug.hwui.show_layers_updates true to flash
hw layers in green when they update. This is also a setting
in the Dev. section of the settings app.

Change-Id: Ibe1d63a4f81567dc1d590c9b088d2e7505df8abf
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index aa2bc3f..0ed4888 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -52,13 +52,10 @@
     initFont();
     initExtensions();
     initConstraints();
+    initProperties();
 
     mDebugLevel = readDebugLevel();
     ALOGD("Enabling debug mode %d", mDebugLevel);
-
-#if RENDER_LAYERS_AS_REGIONS
-    INIT_LOGD("Layers will be composited as regions");
-#endif
 }
 
 void Caches::init() {
@@ -126,6 +123,16 @@
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
 }
 
+void Caches::initProperties() {
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) {
+        INIT_LOGD("  Layers updates debug enabled: %s", property);
+        debugLayersUpdates = !strcmp(property, "true");
+    } else {
+        debugLayersUpdates = false;
+    }
+}
+
 void Caches::terminate() {
     if (!mInitialized) return;
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index ad1098c..f4f56d6 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -236,6 +236,7 @@
 
     // Misc
     GLint maxTextureSize;
+    bool debugLayersUpdates;
 
     TextureCache textureCache;
     LayerCache layerCache;
@@ -267,6 +268,7 @@
     void initFont();
     void initExtensions();
     void initConstraints();
+    void initProperties();
 
     static void eventMarkNull(GLsizei length, const GLchar* marker) { }
     static void startMarkNull(GLsizei length, const GLchar* marker) { }
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 41a5f0d..f81640b 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -45,7 +45,6 @@
     const float width = mLayer->layer.getWidth();
     const float height = mLayer->layer.getHeight();
 
-#if RENDER_LAYERS_AS_REGIONS
     Rect dirty(left, top, right, bottom);
     if (dirty.isEmpty() || (dirty.left <= 0 && dirty.top <= 0 &&
             dirty.right >= width && dirty.bottom >= height)) {
@@ -58,9 +57,6 @@
     }
 
     return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
-#else
-    return OpenGLRenderer::prepareDirty(0.0f, 0.0f, width, height, opaque);
-#endif
 }
 
 void LayerRenderer::finish() {
@@ -87,14 +83,10 @@
 }
 
 Region* LayerRenderer::getRegion() {
-#if RENDER_LAYERS_AS_REGIONS
     if (getSnapshot()->flags & Snapshot::kFlagFboTarget) {
         return OpenGLRenderer::getRegion();
     }
     return &mLayer->region;
-#else
-    return OpenGLRenderer::getRegion();
-#endif
 }
 
 // TODO: This implementation is flawed and can generate T-junctions
@@ -105,7 +97,6 @@
 //       In practice, T-junctions do not appear often so this has yet
 //       to be fixed.
 void LayerRenderer::generateMesh() {
-#if RENDER_LAYERS_AS_REGIONS
     if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
         if (mLayer->mesh) {
             delete mLayer->mesh;
@@ -172,7 +163,6 @@
             indices[index + 5] = quad + 3;   // bottom-right
         }
     }
-#endif
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index a1da878..580d6b5 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -321,13 +321,11 @@
     Rect clip(*mSnapshot->clipRect);
     clip.snapToPixelBoundaries();
 
-#if RENDER_LAYERS_AS_REGIONS
     // Since we don't know what the functor will draw, let's dirty
     // tne entire clip region
     if (hasLayer()) {
         dirtyLayerUnchecked(clip, getRegion());
     }
-#endif
 
     DrawGlInfo info;
     info.clipLeft = clip.left;
@@ -595,10 +593,8 @@
         GLuint previousFbo) {
     layer->setFbo(mCaches.fboCache.get());
 
-#if RENDER_LAYERS_AS_REGIONS
     snapshot->region = &snapshot->layer->region;
     snapshot->flags |= Snapshot::kFlagFboTarget;
-#endif
 
     Rect clip(bounds);
     snapshot->transform->mapRect(clip);
@@ -826,7 +822,6 @@
 }
 
 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
-#if RENDER_LAYERS_AS_REGIONS
     if (layer->region.isRect()) {
         layer->setRegionAsRect();
 
@@ -907,9 +902,6 @@
 
         layer->region.clear();
     }
-#else
-    composeLayerRect(layer, rect);
-#endif
 }
 
 void OpenGLRenderer::drawRegionRects(const Region& region) {
@@ -940,27 +932,22 @@
 
 void OpenGLRenderer::dirtyLayer(const float left, const float top,
         const float right, const float bottom, const mat4 transform) {
-#if RENDER_LAYERS_AS_REGIONS
     if (hasLayer()) {
         Rect bounds(left, top, right, bottom);
         transform.mapRect(bounds);
         dirtyLayerUnchecked(bounds, getRegion());
     }
-#endif
 }
 
 void OpenGLRenderer::dirtyLayer(const float left, const float top,
         const float right, const float bottom) {
-#if RENDER_LAYERS_AS_REGIONS
     if (hasLayer()) {
         Rect bounds(left, top, right, bottom);
         dirtyLayerUnchecked(bounds, getRegion());
     }
-#endif
 }
 
 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
-#if RENDER_LAYERS_AS_REGIONS
     if (bounds.intersect(*mSnapshot->clipRect)) {
         bounds.snapToPixelBoundaries();
         android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
@@ -968,7 +955,6 @@
             region->orSelf(dirty);
         }
     }
-#endif
 }
 
 void OpenGLRenderer::clearLayerRegions() {
@@ -1585,11 +1571,7 @@
     float right = FLT_MIN;
     float bottom = FLT_MIN;
 
-#if RENDER_LAYERS_AS_REGIONS
     const bool hasActiveLayer = hasLayer();
-#else
-    const bool hasActiveLayer = false;
-#endif
 
     // TODO: Support the colors array
     TextureVertex mesh[count];
@@ -1620,7 +1602,6 @@
             TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
             TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2);
 
-#if RENDER_LAYERS_AS_REGIONS
             if (hasActiveLayer) {
                 // TODO: This could be optimized to avoid unnecessary ops
                 left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
@@ -1628,15 +1609,12 @@
                 right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
                 bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
             }
-#endif
         }
     }
 
-#if RENDER_LAYERS_AS_REGIONS
     if (hasActiveLayer) {
         dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
     }
-#endif
 
     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],
@@ -1734,7 +1712,6 @@
 
     if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
         const bool pureTranslate = mSnapshot->transform->isPureTranslate();
-#if RENDER_LAYERS_AS_REGIONS
         // Mark the current layer dirty where we are going to draw the patch
         if (hasLayer() && mesh->hasEmptyQuads) {
             const float offsetX = left + mSnapshot->transform->getTranslateX();
@@ -1752,7 +1729,6 @@
                 }
             }
         }
-#endif
 
         if (CC_LIKELY(pureTranslate)) {
             const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
@@ -2400,22 +2376,16 @@
     const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
-#if RENDER_LAYERS_AS_REGIONS
     const bool hasActiveLayer = hasLayer();
-#else
-    const bool hasActiveLayer = false;
-#endif
 
     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
             positions, hasActiveLayer ? &bounds : NULL)) {
-#if RENDER_LAYERS_AS_REGIONS
         if (hasActiveLayer) {
             if (!pureTranslate) {
                 mSnapshot->transform->mapRect(bounds);
             }
             dirtyLayerUnchecked(bounds, getRegion());
         }
-#endif
     }
 
     return DrawGlInfo::kStatusDrew;
@@ -2501,11 +2471,7 @@
     const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
-#if RENDER_LAYERS_AS_REGIONS
     const bool hasActiveLayer = hasLayer();
-#else
-    const bool hasActiveLayer = false;
-#endif
 
     bool status;
     if (paint->getTextAlign() != SkPaint::kLeft_Align) {
@@ -2517,15 +2483,12 @@
         status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
             positions, hasActiveLayer ? &bounds : NULL);
     }
-    if (status) {
-#if RENDER_LAYERS_AS_REGIONS
-        if (hasActiveLayer) {
-            if (!pureTranslate) {
-                mSnapshot->transform->mapRect(bounds);
-            }
-            dirtyLayerUnchecked(bounds, getRegion());
+
+    if (status && hasActiveLayer) {
+        if (!pureTranslate) {
+            mSnapshot->transform->mapRect(bounds);
         }
-#endif
+        dirtyLayerUnchecked(bounds, getRegion());
     }
 
     drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
@@ -2568,20 +2531,14 @@
     const Rect* clip = &mSnapshot->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
-#if RENDER_LAYERS_AS_REGIONS
     const bool hasActiveLayer = hasLayer();
-#else
-    const bool hasActiveLayer = false;
-#endif
 
     if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
             hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) {
-#if RENDER_LAYERS_AS_REGIONS
         if (hasActiveLayer) {
             mSnapshot->transform->mapRect(bounds);
             dirtyLayerUnchecked(bounds, getRegion());
         }
-#endif
     }
 
     return DrawGlInfo::kStatusDrew;
@@ -2610,6 +2567,8 @@
         return DrawGlInfo::kStatusDone;
     }
 
+    bool debugLayerUpdate = false;
+
     if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) {
         OpenGLRenderer* renderer = layer->renderer;
         Rect& dirty = layer->dirtyRect;
@@ -2625,6 +2584,8 @@
         layer->deferredUpdateScheduled = false;
         layer->renderer = NULL;
         layer->displayList = NULL;
+
+        debugLayerUpdate = mCaches.debugLayersUpdates;
     }
 
     mCaches.activeTexture(0);
@@ -2635,13 +2596,11 @@
 
     layer->setAlpha(alpha, mode);
 
-#if RENDER_LAYERS_AS_REGIONS
     if (CC_LIKELY(!layer->region.isEmpty())) {
         if (layer->region.isRect()) {
             composeLayerRect(layer, layer->regionRect);
         } else if (layer->mesh) {
             const float a = alpha / 255.0f;
-            const Rect& rect = layer->layer;
 
             setupDraw();
             setupDrawWithTexture();
@@ -2653,12 +2612,12 @@
             setupDrawColorFilterUniforms();
             setupDrawTexture(layer->getTexture());
             if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
-                x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
-                y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
+                int tx = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
+                int ty = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
 
                 layer->setFilter(GL_NEAREST);
-                setupDrawModelViewTranslate(x, y,
-                        x + layer->layer.getWidth(), y + layer->layer.getHeight(), true);
+                setupDrawModelViewTranslate(tx, ty,
+                        tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
             } else {
                 layer->setFilter(GL_LINEAR);
                 setupDrawModelViewTranslate(x, y,
@@ -2675,11 +2634,12 @@
             drawRegionRects(layer->region);
 #endif
         }
+
+        if (debugLayerUpdate) {
+            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
+                    0x7f00ff00, SkXfermode::kSrcOver_Mode);
+        }
     }
-#else
-    const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight());
-    composeLayerRect(layer, r);
-#endif
 
     return DrawGlInfo::kStatusDrew;
 }
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 27f530c..6971d8a 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -108,9 +108,7 @@
 
 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
@@ -278,13 +276,11 @@
         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);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 3f3b39a..6b6dc9e 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -25,9 +25,6 @@
  * the OpenGLRenderer.
  */
 
-// If turned on, layers drawn inside FBOs are optimized with regions
-#define RENDER_LAYERS_AS_REGIONS 1
-
 // If turned on, text is interpreted as glyphs instead of UTF-16
 #define RENDER_TEXT_AS_GLYPHS 1
 
@@ -43,9 +40,10 @@
 #define STENCIL_BUFFER_SIZE 0
 
 /**
- * Debug level for app developers.
+ * Debug level for app developers. The value is a numeric value defined
+ * by the DebugLevel enum below.
  */
-#define PROPERTY_DEBUG "hwui.debug_level"
+#define PROPERTY_DEBUG "debug.hwui.level"
 
 /**
  * Debug levels. Debug levels are used as flags.
@@ -57,6 +55,12 @@
     kDebugMoreCaches = kDebugMemory | kDebugCaches
 };
 
+/**
+ * Used to enable/disbale layers update debugging. The accepted values are
+ * "true" and "false". The default value is "false".
+ */
+#define PROPERTY_DEBUG_LAYERS_UPDATES "debug.hwui.show_layers_updates"
+
 // These properties are defined in mega-bytes
 #define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
 #define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"