Add support for a new developer setting: overdraw debugging

Change-Id: I350ba4486577c3289f82c20938f7a35138778727
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 068eb9e..22f1dec 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -131,6 +131,13 @@
     } else {
         debugLayersUpdates = false;
     }
+
+    if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
+        INIT_LOGD("  Overdraw debug enabled: %s", property);
+        debugOverdraw = !strcmp(property, "true");
+    } else {
+        debugOverdraw = false;
+    }
 }
 
 void Caches::terminate() {
@@ -429,7 +436,9 @@
 
 void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool opaque) {
     if (extensions.hasTiledRendering()) {
-        glStartTilingQCOM(x, y, width, height, opaque ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM);
+        glStartTilingQCOM(x, y, width, height,
+                (opaque ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM) |
+                (debugOverdraw ? GL_STENCIL_BUFFER_BIT0_QCOM : 0));
     }
 }
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 50e9e758..48efd10 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -242,6 +242,7 @@
     // Misc
     GLint maxTextureSize;
     bool debugLayersUpdates;
+    bool debugOverdraw;
 
     TextureCache textureCache;
     LayerCache layerCache;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index c475f20..014d2e6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -193,6 +193,8 @@
     mTilingSnapshot = mSnapshot;
     startTiling(mTilingSnapshot, true);
 
+    debugOverdraw(true, true);
+
     if (!opaque) {
         mCaches.enableScissor();
         mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
@@ -230,6 +232,7 @@
 }
 
 void OpenGLRenderer::finish() {
+    renderOverdraw();
     endTiling();
 
     if (!suppressErrorChecks()) {
@@ -264,6 +267,40 @@
     }
 }
 
+void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
+    if (mCaches.debugOverdraw && getTargetFbo() == 0) {
+        if (clear) {
+            mCaches.disableScissor();
+            mCaches.stencil.clear();
+        }
+        if (enable) {
+            mCaches.stencil.enableDebugWrite();
+        } else {
+            mCaches.stencil.disable();
+        }
+    }
+}
+
+void OpenGLRenderer::renderOverdraw() {
+    if (mCaches.debugOverdraw && getTargetFbo() == 0) {
+        const Rect* clip = mTilingSnapshot->clipRect;
+
+        mCaches.enableScissor();
+        mCaches.setScissor(clip->left, mTilingSnapshot->height - clip->bottom,
+                clip->right - clip->left, clip->bottom - clip->top);
+
+        mCaches.stencil.enableDebugTest(2);
+        drawColor(0x2f0000ff, SkXfermode::kSrcOver_Mode);
+        mCaches.stencil.enableDebugTest(3);
+        drawColor(0x2f00ff00, SkXfermode::kSrcOver_Mode);
+        mCaches.stencil.enableDebugTest(4);
+        drawColor(0x3fff0000, SkXfermode::kSrcOver_Mode);
+        mCaches.stencil.enableDebugTest(4, true);
+        drawColor(0x7fff0000, SkXfermode::kSrcOver_Mode);
+        mCaches.stencil.disable();
+    }
+}
+
 void OpenGLRenderer::interrupt() {
     if (mCaches.currentProgram) {
         if (mCaches.currentProgram->isInUse()) {
@@ -275,12 +312,14 @@
     mCaches.unbindIndicesBuffer();
     mCaches.resetVertexPointers();
     mCaches.disbaleTexCoordsVertexArray();
+    debugOverdraw(false, false);
 }
 
 void OpenGLRenderer::resume() {
     sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
     glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+    debugOverdraw(true, false);
 
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
@@ -301,6 +340,7 @@
     sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
     glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+    debugOverdraw(true, false);
 
     mCaches.resetScissor();
     dirtyClip();
@@ -406,7 +446,10 @@
         OpenGLRenderer* renderer = layer->renderer;
         Rect& dirty = layer->dirtyRect;
 
-        if (inFrame) endTiling();
+        if (inFrame) {
+            endTiling();
+            debugOverdraw(false, false);
+        }
 
         renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight());
         renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend());
@@ -731,6 +774,7 @@
     mSnapshot->orthoMatrix.load(mOrthoMatrix);
 
     endTiling();
+    debugOverdraw(false, false);
     // Bind texture to FBO
     glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
     layer->bindTexture();
@@ -779,6 +823,7 @@
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
         // Unbind current FBO and restore previous one
         glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
+        debugOverdraw(true, false);
 
         startTiling(previous);
     }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3e34336..43ef9df 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -739,6 +739,9 @@
      */
     void drawRegionRects(const Region& region);
 
+    void debugOverdraw(bool enable, bool clear);
+    void renderOverdraw();
+
     /**
      * Should be invoked every time the glScissor is modified.
      */
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 0e3268e..31e60e44 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -37,7 +37,7 @@
 // Defines the size in bits of the stencil buffer
 // Note: Only 1 bit is required for clipping but more bits are required
 // to properly implement the winding fill rule when rasterizing paths
-#define STENCIL_BUFFER_SIZE 0
+#define STENCIL_BUFFER_SIZE 8
 
 /**
  * Debug level for app developers. The value is a numeric value defined
@@ -56,11 +56,17 @@
 };
 
 /**
- * Used to enable/disbale layers update debugging. The accepted values are
+ * Used to enable/disable 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"
 
+/**
+ * Used to enable/disable overdraw debugging. The accepted values are
+ * "true" and "false". The default value is "false".
+ */
+#define PROPERTY_DEBUG_OVERDRAW "debug.hwui.show_overdraw"
+
 // 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"
diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/Stencil.cpp
index 7dfdf0e..84df82b 100644
--- a/libs/hwui/Stencil.cpp
+++ b/libs/hwui/Stencil.cpp
@@ -37,7 +37,7 @@
 void Stencil::enableTest() {
     if (mState != kTest) {
         enable();
-        glStencilFunc(GL_EQUAL, 0x0, 0x1);
+        glStencilFunc(GL_EQUAL, 0x1, 0x1);
         // We only want to test, let's keep everything
         glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@@ -56,8 +56,27 @@
     }
 }
 
+void Stencil::enableDebugTest(GLint value, bool greater) {
+    enable();
+    glStencilFunc(greater ? GL_LESS : GL_EQUAL, value, 0xffffffff);
+    // We only want to test, let's keep everything
+    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+    mState = kTest;
+}
+
+void Stencil::enableDebugWrite() {
+    if (mState != kWrite) {
+        enable();
+        glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff);
+        // The test always passes so the first two values are meaningless
+        glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+        mState = kWrite;
+    }
+}
+
 void Stencil::enable() {
-    if (!mState == kDisabled) {
+    if (mState == kDisabled) {
         glEnable(GL_STENCIL_TEST);
     }
 }
diff --git a/libs/hwui/Stencil.h b/libs/hwui/Stencil.h
index 67ccc78..2f8a66a 100644
--- a/libs/hwui/Stencil.h
+++ b/libs/hwui/Stencil.h
@@ -59,6 +59,16 @@
     void enableWrite();
 
     /**
+     * The test passes only when equal to the specified value.
+     */
+    void enableDebugTest(GLint value, bool greater = false);
+
+    /**
+     * Used for debugging. The stencil test always passes and increments.
+     */
+    void enableDebugWrite();
+
+    /**
      * Disables stencil test and write.
      */
     void disable();