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/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
index f72ccf9..0be4c08 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -184,23 +184,6 @@
                    outputAttenuation);
 }
 
-void GrCCCoverageProcessor::getGLSLProcessorKey(const GrShaderCaps&,
-                                                GrProcessorKeyBuilder* b) const {
-    int key = (int)fPrimitiveType << 2;
-    if (GSSubpass::kCorners == fGSSubpass) {
-        key |= 2;
-    }
-    if (Impl::kVertexShader == fImpl) {
-        key |= 1;
-    }
-#ifdef SK_DEBUG
-    uint32_t bloatBits;
-    memcpy(&bloatBits, &fDebugBloat, 4);
-    b->add32(bloatBits);
-#endif
-    b->add32(key);
-}
-
 GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGLSLInstance(const GrShaderCaps&) const {
     std::unique_ptr<Shader> shader;
     switch (fPrimitiveType) {
@@ -218,33 +201,23 @@
             shader = skstd::make_unique<GrCCConicShader>();
             break;
     }
-    return Impl::kGeometryShader == fImpl ? this->createGSImpl(std::move(shader))
-                                          : this->createVSImpl(std::move(shader));
+    return this->onCreateGLSLInstance(std::move(shader));
 }
 
-void GrCCCoverageProcessor::Shader::emitFragmentCode(const GrCCCoverageProcessor& proc,
-                                                     GrGLSLFPFragmentBuilder* f,
-                                                     const char* skOutputColor,
-                                                     const char* skOutputCoverage) const {
+void GrCCCoverageProcessor::Shader::emitFragmentCode(
+        const GrCCCoverageProcessor& proc, GrGLSLFPFragmentBuilder* f, const char* skOutputColor,
+        const char* skOutputCoverage) const {
     f->codeAppendf("half coverage = 0;");
     this->onEmitFragmentCode(f, "coverage");
     f->codeAppendf("%s.a = coverage;", skOutputColor);
     f->codeAppendf("%s = half4(1);", skOutputCoverage);
 }
 
-void GrCCCoverageProcessor::draw(GrOpFlushState* flushState, const GrPipeline& pipeline,
-                                 const SkIRect scissorRects[], const GrMesh meshes[], int meshCount,
-                                 const SkRect& drawBounds) const {
+void GrCCCoverageProcessor::draw(
+        GrOpFlushState* flushState, const GrPipeline& pipeline, const SkIRect scissorRects[],
+        const GrMesh meshes[], int meshCount, const SkRect& drawBounds) const {
     GrPipeline::DynamicStateArrays dynamicStateArrays;
     dynamicStateArrays.fScissorRects = scissorRects;
     GrGpuRTCommandBuffer* cmdBuff = flushState->rtCommandBuffer();
     cmdBuff->draw(*this, pipeline, nullptr, &dynamicStateArrays, meshes, meshCount, drawBounds);
-
-    // Geometry shader backend draws primitives in two subpasses.
-    if (Impl::kGeometryShader == fImpl) {
-        SkASSERT(GSSubpass::kHulls == fGSSubpass);
-        GrCCCoverageProcessor cornerProc(*this, GSSubpass::kCorners);
-        cmdBuff->draw(cornerProc, pipeline, nullptr, &dynamicStateArrays, meshes, meshCount,
-                      drawBounds);
-    }
 }
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h
index bbf898e..9687bba 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.h
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.h
@@ -37,7 +37,7 @@
 public:
     enum class PrimitiveType {
         kTriangles,
-        kWeightedTriangles, // Triangles (from the tessellator) whose winding magnitude > 1.
+        kWeightedTriangles,  // Triangles (from the tessellator) whose winding magnitude > 1.
         kQuadratics,
         kCubics,
         kConics
@@ -68,16 +68,21 @@
         void setW(const Sk2f& P0, const Sk2f& P1, const Sk2f& P2, const Sk2f& trans, float w);
     };
 
-    GrCCCoverageProcessor(GrResourceProvider* rp, PrimitiveType type)
-            : INHERITED(kGrCCCoverageProcessor_ClassID)
-            , fPrimitiveType(type)
-            , fImpl(rp->caps()->shaderCaps()->geometryShaderSupport() ? Impl::kGeometryShader
-                                                                      : Impl::kVertexShader) {
-        if (Impl::kGeometryShader == fImpl) {
-            this->initGS();
-        } else {
-            this->initVS(rp);
-        }
+    virtual void reset(PrimitiveType, GrResourceProvider*) = 0;
+
+    PrimitiveType primitiveType() const { return fPrimitiveType; }
+
+    // Number of bezier points for curves, or 3 for triangles.
+    int numInputPoints() const { return PrimitiveType::kCubics == fPrimitiveType ? 4 : 3; }
+
+    bool isTriangles() const {
+        return PrimitiveType::kTriangles == fPrimitiveType ||
+               PrimitiveType::kWeightedTriangles == fPrimitiveType;
+    }
+
+    int hasInputWeight() const {
+        return PrimitiveType::kWeightedTriangles == fPrimitiveType ||
+               PrimitiveType::kConics == fPrimitiveType;
     }
 
     // GrPrimitiveProcessor overrides.
@@ -87,30 +92,32 @@
         return SkStringPrintf("%s\n%s", this->name(), this->INHERITED::dumpInfo().c_str());
     }
 #endif
-    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
-    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
+    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
+        SkDEBUGCODE(this->getDebugBloatKey(b));
+        b->add32((int)fPrimitiveType);
+    }
+    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
 
 #ifdef SK_DEBUG
     // Increases the 1/2 pixel AA bloat by a factor of debugBloat.
     void enableDebugBloat(float debugBloat) { fDebugBloat = debugBloat; }
     bool debugBloatEnabled() const { return fDebugBloat > 0; }
     float debugBloat() const { SkASSERT(this->debugBloatEnabled()); return fDebugBloat; }
+    void getDebugBloatKey(GrProcessorKeyBuilder* b) const {
+        uint32_t bloatBits;
+        memcpy(&bloatBits, &fDebugBloat, 4);
+        b->add32(bloatBits);
+    }
 #endif
 
     // Appends a GrMesh that will draw the provided instances. The instanceBuffer must be an array
     // of either TriPointInstance or QuadPointInstance, depending on this processor's RendererPass,
     // with coordinates in the desired shape's final atlas-space position.
-    void appendMesh(sk_sp<GrGpuBuffer> instanceBuffer, int instanceCount, int baseInstance,
-                    SkTArray<GrMesh>* out) const {
-        if (Impl::kGeometryShader == fImpl) {
-            this->appendGSMesh(std::move(instanceBuffer), instanceCount, baseInstance, out);
-        } else {
-            this->appendVSMesh(std::move(instanceBuffer), instanceCount, baseInstance, out);
-        }
-    }
+    virtual void appendMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount,
+                            int baseInstance, SkTArray<GrMesh>* out) const = 0;
 
