Detect simpler quad type when possible

Previously, providing 4 SkPoints to draw as a quad meant the tessellator
used either kStandard or kPerspective, and couldn't use the faster
kRect and kRectilinear options. This had been simple and under the
assumption that most provided quad points would be from BSP splitting.

However, to emulate SkiaRenderer's required content_area clipping, the
content area is sent as the srcRect and the original geometry is stored
in the SkPoints. In these situations, the it is easy to detect that the
4 points make a rectangle and then relying on the CTMs matrix for the
quad type is perfectly safe.

Change-Id: Ib2b599fa9c82d275519e17cf813713806a565afe
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/206908
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/GrQuad.cpp b/src/gpu/GrQuad.cpp
index 3032307..c741827 100644
--- a/src/gpu/GrQuad.cpp
+++ b/src/gpu/GrQuad.cpp
@@ -200,6 +200,21 @@
     }
 }
 
+GrQuadType GrQuadTypeForPoints(const SkPoint pts[4], const SkMatrix& matrix) {
+    if (matrix.hasPerspective()) {
+        return GrQuadType::kPerspective;
+    }
+    // If 'pts' was formed by SkRect::toQuad() and not transformed further, it is safe to use the
+    // quad type derived from 'matrix'. Otherwise don't waste any more time and assume kStandard
+    // (most general 2D quad).
+    if ((pts[0].fY == pts[3].fY && pts[1].fY == pts[2].fY) &&
+        (pts[0].fX == pts[1].fX && pts[2].fX == pts[3].fX)) {
+        return GrQuadTypeForTransformedRect(matrix);
+    } else {
+        return GrQuadType::kStandard;
+    }
+}
+
 GrQuad GrQuad::MakeFromRect(const SkRect& rect, const SkMatrix& m) {
     Sk4f x, y;
     SkMatrix::TypeMask tm = m.getType();
diff --git a/src/gpu/GrQuad.h b/src/gpu/GrQuad.h
index a4b3bbf..675a088 100644
--- a/src/gpu/GrQuad.h
+++ b/src/gpu/GrQuad.h
@@ -38,6 +38,9 @@
 // quadType() is only provided on Gr[Persp]Quad in debug builds, production code should use this
 // to efficiently determine quad types.
 GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix);
+// Perform minimal analysis of 'pts' (which are suitable for MakeFromSkQuad), and determine a
+// quad type that will be as minimally general as possible.
+GrQuadType GrQuadTypeForPoints(const SkPoint pts[4], const SkMatrix& matrix);
 
 // Resolve disagreements between the overall requested AA type and the per-edge quad AA flags.
 // knownQuadType must have come from GrQuadTypeForTransformedRect with the matrix that created the
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index 59b5b62..6810a6f 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -401,15 +401,12 @@
                                           const SkPoint quad[4],
                                           const SkPoint localQuad[4],
                                           const GrUserStencilSettings* stencilSettings) {
-    // With arbitrary quads, the quad types are limited to kStandard or kPerspective (unless we
-    // analyzed the points, but callers have more knowledge and should've just use the appropriate
-    // factory, so assume they can't be rectilinear or simpler)
-    GrQuadType deviceType = viewMatrix.hasPerspective() ? GrQuadType::kPerspective
-                                                        : GrQuadType::kStandard;
+    GrQuadType deviceType = GrQuadTypeForPoints(quad, viewMatrix);
+    GrQuadType localType = GrQuadTypeForPoints(localQuad ? localQuad : quad, SkMatrix::I());
     return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
                             GrPerspQuad::MakeFromSkQuad(quad, viewMatrix), deviceType,
                             GrPerspQuad::MakeFromSkQuad(localQuad ? localQuad : quad,
-                                                        SkMatrix::I()), GrQuadType::kStandard);
+                                                        SkMatrix::I()), localType);
 }
 
 std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 6329917..6426199 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -149,9 +149,9 @@
                                           const SkMatrix& viewMatrix,
                                           sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
         GrPerspQuad grDstQuad = GrPerspQuad::MakeFromSkQuad(dstQuad, viewMatrix);
-        GrQuadType dstQuadType = viewMatrix.hasPerspective() ? GrQuadType::kPerspective
-                                                             : GrQuadType::kStandard;
+        GrQuadType dstQuadType = GrQuadTypeForPoints(dstQuad, viewMatrix);
         GrPerspQuad grSrcQuad = GrPerspQuad::MakeFromSkQuad(srcQuad, SkMatrix::I());
+        GrQuadType srcQuadType = GrQuadTypeForPoints(srcQuad, SkMatrix::I());
 
         // If constraint remains fast, the value in srcRect will be ignored since srcQuads provides
         // the local coordinates and a domain won't be used.
@@ -166,7 +166,7 @@
         // Pass domain as srcRect if provided, but send srcQuad as a GrPerspQuad for local coords
         return pool->allocate<TextureOp>(
                 std::move(proxy), filter, color, grDstQuad, dstQuadType, srcRect, constraint,
-                &grSrcQuad, GrQuadType::kStandard, aaType, aaFlags,
+                &grSrcQuad, srcQuadType, aaType, aaFlags,
                 std::move(textureColorSpaceXform));
     }
     static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
@@ -340,10 +340,9 @@
             auto quad = set[p].fDstClipQuad == nullptr ?
                     GrPerspQuad::MakeFromRect(set[p].fDstRect, ctm) :
                     GrPerspQuad::MakeFromSkQuad(set[p].fDstClipQuad, ctm);
-            GrQuadType quadType = GrQuadTypeForTransformedRect(ctm);
-            if (set[p].fDstClipQuad && quadType != GrQuadType::kPerspective) {
-                quadType = GrQuadType::kStandard;
-            }
+            GrQuadType quadType =
+                    set[p].fDstClipQuad ? GrQuadTypeForPoints(set[p].fDstClipQuad, ctm)
+                                        : GrQuadTypeForTransformedRect(ctm);
 
             bounds.joinPossiblyEmptyRect(quad.bounds(quadType));
             GrQuadAAFlags aaFlags;
@@ -381,7 +380,7 @@
                 SkPoint srcQuad[4];
                 GrMapRectPoints(set[p].fDstRect, set[p].fSrcRect, set[p].fDstClipQuad, srcQuad, 4);
                 fSrcQuads.push_back(GrPerspQuad::MakeFromSkQuad(srcQuad, SkMatrix::I()),
-                                    GrQuadType::kStandard);
+                                    GrQuadTypeForPoints(srcQuad, SkMatrix::I()));
                 srcQuadIndex = fSrcQuads.count() - 1;
             }
             fQuads.push_back(quad, quadType,