Reland "More optimizations for CropToRect, for axis-aligned quads that have not been inverted"
This reverts commit 0437f0f5d89d494199287825335b06b45c4428d9.
Reason for revert: layout tests have been suppressed
Original change's description:
> Revert "More optimizations for CropToRect, for axis-aligned quads that have not been inverted"
>
> This reverts commit 88a64b4696d5a01e611e69d594088c0ca5667037.
>
> Reason for revert: Chrome layout tests
>
> Original change's description:
> > More optimizations for CropToRect, for axis-aligned quads that have not been inverted
> >
> > Prior to CropToRect(), GrRTC::crop_filled_rect only operated on SkRects. The
> > quad cropping code generalized the optimization to any axis-aligned quad, but
> > a consequence of this is the code had to be robust to flips and 90 degree
> > rotations. While it can handle more cases, it has lead to a 1-10% performance
> > regression on cropped-rectangle-heavy perf tests in chromium.
> >
> > This change brings back the simplest cropping solution when the axis-aligned
> > quads have not been flipped/rotated, but the general version still exists for
> > the other class of quads as well.
> >
> > Bug: chromium:980608
> > Change-Id: I83d71075cacc3d849fd9aac6436ea3244a0ae4b9
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/225724
> > Commit-Queue: Brian Salomon <bsalomon@google.com>
> > Auto-Submit: Michael Ludwig <michaelludwig@google.com>
> > Reviewed-by: Brian Salomon <bsalomon@google.com>
>
> TBR=bsalomon@google.com,robertphillips@google.com,michaelludwig@google.com
>
> Change-Id: I428cbefa5985c6160df0460d38b0698b43d289de
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: chromium:980608
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/225733
> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
TBR=bsalomon@google.com,robertphillips@google.com,michaelludwig@google.com
Change-Id: Ibef8e521f45111b3307731966e19ef66824567e2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:980608
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/226177
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/geometry/GrQuadUtils.cpp b/src/gpu/geometry/GrQuadUtils.cpp
index 4c7a983..78edc3c 100644
--- a/src/gpu/geometry/GrQuadUtils.cpp
+++ b/src/gpu/geometry/GrQuadUtils.cpp
@@ -93,16 +93,15 @@
return false;
}
-// Updates x and y to intersect with clipDevRect, and applies clipAA policy to edgeFlags for each
-// intersected edge. lx, ly, and lw are updated appropriately and may be null to skip calculations.
-static void crop_rect(const SkRect& clipDevRect, GrAA clipAA, GrQuadAAFlags* edgeFlags,
- float x[4], float y[4], float lx[4], float ly[4], float lw[4]) {
- // Filled in as if clipAA were true, will be inverted at the end if needed.
+// Updates x and y to intersect with clipDevRect. lx, ly, and lw are updated appropriately and may
+// be null to skip calculations. Returns bit mask of edges that were clipped.
+static GrQuadAAFlags crop_rect(const SkRect& clipDevRect, float x[4], float y[4],
+ float lx[4], float ly[4], float lw[4]) {
GrQuadAAFlags clipEdgeFlags = GrQuadAAFlags::kNone;
- // However, the quad's left edge may not align with the SkRect notion of left due to 90 degree
- // rotations or mirrors. So, this processes the logical edges of the quad and clamps it to the 4
- // sides of clipDevRect.
+ // The quad's left edge may not align with the SkRect notion of left due to 90 degree rotations
+ // or mirrors. So, this processes the logical edges of the quad and clamps it to the 4 sides of
+ // clipDevRect.
// Quad's left is v0 to v1 (op. v2 and v3)
if (crop_rect_edge(clipDevRect, 0, 1, 2, 3, x, y, lx, ly, lw)) {
@@ -121,13 +120,68 @@
clipEdgeFlags |= GrQuadAAFlags::kBottom;
}
- if (clipAA == GrAA::kYes) {
- // Turn on all edges that were clipped
- *edgeFlags |= clipEdgeFlags;
- } else {
- // Turn off all edges that were clipped
- *edgeFlags &= ~clipEdgeFlags;
+ return clipEdgeFlags;
+}
+
+// Similar to crop_rect, but assumes that both the device coordinates and optional local coordinates
+// geometrically match the TL, BL, TR, BR vertex ordering, i.e. axis-aligned but not flipped, etc.
+static GrQuadAAFlags crop_simple_rect(const SkRect& clipDevRect, float x[4], float y[4],
+ float lx[4], float ly[4]) {
+ GrQuadAAFlags clipEdgeFlags = GrQuadAAFlags::kNone;
+
+ // Update local coordinates proportionately to how much the device rect edge was clipped
+ const SkScalar dx = lx ? (lx[2] - lx[0]) / (x[2] - x[0]) : 0.f;
+ const SkScalar dy = ly ? (ly[1] - ly[0]) / (y[1] - y[0]) : 0.f;
+ if (clipDevRect.fLeft > x[0]) {
+ if (lx) {
+ lx[0] += (clipDevRect.fLeft - x[0]) * dx;
+ lx[1] = lx[0];
+ }
+ x[0] = clipDevRect.fLeft;
+ x[1] = clipDevRect.fLeft;
+ clipEdgeFlags |= GrQuadAAFlags::kLeft;
}
+ if (clipDevRect.fTop > y[0]) {
+ if (ly) {
+ ly[0] += (clipDevRect.fTop - y[0]) * dy;
+ ly[2] = ly[0];
+ }
+ y[0] = clipDevRect.fTop;
+ y[2] = clipDevRect.fTop;
+ clipEdgeFlags |= GrQuadAAFlags::kTop;
+ }
+ if (clipDevRect.fRight < x[2]) {
+ if (lx) {
+ lx[2] -= (x[2] - clipDevRect.fRight) * dx;
+ lx[3] = lx[2];
+ }
+ x[2] = clipDevRect.fRight;
+ x[3] = clipDevRect.fRight;
+ clipEdgeFlags |= GrQuadAAFlags::kRight;
+ }
+ if (clipDevRect.fBottom < y[1]) {
+ if (ly) {
+ ly[1] -= (y[1] - clipDevRect.fBottom) * dy;
+ ly[3] = ly[1];
+ }
+ y[1] = clipDevRect.fBottom;
+ y[3] = clipDevRect.fBottom;
+ clipEdgeFlags |= GrQuadAAFlags::kBottom;
+ }
+
+ return clipEdgeFlags;
+}
+// Consistent with GrQuad::asRect()'s return value but requires fewer operations since we don't need
+// to calculate the bounds of the quad.
+static bool is_simple_rect(const GrQuad& quad) {
+ if (quad.quadType() != GrQuad::Type::kAxisAligned) {
+ return false;
+ }
+ // v0 at the geometric top-left is unique, so we only need to compare x[0] < x[2] for left
+ // and y[0] < y[1] for top, but add a little padding to protect against numerical precision
+ // on R90 and R270 transforms tricking this check.
+ return ((quad.x(0) + SK_ScalarNearlyZero) < quad.x(2)) &&
+ ((quad.y(0) + SK_ScalarNearlyZero) < quad.y(1));
}
// Calculates barycentric coordinates for each point in (testX, testY) in the triangle formed by
@@ -198,13 +252,34 @@
SkASSERT(quad->isFinite());
if (quad->quadType() == GrQuad::Type::kAxisAligned) {
- // crop_rect keeps the rectangles as rectangles, so there's no need to modify types
+ // crop_rect and crop_rect_simple keep the rectangles as rectangles, so the intersection
+ // of the crop and quad can be calculated exactly. Some care must be taken if the quad
+ // is axis-aligned but does not satisfy asRect() due to flips, etc.
+ GrQuadAAFlags clippedEdges;
if (local) {
- crop_rect(cropRect, cropAA, edgeFlags, quad->xs(), quad->ys(),
- local->xs(), local->ys(), local->ws());
+ if (is_simple_rect(*quad) && is_simple_rect(*local)) {
+ clippedEdges = crop_simple_rect(cropRect, quad->xs(), quad->ys(),
+ local->xs(), local->ys());
+ } else {
+ clippedEdges = crop_rect(cropRect, quad->xs(), quad->ys(),
+ local->xs(), local->ys(), local->ws());
+ }
} else {
- crop_rect(cropRect, cropAA, edgeFlags, quad->xs(), quad->ys(),
- nullptr, nullptr, nullptr);
+ if (is_simple_rect(*quad)) {
+ clippedEdges = crop_simple_rect(cropRect, quad->xs(), quad->ys(), nullptr, nullptr);
+ } else {
+ clippedEdges = crop_rect(cropRect, quad->xs(), quad->ys(),
+ nullptr, nullptr, nullptr);
+ }
+ }
+
+ // Apply the clipped edge updates to the original edge flags
+ if (cropAA == GrAA::kYes) {
+ // Turn on all edges that were clipped
+ *edgeFlags |= clippedEdges;
+ } else {
+ // Turn off all edges that were clipped
+ *edgeFlags &= ~clippedEdges;
}
return true;
}