Create an abstract GrStrokeTessellator class

Now there is only one op to tessellate a stroke, and it creates its
own GrStrokeIndirectTessellator or GrStrokeHardwareTessellator
internally. This will allow us to dynamically switch into hardware
tessellation when we need to batch strokes that have different
parameters or colors.

Bug: chromium:1172543
Bug: skia:10419
Change-Id: I3cddb855fdbb9ab018785584497c843e3e31b75e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/366056
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/tessellate/GrStrokeOp.h b/src/gpu/tessellate/GrStrokeOp.h
index c5adc91..6a2933d 100644
--- a/src/gpu/tessellate/GrStrokeOp.h
+++ b/src/gpu/tessellate/GrStrokeOp.h
@@ -9,85 +9,57 @@
 #define GrStrokeOp_DEFINED
 
 #include "include/core/SkStrokeRec.h"
-#include "include/gpu/GrRecordingContext.h"
 #include "src/gpu/GrSTArenaList.h"
-#include "src/gpu/ops/GrDrawOp.h"
-#include "src/gpu/tessellate/GrStrokeTessellateShader.h"
-#include <array>
+#include "src/gpu/ops/GrMeshDrawOp.h"
+#include "src/gpu/tessellate/GrPathShader.h"
 
-class GrStrokeTessellateShader;
+class GrRecordingContext;
+
+// Prepares GPU data for, and then draws a stroke's tessellated geometry.
+class GrStrokeTessellator {
+public:
+    // Called before draw(). Prepares GPU buffers containing the geometry to tessellate.
+    virtual void prepare(GrMeshDrawOp::Target*, const SkMatrix&, const GrSTArenaList<SkPath>&,
+                         const SkStrokeRec&, int totalCombinedVerbCnt) = 0;
+
+    // Issues draw calls for the tessellated stroie. The caller is responsible for binding its
+    // desired pipeline ahead of time.
+    virtual void draw(GrOpFlushState*) const = 0;
+
+    virtual ~GrStrokeTessellator() {}
+};
 
 // Base class for ops that render opaque, constant-color strokes by linearizing them into sorted
 // "parametric" and "radial" edges. See GrStrokeTessellateShader.
 class GrStrokeOp : public GrDrawOp {
-protected:
+public:
     // The provided matrix must be a similarity matrix for the time being. This is so we can
     // bootstrap this Op on top of GrStrokeGeometry with minimal modifications.
     //
     // Patches can overlap, so until a stencil technique is implemented, the provided paint must be
     // a constant blended color.
-    GrStrokeOp(uint32_t classID, GrAAType, const SkMatrix&, const SkStrokeRec&, const SkPath&,
-               GrPaint&&);
+    GrStrokeOp(GrAAType, const SkMatrix&, const SkPath&, const SkStrokeRec&, GrPaint&&);
 
-    const char* name() const override { return "GrStrokeTessellateOp"; }
+protected:
+    DEFINE_OP_CLASS_ID
+
+    const char* name() const override { return "GrStrokeOp"; }
     void visitProxies(const VisitProxyFunc& fn) const override;
     FixedFunctionFlags fixedFunctionFlags() const override;
     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
                                       bool hasMixedSampledCoverage, GrClampType) override;
     CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override;
 
-    void prePreparePrograms(GrStrokeTessellateShader::Mode, SkArenaAlloc*,
-                            const GrSurfaceProxyView&, GrAppliedClip&&,
-                            const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
-                            GrLoadOp colorLoadOp, const GrCaps&);
+    // Creates the tessellator and the stencil/fill program(s) we will use with it.
+    void prePrepareTessellator(GrPathShader::ProgramArgs&&, GrAppliedClip&&);
 
-    static float NumCombinedSegments(float numParametricSegments, float numRadialSegments) {
-        // The first and last edges are shared by both the parametric and radial sets of edges, so
-        // the total number of edges is:
-        //
-        //   numCombinedEdges = numParametricEdges + numRadialEdges - 2
-        //
-        // It's also important to differentiate between the number of edges and segments in a strip:
-        //
-        //   numCombinedSegments = numCombinedEdges - 1
-        //
-        // So the total number of segments in the combined strip is:
-        //
-        //   numCombinedSegments = numParametricEdges + numRadialEdges - 2 - 1
-        //                       = numParametricSegments + 1 + numRadialSegments + 1 - 2 - 1
-        //                       = numParametricSegments + numRadialSegments - 1
-        //
-        return numParametricSegments + numRadialSegments - 1;
-    }
+    void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
+                      const GrXferProcessor::DstProxyView&, GrXferBarrierFlags,
+                      GrLoadOp colorLoadOp) override;
 
-    static float NumParametricSegments(float numCombinedSegments, float numRadialSegments) {
-        // numCombinedSegments = numParametricSegments + numRadialSegments - 1.
-        // (See num_combined_segments()).
-        return std::max(numCombinedSegments + 1 - numRadialSegments, 0.f);
-    }
+    void onPrepare(GrOpFlushState*) override;
 
-    // Returns the equivalent tolerances in (pre-viewMatrix) local path space that the tessellator
-    // will use when rendering this stroke.
-    GrStrokeTessellateShader::Tolerances preTransformTolerances() const {
-        std::array<float,2> matrixScales;
-        if (!fViewMatrix.getMinMaxScales(matrixScales.data())) {
-            matrixScales.fill(1);
-        }
-        auto [matrixMinScale, matrixMaxScale] = matrixScales;
-        float localStrokeWidth = fStroke.getWidth();
-        if (fStroke.isHairlineStyle()) {
-            // If the stroke is hairline then the tessellator will operate in post-transform space
-            // instead. But for the sake of CPU methods that need to conservatively approximate the
-            // number of segments to emit, we use localStrokeWidth ~= 1/matrixMinScale.
-            float approxScale = matrixMinScale;
-            // If the matrix has strong skew, don't let the scale shoot off to infinity. (This does
-            // not affect the tessellator; only the CPU methods that approximate the number of
-            // segments to emit.)
-            approxScale = std::max(matrixMinScale, matrixMaxScale * .25f);
-            localStrokeWidth = 1/approxScale;
-        }
-        return GrStrokeTessellateShader::Tolerances(matrixMaxScale, localStrokeWidth);
-    }
+    void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
 
     const GrAAType fAAType;
     const SkMatrix fViewMatrix;
@@ -98,9 +70,10 @@
 
     GrSTArenaList<SkPath> fPathList;
     int fTotalCombinedVerbCnt = 0;
-    int fTotalConicWeightCnt = 0;
+    bool fHasConics = false;
 
-    const GrProgramInfo* fStencilProgram = nullptr;
+    GrStrokeTessellator* fTessellator = nullptr;
+    const GrProgramInfo* fStencilProgram = nullptr;  // Only used if the stroke has transparency.
     const GrProgramInfo* fFillProgram = nullptr;
 };