-    void draw(GrOpFlushState*, const GrPipeline&, const SkIRect scissorRects[], const GrMesh[],
-              int meshCount, const SkRect& drawBounds) const;
+    virtual void draw(GrOpFlushState*, const GrPipeline&, const SkIRect scissorRects[],
+                      const GrMesh[], int meshCount, const SkRect& drawBounds) const;
 
     // The Shader provides code to calculate each pixel's coverage in a RenderPass. It also
     // provides details about shape-specific geometry.
@@ -197,82 +204,26 @@
             return Scope::kGeoToFrag == varying.scope() ? varying.gsOut() : varying.vsOut();
         }
 
-        // Our friendship with GrGLSLShaderBuilder does not propogate to subclasses.
+        // Our friendship with GrGLSLShaderBuilder does not propagate to subclasses.
         inline static SkString& AccessCodeString(GrGLSLShaderBuilder* s) { return s->code(); }
     };
 
-private:
-    class GSImpl;
-    class GSTriangleHullImpl;
-    class GSCurveHullImpl;
-    class GSCornerImpl;
-    class VSImpl;
-    class TriangleShader;
-
+protected:
     // Slightly undershoot a bloat radius of 0.5 so vertices that fall on integer boundaries don't
     // accidentally bleed into neighbor pixels.
     static constexpr float kAABloatRadius = 0.491111f;
 
-    // Number of bezier points for curves, or 3 for triangles.
-    int numInputPoints() const { return PrimitiveType::kCubics == fPrimitiveType ? 4 : 3; }
+    GrCCCoverageProcessor(ClassID classID) : INHERITED(classID) {}
 
-    bool isTriangles() const {
-        return PrimitiveType::kTriangles == fPrimitiveType ||
-               PrimitiveType::kWeightedTriangles == fPrimitiveType;
-    }
+    virtual GrGLSLPrimitiveProcessor* onCreateGLSLInstance(std::unique_ptr<Shader>) const = 0;
 
-    int hasInputWeight() const {
-        return PrimitiveType::kWeightedTriangles == fPrimitiveType ||
-               PrimitiveType::kConics == fPrimitiveType;
-    }
+    // Our friendship with GrGLSLShaderBuilder does not propagate to subclasses.
+    inline static SkString& AccessCodeString(GrGLSLShaderBuilder* s) { return s->code(); }
 
-    enum class Impl : bool {
-        kGeometryShader,
-        kVertexShader
-    };
-
-    // Geometry shader backend draws primitives in two subpasses.
-    enum class GSSubpass : bool {
-        kHulls,
-        kCorners
-    };
-
-    GrCCCoverageProcessor(const GrCCCoverageProcessor& proc, GSSubpass subpass)
-            : INHERITED(kGrCCCoverageProcessor_ClassID)
-            , fPrimitiveType(proc.fPrimitiveType)
-            , fImpl(Impl::kGeometryShader)
-            SkDEBUGCODE(, fDebugBloat(proc.fDebugBloat))
-            , fGSSubpass(subpass) {
-        SkASSERT(Impl::kGeometryShader == proc.fImpl);
-        this->initGS();
-    }
-
-    void initGS();
-    void initVS(GrResourceProvider*);
-
-    void appendGSMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount, int baseInstance,
-                      SkTArray<GrMesh>* out) const;
-    void appendVSMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount, int baseInstance,
-                      SkTArray<GrMesh>* out) const;
-
-    GrGLSLPrimitiveProcessor* createGSImpl(std::unique_ptr<Shader>) const;
-    GrGLSLPrimitiveProcessor* createVSImpl(std::unique_ptr<Shader>) const;
-    // The type and meaning of this attribute depends on whether we're using VSImpl or GSImpl.
-    Attribute fVertexAttribute;
-
-    const PrimitiveType fPrimitiveType;
-    const Impl fImpl;
+    PrimitiveType fPrimitiveType;
     SkDEBUGCODE(float fDebugBloat = 0);
 
-    // Used by GSImpl.
-    const GSSubpass fGSSubpass = GSSubpass::kHulls;
-
-    // Used by VSImpl.
-    Attribute fInstanceAttributes[2];
-    sk_sp<const GrGpuBuffer> fVSVertexBuffer;
-    sk_sp<const GrGpuBuffer> fVSIndexBuffer;
-    int fVSNumIndicesPerInstance;
-    GrPrimitiveType fVSTriangleType;
+    class TriangleShader;
 
     typedef GrGeometryProcessor INHERITED;
 };
diff --git a/src/gpu/ccpr/GrCCFiller.cpp b/src/gpu/ccpr/GrCCFiller.cpp
index 311eb95..8e26c2f 100644
--- a/src/gpu/ccpr/GrCCFiller.cpp
+++ b/src/gpu/ccpr/GrCCFiller.cpp
@@ -459,54 +459,58 @@
     return true;
 }
 
