Stop passing GrPrimitiveProcessor to GrMesh::sendToGpu.

It is currently used in GrGLGpu::setupGeometry. Instead:

1) Make GrMesh track whether primitive restart should be enabled.

2) Make GrGLProgram track program attributes.

Change-Id: Ice411a495961fcbc3cedc81e8ae0583537f42153
Reviewed-on: https://skia-review.googlesource.com/132267
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/GrGpuCommandBuffer.cpp b/src/gpu/GrGpuCommandBuffer.cpp
index 4dfc334..13ae6c9 100644
--- a/src/gpu/GrGpuCommandBuffer.cpp
+++ b/src/gpu/GrGpuCommandBuffer.cpp
@@ -34,7 +34,6 @@
                                 const SkRect& bounds) {
 #ifdef SK_DEBUG
     SkASSERT(!primProc.hasInstanceAttribs() || this->gpu()->caps()->instanceAttribSupport());
-    SkASSERT(!primProc.willUsePrimitiveRestart() || this->gpu()->caps()->usePrimitiveRestart());
     for (int i = 0; i < meshCount; ++i) {
         SkASSERT(!GrPrimTypeRequiresGeometryShaderSupport(meshes[i].primitiveType()) ||
                  this->gpu()->caps()->shaderCaps()->geometryShaderSupport());
diff --git a/src/gpu/GrMesh.h b/src/gpu/GrMesh.h
index bdb62f5..1c9fac4 100644
--- a/src/gpu/GrMesh.h
+++ b/src/gpu/GrMesh.h
@@ -28,6 +28,7 @@
     }
 
     GrPrimitiveType primitiveType() const { return fPrimitiveType; }
+
     bool isIndexed() const { return SkToBool(fIndexBuffer.get()); }
     bool isInstanced() const { return SkToBool(fInstanceBuffer.get()); }
     bool hasVertexData() const { return SkToBool(fVertexBuffer.get()); }
@@ -35,55 +36,56 @@
     void setNonIndexedNonInstanced(int vertexCount);
 
     void setIndexed(const GrBuffer* indexBuffer, int indexCount, int baseIndex,
-                    uint16_t minIndexValue, uint16_t maxIndexValue);
+                    uint16_t minIndexValue, uint16_t maxIndexValue, GrPrimitiveRestart);
     void setIndexedPatterned(const GrBuffer* indexBuffer, int indexCount, int vertexCount,
                              int patternRepeatCount, int maxPatternRepetitionsInIndexBuffer);
 
     void setInstanced(const GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
                       int vertexCount);
     void setIndexedInstanced(const GrBuffer* indexBuffer, int indexCount,
-                             const GrBuffer* instanceBuffer, int instanceCount, int baseInstance=0);
+                             const GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
+                             GrPrimitiveRestart);
 
     void setVertexData(const GrBuffer* vertexBuffer, int baseVertex = 0);
 
     class SendToGpuImpl {
     public:
-        virtual void sendMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                                   const GrBuffer* vertexBuffer, int vertexCount,
+        virtual void sendMeshToGpu(GrPrimitiveType, const GrBuffer* vertexBuffer, int vertexCount,
                                    int baseVertex) = 0;
 
-        virtual void sendIndexedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                                          const GrBuffer* indexBuffer, int indexCount,
-                                          int baseIndex, uint16_t minIndexValue,
+        virtual void sendIndexedMeshToGpu(GrPrimitiveType, const GrBuffer* indexBuffer,
+                                          int indexCount, int baseIndex, uint16_t minIndexValue,
                                           uint16_t maxIndexValue, const GrBuffer* vertexBuffer,
-                                          int baseVertex) = 0;
+                                          int baseVertex, GrPrimitiveRestart) = 0;
 
-        virtual void sendInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                                            const GrBuffer* vertexBuffer, int vertexCount,
-                                            int baseVertex, const GrBuffer* instanceBuffer,
-                                            int instanceCount, int baseInstance) = 0;
+        virtual void sendInstancedMeshToGpu(GrPrimitiveType, const GrBuffer* vertexBuffer,
+                                            int vertexCount, int baseVertex,
+                                            const GrBuffer* instanceBuffer, int instanceCount,
+                                            int baseInstance) = 0;
 
-        virtual void sendIndexedInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                                                   const GrBuffer* indexBuffer, int indexCount,
-                                                   int baseIndex, const GrBuffer* vertexBuffer,
-                                                   int baseVertex, const GrBuffer* instanceBuffer,
-                                                   int instanceCount, int baseInstance) = 0;
+        virtual void sendIndexedInstancedMeshToGpu(GrPrimitiveType, const GrBuffer* indexBuffer,
+                                                   int indexCount, int baseIndex,
+                                                   const GrBuffer* vertexBuffer, int baseVertex,
+                                                   const GrBuffer* instanceBuffer,
+                                                   int instanceCount, int baseInstance,
+                                                   GrPrimitiveRestart) = 0;
 
         virtual ~SendToGpuImpl() {}
     };
 
-    void sendToGpu(const GrPrimitiveProcessor&, SendToGpuImpl*) const;
+    void sendToGpu(SendToGpuImpl*) const;
 
     struct PatternBatch;
 
 private:
     using PendingBuffer = GrPendingIOResource<const GrBuffer, kRead_GrIOType>;
 
