Move textureop fallback code out of GrRTC and into AddTextureSetOps

(also renames CreateTextureSetOps to AddTextureSetOps, to match naming of
GrFillRectOp::AddFillRectOps).

Now that GrTextureOp can add more than one op to the GrRTC, it can take
over ownership of its fallback code for the texture set. It already had
taken over the code for non src-over blends when drawing a single texture.

Besides consolidating where the logic of converting TextureSetEntries into
op data lives, this makes the fallback case more consistent in terms of
performance. Previously, it would go through GrRTC::drawTexturedQuad,
which attempts to merge the clip with the draw for correctness reasons.
A batch never attempted these optimizations, so now even when one op per
quad is required, there won't be the overhead of comparing clips.

Change-Id: I30883e3bd45ed4386f81584e3d68229c46b17e47
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/255781
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/tests/BulkRectTest.cpp b/tests/BulkRectTest.cpp
index 10fcb06..3fa1b19 100644
--- a/tests/BulkRectTest.cpp
+++ b/tests/BulkRectTest.cpp
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-
+#include "src/core/SkBlendModePriv.h"
 #include "src/gpu/GrClip.h"
 #include "src/gpu/GrContextPriv.h"
 #include "src/gpu/GrRenderTargetContext.h"
@@ -35,12 +35,13 @@
 typedef GrQuadAAFlags (*PerQuadAAFunc)(int i);
 
 typedef void (*BulkRectTest)(skiatest::Reporter* reporter, GrContext* context,
-                             PerQuadAAFunc perQuadAA, GrAAType overallAA,
+                             PerQuadAAFunc perQuadAA, GrAAType overallAA, SkBlendMode blendMode,
                              int requestedTotNumQuads, int expectedNumOps);
 
 //-------------------------------------------------------------------------------------------------
 static void bulk_fill_rect_create_test(skiatest::Reporter* reporter, GrContext* context,
                                        PerQuadAAFunc perQuadAA, GrAAType overallAA,
+                                       SkBlendMode blendMode,
                                        int requestedTotNumQuads, int expectedNumOps) {
 
     std::unique_ptr<GrRenderTargetContext> rtc = new_RTC(context);
@@ -55,7 +56,7 @@
     }
 
     GrPaint paint;
-
+    paint.setXPFactory(SkBlendMode_AsXPFactory(blendMode));
     GrFillRectOp::AddFillRectOps(rtc.get(), GrNoClip(), context, std::move(paint), overallAA,
                                  SkMatrix::I(), quads, requestedTotNumQuads);
 