-void GrCCFiller::drawFills(GrOpFlushState* flushState, BatchID batchID,
-                           const SkIRect& drawBounds) const {
+void GrCCFiller::drawFills(GrOpFlushState* flushState, GrCCCoverageProcessor* proc,
+                           BatchID batchID, const SkIRect& drawBounds) const {
     using PrimitiveType = GrCCCoverageProcessor::PrimitiveType;
 
     SkASSERT(fInstanceBuffer);
 
+    GrResourceProvider* rp = flushState->resourceProvider();
     const PrimitiveTallies& batchTotalCounts = fBatches[batchID].fTotalPrimitiveCounts;
 
     GrPipeline pipeline(GrScissorTest::kEnabled, SkBlendMode::kPlus);
 
     if (batchTotalCounts.fTriangles) {
-        this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kTriangles,
-                             &PrimitiveTallies::fTriangles, drawBounds);
+        proc->reset(PrimitiveType::kTriangles, rp);
+        this->drawPrimitives(
+                flushState, *proc, pipeline, batchID, &PrimitiveTallies::fTriangles, drawBounds);
     }
 
     if (batchTotalCounts.fWeightedTriangles) {
-        this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kWeightedTriangles,
-                             &PrimitiveTallies::fWeightedTriangles, drawBounds);
+        proc->reset(PrimitiveType::kWeightedTriangles, rp);
+        this->drawPrimitives(
+                flushState, *proc, pipeline, batchID, &PrimitiveTallies::fWeightedTriangles,
+                drawBounds);
     }
 
     if (batchTotalCounts.fQuadratics) {
-        this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kQuadratics,
-                             &PrimitiveTallies::fQuadratics, drawBounds);
+        proc->reset(PrimitiveType::kQuadratics, rp);
+        this->drawPrimitives(
+                flushState, *proc, pipeline, batchID, &PrimitiveTallies::fQuadratics, drawBounds);
     }
 
     if (batchTotalCounts.fCubics) {
-        this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kCubics,
-                             &PrimitiveTallies::fCubics, drawBounds);
+        proc->reset(PrimitiveType::kCubics, rp);
+        this->drawPrimitives(
+                flushState, *proc, pipeline, batchID, &PrimitiveTallies::fCubics, drawBounds);
     }
 
     if (batchTotalCounts.fConics) {
-        this->drawPrimitives(flushState, pipeline, batchID, PrimitiveType::kConics,
-                             &PrimitiveTallies::fConics, drawBounds);
+        proc->reset(PrimitiveType::kConics, rp);
+        this->drawPrimitives(
+                flushState, *proc, pipeline, batchID, &PrimitiveTallies::fConics, drawBounds);
     }
 }
 
-void GrCCFiller::drawPrimitives(GrOpFlushState* flushState, const GrPipeline& pipeline,
-                                BatchID batchID, GrCCCoverageProcessor::PrimitiveType primitiveType,
-                                int PrimitiveTallies::*instanceType,
-                                const SkIRect& drawBounds) const {
+void GrCCFiller::drawPrimitives(
+        GrOpFlushState* flushState, const GrCCCoverageProcessor& proc, const GrPipeline& pipeline,
+        BatchID batchID, int PrimitiveTallies::*instanceType, const SkIRect& drawBounds) const {
     SkASSERT(pipeline.isScissorEnabled());
 
     // Don't call reset(), as that also resets the reserve count.
     fMeshesScratchBuffer.pop_back_n(fMeshesScratchBuffer.count());
     fScissorRectScratchBuffer.pop_back_n(fScissorRectScratchBuffer.count());
 
-    GrCCCoverageProcessor proc(flushState->resourceProvider(), primitiveType);
-
     SkASSERT(batchID > 0);
     SkASSERT(batchID < fBatches.count());
     const Batch& previousBatch = fBatches[batchID - 1];
diff --git a/src/gpu/ccpr/GrCCFiller.h b/src/gpu/ccpr/GrCCFiller.h
index 4eec190..4d61a2e 100644
--- a/src/gpu/ccpr/GrCCFiller.h
+++ b/src/gpu/ccpr/GrCCFiller.h
@@ -45,7 +45,8 @@
     bool prepareToDraw(GrOnFlushResourceProvider*);
 
     // Called after prepareToDraw(). Draws the given batch of path fills.
-    void drawFills(GrOpFlushState*, BatchID, const SkIRect& drawBounds) const;
+    void drawFills(
+            GrOpFlushState*, GrCCCoverageProcessor*, BatchID, const SkIRect& drawBounds) const;
 
 private:
     static constexpr int kNumScissorModes = 2;
@@ -95,9 +96,8 @@
         SkIRect fScissor;
     };
 
-    void drawPrimitives(GrOpFlushState*, const GrPipeline&, BatchID,
-                        GrCCCoverageProcessor::PrimitiveType, int PrimitiveTallies::*instanceType,
-                        const SkIRect& drawBounds) const;
+    void drawPrimitives(GrOpFlushState*, const GrCCCoverageProcessor&, const GrPipeline&, BatchID,
+                        int PrimitiveTallies::*instanceType, const SkIRect& drawBounds) const;
 
     GrCCFillGeometry fGeometry;
     SkSTArray<32, PathInfo, true> fPathInfos;
diff --git a/src/gpu/ccpr/GrCCPerFlushResources.cpp b/src/gpu/ccpr/GrCCPerFlushResources.cpp
index 18d3ee9..5b612be 100644
--- a/src/gpu/ccpr/GrCCPerFlushResources.cpp
+++ b/src/gpu/ccpr/GrCCPerFlushResources.cpp
@@ -17,6 +17,8 @@
 #include "GrSurfaceContextPriv.h"
 #include "SkMakeUnique.h"
 #include "ccpr/GrCCPathCache.h"
+#include "ccpr/GrGSCoverageProcessor.h"
+#include "ccpr/GrVSCoverageProcessor.h"
 
 using FillBatchID = GrCCFiller::BatchID;
 using StrokeBatchID = GrCCStroker::BatchID;
@@ -100,7 +102,7 @@
 };
 
 // Renders coverage counts to a CCPR atlas using the resources' pre-filled GrCCPathParser.
