Add dynamic stroke attribs to tessellated stroking

Allows us to batch together strokes that have different SkStrokeRecs.

Bug: chromium:1172543
Bug: skia:10419
Change-Id: I11dc01e60bc17a6bb3c3b635f9edb2944a2f2edc
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/369579
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/tessellate/GrStrokeTessellateOp.h b/src/gpu/tessellate/GrStrokeTessellateOp.h
index 4a63d0a..2278fbc 100644
--- a/src/gpu/tessellate/GrStrokeTessellateOp.h
+++ b/src/gpu/tessellate/GrStrokeTessellateOp.h
@@ -12,37 +12,61 @@
 #include "src/gpu/GrSTArenaList.h"
 #include "src/gpu/ops/GrMeshDrawOp.h"
 #include "src/gpu/tessellate/GrPathShader.h"
+#include "src/gpu/tessellate/GrStrokeTessellateShader.h"
 
 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;
+    using ShaderFlags = GrStrokeTessellateShader::ShaderFlags;
 
-    // Issues draw calls for the tessellated stroie. The caller is responsible for binding its
+    GrStrokeTessellator(ShaderFlags shaderFlags) : fShaderFlags(shaderFlags) {}
+
+    struct PathStroke {
+        PathStroke(const SkPath& path, const SkStrokeRec& stroke) : fPath(path), fStroke(stroke) {}
+        SkPath fPath;
+        SkStrokeRec fStroke;
+    };
+
+    // Called before draw(). Prepares GPU buffers containing the geometry to tessellate.
+    virtual void prepare(GrMeshDrawOp::Target*, const SkMatrix&, const GrSTArenaList<PathStroke>&,
+                         int totalCombinedVerbCnt) = 0;
+
+    // Issues draw calls for the tessellated stroke. 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 GrStrokeTessellateOp : public GrDrawOp {
-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.
-    GrStrokeTessellateOp(GrAAType, const SkMatrix&, const SkPath&, const SkStrokeRec&, GrPaint&&);
 
 protected:
+    const ShaderFlags fShaderFlags;
+};
+
+// Renders strokes by linearizing them into sorted "parametric" and "radial" edges. See
+// GrStrokeTessellateShader.
+class GrStrokeTessellateOp : public GrDrawOp {
+public:
+    GrStrokeTessellateOp(GrAAType, const SkMatrix&, const SkPath&, const SkStrokeRec&, GrPaint&&);
+
+private:
+    using ShaderFlags = GrStrokeTessellateShader::ShaderFlags;
+    using PathStroke = GrStrokeTessellator::PathStroke;
     DEFINE_OP_CLASS_ID
 
+    SkStrokeRec& headStroke() { return fPathStrokeList.head().fStroke; }
+
+    // Returns whether it is a good tradeoff to use the given dynamic state. Dynamic state improves
+    // batching, but if it isn't already enabled, it comes at the cost of having to write out more
+    // data with each patch or instance.
+    bool shouldUseDynamicState(ShaderFlags dynamicState) const {
+        // Use the dynamic state if either (1) the state is already enabled anyway, or (2) we don't
+        // have many verbs.
+        constexpr static int kMaxVerbsToEnableDynamicState = 50;
+        return (fShaderFlags & dynamicState) ||
+               (fTotalCombinedVerbCnt <= kMaxVerbsToEnableDynamicState);
+    }
+
     const char* name() const override { return "GrStrokeTessellateOp"; }
     void visitProxies(const VisitProxyFunc& fn) const override;
     FixedFunctionFlags fixedFunctionFlags() const override;
@@ -63,14 +87,13 @@
 
     const GrAAType fAAType;
     const SkMatrix fViewMatrix;
-    const SkStrokeRec fStroke;
     SkPMColor4f fColor;
     bool fNeedsStencil = false;
     GrProcessorSet fProcessors;
 
-    GrSTArenaList<SkPath> fPathList;
+    ShaderFlags fShaderFlags = ShaderFlags::kNone;
+    GrSTArenaList<PathStroke> fPathStrokeList;
     int fTotalCombinedVerbCnt = 0;
-    bool fHasConics = false;
 
     GrStrokeTessellator* fTessellator = nullptr;
     const GrProgramInfo* fStencilProgram = nullptr;  // Only used if the stroke has transparency.