-    GrPrimitiveType   fPrimitiveType;
-    PendingBuffer     fIndexBuffer;
-    PendingBuffer     fInstanceBuffer;
-    PendingBuffer     fVertexBuffer;
-    int               fBaseVertex;
+    GrPrimitiveType fPrimitiveType;
+    PendingBuffer fIndexBuffer;
+    PendingBuffer fInstanceBuffer;
+    PendingBuffer fVertexBuffer;
+    int fBaseVertex;
+    GrPrimitiveRestart fPrimitiveRestart;
 
     union {
         struct { // When fIndexBuffer == nullptr and fInstanceBuffer == nullptr.
@@ -133,10 +135,12 @@
     fIndexBuffer.reset(nullptr);
     fInstanceBuffer.reset(nullptr);
     fNonIndexNonInstanceData.fVertexCount = vertexCount;
+    fPrimitiveRestart = GrPrimitiveRestart::kNo;
 }
 
 inline void GrMesh::setIndexed(const GrBuffer* indexBuffer, int indexCount, int baseIndex,
-                               uint16_t minIndexValue, uint16_t maxIndexValue) {
+                               uint16_t minIndexValue, uint16_t maxIndexValue,
+                               GrPrimitiveRestart primitiveRestart) {
     SkASSERT(indexBuffer);
     SkASSERT(indexCount >= 1);
     SkASSERT(baseIndex >= 0);
@@ -148,6 +152,7 @@
     fNonPatternIndexData.fBaseIndex = baseIndex;
     fNonPatternIndexData.fMinIndexValue = minIndexValue;
     fNonPatternIndexData.fMaxIndexValue = maxIndexValue;
+    fPrimitiveRestart = primitiveRestart;
 }
 
 inline void GrMesh::setIndexedPatterned(const GrBuffer* indexBuffer, int indexCount,
@@ -164,6 +169,7 @@
     fIndexData.fPatternRepeatCount = patternRepeatCount;
     fPatternData.fVertexCount = vertexCount;
     fPatternData.fMaxPatternRepetitionsInIndexBuffer = maxPatternRepetitionsInIndexBuffer;
+    fPrimitiveRestart = GrPrimitiveRestart::kNo;
 }
 
 inline void GrMesh::setInstanced(const GrBuffer* instanceBuffer, int instanceCount,
@@ -176,11 +182,12 @@
     fInstanceData.fInstanceCount = instanceCount;
     fInstanceData.fBaseInstance = baseInstance;
     fInstanceNonIndexData.fVertexCount = vertexCount;
+    fPrimitiveRestart = GrPrimitiveRestart::kNo;
 }
 
 inline void GrMesh::setIndexedInstanced(const GrBuffer* indexBuffer, int indexCount,
                                         const GrBuffer* instanceBuffer, int instanceCount,
-                                        int baseInstance) {
+                                        int baseInstance, GrPrimitiveRestart primitiveRestart) {
     SkASSERT(indexBuffer);
     SkASSERT(indexCount >= 1);
     SkASSERT(instanceBuffer);
@@ -191,6 +198,7 @@
     fInstanceData.fInstanceCount = instanceCount;
     fInstanceData.fBaseInstance = baseInstance;
     fInstanceIndexData.fIndexCount = indexCount;
+    fPrimitiveRestart = primitiveRestart;
 }
 
 inline void GrMesh::setVertexData(const GrBuffer* vertexBuffer, int baseVertex) {
@@ -199,36 +207,35 @@
     fBaseVertex = baseVertex;
 }
 
-inline void GrMesh::sendToGpu(const GrPrimitiveProcessor& primProc, SendToGpuImpl* impl) const {
+inline void GrMesh::sendToGpu(SendToGpuImpl* impl) const {
     if (this->isInstanced()) {
         if (!this->isIndexed()) {
-            impl->sendInstancedMeshToGpu(primProc, fPrimitiveType, fVertexBuffer.get(),
+            impl->sendInstancedMeshToGpu(fPrimitiveType, fVertexBuffer.get(),
                                          fInstanceNonIndexData.fVertexCount, fBaseVertex,
                                          fInstanceBuffer.get(), fInstanceData.fInstanceCount,
                                          fInstanceData.fBaseInstance);
         } else {
-            impl->sendIndexedInstancedMeshToGpu(primProc, fPrimitiveType, fIndexBuffer.get(),
-                                                fInstanceIndexData.fIndexCount, 0,
-                                                fVertexBuffer.get(), fBaseVertex,
-                                                fInstanceBuffer.get(), fInstanceData.fInstanceCount,
-                                                fInstanceData.fBaseInstance);
+            impl->sendIndexedInstancedMeshToGpu(
+                    fPrimitiveType, fIndexBuffer.get(), fInstanceIndexData.fIndexCount, 0,
+                    fVertexBuffer.get(), fBaseVertex, fInstanceBuffer.get(),
+                    fInstanceData.fInstanceCount, fInstanceData.fBaseInstance, fPrimitiveRestart);
         }
         return;
     }
 
     if (!this->isIndexed()) {
         SkASSERT(fNonIndexNonInstanceData.fVertexCount > 0);
-        impl->sendMeshToGpu(primProc, fPrimitiveType, fVertexBuffer.get(),
+        impl->sendMeshToGpu(fPrimitiveType, fVertexBuffer.get(),
                             fNonIndexNonInstanceData.fVertexCount, fBaseVertex);
         return;
     }
 
     if (0 == fIndexData.fPatternRepeatCount) {
-        impl->sendIndexedMeshToGpu(primProc, fPrimitiveType, fIndexBuffer.get(),
-                                   fIndexData.fIndexCount, fNonPatternIndexData.fBaseIndex,
+        impl->sendIndexedMeshToGpu(fPrimitiveType, fIndexBuffer.get(), fIndexData.fIndexCount,
+                                   fNonPatternIndexData.fBaseIndex,
                                    fNonPatternIndexData.fMinIndexValue,
                                    fNonPatternIndexData.fMaxIndexValue, fVertexBuffer.get(),
-                                   fBaseVertex);
+                                   fBaseVertex, fPrimitiveRestart);
         return;
     }
 
@@ -240,10 +247,11 @@
         // A patterned index buffer must contain indices in the range [0..vertexCount].
         int minIndexValue = 0;
         int maxIndexValue = fPatternData.fVertexCount * repeatCount - 1;
-        impl->sendIndexedMeshToGpu(primProc, fPrimitiveType, fIndexBuffer.get(),
-                                   fIndexData.fIndexCount * repeatCount, 0, minIndexValue,
-                                   maxIndexValue, fVertexBuffer.get(),
-                                   fBaseVertex + fPatternData.fVertexCount * baseRepetition);
+        SkASSERT(fPrimitiveRestart == GrPrimitiveRestart::kNo);
+        impl->sendIndexedMeshToGpu(
+                fPrimitiveType, fIndexBuffer.get(), fIndexData.fIndexCount * repeatCount, 0,
+                minIndexValue, maxIndexValue, fVertexBuffer.get(),
+                fBaseVertex + fPatternData.fVertexCount * baseRepetition, GrPrimitiveRestart::kNo);
         baseRepetition += repeatCount;
     } while (baseRepetition < fIndexData.fPatternRepeatCount);
 }
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index c4303da..c75f13c 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -99,8 +99,6 @@
     // we put these calls on the base class to prevent having to cast
     virtual bool willUseGeoShader() const = 0;
 
-    bool willUsePrimitiveRestart() const { return fWillUsePrimitiveRestart; }
-
     /**
      * Computes a transformKey from an array of coord transforms. Will only look at the first
      * <numCoords> transforms in the array.
@@ -150,8 +148,6 @@
         return fAttribs.back();
     }
 
-    void setWillUsePrimitiveRestart() { fWillUsePrimitiveRestart = true; }
-
 private:
     void addPendingIOs() const override { GrResourceIOProcessor::addPendingIOs(); }
     void removeRefs() const override { GrResourceIOProcessor::removeRefs(); }
@@ -161,7 +157,6 @@
     SkSTArray<8, Attribute> fAttribs;
     int fVertexStride = 0;
     int fInstanceStride = 0;
-    bool fWillUsePrimitiveRestart = false;
 
     typedef GrProcessor INHERITED;
 };
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
index ef2bcd3..3c9fe89 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
@@ -522,7 +522,6 @@
     SkASSERT(sizeof(int32_t) == this->getVertexStride());
 
     if (caps.usePrimitiveRestart()) {
-        this->setWillUsePrimitiveRestart();
         fVSTriangleType = GrPrimitiveType::kTriangleStrip;
     } else {
         fVSTriangleType = GrPrimitiveType::kTriangles;
@@ -533,8 +532,9 @@
                                          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.get(), fVSNumIndicesPerInstance, instanceBuffer,
-                             instanceCount, baseInstance);
+                             instanceCount, baseInstance, primitiveRestart);
     mesh.setVertexData(fVSVertexBuffer.get(), 0);
 }
 
diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp
index bbc2b81..5edc45f 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.cpp
+++ b/src/gpu/ccpr/GrCCPathProcessor.cpp
@@ -100,10 +100,6 @@
 
     this->addVertexAttrib("edge_norms", kFloat4_GrVertexAttribType);
 
-    if (resourceProvider->caps()->usePrimitiveRestart()) {
-        this->setWillUsePrimitiveRestart();
-    }
-
     fAtlasAccess.instantiate(resourceProvider);
     this->addTextureSampler(&fAtlasAccess);
 
@@ -146,8 +142,10 @@
                                         ? SK_ARRAY_COUNT(kOctoIndicesAsStrips)
                                         : SK_ARRAY_COUNT(kOctoIndicesAsTris);
     GrMesh mesh(primitiveType);
+    auto enablePrimitiveRestart = GrPrimitiveRestart(flushState->caps().usePrimitiveRestart());
+
     mesh.setIndexedInstanced(indexBuffer, numIndicesPerInstance, instanceBuffer,
-                             endInstance - baseInstance, baseInstance);
+                             endInstance - baseInstance, baseInstance, enablePrimitiveRestart);
     mesh.setVertexData(vertexBuffer);
 
     flushState->rtCommandBuffer()->draw(pipeline, *this, &mesh, nullptr, 1, bounds);
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 533c6b4..42a8992 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -251,6 +251,7 @@
     fMipmapProgramArrayBuffer.reset();
     fStencilClipClearArrayBuffer.reset();
 
+    fHWProgram.reset();
     if (fHWProgramID) {
         // detach the current program so there is no confusion on OpenGL's part
         // that we want it to be deleted
@@ -328,6 +329,7 @@
         }
     }
 
+    fHWProgram.reset();
     delete fProgramCache;
     fProgramCache = nullptr;
 
@@ -496,6 +498,7 @@
 
     if (resetBits & kProgram_GrGLBackendState) {
         fHWProgramID = 0;
+        fHWProgram.reset();
     }
 }
 
@@ -1695,11 +1698,7 @@
     this->flushColorWrite(blendInfo.fWriteColor);
     this->flushMinSampleShading(primProc.getSampleShading());
 
-    GrGLuint programID = program->programID();
-    if (fHWProgramID != programID) {
-        GL_CALL(UseProgram(programID));
-        fHWProgramID = programID;
-    }
+    this->flushProgram(std::move(program));
 
     if (blendInfo.fWriteColor) {
         // Swizzle the blend to match what the shader will output.
@@ -1708,7 +1707,7 @@
         this->flushBlend(blendInfo, swizzle);
     }
 
-    program->setData(primProc, pipeline);
+    fHWProgram->setData(primProc, pipeline);
 
     GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.renderTarget());
     GrStencilSettings stencil;
@@ -1730,13 +1729,41 @@
     return true;
 }
 
-void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc,
-                            const GrBuffer* indexBuffer,
+void GrGLGpu::flushProgram(sk_sp<GrGLProgram> program) {
+    if (!program) {
+        fHWProgram.reset();
+        fHWProgramID = 0;
+        return;
+    }
+    SkASSERT((program == fHWProgram) == (fHWProgramID == program->programID()));
+    if (program == fHWProgram) {
+        return;
+    }
+    auto id = program->programID();
+    SkASSERT(id);
+    GL_CALL(UseProgram(id));
+    fHWProgram = std::move(program);
+    fHWProgramID = id;
+}
+
+void GrGLGpu::flushProgram(GrGLuint id) {
+    SkASSERT(id);
+    if (fHWProgramID == id) {
+        SkASSERT(!fHWProgram);
+        return;
+    }
+    fHWProgram.reset();
+    GL_CALL(UseProgram(id));
+    fHWProgramID = id;
+}
+
+void GrGLGpu::setupGeometry(const GrBuffer* indexBuffer,
                             const GrBuffer* vertexBuffer,
                             int baseVertex,
                             const GrBuffer* instanceBuffer,
-                            int baseInstance) {
-    using EnablePrimitiveRestart = GrGLAttribArrayState::EnablePrimitiveRestart;
+                            int baseInstance,
+                            GrPrimitiveRestart enablePrimitiveRestart) {
+    SkASSERT((enablePrimitiveRestart == GrPrimitiveRestart::kNo) || indexBuffer);
 
     GrGLAttribArrayState* attribState;
     if (indexBuffer) {
@@ -1752,30 +1779,29 @@
         size_t            fBufferOffset;
     } bindings[2];
 
-    if (int vertexStride = primProc.getVertexStride()) {
+    if (int vertexStride = fHWProgram->vertexStride()) {
         SkASSERT(vertexBuffer && !vertexBuffer->isMapped());
         bindings[0].fBuffer = vertexBuffer;
         bindings[0].fStride = vertexStride;
         bindings[0].fBufferOffset = vertexBuffer->baseOffset() + baseVertex * vertexStride;
     }
-    if (int instanceStride = primProc.getInstanceStride()) {
+    if (int instanceStride = fHWProgram->instanceStride()) {
         SkASSERT(instanceBuffer && !instanceBuffer->isMapped());
         bindings[1].fBuffer = instanceBuffer;
         bindings[1].fStride = instanceStride;
         bindings[1].fBufferOffset = instanceBuffer->baseOffset() + baseInstance * instanceStride;
     }
 
-    int numAttribs = primProc.numAttribs();
-    auto enableRestart = EnablePrimitiveRestart(primProc.willUsePrimitiveRestart() && indexBuffer);
-    attribState->enableVertexArrays(this, numAttribs, enableRestart);
+    auto numAttributes = fHWProgram->numAttributes();
+    attribState->enableVertexArrays(this, numAttributes, enablePrimitiveRestart);
 
-    for (int i = 0; i < numAttribs; ++i) {
+    for (int i = 0; i < numAttributes; ++i) {
         using InputRate = GrPrimitiveProcessor::Attribute::InputRate;
-        const GrGeometryProcessor::Attribute& attrib = primProc.getAttrib(i);
-        const int divisor = InputRate::kPerInstance == attrib.inputRate() ? 1 : 0;
+        const GrGLProgram::Attribute& attribute = fHWProgram->attribute(i);
+        const int divisor = InputRate::kPerInstance == attribute.fInputRate ? 1 : 0;
         const auto& binding = bindings[divisor];
-        attribState->set(this, i, binding.fBuffer, attrib.type(), binding.fStride,
-                         binding.fBufferOffset + attrib.offsetInRecord(), divisor);
+        attribState->set(this, attribute.fLocation, binding.fBuffer, attribute.fType,
+                         binding.fStride, binding.fBufferOffset + attribute.fOffset, divisor);
     }
 }
 
@@ -2242,7 +2268,7 @@
             GL_CALL(Enable(GR_GL_CULL_FACE));
             GL_CALL(Disable(GR_GL_CULL_FACE));
         }
-        meshes[i].sendToGpu(primProc, this);
+        meshes[i].sendToGpu(this);
         fLastPrimitiveType = meshes[i].primitiveType();
     }
 
@@ -2279,14 +2305,14 @@
     return GR_GL_TRIANGLES;
 }
 
-void GrGLGpu::sendMeshToGpu(const GrPrimitiveProcessor& primProc, GrPrimitiveType primitiveType,
-                            const GrBuffer* vertexBuffer, int vertexCount, int baseVertex) {
+void GrGLGpu::sendMeshToGpu(GrPrimitiveType primitiveType, const GrBuffer* vertexBuffer,
+                            int vertexCount, int baseVertex) {
     const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
     if (this->glCaps().drawArraysBaseVertexIsBroken()) {
-        this->setupGeometry(primProc, nullptr, vertexBuffer, baseVertex, nullptr, 0);
+        this->setupGeometry(nullptr, vertexBuffer, baseVertex, nullptr, 0, GrPrimitiveRestart::kNo);
         GL_CALL(DrawArrays(glPrimType, 0, vertexCount));
     } else {
-        this->setupGeometry(primProc, nullptr, vertexBuffer, 0, nullptr, 0);
+        this->setupGeometry(nullptr, vertexBuffer, 0, nullptr, 0, GrPrimitiveRestart::kNo);
         GL_CALL(DrawArrays(glPrimType, baseVertex, vertexCount));
     }
     if (this->glCaps().requiresFlushBetweenNonAndInstancedDraws()) {
@@ -2295,16 +2321,15 @@
     fStats.incNumDraws();
 }
 
-void GrGLGpu::sendIndexedMeshToGpu(const GrPrimitiveProcessor& primProc,
-                                   GrPrimitiveType primitiveType, const GrBuffer* indexBuffer,
+void GrGLGpu::sendIndexedMeshToGpu(GrPrimitiveType primitiveType, const GrBuffer* indexBuffer,
                                    int indexCount, int baseIndex, uint16_t minIndexValue,
                                    uint16_t maxIndexValue, const GrBuffer* vertexBuffer,
-                                   int baseVertex) {
+                                   int baseVertex, GrPrimitiveRestart enablePrimitiveRestart) {
     const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
     GrGLvoid* const indices = reinterpret_cast<void*>(indexBuffer->baseOffset() +
                                                       sizeof(uint16_t) * baseIndex);
 
-    this->setupGeometry(primProc, indexBuffer, vertexBuffer, baseVertex, nullptr, 0);
+    this->setupGeometry(indexBuffer, vertexBuffer, baseVertex, nullptr, 0, enablePrimitiveRestart);
 
     if (this->glCaps().drawRangeElementsSupport()) {
         GL_CALL(DrawRangeElements(glPrimType, minIndexValue, maxIndexValue, indexCount,
@@ -2318,8 +2343,7 @@
     fStats.incNumDraws();
 }
 
-void GrGLGpu::sendInstancedMeshToGpu(const GrPrimitiveProcessor& primProc, GrPrimitiveType
-                                     primitiveType, const GrBuffer* vertexBuffer,
+void GrGLGpu::sendInstancedMeshToGpu(GrPrimitiveType primitiveType, const GrBuffer* vertexBuffer,
                                      int vertexCount, int baseVertex,
                                      const GrBuffer* instanceBuffer, int instanceCount,
                                      int baseInstance) {
@@ -2331,19 +2355,20 @@
     GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
     int maxInstances = this->glCaps().maxInstancesPerDrawArraysWithoutCrashing(instanceCount);
     for (int i = 0; i < instanceCount; i += maxInstances) {
-        this->setupGeometry(primProc, nullptr, vertexBuffer, 0, instanceBuffer, baseInstance + i);
+        this->setupGeometry(nullptr, vertexBuffer, 0, instanceBuffer, baseInstance + i,
+                            GrPrimitiveRestart::kNo);
         GL_CALL(DrawArraysInstanced(glPrimType, baseVertex, vertexCount,
                                     SkTMin(instanceCount - i, maxInstances)));
         fStats.incNumDraws();
     }
 }
 
-void GrGLGpu::sendIndexedInstancedMeshToGpu(const GrPrimitiveProcessor& primProc,
-                                            GrPrimitiveType primitiveType,
+void GrGLGpu::sendIndexedInstancedMeshToGpu(GrPrimitiveType primitiveType,
                                             const GrBuffer* indexBuffer, int indexCount,
                                             int baseIndex, const GrBuffer* vertexBuffer,
                                             int baseVertex, const GrBuffer* instanceBuffer,
-                                            int instanceCount, int baseInstance) {
+                                            int instanceCount, int baseInstance,
+                                            GrPrimitiveRestart enablePrimitiveRestart) {
     if (fRequiresFlushBeforeNextInstancedDraw) {
         SkASSERT(this->glCaps().requiresFlushBetweenNonAndInstancedDraws());
         GL_CALL(Flush());
@@ -2352,8 +2377,8 @@
     const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
     GrGLvoid* indices = reinterpret_cast<void*>(indexBuffer->baseOffset() +
                                                 sizeof(uint16_t) * baseIndex);
-    this->setupGeometry(primProc, indexBuffer, vertexBuffer, baseVertex,
-                        instanceBuffer, baseInstance);
+    this->setupGeometry(indexBuffer, vertexBuffer, baseVertex, instanceBuffer, baseInstance,
+                        enablePrimitiveRestart);
     GL_CALL(DrawElementsInstanced(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT, indices,
                                   instanceCount));
     fStats.incNumDraws();
@@ -3458,8 +3483,7 @@
     GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(rt->asRenderTarget());
     this->flushRenderTarget(glRT);
 
-    GL_CALL(UseProgram(fStencilClipClearProgram));
-    fHWProgramID = fStencilClipClearProgram;
+    this->flushProgram(fStencilClipClearProgram);
 
     fHWVertexArrayState.setVertexArrayID(this, 0);
 
@@ -3571,8 +3595,7 @@
     this->flushViewport(dstVP);
     fHWBoundRenderTargetUniqueID.makeInvalid();
 
-    GL_CALL(UseProgram(fClearColorProgram.fProgram));
-    fHWProgramID = fClearColorProgram.fProgram;
+    this->flushProgram(fClearColorProgram.fProgram);
 
     fHWVertexArrayState.setVertexArrayID(this, 0);
 
@@ -3632,8 +3655,7 @@
 
     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
 
-    GL_CALL(UseProgram(fCopyPrograms[progIdx].fProgram));
-    fHWProgramID = fCopyPrograms[progIdx].fProgram;
+    this->flushProgram(fCopyPrograms[progIdx].fProgram);
 
     fHWVertexArrayState.setVertexArrayID(this, 0);
 
@@ -3885,8 +3907,7 @@
                 return false;
             }
         }
-        GL_CALL(UseProgram(fMipmapPrograms[progIdx].fProgram));
-        fHWProgramID = fMipmapPrograms[progIdx].fProgram;
+        this->flushProgram(fMipmapPrograms[progIdx].fProgram);
 
         // Texcoord uniform is expected to contain (1/w, (w-1)/w, 1/h, (h-1)/h)
         const float invWidth = 1.0f / width;
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 7240f9d..48cd21b 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -95,24 +95,22 @@
 
     // GrMesh::SendToGpuImpl methods. These issue the actual GL draw calls.
     // Marked final as a hint to the compiler to not use virtual dispatch.
-    void sendMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                       const GrBuffer* vertexBuffer, int vertexCount, int baseVertex) final;
+    void sendMeshToGpu(GrPrimitiveType, const GrBuffer* vertexBuffer, int vertexCount,
+                       int baseVertex) final;
 
-    void sendIndexedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                              const GrBuffer* indexBuffer, int indexCount, int baseIndex,
-                              uint16_t minIndexValue, uint16_t maxIndexValue,
-                              const GrBuffer* vertexBuffer, int baseVertex) final;
+    void sendIndexedMeshToGpu(GrPrimitiveType, const GrBuffer* indexBuffer, int indexCount,
+                              int baseIndex, uint16_t minIndexValue, uint16_t maxIndexValue,
+                              const GrBuffer* vertexBuffer, int baseVertex,
+                              GrPrimitiveRestart) final;
 
-    void sendInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                                const GrBuffer* vertexBuffer, int vertexCount, int baseVertex,
-                                const GrBuffer* instanceBuffer, int instanceCount,
+    void sendInstancedMeshToGpu(GrPrimitiveType, const GrBuffer* vertexBuffer, int vertexCount,
+                                int baseVertex, const GrBuffer* instanceBuffer, int instanceCount,
                                 int baseInstance) final;
 
-    void sendIndexedInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                                       const GrBuffer* indexBuffer, int indexCount, int baseIndex,
-                                       const GrBuffer* vertexBuffer, int baseVertex,
+    void sendIndexedInstancedMeshToGpu(GrPrimitiveType, const GrBuffer* indexBuffer, int indexCount,
+                                       int baseIndex, const GrBuffer* vertexBuffer, int baseVertex,
                                        const GrBuffer* instanceBuffer, int instanceCount,
-                                       int baseInstance) final;
+                                       int baseInstance, GrPrimitiveRestart) final;
 
     // The GrGLGpuRTCommandBuffer does not buffer up draws before submitting them to the gpu.
     // Thus this is the implementation of the clear call for the corresponding passthrough function
@@ -260,13 +258,18 @@
     // willDrawPoints must be true if point primitives will be rendered after setting the GL state.
     bool flushGLState(const GrPipeline&, const GrPrimitiveProcessor&, bool willDrawPoints);
 
+    void flushProgram(sk_sp<GrGLProgram>);
+
+    // Version for programs that aren't GrGLProgram.
+    void flushProgram(GrGLuint);
+
     // Sets up vertex/instance attribute pointers and strides.
-    void setupGeometry(const GrPrimitiveProcessor&,
-                       const GrBuffer* indexBuffer,
+    void setupGeometry(const GrBuffer* indexBuffer,
                        const GrBuffer* vertexBuffer,
                        int baseVertex,
                        const GrBuffer* instanceBuffer,
-                       int baseInstance);
+                       int baseInstance,
+                       GrPrimitiveRestart);
 
     void flushBlend(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle&);
 
@@ -408,7 +411,9 @@
     ///@name Caching of GL State
     ///@{
     int                         fHWActiveTextureUnitIdx;
+
     GrGLuint                    fHWProgramID;
+    sk_sp<GrGLProgram>          fHWProgram;
 
     enum TriState {
         kNo_TriState,
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index ea5c18c..262f0b2 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -36,13 +36,21 @@
         std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
         std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
         std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
-        int fragmentProcessorCnt)
+        int fragmentProcessorCnt,
+        std::unique_ptr<Attribute[]> attributes,
+        int attributeCnt,
+        int vertexStride,
+        int instanceStride)
         : fBuiltinUniformHandles(builtinUniforms)
         , fProgramID(programID)
-        , fGeometryProcessor(std::move(geometryProcessor))
+        , fPrimitiveProcessor(std::move(geometryProcessor))
         , fXferProcessor(std::move(xferProcessor))
         , fFragmentProcessors(std::move(fragmentProcessors))
         , fFragmentProcessorCnt(fragmentProcessorCnt)
+        , fAttributes(std::move(attributes))
+        , fAttributeCnt(attributeCnt)
+        , fVertexStride(vertexStride)
+        , fInstanceStride(instanceStride)
         , fGpu(gpu)
         , fProgramDataManager(gpu, programID, uniforms, pathProcVaryings)
         , fNumTextureSamplers(textureSamplers.count())
@@ -76,8 +84,8 @@
     // Within each group we will bind them in primProc, fragProcs, XP order.
     int nextTexSamplerIdx = 0;
     int nextTexelBufferIdx = fNumTextureSamplers;
-    fGeometryProcessor->setData(fProgramDataManager, primProc,
-                                GrFragmentProcessor::CoordTransformIter(pipeline));
+    fPrimitiveProcessor->setData(fProgramDataManager, primProc,
+                                 GrFragmentProcessor::CoordTransformIter(pipeline));
     this->bindTextures(primProc, &nextTexSamplerIdx, &nextTexelBufferIdx);
 
     this->setFragmentData(primProc, pipeline, &nextTexSamplerIdx, &nextTexelBufferIdx);
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index a43e4f4..6ea1f2c 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -10,6 +10,7 @@
 #define GrGLProgram_DEFINED
 
 #include "GrGLProgramDataManager.h"
+#include "GrPrimitiveProcessor.h"
 #include "glsl/GrGLSLProgramDataManager.h"
 #include "glsl/GrGLSLUniformHandler.h"
 
@@ -22,16 +23,23 @@
 class GrResourceIOProcessor;
 
 /**
- * This class manages a GPU program and records per-program information.
- * We can specify the attribute locations so that they are constant
- * across our shaders. But the driver determines the uniform locations
- * at link time. We don't need to remember the sampler uniform location
- * because we will bind a texture slot to it and never change it
- * Uniforms are program-local so we can't rely on fHWState to hold the
- * previous uniform state after a program change.
+ * This class manages a GPU program and records per-program information. It also records the vertex
+ * and instance attribute layouts that are to be used with the program.
  */
 class GrGLProgram : public SkRefCnt {
 public:
+    /**
+     * This class has its own Attribute representation as it does not need the name and we don't
+     * want to worry about copying the name string to memory with life time of GrGLProgram.
+     * Additionally, these store the attribute location.
+     */
+    struct Attribute {
+        GrVertexAttribType fType;
+        int fOffset;
+        GrGLint fLocation;
+        GrPrimitiveProcessor::Attribute::InputRate fInputRate;
+    };
+
     using UniformHandle = GrGLSLProgramDataManager::UniformHandle;
     using UniformInfoArray = GrGLProgramDataManager::UniformInfoArray;
     using VaryingInfoArray = GrGLProgramDataManager::VaryingInfoArray;
@@ -46,7 +54,11 @@
                 std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
                 std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
                 std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
-                int fragmentProcessorCnt);
+                int fragmentProcessorCnt,
+                std::unique_ptr<Attribute[]>,
+                int attributeCnt,
+                int vertexStride,
+                int instanceStride);
 
     ~GrGLProgram();
 
@@ -109,6 +121,11 @@
      * ensures that any textures requiring mipmaps have their mipmaps correctly built.
      */
     void generateMipmaps(const GrPrimitiveProcessor&, const GrPipeline&);
+    int vertexStride() const { return fVertexStride; }
+    int instanceStride() const { return fInstanceStride; }
+
+    int numAttributes() const { return fAttributeCnt; }
+    const Attribute& attribute(int i) const { return fAttributes[i]; }
 
 private:
     // A helper to loop over effects, set the transforms (via subclass) and bind textures
@@ -130,11 +147,16 @@
     GrGLuint fProgramID;
 
     // the installed effects
-    std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor;
+    std::unique_ptr<GrGLSLPrimitiveProcessor> fPrimitiveProcessor;
     std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
     std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
     int fFragmentProcessorCnt;
 
+    std::unique_ptr<Attribute[]> fAttributes;
+    int fAttributeCnt;
+    int fVertexStride;
+    int fInstanceStride;
+
     GrGLGpu* fGpu;
     GrGLProgramDataManager fProgramDataManager;
 
diff --git a/src/gpu/gl/GrGLVertexArray.cpp b/src/gpu/gl/GrGLVertexArray.cpp
index dbfa0f4..68bcf21 100644
--- a/src/gpu/gl/GrGLVertexArray.cpp
+++ b/src/gpu/gl/GrGLVertexArray.cpp
@@ -150,7 +150,7 @@
 }
 
 void GrGLAttribArrayState::enableVertexArrays(const GrGLGpu* gpu, int enabledCount,
-                                              EnablePrimitiveRestart enablePrimitiveRestart) {
+                                              GrPrimitiveRestart enablePrimitiveRestart) {
     SkASSERT(enabledCount <= fAttribArrayStates.count());
 
     if (!fEnableStateIsValid || enabledCount != fNumEnabledArrays) {
@@ -167,12 +167,12 @@
         fNumEnabledArrays = enabledCount;
     }
 
-    SkASSERT(EnablePrimitiveRestart::kNo == enablePrimitiveRestart ||
+    SkASSERT(GrPrimitiveRestart::kNo == enablePrimitiveRestart ||
              gpu->caps()->usePrimitiveRestart());
 
     if (gpu->caps()->usePrimitiveRestart() &&
         (!fEnableStateIsValid || enablePrimitiveRestart != fPrimitiveRestartEnabled)) {
-        if (EnablePrimitiveRestart::kYes == enablePrimitiveRestart) {
+        if (GrPrimitiveRestart::kYes == enablePrimitiveRestart) {
             GR_GL_CALL(gpu->glInterface(), Enable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX));
         } else {
             GR_GL_CALL(gpu->glInterface(), Disable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX));
diff --git a/src/gpu/gl/GrGLVertexArray.h b/src/gpu/gl/GrGLVertexArray.h
index 20b21ae..e460c04 100644
--- a/src/gpu/gl/GrGLVertexArray.h
+++ b/src/gpu/gl/GrGLVertexArray.h
@@ -45,16 +45,11 @@
              size_t offsetInBytes,
              int divisor = 0);
 
-    enum class EnablePrimitiveRestart : bool {
-        kYes = true,
-        kNo = false
-    };
-
     /**
      * This function enables the first 'enabledCount' vertex arrays and disables the rest.
      */
     void enableVertexArrays(const GrGLGpu*, int enabledCount,
-                            EnablePrimitiveRestart = EnablePrimitiveRestart::kNo);
+                            GrPrimitiveRestart = GrPrimitiveRestart::kNo);
 
     void invalidate() {
         int count = fAttribArrayStates.count();
@@ -90,7 +85,7 @@
 
     SkSTArray<16, AttribArrayState, true> fAttribArrayStates;
     int fNumEnabledArrays;
-    EnablePrimitiveRestart fPrimitiveRestartEnabled;
+    GrPrimitiveRestart fPrimitiveRestartEnabled;
     bool fEnableStateIsValid = false;
 };
 
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 86dcfef..0cdc3b5 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -66,11 +66,13 @@
                                        const GrPipeline& pipeline,
                                        const GrPrimitiveProcessor& primProc,
                                        GrProgramDesc* desc)
-    : INHERITED(pipeline, primProc, desc)
-    , fGpu(gpu)
-    , fVaryingHandler(this)
-    , fUniformHandler(this) {
-}
+        : INHERITED(pipeline, primProc, desc)
+        , fGpu(gpu)
+        , fVaryingHandler(this)
+        , fUniformHandler(this)
+        , fAttributeCnt(0)
+        , fVertexStride(0)
+        , fInstanceStride(0) {}
 
 const GrCaps* GrGLProgramBuilder::caps() const {
     return fGpu->caps();
@@ -225,9 +227,17 @@
         // NVPR actually requires a vertex shader to compile
         bool useNvpr = primProc.isPathRendering();
         if (!useNvpr) {
-            int vaCount = primProc.numAttribs();
-            for (int i = 0; i < vaCount; i++) {
-                GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).name()));
+            fAttributeCnt = primProc.numAttribs();
+            fAttributes.reset(new GrGLProgram::Attribute[fAttributeCnt]);
+            fVertexStride = primProc.getVertexStride();
+            fInstanceStride = primProc.getInstanceStride();
+            for (int i = 0; i < fAttributeCnt; i++) {
+                const auto& attr = primProc.getAttrib(i);
+                fAttributes[i].fInputRate = attr.inputRate();
+                fAttributes[i].fType = attr.type();
+                fAttributes[i].fOffset = attr.offsetInRecord();
+                fAttributes[i].fLocation = i;
+                GL_CALL(BindAttribLocation(programID, i, attr.name()));
             }
         }
 
