Allow non-AA clip rects to be scissor only even on MSAA targets

This appears to fix the performance regressions seen on a number of webpage
SKPs for vkmsaa8 and glmsaa targets on devices that can't disable multisampling.

Bug: skia:10730
Change-Id: I2c10a78cfe864f987b7f17eb69eb2e1712ca0676
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/317772
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/GrClipStack.cpp b/src/gpu/GrClipStack.cpp
index c6741b9..1d7c9a0 100644
--- a/src/gpu/GrClipStack.cpp
+++ b/src/gpu/GrClipStack.cpp
@@ -540,7 +540,10 @@
         return;
     }
 
-    if (forceAA) {
+    // Except for axis-aligned clip rects, upgrade to AA when forced. We skip axis-aligned clip
+    // rects because a non-AA axis aligned rect can always be set as just a scissor test or window
+    // rect, avoiding an expensive stencil mask generation.
+    if (forceAA && !(fShape.isRect() && fLocalToDevice.isScaleTranslate())) {
         fAA = GrAA::kYes;
     }
 
diff --git a/tests/GrClipStackTest.cpp b/tests/GrClipStackTest.cpp
index 79730e5..372e865 100644
--- a/tests/GrClipStackTest.cpp
+++ b/tests/GrClipStackTest.cpp
@@ -1605,27 +1605,36 @@
     SkPath nonAAPath = make_octagon({2.f, 10.f, 16.f, 20.f});
     cs.clipPath(SkMatrix::I(), nonAAPath, GrAA::kNo, SkClipOp::kIntersect);
 
-    // Non-AA can combine with AA that wouldn't normally have combined
+    // Non-AA rects remain non-AA so they can be applied as a scissor
     SkRect nonAARect = {4.5f, 5.f, 17.25f, 18.23f};
     cs.clipRect(SkMatrix::I(), nonAARect, GrAA::kNo, SkClipOp::kIntersect);
 
     // The stack reports elements newest first, but the non-AA rect op was combined in place with
     // the first aa rect, so we should see nonAAPath as AA, and then the intersection of rects.
-    SkRect expectedRect = aaRect;
-    SkAssertResult(expectedRect.intersect(nonAARect));
     auto elements = cs.begin();
 
-    const GrClipStack::Element& aaPath = *elements;
-    REPORTER_ASSERT(r, aaPath.fShape.path() == nonAAPath, "Expected path element");
-    REPORTER_ASSERT(r, aaPath.fAA == GrAA::kYes, "Path element not promoted to AA");
+    const GrClipStack::Element& nonAARectElement = *elements;
+    REPORTER_ASSERT(r, nonAARectElement.fShape.isRect(), "Expected rect element");
+    REPORTER_ASSERT(r, nonAARectElement.fAA == GrAA::kNo,
+                    "Axis-aligned non-AA rect ignores forceAA");
+    REPORTER_ASSERT(r, nonAARectElement.fShape.rect() == nonAARect,
+                    "Mixed AA rects should not combine");
 
     ++elements;
-    const GrClipStack::Element& rect = *elements;
-    REPORTER_ASSERT(r, rect.fShape.rect() == expectedRect, "Mixed AA rects did not combine");
-    REPORTER_ASSERT(r, rect.fAA == GrAA::kYes, "Rect elements not promoted to AA");
+    const GrClipStack::Element& aaPathElement = *elements;
+    REPORTER_ASSERT(r, aaPathElement.fShape.isPath(), "Expected path element");
+    REPORTER_ASSERT(r, aaPathElement.fShape.path() == nonAAPath, "Wrong path element");
+    REPORTER_ASSERT(r, aaPathElement.fAA == GrAA::kYes, "Path element not promoted to AA");
 
     ++elements;
-    REPORTER_ASSERT(r, !(elements != cs.end()), "Expected only two clip elements");
+    const GrClipStack::Element& aaRectElement = *elements;
+    REPORTER_ASSERT(r, aaRectElement.fShape.isRect(), "Expected rect element");
+    REPORTER_ASSERT(r, aaRectElement.fShape.rect() == aaRect,
+                    "Mixed AA rects should not combine");
+    REPORTER_ASSERT(r, aaRectElement.fAA == GrAA::kYes, "Rect element stays AA");
+
+    ++elements;
+    REPORTER_ASSERT(r, !(elements != cs.end()), "Expected only three clip elements");
 }
 
 // Tests preApply works as expected for device rects, rrects, and reports clipped-out, etc. as