-class RenderAtlasOp : public AtlasOp {
+template<typename ProcessorType> class RenderAtlasOp : public AtlasOp {
 public:
     DEFINE_OP_CLASS_ID
 
@@ -118,8 +120,9 @@
     const char* name() const override { return "RenderAtlasOp (CCPR)"; }
 
     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
-        fResources->filler().drawFills(flushState, fFillBatchID, fDrawBounds);
-        fResources->stroker().drawStrokes(flushState, fStrokeBatchID, fDrawBounds);
+        ProcessorType proc;
+        fResources->filler().drawFills(flushState, &proc, fFillBatchID, fDrawBounds);
+        fResources->stroker().drawStrokes(flushState, &proc, fStrokeBatchID, fDrawBounds);
     }
 
 private:
@@ -495,9 +498,16 @@
         }
 
         if (auto rtc = atlas->makeRenderTargetContext(onFlushRP, std::move(backingTexture))) {
-            auto op = RenderAtlasOp::Make(rtc->surfPriv().getContext(), sk_ref_sp(this),
-                                          atlas->getFillBatchID(), atlas->getStrokeBatchID(),
-                                          atlas->drawBounds());
+            std::unique_ptr<GrDrawOp> op;
+            if (onFlushRP->caps()->shaderCaps()->geometryShaderSupport()) {
+                op = RenderAtlasOp<GrGSCoverageProcessor>::Make(
+                        rtc->surfPriv().getContext(), sk_ref_sp(this), atlas->getFillBatchID(),
+                        atlas->getStrokeBatchID(), atlas->drawBounds());
+            } else {
+                op = RenderAtlasOp<GrVSCoverageProcessor>::Make(
+                        rtc->surfPriv().getContext(), sk_ref_sp(this), atlas->getFillBatchID(),
+                        atlas->getStrokeBatchID(), atlas->drawBounds());
+            }
             rtc->addDrawOp(GrNoClip(), std::move(op));
             out->push_back(std::move(rtc));
         }
diff --git a/src/gpu/ccpr/GrCCStroker.cpp b/src/gpu/ccpr/GrCCStroker.cpp
index c097c0a..65f1c41 100644
--- a/src/gpu/ccpr/GrCCStroker.cpp
+++ b/src/gpu/ccpr/GrCCStroker.cpp
@@ -672,8 +672,8 @@
     return true;
 }
 
-void GrCCStroker::drawStrokes(GrOpFlushState* flushState, BatchID batchID,
-                              const SkIRect& drawBounds) const {
+void GrCCStroker::drawStrokes(GrOpFlushState* flushState, GrCCCoverageProcessor* proc,
+                              BatchID batchID, const SkIRect& drawBounds) const {
     using PrimitiveType = GrCCCoverageProcessor::PrimitiveType;
     SkASSERT(fInstanceBuffer);
 
@@ -708,14 +708,14 @@
     }
 
     // Draw triangles.
-    GrCCCoverageProcessor triProc(flushState->resourceProvider(), PrimitiveType::kTriangles);
+    proc->reset(PrimitiveType::kTriangles, flushState->resourceProvider());
     this->drawConnectingGeometry<&InstanceTallies::fTriangles>(
-            flushState, pipeline, triProc, batch, startIndices, startScissorSubBatch, drawBounds);
+            flushState, pipeline, *proc, batch, startIndices, startScissorSubBatch, drawBounds);
 
     // Draw conics.