@@ -379,7 +389,7 @@
 }
 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
     for (int i = 0; i < shaderIDs.count(); ++i) {
-      GL_CALL(DeleteShader(shaderIDs[i]));
+        GL_CALL(DeleteShader(shaderIDs[i]));
     }
 }
 
@@ -394,5 +404,9 @@
                            std::move(fGeometryProcessor),
                            std::move(fXferProcessor),
                            std::move(fFragmentProcessors),
-                           fFragmentProcessorCnt);
+                           fFragmentProcessorCnt,
+                           std::move(fAttributes),
+                           fAttributeCnt,
+                           fVertexStride,
+                           fInstanceStride);
 }
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index 54c91b4..ea3432b 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -9,6 +9,7 @@
 #define GrGLProgramBuilder_DEFINED
 
 #include "GrPipeline.h"
+#include "gl/GrGLProgram.h"
 #include "gl/GrGLProgramDataManager.h"
 #include "gl/GrGLUniformHandler.h"
 #include "gl/GrGLVaryingHandler.h"
@@ -79,6 +80,11 @@
     GrGLVaryingHandler    fVaryingHandler;
     GrGLUniformHandler    fUniformHandler;
 
+    std::unique_ptr<GrGLProgram::Attribute[]> fAttributes;
+    int fAttributeCnt;
+    int fVertexStride;
+    int fInstanceStride;
+
     // shader pulled from cache. Data is organized as:
     // SkSL::Program::Inputs inputs
     // int binaryFormat
