Update GrConvexPolyEffect to support an input FP.

Change-Id: I813a4e4a5b4b0dc4f8ea59056d125386e6049ab4
Bug: skia:10217
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/296516
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
diff --git a/gm/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp
index 786879a..bf61924 100644
--- a/gm/convexpolyeffect.cpp
+++ b/gm/convexpolyeffect.cpp
@@ -126,7 +126,8 @@
                 path->transform(m, &p);
 
                 GrClipEdgeType edgeType = (GrClipEdgeType) et;
-                std::unique_ptr<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(edgeType, p));
+                std::unique_ptr<GrFragmentProcessor> fp =
+                    GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, p);
                 if (!fp) {
                     continue;
                 }
@@ -165,7 +166,8 @@
             for (int et = 0; et < kGrClipEdgeTypeCnt; ++et) {
                 SkRect rect = iter.get()->makeOffset(x, y);
                 GrClipEdgeType edgeType = (GrClipEdgeType) et;
-                std::unique_ptr<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(edgeType, rect));
+                std::unique_ptr<GrFragmentProcessor> fp =
+                    GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, rect);
                 if (!fp) {
                     continue;
                 }
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index dd12281..6553238 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -23,7 +23,6 @@
 #include "src/gpu/GrStencilAttachment.h"
 #include "src/gpu/GrStyle.h"
 #include "src/gpu/GrTextureProxy.h"
-#include "src/gpu/effects/GrConvexPolyEffect.h"
 #include "src/gpu/effects/GrRRectEffect.h"
 #include "src/gpu/effects/generated/GrDeviceSpaceEffect.h"
 #include "src/gpu/geometry/GrStyledShape.h"
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index 08e91ba..b97c3d4 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -687,9 +687,22 @@
         return ClipResult::kNotClipped;
     }
 
