Add new property to debug non-rectangular clip operations

This change adds a new property called "debug.hwui.show_stencil_clip"
that accepts the following values:

- "highlight", colorizes in green any drawing command that's tested
  against a non-rectangular clip region
- "region", shows the non-rectangular clip region in blue every time
  it is used
- "hide", default value, nothing is shown

Change-Id: I83c8602310edc4aaeb8b905371cdd185b17d32b5
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 88f1d83..5befb95 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -91,6 +91,7 @@
 
     debugLayersUpdates = false;
     debugOverdraw = false;
+    debugStencilClip = kStencilHide;
 
     mInitialized = true;
 }
@@ -132,6 +133,7 @@
 bool Caches::initProperties() {
     bool prevDebugLayersUpdates = debugLayersUpdates;
     bool prevDebugOverdraw = debugOverdraw;
+    StencilClipDebug prevDebugStencilClip = debugStencilClip;
 
     char property[PROPERTY_VALUE_MAX];
     if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) {
@@ -148,8 +150,23 @@
         debugOverdraw = false;
     }
 
+    // See Properties.h for valid values
+    if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, NULL) > 0) {
+        INIT_LOGD("  Stencil clip debug enabled: %s", property);
+        if (!strcmp(property, "hide")) {
+            debugStencilClip = kStencilHide;
+        } else if (!strcmp(property, "highlight")) {
+            debugStencilClip = kStencilShowHighlight;
+        } else if (!strcmp(property, "region")) {
+            debugStencilClip = kStencilShowRegion;
+        }
+    } else {
+        debugStencilClip = kStencilHide;
+    }
+
     return (prevDebugLayersUpdates != debugLayersUpdates) ||
-            (prevDebugOverdraw != debugOverdraw);
+            (prevDebugOverdraw != debugOverdraw) ||
+            (prevDebugStencilClip != debugStencilClip);
 }
 
 void Caches::terminate() {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 0ca2ffd..c35ad883 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -245,9 +245,18 @@
 
     // Misc
     GLint maxTextureSize;
+
+    // Debugging
     bool debugLayersUpdates;
     bool debugOverdraw;
 
+    enum StencilClipDebug {
+        kStencilHide,
+        kStencilShowHighlight,
+        kStencilShowRegion
+    };
+    StencilClipDebug debugStencilClip;
+
     TextureCache textureCache;
     LayerCache layerCache;
     RenderBufferCache renderBufferCache;
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 9a6494f..773fe82 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -48,6 +48,7 @@
 #define DEBUG_RENDER_BUFFERS 0
 
 // Turn on to make stencil operations easier to debug
+// (writes 255 instead of 1 in the buffer, forces 8 bit stencil)
 #define DEBUG_STENCIL 0
 
 // Turn on to display debug info about 9patch objects
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1afeaf0..34d1c98 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1368,6 +1368,12 @@
             drawRegionRects(*mSnapshot->clipRegion, 0xff000000, SkXfermode::kSrc_Mode, false);
 
             mCaches.stencil.enableTest();
+
+            // Draw the region used to generate the stencil if the appropriate debug
+            // mode is enabled
+            if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
+                drawRegionRects(*mSnapshot->clipRegion, 0x7f0000ff, SkXfermode::kSrcOver_Mode);
+            }
         } else {
             mCaches.stencil.disable();
         }
@@ -1515,12 +1521,20 @@
         }
         setStencilFromClip();
     }
+
     mDescription.reset();
+
     mSetShaderColor = false;
     mColorSet = false;
     mColorA = mColorR = mColorG = mColorB = 0.0f;
     mTextureUnit = 0;
     mTrackDirtyRegions = true;
+
+    // Enable debug highlight when what we're about to draw is tested against
+    // the stencil buffer and if stencil highlight debugging is on
+    mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
+            mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
+            mCaches.stencil.isTestEnabled();
 }
 
 void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 7b67b3c..13ee336 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -83,6 +83,8 @@
 
 #define PROGRAM_HAS_COLORS 42
 
+#define PROGRAM_HAS_DEBUG_HIGHLIGHT 43
+
 ///////////////////////////////////////////////////////////////////////////////
 // Types
 ///////////////////////////////////////////////////////////////////////////////
@@ -159,6 +161,8 @@
     bool hasGammaCorrection;
     float gamma;
 
+    bool hasDebugHighlight;
+
     /**
      * Resets this description. All fields are reset back to the default
      * values they hold after building a new instance.
@@ -199,6 +203,8 @@
 
         hasGammaCorrection = false;
         gamma = 2.2f;
+
+        hasDebugHighlight = false;
     }
 
     /**
@@ -267,6 +273,7 @@
         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;
+        if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
         return key;
     }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 74d598d..0f014cb 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -351,6 +351,8 @@
         // PorterDuff
         "    fragColor = blendColors(colorBlend, fragColor);\n"
 };
+const char* gFS_Main_DebugHighlight =
+        "    gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
 const char* gFS_Footer =
         "}\n\n";
 
@@ -604,7 +606,8 @@
 
     // Optimization for common cases
     if (!description.isAA && !blendFramebuffer && !description.hasColors &&
-            description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
+            description.colorOp == ProgramDescription::kColorNone &&
+            !description.isPoint && !description.hasDebugHighlight) {
         bool fast = false;
 
         const bool noShader = !description.hasGradient && !description.hasBitmap;
@@ -752,6 +755,9 @@
         if (description.hasColors) {
             shader.append(gFS_Main_FragColor_HasColors);
         }
+        if (description.hasDebugHighlight) {
+            shader.append(gFS_Main_DebugHighlight);
+        }
     }
     // End the shader
     shader.append(gFS_Footer);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index f3957cf..4ee16ed 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -68,6 +68,20 @@
 #define PROPERTY_DEBUG_OVERDRAW "debug.hwui.show_overdraw"
 
 /**
+ * Used to enable/disable non-rectangular clipping debugging.
+ *
+ * The accepted values are:
+ * "highlight", drawing commands clipped by the stencil will
+ *              be colored differently
+ * "region", renders the clipping region on screen whenever
+ *           the stencil is set
+ * "hide", don't show the clip
+ *
+ * The default value is "hide".
+ */
+#define PROPERTY_DEBUG_STENCIL_CLIP "debug.hwui.show_stencil_clip"
+
+/**
  * Used to enable/disable scissor optimization. The accepted values are
  * "true" and "false". The default value is "false".
  *
diff --git a/libs/hwui/Stencil.h b/libs/hwui/Stencil.h
index 047f7ee..83ad668 100644
--- a/libs/hwui/Stencil.h
+++ b/libs/hwui/Stencil.h
@@ -87,6 +87,13 @@
         return mState != kDisabled;
     }
 
+    /**
+     * Indicates whether testing only is enabled.
+     */
+    bool isTestEnabled() {
+        return mState == kTest;
+    }
+
 private:
     void enable();