diff --git a/src/gpu/glsl/GrGLSLUniformHandler.h b/src/gpu/glsl/GrGLSLUniformHandler.h
index fe89b882..4c52d3c 100644
--- a/src/gpu/glsl/GrGLSLUniformHandler.h
+++ b/src/gpu/glsl/GrGLSLUniformHandler.h
@@ -30,6 +30,7 @@
     virtual ~GrGLSLUniformHandler() {}
 
     using UniformHandle = GrGLSLProgramDataManager::UniformHandle;
+
     GR_DEFINE_RESOURCE_HANDLE_CLASS(SamplerHandle);
     GR_DEFINE_RESOURCE_HANDLE_CLASS(TexelBufferHandle);
 
diff --git a/src/gpu/ops/GrAAConvexPathRenderer.cpp b/src/gpu/ops/GrAAConvexPathRenderer.cpp
index d1fbbc4..f94f527 100644
--- a/src/gpu/ops/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAAConvexPathRenderer.cpp
@@ -836,7 +836,8 @@
                                      fHelper.compatibleWithAlphaAsCoverage());
 
             GrMesh mesh(GrPrimitiveType::kTriangles);
-            mesh.setIndexed(indexBuffer, tess.numIndices(), firstIndex, 0, tess.numPts() - 1);
+            mesh.setIndexed(indexBuffer, tess.numIndices(), firstIndex, 0, tess.numPts() - 1,
+                            GrPrimitiveRestart::kNo);
             mesh.setVertexData(vertexBuffer, firstVertex);
             target->draw(gp.get(), pipeline, mesh);
         }
