Use path intersection instead of saveLayer+mesh to mask projected ripples
bug:14297149
SaveLayer's performance cost is high, and proportional to the surface
being projected onto. Since ripples (even unbounded ones) are now
always projected to the arbitrary background content behind them, this
cost is especially important to avoid.
This removes the last semi-secret, saveLayer from the projected
ripple implementation.
Also fixes the HW test app to correctly demonstrate this projection
masking behavior.
Additionaly, alters PathTessellator to gracefully handle
counter-clockwise paths, and simplifies the work done by
ShadowTessellator to ensure all of its paths are counterclockwise.
Change-Id: Ibe9e12812bd10a774e20b1d444a140c368cbba8c
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index fc173f7..704a691 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -207,6 +207,16 @@
transformXY->mapPoint(point.x, point.y);
}
+static void reverseVertexArray(Vertex* polygon, int len) {
+ int n = len / 2;
+ for (int i = 0; i < n; i++) {
+ Vertex tmp = polygon[i];
+ int k = len - 1 - i;
+ polygon[i] = polygon[k];
+ polygon[k] = tmp;
+ }
+}
+
static void tessellateShadows(
const Matrix4* drawTransform, const Rect* localClip,
bool isCasterOpaque, const SkPath* casterPerimeter,
@@ -219,10 +229,9 @@
const float casterRefinementThresholdSquared = 4.0f;
PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
casterRefinementThresholdSquared, casterVertices2d);
- if (!ShadowTessellator::isClockwisePath(*casterPerimeter)) {
- ShadowTessellator::reverseVertexArray(casterVertices2d.editArray(),
- casterVertices2d.size());
- }
+
+ // Shadow requires CCW for now. TODO: remove potential double-reverse
+ reverseVertexArray(casterVertices2d.editArray(), casterVertices2d.size());
if (casterVertices2d.size() == 0) return;