-    GrCCCoverageProcessor conicProc(flushState->resourceProvider(), PrimitiveType::kConics);
+    proc->reset(PrimitiveType::kConics, flushState->resourceProvider());
     this->drawConnectingGeometry<&InstanceTallies::fConics>(
-            flushState, pipeline, conicProc, batch, startIndices, startScissorSubBatch, drawBounds);
+            flushState, pipeline, *proc, batch, startIndices, startScissorSubBatch, drawBounds);
 }
 
 void GrCCStroker::appendStrokeMeshesToBuffers(int numSegmentsLog2, const Batch& batch,
diff --git a/src/gpu/ccpr/GrCCStroker.h b/src/gpu/ccpr/GrCCStroker.h
index 6ddbd15..741f265 100644
--- a/src/gpu/ccpr/GrCCStroker.h
+++ b/src/gpu/ccpr/GrCCStroker.h
@@ -55,7 +55,8 @@
     bool prepareToDraw(GrOnFlushResourceProvider*);
 
     // Called after prepareToDraw(). Draws the given batch of path strokes.
-    void drawStrokes(GrOpFlushState*, BatchID, const SkIRect& drawBounds) const;
+    void drawStrokes(
+            GrOpFlushState*, GrCCCoverageProcessor*, BatchID, const SkIRect& drawBounds) const;
 
 private:
     static constexpr int kNumScissorModes = 2;
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp b/src/gpu/ccpr/GrGSCoverageProcessor.cpp
similarity index 85%
rename from src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
rename to src/gpu/ccpr/GrGSCoverageProcessor.cpp
index 2c1d40a..2a3acc3 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp
+++ b/src/gpu/ccpr/GrGSCoverageProcessor.cpp
@@ -5,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-#include "GrCCCoverageProcessor.h"
+#include "GrGSCoverageProcessor.h"
 
 #include "GrMesh.h"
 #include "glsl/GrGLSLVertexGeoBuilder.h"
@@ -16,9 +16,9 @@
 /**
  * This class and its subclasses implement the coverage processor with geometry shaders.
  */
-class GrCCCoverageProcessor::GSImpl : public GrGLSLGeometryProcessor {
+class GrGSCoverageProcessor::Impl : public GrGLSLGeometryProcessor {
 protected:
-    GSImpl(std::unique_ptr<Shader> shader) : fShader(std::move(shader)) {}
+    Impl(std::unique_ptr<Shader> shader) : fShader(std::move(shader)) {}
 
     virtual bool hasCoverage() const { return false; }
 
@@ -28,11 +28,11 @@
     }
 
     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
-        const GrCCCoverageProcessor& proc = args.fGP.cast<GrCCCoverageProcessor>();
+        const GrGSCoverageProcessor& proc = args.fGP.cast<GrGSCoverageProcessor>();
 
         // The vertex shader simply forwards transposed x or y values to the geometry shader.
         SkASSERT(1 == proc.numVertexAttributes());
-        gpArgs->fPositionVar = proc.fVertexAttribute.asShaderVar();
+        gpArgs->fPositionVar = proc.fInputXOrYValues.asShaderVar();
 
         // Geometry shader.
         GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
@@ -45,9 +45,9 @@
         fShader->emitFragmentCode(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
     }
 
-    void emitGeometryShader(const GrCCCoverageProcessor& proc,
-                            GrGLSLVaryingHandler* varyingHandler, GrGLSLGeometryBuilder* g,
-                            const char* rtAdjust) const {
+    void emitGeometryShader(
+            const GrGSCoverageProcessor& proc, GrGLSLVaryingHandler* varyingHandler,
+            GrGLSLGeometryBuilder* g, const char* rtAdjust) const {
         int numInputPoints = proc.numInputPoints();
         SkASSERT(3 == numInputPoints || 4 == numInputPoints);
 
@@ -59,9 +59,9 @@
         GrShaderVar wind("wind", kHalf_GrSLType);
         g->declareGlobal(wind);
         Shader::CalcWind(proc, g, "pts", wind.c_str());
-        if (PrimitiveType::kWeightedTriangles == proc.fPrimitiveType) {
+        if (PrimitiveType::kWeightedTriangles == proc.primitiveType()) {
             SkASSERT(3 == numInputPoints);
-            SkASSERT(kFloat4_GrVertexAttribType == proc.fVertexAttribute.cpuType());
+            SkASSERT(kFloat4_GrVertexAttribType == proc.fInputXOrYValues.cpuType());
             g->codeAppendf("%s *= half(sk_in[0].sk_Position.w);", wind.c_str());
         }
 
@@ -74,7 +74,7 @@
             coverage = emitArgs.emplace_back("coverage", kHalf_GrSLType).c_str();
         }
         const char* cornerCoverage = nullptr;
-        if (GSSubpass::kCorners == proc.fGSSubpass) {
+        if (Subpass::kCorners == proc.fSubpass) {
             cornerCoverage = emitArgs.emplace_back("corner_coverage", kHalf2_GrSLType).c_str();
         }
         g->emitFunction(kVoid_GrSLType, "emitVertex", emitArgs.count(), emitArgs.begin(), [&]() {
@@ -103,11 +103,9 @@
         this->onEmitGeometryShader(proc, g, wind, emitVertexFn.c_str());
     }
 
-    virtual void onEmitGeometryShader(const GrCCCoverageProcessor&, GrGLSLGeometryBuilder*,
+    virtual void onEmitGeometryShader(const GrGSCoverageProcessor&, GrGLSLGeometryBuilder*,
                                       const GrShaderVar& wind, const char* emitVertexFn) const = 0;
 
-    virtual ~GSImpl() {}
-
     const std::unique_ptr<Shader> fShader;
 
     typedef GrGLSLGeometryProcessor INHERITED;
@@ -121,15 +119,15 @@
  * coverage ramp from -1 to 0. These edge coverage values convert jagged conservative raster edges
  * into smooth, antialiased ones.
  *
- * The final corners get touched up in a later step by GSTriangleCornerImpl.
+ * The final corners get touched up in a later step by TriangleCornerImpl.
  */
-class GrCCCoverageProcessor::GSTriangleHullImpl : public GrCCCoverageProcessor::GSImpl {
+class GrGSCoverageProcessor::TriangleHullImpl : public GrGSCoverageProcessor::Impl {
 public:
-    GSTriangleHullImpl(std::unique_ptr<Shader> shader) : GSImpl(std::move(shader)) {}
+    TriangleHullImpl(std::unique_ptr<Shader> shader) : Impl(std::move(shader)) {}
 
     bool hasCoverage() const override { return true; }
 
-    void onEmitGeometryShader(const GrCCCoverageProcessor&, GrGLSLGeometryBuilder* g,
+    void onEmitGeometryShader(const GrGSCoverageProcessor&, GrGLSLGeometryBuilder* g,
                               const GrShaderVar& wind, const char* emitVertexFn) const override {
         fShader->emitSetupCode(g, "pts", wind.c_str());
 
@@ -219,11 +217,11 @@
 /**
  * Generates a conservative raster around a convex quadrilateral that encloses a cubic or quadratic.
  */
-class GrCCCoverageProcessor::GSCurveHullImpl : public GrCCCoverageProcessor::GSImpl {
+class GrGSCoverageProcessor::CurveHullImpl : public GrGSCoverageProcessor::Impl {
 public:
-    GSCurveHullImpl(std::unique_ptr<Shader> shader) : GSImpl(std::move(shader)) {}
+    CurveHullImpl(std::unique_ptr<Shader> shader) : Impl(std::move(shader)) {}
 
-    void onEmitGeometryShader(const GrCCCoverageProcessor&, GrGLSLGeometryBuilder* g,
+    void onEmitGeometryShader(const GrGSCoverageProcessor&, GrGLSLGeometryBuilder* g,
                               const GrShaderVar& wind, const char* emitVertexFn) const override {
         const char* hullPts = "pts";
         fShader->emitSetupCode(g, "pts", wind.c_str(), &hullPts);
@@ -286,13 +284,13 @@
  * Generates conservative rasters around corners (aka pixel-size boxes) and calculates
  * coverage and attenuation ramps to fix up the coverage values written by the hulls.
  */
-class GrCCCoverageProcessor::GSCornerImpl : public GrCCCoverageProcessor::GSImpl {
+class GrGSCoverageProcessor::CornerImpl : public GrGSCoverageProcessor::Impl {
 public:
-    GSCornerImpl(std::unique_ptr<Shader> shader) : GSImpl(std::move(shader)) {}
+    CornerImpl(std::unique_ptr<Shader> shader) : Impl(std::move(shader)) {}
 
     bool hasCoverage() const override { return true; }
 
-    void onEmitGeometryShader(const GrCCCoverageProcessor& proc, GrGLSLGeometryBuilder* g,
+    void onEmitGeometryShader(const GrGSCoverageProcessor& proc, GrGLSLGeometryBuilder* g,
                               const GrShaderVar& wind, const char* emitVertexFn) const override {
         fShader->emitSetupCode(g, "pts", wind.c_str());
 
@@ -375,45 +373,58 @@
     }
 };
 
-void GrCCCoverageProcessor::initGS() {
-    SkASSERT(Impl::kGeometryShader == fImpl);
+void GrGSCoverageProcessor::reset(PrimitiveType primitiveType, GrResourceProvider*) {
+    fPrimitiveType = primitiveType;  // This will affect the return values for numInputPoints, etc.
+
     if (4 == this->numInputPoints() || this->hasInputWeight()) {
-        fVertexAttribute =
+        fInputXOrYValues =
                 {"x_or_y_values", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
         GR_STATIC_ASSERT(sizeof(QuadPointInstance) ==
                          2 * GrVertexAttribTypeSize(kFloat4_GrVertexAttribType));
         GR_STATIC_ASSERT(offsetof(QuadPointInstance, fY) ==
                          GrVertexAttribTypeSize(kFloat4_GrVertexAttribType));
     } else {
-        fVertexAttribute =
+        fInputXOrYValues =
                 {"x_or_y_values", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
         GR_STATIC_ASSERT(sizeof(TriPointInstance) ==
                          2 * GrVertexAttribTypeSize(kFloat3_GrVertexAttribType));
         GR_STATIC_ASSERT(offsetof(TriPointInstance, fY) ==
                          GrVertexAttribTypeSize(kFloat3_GrVertexAttribType));
     }
-    this->setVertexAttributes(&fVertexAttribute, 1);
-    this->setWillUseGeoShader();
+
+    this->setVertexAttributes(&fInputXOrYValues, 1);
 }
 
-void GrCCCoverageProcessor::appendGSMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount,
-                                         int baseInstance, SkTArray<GrMesh>* out) const {
-    // GSImpl doesn't actually make instanced draw calls. Instead, we feed transposed x,y point
-    // values to the GPU in a regular vertex array and draw kLines (see initGS). Then, each vertex
-    // invocation receives either the shape's x or y values as inputs, which it forwards to the
-    // geometry shader.
-    SkASSERT(Impl::kGeometryShader == fImpl);
+void GrGSCoverageProcessor::appendMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount,
+                                       int baseInstance, SkTArray<GrMesh>* out) const {
+    // We don't actually make instanced draw calls. Instead, we feed transposed x,y point values to
+    // the GPU in a regular vertex array and draw kLines (see initGS). Then, each vertex invocation
+    // receives either the shape's x or y values as inputs, which it forwards to the geometry
+    // shader.
     GrMesh& mesh = out->emplace_back(GrPrimitiveType::kLines);
     mesh.setNonIndexedNonInstanced(instanceCount * 2);
     mesh.setVertexData(std::move(instanceBuffer), baseInstance * 2);
 }
 
-GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createGSImpl(std::unique_ptr<Shader> shadr) const {
-    if (GSSubpass::kHulls == fGSSubpass) {
-        return this->isTriangles()
-                   ? (GSImpl*) new GSTriangleHullImpl(std::move(shadr))
-                   : (GSImpl*) new GSCurveHullImpl(std::move(shadr));
+void GrGSCoverageProcessor::draw(
+        GrOpFlushState* flushState, const GrPipeline& pipeline, const SkIRect scissorRects[],
+        const GrMesh meshes[], int meshCount, const SkRect& drawBounds) const {
+    // The geometry shader impl draws primitives in two subpasses: The first pass fills the interior
+    // and does edge AA. The second pass does touch up on corner pixels.
+    for (int i = 0; i < 2; ++i) {
+        fSubpass = (Subpass) i;
+        this->GrCCCoverageProcessor::draw(
+                flushState, pipeline, scissorRects, meshes, meshCount, drawBounds);
     }
-    SkASSERT(GSSubpass::kCorners == fGSSubpass);
-    return new GSCornerImpl(std::move(shadr));
+}
+
+GrGLSLPrimitiveProcessor* GrGSCoverageProcessor::onCreateGLSLInstance(
+        std::unique_ptr<Shader> shader) const {
+    if (Subpass::kHulls == fSubpass) {
+        return this->isTriangles()
+                   ? (Impl*) new TriangleHullImpl(std::move(shader))
+                   : (Impl*) new CurveHullImpl(std::move(shader));
+    }
+    SkASSERT(Subpass::kCorners == fSubpass);
+    return new CornerImpl(std::move(shader));
 }
diff --git a/src/gpu/ccpr/GrGSCoverageProcessor.h b/src/gpu/ccpr/GrGSCoverageProcessor.h
new file mode 100644
index 0000000..f517765
--- /dev/null
+++ b/src/gpu/ccpr/GrGSCoverageProcessor.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGSCoverageProcessor_DEFINED
+#define GrGSCoverageProcessor_DEFINED
+
+#include "ccpr/GrCCCoverageProcessor.h"
+
+/**
+ * This class implements GrCCCoverageProcessor with analytic coverage using geometry shaders.
+ */
+class GrGSCoverageProcessor : public GrCCCoverageProcessor {
+public:
+    GrGSCoverageProcessor() : GrCCCoverageProcessor(kGrGSCoverageProcessor_ClassID) {
+        this->setWillUseGeoShader();
+    }
+
+private:
+    void reset(PrimitiveType, GrResourceProvider*) override;
+
+    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
+        SkDEBUGCODE(this->getDebugBloatKey(b));
+        b->add32(((int)fPrimitiveType << 16) | (int)fSubpass);
+    }
+
+    void appendMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount, int baseInstance,
+                    SkTArray<GrMesh>* out) const override;
+
+    void draw(GrOpFlushState*, const GrPipeline&, const SkIRect scissorRects[], const GrMesh[],
+              int meshCount, const SkRect& drawBounds) const override;
+
+    GrGLSLPrimitiveProcessor* onCreateGLSLInstance(std::unique_ptr<Shader>) const override;
+
+    // The geometry shader impl draws primitives in two subpasses. The first pass fills the interior
+    // and does edge AA. The second pass does touch up on corner pixels.
+    enum class Subpass : bool {
+        kHulls,
+        kCorners
+    };
+
+    Attribute fInputXOrYValues;
+    mutable Subpass fSubpass = Subpass::kHulls;
+
+    class Impl;
+    class TriangleHullImpl;
+    class CurveHullImpl;
+    class CornerImpl;
+};
+
+#endif
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrVSCoverageProcessor.cpp
similarity index 79%
rename from src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
rename to src/gpu/ccpr/GrVSCoverageProcessor.cpp
index 10300f3..dc00b96 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
+++ b/src/gpu/ccpr/GrVSCoverageProcessor.cpp
@@ -5,15 +5,15 @@
  * found in the LICENSE file.
  */
 
-#include "GrCCCoverageProcessor.h"
+#include "GrVSCoverageProcessor.h"
 
 #include "GrMesh.h"
 #include "glsl/GrGLSLVertexGeoBuilder.h"
 
 // This class implements the coverage processor with vertex shaders.
-class GrCCCoverageProcessor::VSImpl : public GrGLSLGeometryProcessor {
+class GrVSCoverageProcessor::Impl : public GrGLSLGeometryProcessor {
 public:
-    VSImpl(std::unique_ptr<Shader> shader, int numSides)
+    Impl(std::unique_ptr<Shader> shader, int numSides)
             : fShader(std::move(shader)), fNumSides(numSides) {}
 
 private:
@@ -248,28 +248,27 @@
 // previous coverage values with ones that ramp to zero in the bloat vertices that fall outside the
 // triangle.
 //
-// Curves are drawn in two separate passes. Here we just draw a conservative raster around the input
-// points. The Shader takes care of everything else for now. The final curve corners get touched up
-// in a later step by VSCornerImpl.
-void GrCCCoverageProcessor::VSImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
-    const GrCCCoverageProcessor& proc = args.fGP.cast<GrCCCoverageProcessor>();
+// 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.fInstanceAttributes[kInstanceAttribIdx_X].name(), swizzle,
-                   proc.fInstanceAttributes[kInstanceAttribIdx_Y].name(), swizzle);
+                   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.fInstanceAttributes[kInstanceAttribIdx_X].cpuType());
+                 proc.fInputXAndYValues[kInstanceAttribIdx_X].cpuType());
         v->codeAppendf("wind *= half(%s.w);",
-                       proc.fInstanceAttributes[kInstanceAttribIdx_X].name());
+                       proc.fInputXAndYValues[kInstanceAttribIdx_X].name());
     }
 
     float bloat = kAABloatRadius;
@@ -285,12 +284,12 @@
 
     // 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.fVertexAttribute.name(),
+                   proc.fPerVertexData.name(),
                    ((fNumSides - 1) << kVertexData_LeftNeighborIdShift) |
                    ((fNumSides - 1) << kVertexData_RightNeighborIdShift) |
                    (((1 << kVertexData_RightNeighborIdShift) - 1) ^ 3) |
                    (fNumSides - 1),
-                   proc.fVertexAttribute.name());
+                   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
@@ -323,7 +322,7 @@
     v->codeAppend ("rightdir = (float2(0) != rightdir) ? normalize(rightdir) : float2(1, 0);");
 
     v->codeAppendf("if (0 != (%s & %i)) {",  // Are we a corner?
-                   proc.fVertexAttribute.name(), kVertexData_IsCornerBit);
+                   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
@@ -342,7 +341,7 @@
     // 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.fVertexAttribute.name(),
+    v->codeAppendf("int bloatidx = (%s >> %i) & 3;", proc.fPerVertexData.name(),
                    kVertexData_BloatIdxShift);
     v->codeAppend ("switch (bloatidx) {");
     v->codeAppend (    "case 3:");
@@ -377,12 +376,12 @@
         v->codeAppend ("}");
 
         v->codeAppendf("if (0 != (%s & %i)) {",  // Are we an edge?
-                       proc.fVertexAttribute.name(), kVertexData_IsEdgeBit);
+                       proc.fPerVertexData.name(), kVertexData_IsEdgeBit);
         v->codeAppend (    "coverage = left_coverage;");
         v->codeAppend ("}");
 
         v->codeAppendf("if (0 != (%s & %i)) {",  // Invert coverage?
-                       proc.fVertexAttribute.name(),
+                       proc.fPerVertexData.name(),
                        kVertexData_InvertNegativeCoverageBit);
         v->codeAppend (    "coverage = -1 - coverage;");
         v->codeAppend ("}");
@@ -392,7 +391,7 @@
     v->codeAppend ("half2 corner_coverage = half2(0);");
 
     v->codeAppendf("if (0 != (%s & %i)) {",  // Are we a corner?
-                   proc.fVertexAttribute.name(), kVertexData_IsCornerBit);
+                   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
@@ -432,7 +431,7 @@
     GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
     v->codeAppend ("coverage *= wind;");
     v->codeAppend ("corner_coverage.x *= wind;");
-    fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &v->code(),
+    fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &AccessCodeString(v),
                           gpArgs->fPositionVar.c_str(), "coverage", "corner_coverage");
 
     varyingHandler->emitAttributes(proc);
@@ -442,31 +441,28 @@
     fShader->emitFragmentCode(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
 }
 
-void GrCCCoverageProcessor::initVS(GrResourceProvider* rp) {
-    SkASSERT(Impl::kVertexShader == fImpl);
+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);
-            fVSVertexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kVertex,
-                                                         sizeof(kTriangleVertices),
-                                                         kTriangleVertices,
-                                                         gTriangleVertexBufferKey);
+            fVertexBuffer = rp->findOrMakeStaticBuffer(
+                    GrGpuBufferType::kVertex, sizeof(kTriangleVertices), kTriangleVertices,
+                    gTriangleVertexBufferKey);
             GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey);
             if (caps.usePrimitiveRestart()) {
-                fVSIndexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kIndex,
-                                                            sizeof(kTriangleIndicesAsStrips),
-                                                            kTriangleIndicesAsStrips,
-                                                            gTriangleIndexBufferKey);
-                fVSNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsStrips);
+                fIndexBuffer = rp->findOrMakeStaticBuffer(
+                        GrGpuBufferType::kIndex, sizeof(kTriangleIndicesAsStrips),
+                        kTriangleIndicesAsStrips, gTriangleIndexBufferKey);
+                fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsStrips);
             } else {
-                fVSIndexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kIndex,
-                                                            sizeof(kTriangleIndicesAsTris),
-                                                            kTriangleIndicesAsTris,
-                                                            gTriangleIndexBufferKey);
-                fVSNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsTris);
+                fIndexBuffer = rp->findOrMakeStaticBuffer(
+                        GrGpuBufferType::kIndex, sizeof(kTriangleIndicesAsTris),
+                        kTriangleIndicesAsTris, gTriangleIndexBufferKey);
+                fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsTris);
             }
             break;
         }
@@ -475,22 +471,20 @@
         case PrimitiveType::kCubics:
         case PrimitiveType::kConics: {
             GR_DEFINE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey);
-            fVSVertexBuffer =
-                    rp->findOrMakeStaticBuffer(GrGpuBufferType::kVertex, sizeof(kCurveVertices),
-                                               kCurveVertices, gCurveVertexBufferKey);
+            fVertexBuffer = rp->findOrMakeStaticBuffer(
+                    GrGpuBufferType::kVertex, sizeof(kCurveVertices), kCurveVertices,
+                    gCurveVertexBufferKey);
             GR_DEFINE_STATIC_UNIQUE_KEY(gCurveIndexBufferKey);
             if (caps.usePrimitiveRestart()) {
-                fVSIndexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kIndex,
-                                                            sizeof(kCurveIndicesAsStrips),
-                                                            kCurveIndicesAsStrips,
-                                                            gCurveIndexBufferKey);
-                fVSNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsStrips);
+                fIndexBuffer = rp->findOrMakeStaticBuffer(
+                        GrGpuBufferType::kIndex, sizeof(kCurveIndicesAsStrips),
+                        kCurveIndicesAsStrips, gCurveIndexBufferKey);
+                fNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsStrips);
             } else {
-                fVSIndexBuffer = rp->findOrMakeStaticBuffer(GrGpuBufferType::kIndex,
-                                                            sizeof(kCurveIndicesAsTris),
-                                                            kCurveIndicesAsTris,
-                                                            gCurveIndexBufferKey);
-                fVSNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsTris);
+                fIndexBuffer = rp->findOrMakeStaticBuffer(
+                        GrGpuBufferType::kIndex, sizeof(kCurveIndicesAsTris), kCurveIndicesAsTris,
+                        gCurveIndexBufferKey);
+                fNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsTris);
             }
             break;
         }