@@ -923,7 +924,8 @@
 
             for (int j = 0; j < draws.count(); ++j) {
                 const Draw& draw = draws[j];
-                mesh.setIndexed(indexBuffer, draw.fIndexCnt, firstIndex, 0, draw.fVertexCnt - 1);
+                mesh.setIndexed(indexBuffer, draw.fIndexCnt, firstIndex, 0, draw.fVertexCnt - 1,
+                                GrPrimitiveRestart::kNo);
                 mesh.setVertexData(vertexBuffer, firstVertex);
                 target->draw(quadProcessor.get(), pipeline, mesh);
                 firstIndex += draw.fIndexCnt;
diff --git a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
index 2c1ea50..02520c1 100644
--- a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
@@ -229,7 +229,8 @@
             return;
         }
         memcpy(idxs, indices, indexCount * sizeof(uint16_t));
-        mesh.setIndexed(indexBuffer, indexCount, firstIndex, 0, vertexCount - 1);
+        mesh.setIndexed(indexBuffer, indexCount, firstIndex, 0, vertexCount - 1,
+                        GrPrimitiveRestart::kNo);
         mesh.setVertexData(vertexBuffer, firstVertex);
         target->draw(gp, pipeline, mesh);
     }
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index 1c5acb0..91eca93 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -269,7 +269,8 @@
             if (!this->isIndexed()) {
                 fMesh.setNonIndexedNonInstanced(vertexCount);
             } else {
-                fMesh.setIndexed(fIndexBuffer, indexCount, fFirstIndex, 0, vertexCount - 1);
+                fMesh.setIndexed(fIndexBuffer, indexCount, fFirstIndex, 0, vertexCount - 1,
+                                 GrPrimitiveRestart::kNo);
             }
             fMesh.setVertexData(fVertexBuffer, fFirstVertex);
             fTarget->draw(fGeometryProcessor, fPipeline, fMesh);
diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp
index dded70a..112ba8b 100644
--- a/src/gpu/ops/GrDrawVerticesOp.cpp
+++ b/src/gpu/ops/GrDrawVerticesOp.cpp
@@ -245,7 +245,8 @@
     if (!indices) {
         mesh.setNonIndexedNonInstanced(fVertexCount);
     } else {
-        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertexCount - 1);
+        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertexCount - 1,
+                        GrPrimitiveRestart::kNo);
     }
     mesh.setVertexData(vertexBuffer, firstVertex);
     target->draw(gp.get(), fHelper.makePipeline(target), mesh);
diff --git a/src/gpu/ops/GrOvalOpFactory.cpp b/src/gpu/ops/GrOvalOpFactory.cpp
index 654daae..f6a2a1a 100644
--- a/src/gpu/ops/GrOvalOpFactory.cpp
+++ b/src/gpu/ops/GrOvalOpFactory.cpp
@@ -1413,7 +1413,8 @@
         }
 
         GrMesh mesh(GrPrimitiveType::kTriangles);
-        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1);
+        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
+                        GrPrimitiveRestart::kNo);
         mesh.setVertexData(vertexBuffer, firstVertex);
         target->draw(gp.get(),  fHelper.makePipeline(target), mesh);
     }
@@ -1722,7 +1723,8 @@
         }
 
         GrMesh mesh(GrPrimitiveType::kTriangles);