-    if (auto fp = GrConvexPolyEffect::Make(GetClipEdgeType(invert, aa), deviceSpacePath)) {
-        fAnalyticFPs.push_back(std::move(fp));
-        return ClipResult::kClipped;
+    if (fAnalyticFPs.empty()) {
+        // Create our first analytic effect in the stack.
+        auto fp = GrConvexPolyEffect::Make(/*inputFP=*/nullptr, GetClipEdgeType(invert, aa),
+                                           deviceSpacePath);
+        if (fp != nullptr) {
+            fAnalyticFPs.push_back(std::move(fp));
+            return ClipResult::kClipped;
+        }
+    } else {
+        // Combine this analytic effect with the previous effect in the stack.
+        auto fp = GrConvexPolyEffect::Make(&fAnalyticFPs.back(), GetClipEdgeType(invert, aa),
+                                           deviceSpacePath);
+        if (fp != nullptr) {
+            fAnalyticFPs.back() = std::move(fp);
+            return ClipResult::kClipped;
+        }
     }
 
     if (fCCPRClipPaths.count() < fMaxCCPRClipPaths && GrAA::kYes == aa) {
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index c71ac77..34fae78 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -66,7 +66,12 @@
     if (GrProcessorEdgeTypeIsInverseFill(cpe.getEdgeType())) {
         fragBuilder->codeAppend("\talpha = 1.0 - alpha;\n");
     }
-    fragBuilder->codeAppendf("\t%s = %s * alpha;\n", args.fOutputColor, args.fInputColor);
+
+    SkString inputSample = cpe.hasInputFP()
+                ? this->invokeChild(/*childIndex=*/0, args.fInputColor, args)
+                : SkString(args.fInputColor);
+
+    fragBuilder->codeAppendf("\t%s = %s * alpha;\n", args.fOutputColor, inputSample.c_str());
 }
 
 void GrGLConvexPolyEffect::onSetData(const GrGLSLProgramDataManager& pdman,
@@ -89,8 +94,9 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType type,
-                                                              const SkPath& path) {
+std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(
+        std::unique_ptr<GrFragmentProcessor>* inputFP,
+        GrClipEdgeType type, const SkPath& path) {
     if (GrClipEdgeType::kHairlineAA == type) {
         return nullptr;
     }
@@ -105,14 +111,16 @@
     // skip the draw or omit the clip element.
     if (!SkPathPriv::CheapComputeFirstDirection(path, &dir)) {
         if (GrProcessorEdgeTypeIsInverseFill(type)) {
-            return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fWHITE,
+            return GrConstColorProcessor::Make(inputFP ? std::move(*inputFP) : nullptr,
+                                               SK_PMColor4fWHITE,
                                                GrConstColorProcessor::InputMode::kModulateRGBA);
         }
         // This could use kIgnore instead of kModulateRGBA but it would trigger a debug print
         // about a coverage processor not being compatible with the alpha-as-coverage optimization.
         // We don't really care about this unlikely case so we just use kModulateRGBA to suppress
         // the print.
-        return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
+        return GrConstColorProcessor::Make(inputFP ? std::move(*inputFP) : nullptr,
+                                           SK_PMColor4fTRANSPARENT,
                                            GrConstColorProcessor::InputMode::kModulateRGBA);
     }
 
@@ -160,15 +168,16 @@
     if (path.isInverseFillType()) {
         type = GrInvertProcessorEdgeType(type);
     }
-    return Make(type, n, edges);
+    return Make(inputFP, type, n, edges);
 }
 
-std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType edgeType,
-                                                              const SkRect& rect) {
+std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(
+        std::unique_ptr<GrFragmentProcessor>* inputFP,
+        GrClipEdgeType edgeType, const SkRect& rect) {
     if (GrClipEdgeType::kHairlineAA == edgeType){
         return nullptr;
     }
-    return GrAARectEffect::Make(/*inputFP=*/nullptr, edgeType, rect);
+    return GrAARectEffect::Make(inputFP ? std::move(*inputFP) : nullptr, edgeType, rect);
 }
 
 GrConvexPolyEffect::~GrConvexPolyEffect() {}
@@ -182,7 +191,8 @@
     return new GrGLConvexPolyEffect;
 }
 
-GrConvexPolyEffect::GrConvexPolyEffect(GrClipEdgeType edgeType, int n, const SkScalar edges[])
+GrConvexPolyEffect::GrConvexPolyEffect(std::unique_ptr<GrFragmentProcessor> inputFP,
+                                       GrClipEdgeType edgeType, int n, const SkScalar edges[])
         : INHERITED(kGrConvexPolyEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag)
         , fEdgeType(edgeType)
         , fEdgeCount(n) {
@@ -194,12 +204,17 @@
     for (int i = 0; i < n; ++i) {
         fEdges[3 * i + 2] += SK_ScalarHalf;
     }
+
+    if (inputFP != nullptr) {
+        this->registerChildProcessor(std::move(inputFP));
+    }
 }
 
 GrConvexPolyEffect::GrConvexPolyEffect(const GrConvexPolyEffect& that)
         : INHERITED(kGrConvexPolyEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag)
         , fEdgeType(that.fEdgeType)
         , fEdgeCount(that.fEdgeCount) {
+    this->cloneAndRegisterAllChildProcessors(that);
     memcpy(fEdges, that.fEdges, 3 * that.fEdgeCount * sizeof(SkScalar));
 }
 
@@ -230,7 +245,7 @@
     do {
         GrClipEdgeType edgeType = static_cast<GrClipEdgeType>(
                 d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
-        fp = GrConvexPolyEffect::Make(edgeType, count, edges);
+        fp = GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, count, edges);
     } while (nullptr == fp);
     return fp;
 }