@@ -515,39 +509,39 @@
         xyAttribType = kFloat3_GrVertexAttribType;
         xySLType = kFloat3_GrSLType;
     }
-    fInstanceAttributes[kInstanceAttribIdx_X] = {"X", xyAttribType, xySLType};
-    fInstanceAttributes[kInstanceAttribIdx_Y] = {"Y", xyAttribType, xySLType};
-    this->setInstanceAttributes(fInstanceAttributes, 2);
-    fVertexAttribute = {"vertexdata", kInt_GrVertexAttribType, kInt_GrSLType};
-    this->setVertexAttributes(&fVertexAttribute, 1);
+    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()) {
-        fVSTriangleType = GrPrimitiveType::kTriangleStrip;
+        fTriangleType = GrPrimitiveType::kTriangleStrip;
     } else {
-        fVSTriangleType = GrPrimitiveType::kTriangles;
+        fTriangleType = GrPrimitiveType::kTriangles;
     }
 }
 
-void GrCCCoverageProcessor::appendVSMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount,
-                                         int baseInstance, SkTArray<GrMesh>* out) const {
-    SkASSERT(Impl::kVertexShader == fImpl);
-    GrMesh& mesh = out->emplace_back(fVSTriangleType);
-    auto primitiveRestart = GrPrimitiveRestart(GrPrimitiveType::kTriangleStrip == fVSTriangleType);
-    mesh.setIndexedInstanced(fVSIndexBuffer, fVSNumIndicesPerInstance, std::move(instanceBuffer),
+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(fVSVertexBuffer, 0);
+    mesh.setVertexData(fVertexBuffer, 0);
 }
 
-GrGLSLPrimitiveProcessor* GrCCCoverageProcessor::createVSImpl(std::unique_ptr<Shader> shadr) const {
+GrGLSLPrimitiveProcessor* GrVSCoverageProcessor::onCreateGLSLInstance(
+        std::unique_ptr<Shader> shader) const {
     switch (fPrimitiveType) {
         case PrimitiveType::kTriangles:
         case PrimitiveType::kWeightedTriangles:
-            return new VSImpl(std::move(shadr), 3);
+            return new Impl(std::move(shader), 3);
         case PrimitiveType::kQuadratics:
         case PrimitiveType::kCubics:
         case PrimitiveType::kConics:
-            return new VSImpl(std::move(shadr), 4);
+            return new Impl(std::move(shader), 4);
     }
-    SK_ABORT("Invalid RenderPass");
+    SK_ABORT("Invalid PrimitiveType");
     return nullptr;
 }
diff --git a/src/gpu/ccpr/GrVSCoverageProcessor.h b/src/gpu/ccpr/GrVSCoverageProcessor.h
new file mode 100644
index 0000000..e278548
--- /dev/null
+++ b/src/gpu/ccpr/GrVSCoverageProcessor.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrVSCoverageProcessor_DEFINED
+#define GrVSCoverageProcessor_DEFINED
+
+#include "ccpr/GrCCCoverageProcessor.h"
+
+/**
+ * This class implements GrCCCoverageProcessor with analytic coverage using vertex shaders.
+ */
+class GrVSCoverageProcessor : public GrCCCoverageProcessor {
+public:
+    GrVSCoverageProcessor() : GrCCCoverageProcessor(kGrVSCoverageProcessor_ClassID) {}
+
+private:
+    void reset(PrimitiveType, GrResourceProvider*) override;
+
+    void appendMesh(sk_sp<const GrGpuBuffer> instanceBuffer, int instanceCount, int baseInstance,
+                    SkTArray<GrMesh>* out) const override;
+
+    GrGLSLPrimitiveProcessor* onCreateGLSLInstance(std::unique_ptr<Shader>) const override;
+
+    Attribute fPerVertexData;
+    Attribute fInputXAndYValues[2];
+    sk_sp<const GrGpuBuffer> fVertexBuffer;
+    sk_sp<const GrGpuBuffer> fIndexBuffer;
+    int fNumIndicesPerInstance;
+    GrPrimitiveType fTriangleType;
+
+    class Impl;
+};
+
+#endif