-        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1);
+        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
+                        GrPrimitiveRestart::kNo);
         mesh.setVertexData(vertexBuffer, firstVertex);
         target->draw(gp.get(), fHelper.makePipeline(target), mesh);
     }
@@ -2646,7 +2648,8 @@
         }
 
         GrMesh mesh(GrPrimitiveType::kTriangles);
-        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1);
+        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
+                        GrPrimitiveRestart::kNo);
         mesh.setVertexData(vertexBuffer, firstVertex);
         target->draw(gp.get(), fHelper.makePipeline(target), mesh);
     }
diff --git a/src/gpu/ops/GrShadowRRectOp.cpp b/src/gpu/ops/GrShadowRRectOp.cpp
index 91c57ce..8f5e234 100644
--- a/src/gpu/ops/GrShadowRRectOp.cpp
+++ b/src/gpu/ops/GrShadowRRectOp.cpp
@@ -626,7 +626,8 @@
                 kPipelineFlags, GrProcessorSet::MakeEmptySet(), target->detachAppliedClip());
 
         GrMesh mesh(GrPrimitiveType::kTriangles);
-        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1);
+        mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
+                        GrPrimitiveRestart::kNo);
         mesh.setVertexData(vertexBuffer, firstVertex);
         target->draw(gp.get(), pipeline, mesh);
     }
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
index 5493dd9..dde64f3 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
@@ -520,8 +520,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrVkGpuRTCommandBuffer::bindGeometry(const GrPrimitiveProcessor& primProc,
-                                          const GrBuffer* indexBuffer,
+void GrVkGpuRTCommandBuffer::bindGeometry(const GrBuffer* indexBuffer,
                                           const GrBuffer* vertexBuffer,
                                           const GrBuffer* instanceBuffer) {
     GrVkSecondaryCommandBuffer* currCmdBuf = fCommandBufferInfos[fCurrentCmdInfo].currentCmdBuf();
@@ -534,7 +533,7 @@
     // assigned in GrVkPipeline. That is, vertex first (if any) followed by instance.
     uint32_t binding = 0;
 
-    if (primProc.hasVertexAttribs()) {
+    if (vertexBuffer) {
         SkASSERT(vertexBuffer);
         SkASSERT(!vertexBuffer->isCPUBacked());
         SkASSERT(!vertexBuffer->isMapped());
@@ -543,7 +542,7 @@
                                     static_cast<const GrVkVertexBuffer*>(vertexBuffer));
     }
 
-    if (primProc.hasInstanceAttribs()) {
+    if (instanceBuffer) {
         SkASSERT(instanceBuffer);
         SkASSERT(!instanceBuffer->isCPUBacked());
         SkASSERT(!instanceBuffer->isMapped());
@@ -689,7 +688,7 @@
         }
 
         SkASSERT(pipelineState);
-        mesh.sendToGpu(primProc, this);
+        mesh.sendToGpu(this);
     }
 
     cbInfo.fBounds.join(bounds);
@@ -701,8 +700,7 @@
     pipelineState->freeTempResources(fGpu);
 }
 
-void GrVkGpuRTCommandBuffer::sendInstancedMeshToGpu(const GrPrimitiveProcessor& primProc,
-                                                    GrPrimitiveType,
+void GrVkGpuRTCommandBuffer::sendInstancedMeshToGpu(GrPrimitiveType,
                                                     const GrBuffer* vertexBuffer,
                                                     int vertexCount,
                                                     int baseVertex,
@@ -710,13 +708,12 @@
                                                     int instanceCount,
                                                     int baseInstance) {
     CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
-    this->bindGeometry(primProc, nullptr, vertexBuffer, instanceBuffer);
+    this->bindGeometry(nullptr, vertexBuffer, instanceBuffer);
     cbInfo.currentCmdBuf()->draw(fGpu, vertexCount, instanceCount, baseVertex, baseInstance);
     fGpu->stats()->incNumDraws();
 }
 
-void GrVkGpuRTCommandBuffer::sendIndexedInstancedMeshToGpu(const GrPrimitiveProcessor& primProc,
-                                                           GrPrimitiveType,
+void GrVkGpuRTCommandBuffer::sendIndexedInstancedMeshToGpu(GrPrimitiveType,
                                                            const GrBuffer* indexBuffer,
                                                            int indexCount,
                                                            int baseIndex,
@@ -724,11 +721,12 @@
                                                            int baseVertex,
                                                            const GrBuffer* instanceBuffer,
                                                            int instanceCount,
-                                                           int baseInstance) {
+                                                           int baseInstance,
+                                                           GrPrimitiveRestart restart) {
+    SkASSERT(restart == GrPrimitiveRestart::kNo);
     CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
-    this->bindGeometry(primProc, indexBuffer, vertexBuffer, instanceBuffer);
+    this->bindGeometry(indexBuffer, vertexBuffer, instanceBuffer);
     cbInfo.currentCmdBuf()->drawIndexed(fGpu, indexCount, instanceCount,
                                         baseIndex, baseVertex, baseInstance);
     fGpu->stats()->incNumDraws();
 }
-
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.h b/src/gpu/vk/GrVkGpuCommandBuffer.h
index f2d48c7..93990be 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.h
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.h
@@ -82,8 +82,7 @@
     GrGpu* gpu() override;
 
     // Bind vertex and index buffers
-    void bindGeometry(const GrPrimitiveProcessor&,
-                      const GrBuffer* indexBuffer,
+    void bindGeometry(const GrBuffer* indexBuffer,
                       const GrBuffer* vertexBuffer,
                       const GrBuffer* instanceBuffer);
 
@@ -101,30 +100,30 @@
 
     // GrMesh::SendToGpuImpl methods. These issue the actual Vulkan draw commands.
     // Marked final as a hint to the compiler to not use virtual dispatch.
-    void sendMeshToGpu(const GrPrimitiveProcessor& primProc, GrPrimitiveType primType,
-                       const GrBuffer* vertexBuffer, int vertexCount, int baseVertex) final {
-        this->sendInstancedMeshToGpu(primProc, primType, vertexBuffer, vertexCount, baseVertex,
-                                     nullptr, 1, 0);
+    void sendMeshToGpu(GrPrimitiveType primType, const GrBuffer* vertexBuffer, int vertexCount,
+                       int baseVertex) final {
+        this->sendInstancedMeshToGpu(primType, vertexBuffer, vertexCount, baseVertex, nullptr, 1,
+                                     0);
     }
 
-    void sendIndexedMeshToGpu(const GrPrimitiveProcessor& primProc, GrPrimitiveType primType,
-                              const GrBuffer* indexBuffer, int indexCount, int baseIndex,
-                              uint16_t /*minIndexValue*/, uint16_t /*maxIndexValue*/,
-                              const GrBuffer* vertexBuffer, int baseVertex) final {
-        this->sendIndexedInstancedMeshToGpu(primProc, primType, indexBuffer, indexCount, baseIndex,
-                                            vertexBuffer, baseVertex, nullptr, 1, 0);
+    void sendIndexedMeshToGpu(GrPrimitiveType primType, const GrBuffer* indexBuffer, int indexCount,
+                              int baseIndex, uint16_t /*minIndexValue*/, uint16_t /*maxIndexValue*/,
+                              const GrBuffer* vertexBuffer, int baseVertex,
+                              GrPrimitiveRestart restart) final {
+        SkASSERT(restart == GrPrimitiveRestart::kNo);
+        this->sendIndexedInstancedMeshToGpu(primType, indexBuffer, indexCount, baseIndex,
+                                            vertexBuffer, baseVertex, nullptr, 1, 0,
+                                            GrPrimitiveRestart::kNo);
     }
 
-    void sendInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                                const GrBuffer* vertexBuffer, int vertexCount, int baseVertex,
-                                const GrBuffer* instanceBuffer, int instanceCount,
+    void sendInstancedMeshToGpu(GrPrimitiveType, const GrBuffer* vertexBuffer, int vertexCount,
+                                int baseVertex, const GrBuffer* instanceBuffer, int instanceCount,
                                 int baseInstance) final;
 
-    void sendIndexedInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
-                                       const GrBuffer* indexBuffer, int indexCount, int baseIndex,
-                                       const GrBuffer* vertexBuffer, int baseVertex,
+    void sendIndexedInstancedMeshToGpu(GrPrimitiveType, const GrBuffer* indexBuffer, int indexCount,
+                                       int baseIndex, const GrBuffer* vertexBuffer, int baseVertex,
                                        const GrBuffer* instanceBuffer, int instanceCount,
-                                       int baseInstance) final;
+                                       int baseInstance, GrPrimitiveRestart) final;
 
     void onClear(const GrFixedClip&, GrColor color) override;