diff --git a/src/gpu/effects/GrConvexPolyEffect.h b/src/gpu/effects/GrConvexPolyEffect.h
index 2bb3373..b238bde 100644
--- a/src/gpu/effects/GrConvexPolyEffect.h
+++ b/src/gpu/effects/GrConvexPolyEffect.h
@@ -23,9 +23,7 @@
  */
 class GrConvexPolyEffect : public GrFragmentProcessor {
 public:
-    enum {
-        kMaxEdges = 8,
-    };
+    static constexpr int kMaxEdges = 8;
 
     /**
      * edges is a set of n edge equations where n is limited to kMaxEdges. It contains 3*n values.
@@ -37,25 +35,32 @@
      * them in src space. There are a number of ways this could be accomplished but we'd probably
      * have to modify the effect/shaderbuilder interface to make it possible (e.g. give access
      * to the view matrix or untransformed positions in the fragment shader).
+     *
+     * The input fragment processor is passed as a pointer because it is only absorbed if creation
+     * of the convex-poly effect is successful. If Make returns nullptr, the inputFP is left as-is.
      */
-    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, int n,
-                                                     const SkScalar edges[]) {
+    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor>* inputFP,
+                                                     GrClipEdgeType edgeType,
+                                                     int n, const SkScalar edges[]) {
         if (n <= 0 || n > kMaxEdges || GrClipEdgeType::kHairlineAA == edgeType) {
             return nullptr;
         }
-        return std::unique_ptr<GrFragmentProcessor>(new GrConvexPolyEffect(edgeType, n, edges));
+        return std::unique_ptr<GrFragmentProcessor>(
+            new GrConvexPolyEffect(inputFP ? std::move(*inputFP) : nullptr, edgeType, n, edges));
     }
 
     /**
      * Creates an effect that clips against the path. If the path is not a convex polygon, is
      * inverse filled, or has too many edges, this will return nullptr.
      */
-    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkPath&);
+    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor>*,
+                                                     GrClipEdgeType, const SkPath&);
 
     /**
      * Creates an effect that fills inside the rect with AA edges..
      */
-    static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRect&);
+    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor>*,
+                                                     GrClipEdgeType, const SkRect&);
 
     ~GrConvexPolyEffect() override;
 
@@ -69,8 +74,12 @@
 
     const SkScalar* getEdges() const { return fEdges; }
 
+    bool hasInputFP() const { return numChildProcessors() > 0; }
+
 private:
-    GrConvexPolyEffect(GrClipEdgeType edgeType, int n, const SkScalar edges[]);
+    GrConvexPolyEffect(std::unique_ptr<GrFragmentProcessor> inputFP,
+                       GrClipEdgeType edgeType,
+                       int n, const SkScalar edges[]);
     GrConvexPolyEffect(const GrConvexPolyEffect&);
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
index 8dc775f..e418784 100644
--- a/src/gpu/effects/GrRRectEffect.cpp
+++ b/src/gpu/effects/GrRRectEffect.cpp
@@ -726,7 +726,7 @@
                                                          const SkRRect& rrect,
                                                          const GrShaderCaps& caps) {
     if (rrect.isRect()) {
-        return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
+        return GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, rrect.getBounds());
     }
 
     if (rrect.isOval()) {
@@ -738,7 +738,7 @@
             SkRRectPriv::GetSimpleRadii(rrect).fY < kRadiusMin) {
             // In this case the corners are extremely close to rectangular and we collapse the
             // clip to a rectangular clip.
-            return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
+            return GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, rrect.getBounds());
         }
         if (SkRRectPriv::GetSimpleRadii(rrect).fX == SkRRectPriv::GetSimpleRadii(rrect).fY) {
             return CircularRRectEffect::Make(/*inputFP=*/nullptr, edgeType,
@@ -804,7 +804,7 @@
                 return CircularRRectEffect::Make(/*inputFP=*/nullptr, edgeType, cornerFlags, *rr);
             }
             case CircularRRectEffect::kNone_CornerFlags:
-                return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
+                return GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, rrect.getBounds());
             default: {
                 if (squashedRadii) {
                     // If we got here then we squashed some but not all the radii to zero. (If all