@@ -82,18 +83,22 @@
 //-------------------------------------------------------------------------------------------------
 static void bulk_texture_rect_create_test(skiatest::Reporter* reporter, GrContext* context,
                                           PerQuadAAFunc perQuadAA, GrAAType overallAA,
+                                          SkBlendMode blendMode,
                                           int requestedTotNumQuads, int expectedNumOps) {
 
     std::unique_ptr<GrRenderTargetContext> rtc = new_RTC(context);
 
-    sk_sp<GrSurfaceProxy> proxy = create_proxy(context);
-
-    GrSurfaceProxyView proxyView(std::move(proxy), kTopLeft_GrSurfaceOrigin, GrSwizzle::RGBA());
+    sk_sp<GrSurfaceProxy> proxyA = create_proxy(context);
+    sk_sp<GrSurfaceProxy> proxyB = create_proxy(context);
+    GrSurfaceProxyView proxyViewA(std::move(proxyA), kTopLeft_GrSurfaceOrigin, GrSwizzle::RGBA());
+    GrSurfaceProxyView proxyViewB(std::move(proxyB), kTopLeft_GrSurfaceOrigin, GrSwizzle::RGBA());
 
     auto set = new GrRenderTargetContext::TextureSetEntry[requestedTotNumQuads];
 
     for (int i = 0; i < requestedTotNumQuads; ++i) {
-        set[i].fProxyView = proxyView;
+        // Alternate between two proxies to prevent op merging if the batch API was forced to submit
+        // one op at a time (to work, this does require that all fDstRects overlap).
+        set[i].fProxyView = i % 2 == 0 ? proxyViewA : proxyViewB;
         set[i].fSrcColorType = GrColorType::kRGBA_8888;
         set[i].fSrcRect = SkRect::MakeWH(100.0f, 100.0f);
         set[i].fDstRect = SkRect::MakeWH(100.5f, 100.5f); // prevent the int non-AA optimization
@@ -103,9 +108,10 @@
         set[i].fAAFlags = perQuadAA(i);
     }
 
-    GrTextureOp::CreateTextureSetOps(rtc.get(), GrNoClip(), context, set, requestedTotNumQuads,
+    GrTextureOp::AddTextureSetOps(rtc.get(), GrNoClip(), context, set, requestedTotNumQuads,
                                      GrSamplerState::Filter::kNearest,
                                      GrTextureOp::Saturate::kYes,
+                                     blendMode,
                                      overallAA,
                                      SkCanvas::kStrict_SrcRectConstraint,
                                      SkMatrix::I(), nullptr);
@@ -115,9 +121,18 @@
 
     int actualTotNumQuads = 0;
 
+    if (blendMode != SkBlendMode::kSrcOver ||
+        !context->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
+        // In either of these two cases, GrTextureOp creates one op per quad instead. Since
+        // each entry alternates proxies but overlaps geometrically, this will prevent the ops
+        // from being merged back into fewer ops.
+        expectedNumOps = requestedTotNumQuads;
+    }
+    uint32_t expectedOpID = blendMode == SkBlendMode::kSrcOver ? GrTextureOp::ClassID()
+                                                               : GrFillRectOp::ClassID();
     for (int i = 0; i < actualNumOps; ++i) {
         const GrOp* tmp = opsTask->getChain(i);
-        REPORTER_ASSERT(reporter, tmp->classID() == GrTextureOp::ClassID());
+        REPORTER_ASSERT(reporter, tmp->classID() == expectedOpID);
         REPORTER_ASSERT(reporter, tmp->isChainTail());
         actualTotNumQuads += ((GrDrawOp*) tmp)->numQuads();
     }
@@ -132,11 +147,6 @@
 
 //-------------------------------------------------------------------------------------------------
 static void run_test(GrContext* context, skiatest::Reporter* reporter, BulkRectTest test) {
-
-    if (!context->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
-        return;
-    }
-
     // This is the simple case where there is no AA at all. We expect 2 non-AA clumps of quads.
     {
         auto noAA = [](int i) -> GrQuadAAFlags {
@@ -145,7 +155,7 @@
 
         static const int kNumExpectedOps = 2;
 
-        test(reporter, context, noAA, GrAAType::kNone,
+        test(reporter, context, noAA, GrAAType::kNone, SkBlendMode::kSrcOver,
              2*GrResourceProvider::MaxNumNonAAQuads(), kNumExpectedOps);
     }
 
@@ -158,7 +168,7 @@
 
         static const int kNumExpectedOps = 2;
 
-        test(reporter, context, noAA, GrAAType::kCoverage,
+        test(reporter, context, noAA, GrAAType::kCoverage, SkBlendMode::kSrcOver,
              2*GrResourceProvider::MaxNumNonAAQuads(), kNumExpectedOps);
     }
 
@@ -172,7 +182,7 @@
         int numExpectedOps = 2*GrResourceProvider::MaxNumNonAAQuads() /
                                                  GrResourceProvider::MaxNumAAQuads();
 
-        test(reporter, context, alternateAA, GrAAType::kCoverage,
+        test(reporter, context, alternateAA, GrAAType::kCoverage, SkBlendMode::kSrcOver,
              2*GrResourceProvider::MaxNumNonAAQuads(), numExpectedOps);
     }
 
@@ -187,7 +197,22 @@
 
         static const int kNumExpectedOps = 2;
 
-        test(reporter, context, runOfNonAA, GrAAType::kCoverage,
+        test(reporter, context, runOfNonAA, GrAAType::kCoverage, SkBlendMode::kSrcOver,
+             2*GrResourceProvider::MaxNumAAQuads(), kNumExpectedOps);
+    }
+
+    // In this case we use a blend mode other than src-over, which hits the GrFillRectOp fallback
+    // code path for GrTextureOp. We pass in the expected results if batching was successful, to
+    // that bulk_fill_rect_create_test batches on all modes; bulk_texture_rect_create_test is
+    // responsible for revising its expectations.
+    {
+        auto fixedAA = [](int i) -> GrQuadAAFlags {
+            return GrQuadAAFlags::kAll;
+        };
+
+        static const int kNumExpectedOps = 2;
+
+        test(reporter, context, fixedAA, GrAAType::kCoverage, SkBlendMode::kSrcATop,
              2*GrResourceProvider::MaxNumAAQuads(), kNumExpectedOps);
     }
 }