Split GrCCCoverageProcessor into subclasses

Makes separate subclasses for geometry and vertex shaders.

Bug: skia:
Change-Id: Ifced79af3092090a71d03fe252fb4da76738cf08
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/204545
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/ccpr/GrVSCoverageProcessor.cpp b/src/gpu/ccpr/GrVSCoverageProcessor.cpp
new file mode 100644
index 0000000..dc00b96
--- /dev/null
+++ b/src/gpu/ccpr/GrVSCoverageProcessor.cpp
@@ -0,0 +1,547 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrVSCoverageProcessor.h"
+
+#include "GrMesh.h"
+#include "glsl/GrGLSLVertexGeoBuilder.h"
+
+// This class implements the coverage processor with vertex shaders.
+class GrVSCoverageProcessor::Impl : public GrGLSLGeometryProcessor {
+public:
+    Impl(std::unique_ptr<Shader> shader, int numSides)
+            : fShader(std::move(shader)), fNumSides(numSides) {}
+
+private:
+    void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
+                 FPCoordTransformIter&& transformIter) final {
+        this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
+    }
+
+    void onEmitCode(EmitArgs&, GrGPArgs*) override;
+
+    const std::unique_ptr<Shader> fShader;
+    const int fNumSides;
+};
+
+static constexpr int kInstanceAttribIdx_X = 0;  // Transposed X values of all input points.
+static constexpr int kInstanceAttribIdx_Y = 1;  // Transposed Y values of all input points.
+
+// Vertex data tells the shader how to offset vertices for conservative raster, as well as how to
+// calculate coverage values for corners and edges.
+static constexpr int kVertexData_LeftNeighborIdShift = 10;
+static constexpr int kVertexData_RightNeighborIdShift = 8;
+static constexpr int kVertexData_BloatIdxShift = 6;
+static constexpr int kVertexData_InvertNegativeCoverageBit = 1 << 5;
+static constexpr int kVertexData_IsCornerBit = 1 << 4;
+static constexpr int kVertexData_IsEdgeBit = 1 << 3;
+static constexpr int kVertexData_IsHullBit = 1 << 2;
+
+static constexpr int32_t pack_vertex_data(int32_t leftNeighborID, int32_t rightNeighborID,
+                                          int32_t bloatIdx, int32_t cornerID,
+                                          int32_t extraData = 0) {
+    return (leftNeighborID << kVertexData_LeftNeighborIdShift) |
+           (rightNeighborID << kVertexData_RightNeighborIdShift) |
+           (bloatIdx << kVertexData_BloatIdxShift) |
+           cornerID | extraData;
+}
+
+static constexpr int32_t hull_vertex_data(int32_t cornerID, int32_t bloatIdx, int n) {
+    return pack_vertex_data((cornerID + n - 1) % n, (cornerID + 1) % n, bloatIdx, cornerID,
+                            kVertexData_IsHullBit);
+}
+
+static constexpr int32_t edge_vertex_data(int32_t edgeID, int32_t endptIdx, int32_t bloatIdx,
+                                          int n) {
+    return pack_vertex_data(0 == endptIdx ? (edgeID + 1) % n : edgeID,
+                            0 == endptIdx ? (edgeID + 1) % n : edgeID,
+                            bloatIdx, 0 == endptIdx ? edgeID : (edgeID + 1) % n,
+                            kVertexData_IsEdgeBit |
+                            (!endptIdx ? kVertexData_InvertNegativeCoverageBit : 0));
+}
+
+static constexpr int32_t corner_vertex_data(int32_t leftID, int32_t cornerID, int32_t rightID,
+                                            int32_t bloatIdx) {
+    return pack_vertex_data(leftID, rightID, bloatIdx, cornerID, kVertexData_IsCornerBit);
+}
+
+static constexpr int32_t kTriangleVertices[] = {
+    hull_vertex_data(0, 0, 3),
+    hull_vertex_data(0, 1, 3),
+    hull_vertex_data(0, 2, 3),
+    hull_vertex_data(1, 0, 3),
+    hull_vertex_data(1, 1, 3),
+    hull_vertex_data(1, 2, 3),
+    hull_vertex_data(2, 0, 3),
+    hull_vertex_data(2, 1, 3),
+    hull_vertex_data(2, 2, 3),
+
+    edge_vertex_data(0, 0, 0, 3),
+    edge_vertex_data(0, 0, 1, 3),
+    edge_vertex_data(0, 0, 2, 3),
+    edge_vertex_data(0, 1, 0, 3),
+    edge_vertex_data(0, 1, 1, 3),
+    edge_vertex_data(0, 1, 2, 3),
+
+    edge_vertex_data(1, 0, 0, 3),
+    edge_vertex_data(1, 0, 1, 3),
+    edge_vertex_data(1, 0, 2, 3),
+    edge_vertex_data(1, 1, 0, 3),
+    edge_vertex_data(1, 1, 1, 3),
+    edge_vertex_data(1, 1, 2, 3),
+
+    edge_vertex_data(2, 0, 0, 3),
+    edge_vertex_data(2, 0, 1, 3),
+    edge_vertex_data(2, 0, 2, 3),
+    edge_vertex_data(2, 1, 0, 3),
+    edge_vertex_data(2, 1, 1, 3),
+    edge_vertex_data(2, 1, 2, 3),
+
+    corner_vertex_data(2, 0, 1, 0),
+    corner_vertex_data(2, 0, 1, 1),
+    corner_vertex_data(2, 0, 1, 2),
+    corner_vertex_data(2, 0, 1, 3),
+
+    corner_vertex_data(0, 1, 2, 0),
+    corner_vertex_data(0, 1, 2, 1),
+    corner_vertex_data(0, 1, 2, 2),
+    corner_vertex_data(0, 1, 2, 3),
+
+    corner_vertex_data(1, 2, 0, 0),
+    corner_vertex_data(1, 2, 0, 1),
+    corner_vertex_data(1, 2, 0, 2),
+    corner_vertex_data(1, 2, 0, 3),
+};
+
+GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleVertexBufferKey);
+
+static constexpr uint16_t kRestartStrip = 0xffff;
+
+static constexpr uint16_t kTriangleIndicesAsStrips[] =  {
+    1, 2, 0, 3, 8, kRestartStrip, // First corner and main body of the hull.
+    4, 5, 3, 6, 8, 7, kRestartStrip, // Opposite side and corners of the hull.
+    10, 9, 11, 14, 12, 13, kRestartStrip, // First edge.
+    16, 15, 17, 20, 18, 19, kRestartStrip, // Second edge.
+    22, 21, 23, 26, 24, 25, kRestartStrip, // Third edge.
+    28, 27, 29, 30, kRestartStrip, // First corner.
+    32, 31, 33, 34, kRestartStrip, // Second corner.
+    36, 35, 37, 38 // Third corner.
+};
+
+static constexpr uint16_t kTriangleIndicesAsTris[] =  {
+    // First corner and main body of the hull.
+    1, 2, 0,
+    2, 3, 0,
+    0, 3, 8, // Main body.
+
+    // Opposite side and corners of the hull.
+    4, 5, 3,
+    5, 6, 3,
+    3, 6, 8,
+    6, 7, 8,
+
+    // First edge.
+    10,  9, 11,
+     9, 14, 11,
+    11, 14, 12,
+    14, 13, 12,
+
+    // Second edge.
+    16, 15, 17,
+    15, 20, 17,
+    17, 20, 18,
+    20, 19, 18,
+
+    // Third edge.
+    22, 21, 23,
+    21, 26, 23,
+    23, 26, 24,
+    26, 25, 24,
+
+    // First corner.
+    28, 27, 29,
+    27, 30, 29,
+
+    // Second corner.
+    32, 31, 33,
+    31, 34, 33,
+
+    // Third corner.
+    36, 35, 37,
+    35, 38, 37,
+};
+
+GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey);
+
+// Curves, including quadratics, are drawn with a four-sided hull.
+static constexpr int32_t kCurveVertices[] = {
+    hull_vertex_data(0, 0, 4),
+    hull_vertex_data(0, 1, 4),
+    hull_vertex_data(0, 2, 4),
+    hull_vertex_data(1, 0, 4),
+    hull_vertex_data(1, 1, 4),
+    hull_vertex_data(1, 2, 4),
+    hull_vertex_data(2, 0, 4),
+    hull_vertex_data(2, 1, 4),
+    hull_vertex_data(2, 2, 4),
+    hull_vertex_data(3, 0, 4),
+    hull_vertex_data(3, 1, 4),
+    hull_vertex_data(3, 2, 4),
+
+    corner_vertex_data(3, 0, 1, 0),
+    corner_vertex_data(3, 0, 1, 1),
+    corner_vertex_data(3, 0, 1, 2),
+    corner_vertex_data(3, 0, 1, 3),
+
+    corner_vertex_data(2, 3, 0, 0),
+    corner_vertex_data(2, 3, 0, 1),
+    corner_vertex_data(2, 3, 0, 2),
+    corner_vertex_data(2, 3, 0, 3),
+};
+
+GR_DECLARE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey);
+
+static constexpr uint16_t kCurveIndicesAsStrips[] =  {
+    1, 0, 2, 11, 3, 5, 4, kRestartStrip, // First half of the hull (split diagonally).
+    7, 6, 8, 5, 9, 11, 10, kRestartStrip, // Second half of the hull.
+    13, 12, 14, 15, kRestartStrip, // First corner.
+    17, 16, 18, 19 // Final corner.
+};
+
+static constexpr uint16_t kCurveIndicesAsTris[] =  {
+    // First half of the hull (split diagonally).
+     1,  0,  2,
+     0, 11,  2,
+     2, 11,  3,
+    11,  5,  3,
+     3,  5,  4,
+
+    // Second half of the hull.
+    7,  6,  8,
+    6,  5,  8,
+    8,  5,  9,
+    5, 11,  9,
+    9, 11, 10,
+
+    // First corner.
+    13, 12, 14,
+    12, 15, 14,
+
+    // Final corner.
+    17, 16, 18,
+    16, 19, 18,
+};
+
+GR_DECLARE_STATIC_UNIQUE_KEY(gCurveIndexBufferKey);
+
+// Generates a conservative raster hull around a triangle or curve. For triangles we generate
+// additional conservative rasters with coverage ramps around the edges and corners.
+//
+// Triangles are drawn in three steps: (1) Draw a conservative raster of the entire triangle, with a
+// coverage of +1. (2) Draw conservative rasters around each edge, with a coverage ramp from -1 to
+// 0. These edge coverage values convert jagged conservative raster edges into smooth, antialiased
+// ones. (3) Draw conservative rasters (aka pixel-size boxes) around each corner, replacing the
+// previous coverage values with ones that ramp to zero in the bloat vertices that fall outside the
+// triangle.
+//
+// Curve shaders handle the opposite edge and corners on their own. For curves we just generate a
+// conservative raster here and the shader does the rest.
+void GrVSCoverageProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
+    const GrVSCoverageProcessor& proc = args.fGP.cast<GrVSCoverageProcessor>();
+    GrGLSLVertexBuilder* v = args.fVertBuilder;
+    int numInputPoints = proc.numInputPoints();
+
+    int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3;
+    const char* swizzle = (4 == inputWidth) ? "xyzw" : "xyz";
+    v->codeAppendf("float%ix2 pts = transpose(float2x%i(%s.%s, %s.%s));", inputWidth, inputWidth,
+                   proc.fInputXAndYValues[kInstanceAttribIdx_X].name(), swizzle,
+                   proc.fInputXAndYValues[kInstanceAttribIdx_Y].name(), swizzle);
+
+    v->codeAppend ("half wind;");
+    Shader::CalcWind(proc, v, "pts", "wind");
+    if (PrimitiveType::kWeightedTriangles == proc.fPrimitiveType) {
+        SkASSERT(3 == numInputPoints);
+        SkASSERT(kFloat4_GrVertexAttribType ==
+                 proc.fInputXAndYValues[kInstanceAttribIdx_X].cpuType());
+        v->codeAppendf("wind *= half(%s.w);",
+                       proc.fInputXAndYValues[kInstanceAttribIdx_X].name());
+    }
+
+    float bloat = kAABloatRadius;
+#ifdef SK_DEBUG
+    if (proc.debugBloatEnabled()) {
+        bloat *= proc.debugBloat();
+    }
+#endif
+    v->defineConstant("bloat", bloat);
+
+    const char* hullPts = "pts";
+    fShader->emitSetupCode(v, "pts", "wind", (4 == fNumSides) ? &hullPts : nullptr);
+
+    // Reverse all indices if the wind is counter-clockwise: [0, 1, 2] -> [2, 1, 0].
+    v->codeAppendf("int clockwise_indices = wind > 0 ? %s : 0x%x - %s;",
+                   proc.fPerVertexData.name(),
+                   ((fNumSides - 1) << kVertexData_LeftNeighborIdShift) |
+                   ((fNumSides - 1) << kVertexData_RightNeighborIdShift) |
+                   (((1 << kVertexData_RightNeighborIdShift) - 1) ^ 3) |
+                   (fNumSides - 1),
+                   proc.fPerVertexData.name());
+
+    // Here we generate conservative raster geometry for the input polygon. It is the convex
+    // hull of N pixel-size boxes, one centered on each the input points. Each corner has three
+    // vertices, where one or two may cause degenerate triangles. The vertex data tells us how
+    // to offset each vertex. Triangle edges and corners are also handled here using the same
+    // concept. For more details on conservative raster, see:
+    // https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter42.html
+    v->codeAppendf("float2 corner = %s[clockwise_indices & 3];", hullPts);
+    v->codeAppendf("float2 left = %s[clockwise_indices >> %i];",
+                   hullPts, kVertexData_LeftNeighborIdShift);
+    v->codeAppendf("float2 right = %s[(clockwise_indices >> %i) & 3];",
+                   hullPts, kVertexData_RightNeighborIdShift);
+
+    v->codeAppend ("float2 leftbloat = sign(corner - left);");
+    v->codeAppend ("leftbloat = float2(0 != leftbloat.y ? leftbloat.y : leftbloat.x, "
+                                      "0 != leftbloat.x ? -leftbloat.x : -leftbloat.y);");
+
+    v->codeAppend ("float2 rightbloat = sign(right - corner);");
+    v->codeAppend ("rightbloat = float2(0 != rightbloat.y ? rightbloat.y : rightbloat.x, "
+                                       "0 != rightbloat.x ? -rightbloat.x : -rightbloat.y);");
+
+    v->codeAppend ("bool2 left_right_notequal = notEqual(leftbloat, rightbloat);");
+
+    v->codeAppend ("float2 bloatdir = leftbloat;");
+
+    v->codeAppend ("float2 leftdir = corner - left;");
+    v->codeAppend ("leftdir = (float2(0) != leftdir) ? normalize(leftdir) : float2(1, 0);");
+
+    v->codeAppend ("float2 rightdir = right - corner;");
+    v->codeAppend ("rightdir = (float2(0) != rightdir) ? normalize(rightdir) : float2(1, 0);");
+
+    v->codeAppendf("if (0 != (%s & %i)) {",  // Are we a corner?
+                   proc.fPerVertexData.name(), kVertexData_IsCornerBit);
+
+                       // In corner boxes, all 4 coverage values will not map linearly.
+                       // Therefore it is important to align the box so its diagonal shared
+                       // edge points out of the triangle, in the direction that ramps to 0.
+    v->codeAppend (    "bloatdir = float2(leftdir.x > rightdir.x ? +1 : -1, "
+                                         "leftdir.y > rightdir.y ? +1 : -1);");
+
+                       // For corner boxes, we hack left_right_notequal to always true. This
+                       // in turn causes the upcoming code to always rotate, generating all
+                       // 4 vertices of the corner box.
+    v->codeAppendf(    "left_right_notequal = bool2(true);");
+    v->codeAppend ("}");
+
+    // At each corner of the polygon, our hull will have either 1, 2, or 3 vertices (or 4 if
+    // it's a corner box). We begin with this corner's first raster vertex (leftbloat), then
+    // continue rotating 90 degrees clockwise until we reach the desired raster vertex for this
+    // invocation. Corners with less than 3 corresponding raster vertices will result in
+    // redundant vertices and degenerate triangles.
+    v->codeAppendf("int bloatidx = (%s >> %i) & 3;", proc.fPerVertexData.name(),
+                   kVertexData_BloatIdxShift);
+    v->codeAppend ("switch (bloatidx) {");
+    v->codeAppend (    "case 3:");
+                            // Only corners will have bloatidx=3, and corners always rotate.
+    v->codeAppend (        "bloatdir = float2(-bloatdir.y, +bloatdir.x);"); // 90 deg CW.
+                           // fallthru.
+    v->codeAppend (    "case 2:");
+    v->codeAppendf(        "if (all(left_right_notequal)) {");
+    v->codeAppend (            "bloatdir = float2(-bloatdir.y, +bloatdir.x);"); // 90 deg CW.
+    v->codeAppend (        "}");
+                           // fallthru.
+    v->codeAppend (    "case 1:");
+    v->codeAppendf(        "if (any(left_right_notequal)) {");
+    v->codeAppend (            "bloatdir = float2(-bloatdir.y, +bloatdir.x);"); // 90 deg CW.
+    v->codeAppend (        "}");
+                           // fallthru.
+    v->codeAppend ("}");
+
+    v->codeAppend ("float2 vertex = fma(bloatdir, float2(bloat), corner);");
+    gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
+
+    // Hulls have a coverage of +1 all around.
+    v->codeAppend ("half coverage = +1;");
+
+    if (3 == fNumSides) {
+        v->codeAppend ("half left_coverage; {");
+        Shader::CalcEdgeCoverageAtBloatVertex(v, "left", "corner", "bloatdir", "left_coverage");
+        v->codeAppend ("}");
+
+        v->codeAppend ("half right_coverage; {");
+        Shader::CalcEdgeCoverageAtBloatVertex(v, "corner", "right", "bloatdir", "right_coverage");
+        v->codeAppend ("}");
+
+        v->codeAppendf("if (0 != (%s & %i)) {",  // Are we an edge?
+                       proc.fPerVertexData.name(), kVertexData_IsEdgeBit);
+        v->codeAppend (    "coverage = left_coverage;");
+        v->codeAppend ("}");
+
+        v->codeAppendf("if (0 != (%s & %i)) {",  // Invert coverage?
+                       proc.fPerVertexData.name(),
+                       kVertexData_InvertNegativeCoverageBit);
+        v->codeAppend (    "coverage = -1 - coverage;");
+        v->codeAppend ("}");
+    }
+
+    // Non-corner geometry should have zero effect from corner coverage.
+    v->codeAppend ("half2 corner_coverage = half2(0);");
+
+    v->codeAppendf("if (0 != (%s & %i)) {",  // Are we a corner?
+                   proc.fPerVertexData.name(), kVertexData_IsCornerBit);
+                       // We use coverage=-1 to erase what the hull geometry wrote.
+                       //
+                       // In the context of curves, this effectively means "wind = -wind" and
+                       // causes the Shader to erase what it had written previously for the hull.
+                       //
+                       // For triangles it just erases the "+1" value written by the hull geometry.
+    v->codeAppend (    "coverage = -1;");
+    if (3 == fNumSides) {
+                       // Triangle corners also have to erase what the edge geometry wrote.
+        v->codeAppend ("coverage -= left_coverage + right_coverage;");
+    }
+
+                       // Corner boxes require attenuated coverage.
+    v->codeAppend (    "half attenuation; {");
+    Shader::CalcCornerAttenuation(v, "leftdir", "rightdir", "attenuation");
+    v->codeAppend (    "}");
+
+                       // Attenuate corner coverage towards the outermost vertex (where bloatidx=0).
+                       // This is all that curves need: At each vertex of the corner box, the curve
+                       // Shader will calculate the curve's local coverage value, interpolate it
+                       // alongside our attenuation parameter, and multiply the two together for a
+                       // final coverage value.
+    v->codeAppend (    "corner_coverage = (0 == bloatidx) ? half2(0, attenuation) : half2(1);");
+
+    if (3 == fNumSides) {
+                       // For triangles we also provide the actual coverage values at each vertex of
+                       // the corner box.
+        v->codeAppend ("if (1 == bloatidx || 2 == bloatidx) {");
+        v->codeAppend (    "corner_coverage.x += right_coverage;");
+        v->codeAppend ("}");
+        v->codeAppend ("if (bloatidx >= 2) {");
+        v->codeAppend (    "corner_coverage.x += left_coverage;");
+        v->codeAppend ("}");
+    }
+    v->codeAppend ("}");
+
+    GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
+    v->codeAppend ("coverage *= wind;");
+    v->codeAppend ("corner_coverage.x *= wind;");
+    fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &AccessCodeString(v),
+                          gpArgs->fPositionVar.c_str(), "coverage", "corner_coverage");
+
+    varyingHandler->emitAttributes(proc);
+    SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform());
+
+    // Fragment shader.
+    fShader->emitFragmentCode(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
+}
+
+void GrVSCoverageProcessor::reset(PrimitiveType primitiveType, GrResourceProvider* rp) {
+    const GrCaps& caps = *rp->caps();
+
+    fPrimitiveType = primitiveType;
+    switch (fPrimitiveType) {
+        case PrimitiveType::kTriangles:
+        case PrimitiveType::kWeightedTriangles: {
+            GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleVertexBufferKey);
+            fVertexBuffer = rp->findOrMakeStaticBuffer(
+                    GrGpuBufferType::kVertex, sizeof(kTriangleVertices), kTriangleVertices,
+                    gTriangleVertexBufferKey);
+            GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey);
+            if (caps.usePrimitiveRestart()) {
+                fIndexBuffer = rp->findOrMakeStaticBuffer(
+                        GrGpuBufferType::kIndex, sizeof(kTriangleIndicesAsStrips),
+                        kTriangleIndicesAsStrips, gTriangleIndexBufferKey);
+                fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsStrips);
+            } else {
+                fIndexBuffer = rp->findOrMakeStaticBuffer(
+                        GrGpuBufferType::kIndex, sizeof(kTriangleIndicesAsTris),
+                        kTriangleIndicesAsTris, gTriangleIndexBufferKey);
+                fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsTris);
+            }
+            break;
+        }
+
+        case PrimitiveType::kQuadratics:
+        case PrimitiveType::kCubics:
+        case PrimitiveType::kConics: {
+            GR_DEFINE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey);
+            fVertexBuffer = rp->findOrMakeStaticBuffer(
+                    GrGpuBufferType::kVertex, sizeof(kCurveVertices), kCurveVertices,
+                    gCurveVertexBufferKey);
+            GR_DEFINE_STATIC_UNIQUE_KEY(gCurveIndexBufferKey);
+            if (caps.usePrimitiveRestart()) {
+                fIndexBuffer = rp->findOrMakeStaticBuffer(
+                        GrGpuBufferType::kIndex, sizeof(kCurveIndicesAsStrips),
+                        kCurveIndicesAsStrips, gCurveIndexBufferKey);
+                fNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsStrips);
+            } else {
+                fIndexBuffer = rp->findOrMakeStaticBuffer(
+                        GrGpuBufferType::kIndex, sizeof(kCurveIndicesAsTris), kCurveIndicesAsTris,
+                        gCurveIndexBufferKey);
+                fNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsTris);
+            }
+            break;
+        }
+    }
+
+    GrVertexAttribType xyAttribType;
+    GrSLType xySLType;
+    if (4 == this->numInputPoints() || this->hasInputWeight()) {
+        GR_STATIC_ASSERT(offsetof(QuadPointInstance, fX) == 0);
+        GR_STATIC_ASSERT(sizeof(QuadPointInstance::fX) ==
+                         GrVertexAttribTypeSize(kFloat4_GrVertexAttribType));
+        GR_STATIC_ASSERT(sizeof(QuadPointInstance::fY) ==
+                         GrVertexAttribTypeSize(kFloat4_GrVertexAttribType));
+        xyAttribType = kFloat4_GrVertexAttribType;
+        xySLType = kFloat4_GrSLType;
+    } else {
+        GR_STATIC_ASSERT(offsetof(TriPointInstance, fX) == 0);
+        GR_STATIC_ASSERT(sizeof(TriPointInstance::fX) ==
+                         GrVertexAttribTypeSize(kFloat3_GrVertexAttribType));
+        GR_STATIC_ASSERT(sizeof(TriPointInstance::fY) ==
+                         GrVertexAttribTypeSize(kFloat3_GrVertexAttribType));
+        xyAttribType = kFloat3_GrVertexAttribType;
+        xySLType = kFloat3_GrSLType;
+    }
+    fInputXAndYValues[kInstanceAttribIdx_X] = {"X", xyAttribType, xySLType};
+    fInputXAndYValues[kInstanceAttribIdx_Y] = {"Y", xyAttribType, xySLType};
+    this->setInstanceAttributes(fInputXAndYValues, 2);
+    fPerVertexData = {"vertexdata", kInt_GrVertexAttribType, kInt_GrSLType};
+    this->setVertexAttributes(&fPerVertexData, 1);
+
+    if (caps.usePrimitiveRestart()) {
+        fTriangleType = GrPrimitiveType::kTriangleStrip;
+    } else {
+        fTriangleType = GrPrimitiveType::kTriangles;
+    }
+}
+
+void GrVSCoverageProcessor::appendMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount,
+                                       int baseInstance, SkTArray<GrMesh>* out) const {
+    GrMesh& mesh = out->emplace_back(fTriangleType);
+    auto primitiveRestart = GrPrimitiveRestart(GrPrimitiveType::kTriangleStrip == fTriangleType);
+    mesh.setIndexedInstanced(fIndexBuffer, fNumIndicesPerInstance, std::move(instanceBuffer),
+                             instanceCount, baseInstance, primitiveRestart);
+    mesh.setVertexData(fVertexBuffer, 0);
+}
+
+GrGLSLPrimitiveProcessor* GrVSCoverageProcessor::onCreateGLSLInstance(
+        std::unique_ptr<Shader> shader) const {
+    switch (fPrimitiveType) {
+        case PrimitiveType::kTriangles:
+        case PrimitiveType::kWeightedTriangles:
+            return new Impl(std::move(shader), 3);
+        case PrimitiveType::kQuadratics:
+        case PrimitiveType::kCubics:
+        case PrimitiveType::kConics:
+            return new Impl(std::move(shader), 4);
+    }
+    SK_ABORT("Invalid PrimitiveType");
+    return nullptr;
+}