Combine coverage in GrAppliedClip using RunInSeries.

This lets us end up with a single coverage processor instead of an array
of them. Coverage processors simply multiply against their input so the
results are conceptually equivalent.

In practice, it is uncommon to have more than one applied clip (at least
on GMs).

Change-Id: I73d5da8015f48c6cb1d3f37257e7e0c4329579b5
Bug: skia:10217
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/305117
Commit-Queue: John Stiles <johnstiles@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/GrAppliedClip.h b/src/gpu/GrAppliedClip.h
index 75e614a..c02f815 100644
--- a/src/gpu/GrAppliedClip.h
+++ b/src/gpu/GrAppliedClip.h
@@ -104,59 +104,57 @@
     const GrWindowRectsState& windowRectsState() const { return fHardClip.windowRectsState(); }
     uint32_t stencilStackID() const { return fHardClip.stencilStackID(); }
     bool hasStencilClip() const { return fHardClip.hasStencilClip(); }
-    int numClipCoverageFragmentProcessors() const { return fClipCoverageFPs.count(); }
-    const GrFragmentProcessor* clipCoverageFragmentProcessor(int i) const {
-        SkASSERT(fClipCoverageFPs[i]);
-        return fClipCoverageFPs[i].get();
+    int hasCoverageFragmentProcessor() const { return fCoverageFP != nullptr; }
+    const GrFragmentProcessor* coverageFragmentProcessor() const {
+        SkASSERT(fCoverageFP != nullptr);
+        return fCoverageFP.get();
     }
-    std::unique_ptr<const GrFragmentProcessor> detachClipCoverageFragmentProcessor(int i) {
-        SkASSERT(fClipCoverageFPs[i]);
-        return std::move(fClipCoverageFPs[i]);
+    std::unique_ptr<const GrFragmentProcessor> detachCoverageFragmentProcessor() {
+        SkASSERT(fCoverageFP != nullptr);
+        return std::move(fCoverageFP);
     }
 
     const GrAppliedHardClip& hardClip() const { return fHardClip; }
     GrAppliedHardClip& hardClip() { return fHardClip; }
 
     void addCoverageFP(std::unique_ptr<GrFragmentProcessor> fp) {
-        SkASSERT(fp);
-        fClipCoverageFPs.push_back(std::move(fp));
+        if (fCoverageFP == nullptr) {
+            fCoverageFP = std::move(fp);
+        } else {
+            // Run this coverage FP in series with the previously-added coverage.
+            std::unique_ptr<GrFragmentProcessor> series[] = {
+                std::move(fCoverageFP),
+                std::move(fp),
+            };
+            fCoverageFP = GrFragmentProcessor::RunInSeries(series, SK_ARRAY_COUNT(series));
+        }
     }
 
     bool doesClip() const {
-        return fHardClip.doesClip() || !fClipCoverageFPs.empty();
+        return fHardClip.doesClip() || fCoverageFP != nullptr;
     }
 
     bool operator==(const GrAppliedClip& that) const {
         if (fHardClip != that.fHardClip ||
-            fClipCoverageFPs.count() != that.fClipCoverageFPs.count()) {
+            this->hasCoverageFragmentProcessor() != that.hasCoverageFragmentProcessor()) {
             return false;
         }
-        for (int i = 0; i < fClipCoverageFPs.count(); ++i) {
-            if (!fClipCoverageFPs[i] || !that.fClipCoverageFPs[i]) {
-                if (fClipCoverageFPs[i] == that.fClipCoverageFPs[i]) {
-                    continue; // Both are null.
-                }
-                return false;
-            }
-            if (!fClipCoverageFPs[i]->isEqual(*that.fClipCoverageFPs[i])) {
-                return false;
-            }
+        if (fCoverageFP != nullptr && !fCoverageFP->isEqual(*that.fCoverageFP)) {
+            return false;
         }
         return true;
     }
     bool operator!=(const GrAppliedClip& that) const { return !(*this == that); }
 
     void visitProxies(const GrOp::VisitProxyFunc& func) const {
-        for (const std::unique_ptr<GrFragmentProcessor>& fp : fClipCoverageFPs) {
-            if (fp) { // This might be called after detach.
-                fp->visitProxies(func);
-            }
+        if (fCoverageFP != nullptr) {
+            fCoverageFP->visitProxies(func);
         }
     }
 
 private:
     GrAppliedHardClip fHardClip;
-    SkSTArray<4, std::unique_ptr<GrFragmentProcessor>> fClipCoverageFPs;
+    std::unique_ptr<GrFragmentProcessor> fCoverageFP;
 };
 
 #endif
diff --git a/src/gpu/GrOpsTask.cpp b/src/gpu/GrOpsTask.cpp
index 614e982..9630914 100644
--- a/src/gpu/GrOpsTask.cpp
+++ b/src/gpu/GrOpsTask.cpp
@@ -311,10 +311,9 @@
     fBounds = that->fBounds;
 
     that->fDstProxyView.setProxyView({});
-    if (that->fAppliedClip) {
-        for (int i = 0; i < that->fAppliedClip->numClipCoverageFragmentProcessors(); ++i) {
-            that->fAppliedClip->detachClipCoverageFragmentProcessor(i);
-        }
+    if (that->fAppliedClip && that->fAppliedClip->hasCoverageFragmentProcessor()) {
+        // Obliterates the processor.
+        that->fAppliedClip->detachCoverageFragmentProcessor();
     }
     this->validate();
     return true;
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index ac4869e..cfc7479 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -46,7 +46,7 @@
     fNumColorProcessors = processors.hasColorFragmentProcessor() ? 1 : 0;
     int numTotalProcessors = fNumColorProcessors +
                              (processors.hasCoverageFragmentProcessor() ? 1 : 0) +
-                             appliedClip.numClipCoverageFragmentProcessors();
+                             (appliedClip.hasCoverageFragmentProcessor() ? 1 : 0);
     fFragmentProcessors.reset(numTotalProcessors);
 
     int currFPIdx = 0;
@@ -56,8 +56,8 @@
     if (processors.hasCoverageFragmentProcessor()) {
         fFragmentProcessors[currFPIdx++] = processors.detachCoverageFragmentProcessor();
     }
-    for (int i = 0; i < appliedClip.numClipCoverageFragmentProcessors(); ++i) {
-        fFragmentProcessors[currFPIdx++] = appliedClip.detachClipCoverageFragmentProcessor(i);
+    if (appliedClip.hasCoverageFragmentProcessor()) {
+        fFragmentProcessors[currFPIdx++] = appliedClip.detachCoverageFragmentProcessor();
     }
 }
 
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index c8a32b8..0738f8c 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -230,7 +230,8 @@
 
     friend bool operator&(Flags, InputFlags);
 
-    using FragmentProcessorArray = SkAutoSTArray<6, std::unique_ptr<const GrFragmentProcessor>>;
+    // A pipeline can contain up to three processors: color, paint coverage, and clip coverage.
+    using FragmentProcessorArray = SkAutoSTArray<3, std::unique_ptr<const GrFragmentProcessor>>;
 
     GrSurfaceProxyView fDstProxyView;
     SkIPoint fDstTextureOffset;
diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp
index 67e6696..7dbae26 100644
--- a/src/gpu/GrProcessorSet.cpp
+++ b/src/gpu/GrProcessorSet.cpp
@@ -148,13 +148,11 @@
         }
         coverageUsesLocalCoords |= fCoverageFragmentProcessor->usesVaryingCoords();
     }
-    if (clip) {
-        hasCoverageFP = hasCoverageFP || clip->numClipCoverageFragmentProcessors();
-        for (int i = 0; i < clip->numClipCoverageFragmentProcessors(); ++i) {
-            const GrFragmentProcessor* clipFP = clip->clipCoverageFragmentProcessor(i);
-            analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
-            coverageUsesLocalCoords |= clipFP->usesVaryingCoords();
-        }
+    if (clip && clip->hasCoverageFragmentProcessor()) {
+        hasCoverageFP = true;
+        const GrFragmentProcessor* clipFP = clip->coverageFragmentProcessor();
+        analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
+        coverageUsesLocalCoords |= clipFP->usesVaryingCoords();
     }
     int colorFPsToEliminate = colorAnalysis.initialProcessorsToEliminate(overrideInputColor);
     analysis.fInputColorType = static_cast<Analysis::PackedInputColorType>(
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
index 90b76ca..86dbc33 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
@@ -90,7 +90,7 @@
     if (fProcessors) {
         GrProcessorAnalysisCoverage coverage = geometryCoverage;
         if (GrProcessorAnalysisCoverage::kNone == coverage) {
-            coverage = clip->numClipCoverageFragmentProcessors()
+            coverage = clip->hasCoverageFragmentProcessor()
                                ? GrProcessorAnalysisCoverage::kSingleChannel
                                : GrProcessorAnalysisCoverage::kNone;
         }