Allow batching of coverage and non-coverage GrTextureOps.

Fall back to simpler tessellation for quads with no AA. In perspective
op only fall back when an individual quad is both non-aa and non-
perspective.

Change-Id: I0caadfe47a007c591f67f18753150ca23b43423b
Reviewed-on: https://skia-review.googlesource.com/c/161642
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 94e5ad5..0c44446 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -377,6 +377,17 @@
     static void AssignPositionsAndTexCoords(V* vertices, const GrPerspQuad& quad,
                                             GrQuadAAFlags aaFlags, const SkRect& texRect) {
         SkASSERT((quad.w4f() == Sk4f(1.f)).allTrue());
+        if (aaFlags == GrQuadAAFlags::kNone) {
+            for (int i = 0; i < 4; ++i) {
+                vertices[i].fPosition = {quad.x(i), quad.y(i)};
+                for (int j = 0; j < 4; ++j) {
+                    // This works because the position w components are known to be 1.
+                    vertices[i].fEdges[j] = {0, 0, 1};
+                }
+            }
+            SkPointPriv::SetRectTriStrip(&vertices[0].fTextureCoords, texRect, sizeof(V));
+            return;
+        }
         auto x = quad.x4f();
         auto y = quad.y4f();
         Sk4f a, b, c;
@@ -411,6 +422,17 @@
         auto y = quad.y4f();
         auto iw = quad.iw4f();
 
+        if ((iw == Sk4f(1)).allTrue() && aaFlags == GrQuadAAFlags::kNone) {
+            for (int i = 0; i < 4; ++i) {
+                vertices[i].fPosition = quad.point(i);
+                for (int j = 0; j < 4; ++j) {
+                    // This works because the position w components are known to be 1.
+                    vertices[i].fEdges[j] = {0, 0, 1};
+                }
+            }
+            SkPointPriv::SetRectTriStrip(&vertices[0].fTextureCoords, texRect, sizeof(V));
+            return;
+        }
         Sk4f a, b, c;
         auto x2d = x * iw;
         auto y2d = y * iw;
@@ -849,6 +871,7 @@
         int numTotalQuads = 0;
         auto textureType = fProxies[0].fProxy->textureType();
         auto config = fProxies[0].fProxy->config();
+        GrAAType aaType = this->aaType();
         for (const auto& op : ChainRange<TextureOp>(this)) {
             hasPerspective |= op.fPerspective;
             if (op.fDomain) {
@@ -864,9 +887,13 @@
                 SkASSERT(proxy->config() == config);
                 SkASSERT(proxy->textureType() == textureType);
             }
+            if (op.aaType() == GrAAType::kCoverage) {
+                SkASSERT(aaType == GrAAType::kCoverage || aaType == GrAAType::kNone);
+                aaType = GrAAType::kCoverage;
+            }
         }
 
-        bool coverageAA = GrAAType::kCoverage == this->aaType();
+        bool coverageAA = GrAAType::kCoverage == aaType;
         sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(
                 textureType, config, this->filter(), std::move(fTextureColorSpaceXform),
                 std::move(fPaintColorSpaceXform), coverageAA, hasPerspective, domain,
@@ -876,7 +903,7 @@
         args.fCaps = &target->caps();
         args.fResourceProvider = target->resourceProvider();
         args.fFlags = 0;
-        if (GrAAType::kMSAA == this->aaType()) {
+        if (aaType == GrAAType::kMSAA) {
             args.fFlags |= GrPipeline::kHWAntialias_Flag;
         }
 
@@ -994,10 +1021,13 @@
                                        that->fPaintColorSpaceXform.get())) {
             return CombineResult::kCannotCombine;
         }
-        // TODO: Should we allow kNone and kCoverage to merge by upgrading kNone to kCoverage?
-        // If we allowed chaining the head op would have to pre-iterate to determine the aa-type.
+        bool upgradeToCoverageAAOnMerge = false;
         if (this->aaType() != that->aaType()) {
-            return CombineResult::kCannotCombine;
+            if (!((this->aaType() == GrAAType::kCoverage && that->aaType() == GrAAType::kNone) ||
+                  (that->aaType() == GrAAType::kCoverage && this->aaType() == GrAAType::kNone))) {
+                return CombineResult::kCannotCombine;
+            }
+            upgradeToCoverageAAOnMerge = true;
         }
         if (fFilter != that->fFilter) {
             return CombineResult::kCannotCombine;
@@ -1020,6 +1050,9 @@
         this->joinBounds(*that);
         fPerspective |= that->fPerspective;
         fDomain |= that->fDomain;
+        if (upgradeToCoverageAAOnMerge) {
+            fAAType = static_cast<unsigned>(GrAAType::kCoverage);
+        }
         return CombineResult::kMerged;
     }