Update how we send draws to gpu backend to reduce state setting.

The main change here is that we pull primitive type off of the vertices, we set the gpu state on gpu once per pipeline/prim proc draw batch, and we create the ProgramDescriptor only for the Cache/ProgramBuilder.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1806983002

Review URL: https://codereview.chromium.org/1806983002
diff --git a/src/gpu/GrBatchFlushState.h b/src/gpu/GrBatchFlushState.h
index 2008fa6..1f82453 100644
--- a/src/gpu/GrBatchFlushState.h
+++ b/src/gpu/GrBatchFlushState.h
@@ -161,14 +161,14 @@
 public:
     Target(GrBatchFlushState* state, GrVertexBatch* batch) : INHERITED(state, batch) {}
 
-    void initDraw(const GrPrimitiveProcessor* primProc, const GrPipeline* pipeline) {
+    void initDraw(const GrPrimitiveProcessor* primProc) {
         GrVertexBatch::DrawArray* draws = this->vertexBatch()->fDrawArrays.addToTail();
         draws->fPrimitiveProcessor.reset(primProc);
         this->state()->advanceToken();
     }
 
-    void draw(const GrVertices& vertices) {
-        this->vertexBatch()->fDrawArrays.tail()->fDraws.push_back(vertices);
+    void draw(const GrMesh& mesh) {
+        this->vertexBatch()->fDrawArrays.tail()->fDraws.push_back(mesh);
     }
 
     void* makeVertexSpace(size_t vertexSize, int vertexCount,
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 512ce9b..f3f00f1 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -12,6 +12,7 @@
 #include "GrContext.h"
 #include "GrGpuResourcePriv.h"
 #include "GrIndexBuffer.h"
+#include "GrMesh.h"
 #include "GrPathRendering.h"
 #include "GrPipeline.h"
 #include "GrResourceCache.h"
@@ -21,10 +22,9 @@
 #include "GrSurfacePriv.h"
 #include "GrTransferBuffer.h"
 #include "GrVertexBuffer.h"
-#include "GrVertices.h"
 #include "SkTypes.h"
 
-GrVertices& GrVertices::operator =(const GrVertices& di) {
+GrMesh& GrMesh::operator =(const GrMesh& di) {
     fPrimitiveType  = di.fPrimitiveType;
     fStartVertex    = di.fStartVertex;
     fStartIndex     = di.fStartIndex;
@@ -492,17 +492,12 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrGpu::draw(const DrawArgs& args, const GrVertices& vertices) {
+void GrGpu::draw(const GrPipeline& pipeline,
+                 const GrPrimitiveProcessor& primProc,
+                 const GrMesh* meshes,
+                 int meshCount) {
     this->handleDirtyContext();
-    if (GrXferBarrierType barrierType = args.fPipeline->xferBarrierType(*this->caps())) {
-        this->xferBarrier(args.fPipeline->getRenderTarget(), barrierType);
-    }
 
-    GrVertices::Iterator iter;
-    const GrNonInstancedVertices* verts = iter.init(vertices);
-    do {
-        this->onDraw(args, *verts);
-        fStats.incNumDraws();
-    } while ((verts = iter.next()));
+    this->onDraw(pipeline, primProc, meshes, meshCount);
 }
 
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 9725590..161ca5c 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -23,6 +23,7 @@
 class GrContext;
 class GrGLContext;
 class GrIndexBuffer;
+class GrMesh;
 class GrNonInstancedVertices;
 class GrPath;
 class GrPathRange;
@@ -37,7 +38,6 @@
 class GrTexture;
 class GrTransferBuffer;
 class GrVertexBuffer;
-class GrVertices;
 
 class GrGpu : public SkRefCnt {
 public:
@@ -353,10 +353,6 @@
     // is dirty.
     ResetTimestamp getResetTimestamp() const { return fResetTimestamp; }
 
-    virtual void buildProgramDesc(GrProgramDesc*,
-                                  const GrPrimitiveProcessor&,
-                                  const GrPipeline&) const = 0;
-
     // Called to perform a surface to surface copy. Fallbacks to issuing a draw from the src to dst
     // take place at the GrDrawTarget level and this function implement faster copy paths. The rect
     // and point are pre-clipped. The src rect and implied dst rect are guaranteed to be within the
@@ -382,21 +378,13 @@
     // multisample information itself.
     const MultisampleSpecs& getMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&);
 
-    struct DrawArgs {
-        DrawArgs(const GrPrimitiveProcessor* primProc,
-                 const GrPipeline* pipeline,
-                 const GrProgramDesc* desc)
-            : fPrimitiveProcessor(primProc)
-            , fPipeline(pipeline)
-            , fDesc(desc) {
-            SkASSERT(primProc && pipeline && desc);
-        }
-        const GrPrimitiveProcessor* fPrimitiveProcessor;
-        const GrPipeline* fPipeline;
-        const GrProgramDesc* fDesc;
-    };
-
-    void draw(const DrawArgs&, const GrVertices&);
+    // We pass in an array of meshCount GrMesh to the draw. The backend should loop over each
+    // GrMesh object and emit a draw for it. Each draw will use the same GrPipeline and
+    // GrPrimitiveProcessor.
+    void draw(const GrPipeline&,
+              const GrPrimitiveProcessor&,
+              const GrMesh*,
+              int meshCount);
 
     // Called by drawtarget when flushing. 
     // Provides a hook for post-flush actions (e.g. PLS reset and Vulkan command buffer submits).
@@ -571,13 +559,15 @@
     // overridden by backend-specific derived class to perform the clear.
     virtual void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) = 0;
 
-
     // Overridden by backend specific classes to perform a clear of the stencil clip bits.  This is
     // ONLY used by the the clip target
     virtual void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) = 0;
 
     // overridden by backend-specific derived class to perform the draw call.
-    virtual void onDraw(const DrawArgs&, const GrNonInstancedVertices&) = 0;
+    virtual void onDraw(const GrPipeline&,
+                        const GrPrimitiveProcessor&,
+                        const GrMesh*,
+                        int meshCount) = 0;
 
     virtual bool onMakeCopyForTextureParams(GrTexture* texture, const GrTextureParams&,
                                             GrTextureProducer::CopyParams*) const { return false; }
diff --git a/src/gpu/GrVertices.h b/src/gpu/GrMesh.h
similarity index 75%
rename from src/gpu/GrVertices.h
rename to src/gpu/GrMesh.h
index 03ede07..5ff23dc 100644
--- a/src/gpu/GrVertices.h
+++ b/src/gpu/GrMesh.h
@@ -5,13 +5,13 @@
  * found in the LICENSE file.
  */
 
-#ifndef GrVertices_DEFINED
-#define GrVertices_DEFINED
+#ifndef GrMesh_DEFINED
+#define GrMesh_DEFINED
 
 #include "GrIndexBuffer.h"
 #include "GrVertexBuffer.h"
 
-class GrNonInstancedVertices {
+class GrNonInstancedMesh {
 public:
     GrPrimitiveType primitiveType() const { return fPrimitiveType; }
     int startVertex() const { return fStartVertex; }
@@ -31,7 +31,7 @@
     int                     fIndexCount;
     GrPendingIOResource<const GrVertexBuffer, kRead_GrIOType> fVertexBuffer;
     GrPendingIOResource<const GrIndexBuffer, kRead_GrIOType>  fIndexBuffer;
-    friend class GrVertices;
+    friend class GrMesh;
 };
 
 /**
@@ -40,11 +40,11 @@
  * and draw-issuing responsibility to GrPrimitiveProcessor. The rest of the vertex info lives there
  * already (stride, attribute mappings).
  */
-class GrVertices : public GrNonInstancedVertices {
+class GrMesh : public GrNonInstancedMesh {
 public:
-    GrVertices() {}
-    GrVertices(const GrVertices& di) { (*this) = di; }
-    GrVertices& operator =(const GrVertices& di);
+    GrMesh() {}
+    GrMesh(const GrMesh& di) { (*this) = di; }
+    GrMesh& operator =(const GrMesh& di);
 
     void init(GrPrimitiveType primType, const GrVertexBuffer* vertexBuffer, int startVertex,
                 int vertexCount) {
@@ -131,41 +131,41 @@
 
     class Iterator {
     public:
-        const GrNonInstancedVertices* init(const GrVertices& vertices) {
-            fVertices = &vertices;
-            if (vertices.fInstanceCount <= vertices.fMaxInstancesPerDraw) {
+        const GrNonInstancedMesh* init(const GrMesh& mesh) {
+            fMesh = &mesh;
+            if (mesh.fInstanceCount <= mesh.fMaxInstancesPerDraw) {
                 fInstancesRemaining = 0;
                 // Note, this also covers the non-instanced case!
-                return &vertices;
+                return &mesh;
             }
-            SkASSERT(vertices.isInstanced());
-            fInstanceBatch.fIndexBuffer.reset(vertices.fIndexBuffer.get());
-            fInstanceBatch.fVertexBuffer.reset(vertices.fVertexBuffer.get());
-            fInstanceBatch.fIndexCount = vertices.fMaxInstancesPerDraw *
-                                         vertices.fIndicesPerInstance;
-            fInstanceBatch.fVertexCount = vertices.fMaxInstancesPerDraw *
-                                          vertices.fVerticesPerInstance;
-            fInstanceBatch.fPrimitiveType = vertices.fPrimitiveType;
-            fInstanceBatch.fStartIndex = vertices.fStartIndex;
-            fInstanceBatch.fStartVertex = vertices.fStartVertex;
-            fInstancesRemaining = vertices.fInstanceCount - vertices.fMaxInstancesPerDraw;
+            SkASSERT(mesh.isInstanced());
+            fInstanceBatch.fIndexBuffer.reset(mesh.fIndexBuffer.get());
+            fInstanceBatch.fVertexBuffer.reset(mesh.fVertexBuffer.get());
+            fInstanceBatch.fIndexCount = mesh.fMaxInstancesPerDraw *
+                                         mesh.fIndicesPerInstance;
+            fInstanceBatch.fVertexCount = mesh.fMaxInstancesPerDraw *
+                                          mesh.fVerticesPerInstance;
+            fInstanceBatch.fPrimitiveType = mesh.fPrimitiveType;
+            fInstanceBatch.fStartIndex = mesh.fStartIndex;
+            fInstanceBatch.fStartVertex = mesh.fStartVertex;
+            fInstancesRemaining = mesh.fInstanceCount - mesh.fMaxInstancesPerDraw;
             return &fInstanceBatch;
         }
 
-        const GrNonInstancedVertices* next() {
+        const GrNonInstancedMesh* next() {
             if (!fInstancesRemaining) {
                 return nullptr;
             }
             fInstanceBatch.fStartVertex += fInstanceBatch.fVertexCount;
-            int instances = SkTMin(fInstancesRemaining, fVertices->fMaxInstancesPerDraw);
-            fInstanceBatch.fIndexCount = instances * fVertices->fIndicesPerInstance;
-            fInstanceBatch.fVertexCount = instances * fVertices->fVerticesPerInstance;
+            int instances = SkTMin(fInstancesRemaining, fMesh->fMaxInstancesPerDraw);
+            fInstanceBatch.fIndexCount = instances * fMesh->fIndicesPerInstance;
+            fInstanceBatch.fVertexCount = instances * fMesh->fVerticesPerInstance;
             fInstancesRemaining -= instances;
             return &fInstanceBatch;
         }
     private:
-        GrNonInstancedVertices fInstanceBatch;
-        const GrVertices* fVertices;
+        GrNonInstancedMesh fInstanceBatch;
+        const GrMesh* fMesh;
         int fInstancesRemaining;
     };
 
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index d1b8a6b..d0be27d 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -607,7 +607,7 @@
         // Setup geometry processor
         SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroked, localMatrix));
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         int instanceCount = fGeoData.count();
         size_t vertexStride = gp->getVertexStride();
@@ -793,7 +793,7 @@
         // Setup geometry processor
         SkAutoTUnref<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         int instanceCount = fGeoData.count();
         QuadHelper helper;
@@ -1011,7 +1011,7 @@
         SkAutoTUnref<GrGeometryProcessor> gp(new DIEllipseGeometryProcessor(this->viewMatrix(),
                                                                             this->style()));
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         int instanceCount = fGeoData.count();
         size_t vertexStride = gp->getVertexStride();
@@ -1278,7 +1278,7 @@
         // Setup geometry processor
         SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroked, localMatrix));
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         int instanceCount = fGeoData.count();
         size_t vertexStride = gp->getVertexStride();
@@ -1426,7 +1426,7 @@
         // Setup geometry processor
         SkAutoTUnref<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         int instanceCount = fGeoData.count();
         size_t vertexStride = gp->getVertexStride();
diff --git a/src/gpu/GrPathRendering.h b/src/gpu/GrPathRendering.h
index a2e9c02..b2863b5 100644
--- a/src/gpu/GrPathRendering.h
+++ b/src/gpu/GrPathRendering.h
@@ -152,38 +152,35 @@
         this->onStencilPath(args, path);
     }
 
-    struct DrawPathArgs : public GrGpu::DrawArgs {
-        DrawPathArgs(const GrPrimitiveProcessor* primProc,
-                     const GrPipeline* pipeline,
-                     const GrProgramDesc* desc,
-                     const GrStencilSettings* stencil)
-            : DrawArgs(primProc, pipeline, desc)
-            , fStencil(stencil) {
-        }
-
-        const GrStencilSettings* fStencil;
-    };
-
-    void drawPath(const DrawPathArgs& args, const GrPath* path) {
+    void drawPath(const GrPipeline& pipeline,
+                  const GrPrimitiveProcessor& primProc,
+                  const GrStencilSettings& stencil,
+                  const GrPath* path) {
         fGpu->handleDirtyContext();
-        if (GrXferBarrierType barrierType = args.fPipeline->xferBarrierType(*fGpu->caps())) {
-            fGpu->xferBarrier(args.fPipeline->getRenderTarget(), barrierType);
+        if (GrXferBarrierType barrierType = pipeline.xferBarrierType(*fGpu->caps())) {
+            fGpu->xferBarrier(pipeline.getRenderTarget(), barrierType);
         }
-        this->onDrawPath(args, path);
+        this->onDrawPath(pipeline, primProc, stencil, path);
     }
 
-    void drawPaths(const DrawPathArgs& args, const GrPathRange* pathRange, const void* indices,
-                   PathIndexType indexType, const float transformValues[],
-                   PathTransformType transformType, int count) {
+    void drawPaths(const GrPipeline& pipeline,
+                   const GrPrimitiveProcessor& primProc,
+                   const GrStencilSettings& stencil,
+                   const GrPathRange* pathRange,
+                   const void* indices,
+                   PathIndexType indexType,
+                   const float transformValues[],
+                   PathTransformType transformType,
+                   int count) {
         fGpu->handleDirtyContext();
-        if (GrXferBarrierType barrierType = args.fPipeline->xferBarrierType(*fGpu->caps())) {
-            fGpu->xferBarrier(args.fPipeline->getRenderTarget(), barrierType);
+        if (GrXferBarrierType barrierType = pipeline.xferBarrierType(*fGpu->caps())) {
+            fGpu->xferBarrier(pipeline.getRenderTarget(), barrierType);
         }
 #ifdef SK_DEBUG
         pathRange->assertPathsLoaded(indices, indexType, count);
 #endif
-        this->onDrawPaths(args, pathRange, indices, indexType, transformValues, transformType,
-                          count);
+        this->onDrawPaths(pipeline, primProc, stencil, pathRange, indices, indexType,
+                          transformValues, transformType, count);
     }
 
 protected:
@@ -191,9 +188,19 @@
         : fGpu(gpu) {
     }
     virtual void onStencilPath(const StencilPathArgs&, const GrPath*) = 0;
-    virtual void onDrawPath(const DrawPathArgs&, const GrPath*) = 0;
-    virtual void onDrawPaths(const DrawPathArgs&, const GrPathRange*, const void*, PathIndexType,
-                             const float[], PathTransformType, int) = 0;
+    virtual void onDrawPath(const GrPipeline&,
+                            const GrPrimitiveProcessor&,
+                            const GrStencilSettings&,
+                            const GrPath*) = 0;
+    virtual void onDrawPaths(const GrPipeline&,
+                             const GrPrimitiveProcessor&,
+                             const GrStencilSettings&,
+                             const GrPathRange*,
+                             const void* indices,
+                             PathIndexType,
+                             const float transformValues[],
+                             PathTransformType,
+                             int count) = 0;
 
     GrGpu* fGpu;
 private:
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index f25455a..38758c6 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -306,9 +306,6 @@
                               GrPixelConfig srcConfig, DrawPreference*,
                               WritePixelTempDrawInfo*) override { return false; }
 
-    void buildProgramDesc(GrProgramDesc*, const GrPrimitiveProcessor&,
-                          const GrPipeline&) const override {}
-
     void discard(GrRenderTarget*) override {}
 
     bool onCopySurface(GrSurface* dst,
@@ -367,7 +364,10 @@
 
     void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) override {}
 
-    void onDraw(const DrawArgs&, const GrNonInstancedVertices&) override {}
+    void onDraw(const GrPipeline&,
+                const GrPrimitiveProcessor&,
+                const GrMesh*,
+                int meshCount) override {}
 
     bool onReadPixels(GrSurface* surface,
                       int left, int top, int width, int height,
diff --git a/src/gpu/batches/GrAAConvexPathRenderer.cpp b/src/gpu/batches/GrAAConvexPathRenderer.cpp
index 9af3d79..f6be366 100644
--- a/src/gpu/batches/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/batches/GrAAConvexPathRenderer.cpp
@@ -793,7 +793,7 @@
             return;
         }
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         size_t vertexStride = gp->getVertexStride();
 
@@ -835,12 +835,12 @@
 
             extract_verts(tess, verts, vertexStride, args.fColor, idxs, canTweakAlphaForCoverage);
 
-            GrVertices info;
-            info.initIndexed(kTriangles_GrPrimitiveType,
+            GrMesh mesh;
+            mesh.initIndexed(kTriangles_GrPrimitiveType,
                              vertexBuffer, indexBuffer,
                              firstVertex, firstIndex,
                              tess.numPts(), tess.numIndices());
-            target->draw(info);
+            target->draw(mesh);
         }
     }
 
@@ -864,7 +864,7 @@
         SkAutoTUnref<GrGeometryProcessor> quadProcessor(
                 QuadEdgeEffect::Create(this->color(), invert, this->usesLocalCoords()));
 
-        target->initDraw(quadProcessor, this->pipeline());
+        target->initDraw(quadProcessor);
 
         // TODO generate all segments for all paths and use one vertex buffer
         for (int i = 0; i < instanceCount; i++) {
@@ -924,13 +924,13 @@
             SkSTArray<kPreallocDrawCnt, Draw, true> draws;
             create_vertices(segments, fanPt, &draws, verts, idxs);
 
-            GrVertices vertices;
+            GrMesh mesh;
 
             for (int j = 0; j < draws.count(); ++j) {
                 const Draw& draw = draws[j];
-                vertices.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer,
-                                     firstVertex, firstIndex, draw.fVertexCnt, draw.fIndexCnt);
-                target->draw(vertices);
+                mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer,
+                                 firstVertex, firstIndex, draw.fVertexCnt, draw.fIndexCnt);
+                target->draw(mesh);
                 firstVertex += draw.fVertexCnt;
                 firstIndex += draw.fIndexCnt;
             }
diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
index 4948d29..7e96b86 100644
--- a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
@@ -209,7 +209,7 @@
                                                    flags,
                                                    this->usesLocalCoords()));
 
-        target->initDraw(dfProcessor, this->pipeline());
+        target->initDraw(dfProcessor);
 
         FlushInfo flushInfo;
 
@@ -407,7 +407,7 @@
                                          &atlasLocation);
         if (!success) {
             this->flush(target, flushInfo);
-            target->initDraw(dfProcessor, pipeline);
+            target->initDraw(dfProcessor);
 
             SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height,
                                                      dfStorage.get(), &atlasLocation);
@@ -491,12 +491,12 @@
     }
 
     void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const {
-        GrVertices vertices;
+        GrMesh mesh;
         int maxInstancesPerDraw = flushInfo->fIndexBuffer->maxQuads();
-        vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer,
+        mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer,
             flushInfo->fIndexBuffer, flushInfo->fVertexOffset, kVerticesPerQuad,
             kIndicesPerQuad, flushInfo->fInstancesToFlush, maxInstancesPerDraw);
-        target->draw(vertices);
+        target->draw(mesh);
         flushInfo->fVertexOffset += kVerticesPerQuad * flushInfo->fInstancesToFlush;
         flushInfo->fInstancesToFlush = 0;
     }
diff --git a/src/gpu/batches/GrAAHairLinePathRenderer.cpp b/src/gpu/batches/GrAAHairLinePathRenderer.cpp
index 87e1940..7d45ed7 100644
--- a/src/gpu/batches/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/batches/GrAAHairLinePathRenderer.cpp
@@ -860,7 +860,7 @@
     if (lineCount) {
         SkAutoTUnref<const GrIndexBuffer> linesIndexBuffer(
             ref_lines_index_buffer(target->resourceProvider()));
-        target->initDraw(lineGP, this->pipeline());
+        target->initDraw(lineGP);
 
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
@@ -882,11 +882,11 @@
         }
 
         {
-            GrVertices vertices;
-            vertices.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, linesIndexBuffer,
-                                   firstVertex, kLineSegNumVertices, kIdxsPerLineSeg, lineCount,
-                                   kLineSegsNumInIdxBuffer);
-            target->draw(vertices);
+            GrMesh mesh;
+            mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, linesIndexBuffer,
+                               firstVertex, kLineSegNumVertices, kIdxsPerLineSeg, lineCount,
+                               kLineSegsNumInIdxBuffer);
+            target->draw(mesh);
         }
     }
 
@@ -922,27 +922,27 @@
         }
 
         if (quadCount > 0) {
-            target->initDraw(quadGP, this->pipeline());
+            target->initDraw(quadGP);
 
             {
-                GrVertices tempVerts;
-                tempVerts.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer,
-                                        firstVertex, kQuadNumVertices, kIdxsPerQuad, quadCount,
-                                        kQuadsNumInIdxBuffer);
-                target->draw(tempVerts);
+                GrMesh mesh;
+                mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer,
+                                   firstVertex, kQuadNumVertices, kIdxsPerQuad, quadCount,
+                                   kQuadsNumInIdxBuffer);
+                target->draw(mesh);
                 firstVertex += quadCount * kQuadNumVertices;
            }
         }
 
         if (conicCount > 0) {
-            target->initDraw(conicGP, this->pipeline());
+            target->initDraw(conicGP);
 
             {
-                GrVertices tempVerts;
-                tempVerts.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer,
-                                        firstVertex, kQuadNumVertices, kIdxsPerQuad, conicCount,
-                                        kQuadsNumInIdxBuffer);
-                target->draw(tempVerts);
+                GrMesh mesh;
+                mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer,
+                                   firstVertex, kQuadNumVertices, kIdxsPerQuad, conicCount,
+                                   kQuadsNumInIdxBuffer);
+                target->draw(mesh);
             }
         }
     }
diff --git a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
index 13267fd..120ecc7 100644
--- a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
@@ -165,7 +165,7 @@
             return;
         }
         const GrVertexBuffer* vertexBuffer;
-        GrVertices info;
+        GrMesh mesh;
         int firstVertex;
         void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
                                               &firstVertex);
@@ -183,9 +183,9 @@
             return;
         }
         memcpy(idxs, indices, indexCount * sizeof(uint16_t));
-        info.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex,
-                firstIndex, vertexCount, indexCount);
-        target->draw(info);
+        mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex,
+                         firstIndex, vertexCount, indexCount);
+        target->draw(mesh);
     }
 
     void onPrepareDraws(Target* target) const override {
@@ -201,7 +201,7 @@
             return;
         }
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         size_t vertexStride = gp->getVertexStride();
 
diff --git a/src/gpu/batches/GrAAStrokeRectBatch.cpp b/src/gpu/batches/GrAAStrokeRectBatch.cpp
index 8cb1c24..54bc495 100644
--- a/src/gpu/batches/GrAAStrokeRectBatch.cpp
+++ b/src/gpu/batches/GrAAStrokeRectBatch.cpp
@@ -193,7 +193,7 @@
         return;
     }
 
-    target->initDraw(gp, this->pipeline());
+    target->initDraw(gp);
 
     size_t vertexStride = gp->getVertexStride();
 
@@ -210,7 +210,7 @@
         GetIndexBuffer(target->resourceProvider(), this->miterStroke()));
     InstancedHelper helper;
     void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
-                                 indexBuffer, verticesPerInstance,  indicesPerInstance,
+                                 indexBuffer, verticesPerInstance, indicesPerInstance,
                                  instanceCount);
     if (!vertices || !indexBuffer) {
          SkDebugf("Could not allocate vertices\n");
diff --git a/src/gpu/batches/GrAtlasTextBatch.cpp b/src/gpu/batches/GrAtlasTextBatch.cpp
index 1d8d7fe..8b89039 100644
--- a/src/gpu/batches/GrAtlasTextBatch.cpp
+++ b/src/gpu/batches/GrAtlasTextBatch.cpp
@@ -116,7 +116,7 @@
     size_t vertexStride = gp->getVertexStride();
     SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat));
 
-    target->initDraw(gp, this->pipeline());
+    target->initDraw(gp);
 
     int glyphCount = this->numGlyphs();
     const GrVertexBuffer* vertexBuffer;
@@ -180,13 +180,13 @@
 }
 
 void GrAtlasTextBatch::flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const {
-    GrVertices vertices;
+    GrMesh mesh;
     int maxGlyphsPerDraw = flushInfo->fIndexBuffer->maxQuads();
-    vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer,
-                           flushInfo->fIndexBuffer, flushInfo->fVertexOffset,
-                           kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyphsToFlush,
-                           maxGlyphsPerDraw);
-    target->draw(vertices);
+    mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer,
+                       flushInfo->fIndexBuffer, flushInfo->fVertexOffset,
+                       kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyphsToFlush,
+                       maxGlyphsPerDraw);
+    target->draw(mesh);
     flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
     flushInfo->fGlyphsToFlush = 0;
 }
@@ -313,5 +313,5 @@
 
 void GrBlobRegenHelper::flush() {
     fBatch->flush(fTarget, fFlushInfo);
-    fTarget->initDraw(fGP, fBatch->pipeline());
+    fTarget->initDraw(fGP);
 }
diff --git a/src/gpu/batches/GrDefaultPathRenderer.cpp b/src/gpu/batches/GrDefaultPathRenderer.cpp
index a5862c6..acaff17 100644
--- a/src/gpu/batches/GrDefaultPathRenderer.cpp
+++ b/src/gpu/batches/GrDefaultPathRenderer.cpp
@@ -11,9 +11,9 @@
 #include "GrBatchTest.h"
 #include "GrContext.h"
 #include "GrDefaultGeoProcFactory.h"
+#include "GrMesh.h"
 #include "GrPathUtils.h"
 #include "GrPipelineBuilder.h"
-#include "GrVertices.h"
 #include "SkGeometry.h"
 #include "SkString.h"
 #include "SkStrokeRec.h"
@@ -269,7 +269,7 @@
         size_t vertexStride = gp->getVertexStride();
         SkASSERT(vertexStride == sizeof(SkPoint));
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         int instanceCount = fGeoData.count();
 
@@ -362,14 +362,14 @@
             SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices);
         }
 
-        GrVertices vertices;
+        GrMesh mesh;
         if (isIndexed) {
-            vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex,
-                                 vertexOffset, indexOffset);
+            mesh.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex,
+                             vertexOffset, indexOffset);
         } else {
-            vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset);
+            mesh.init(primitiveType, vertexBuffer, firstVertex, vertexOffset);
         }
-        target->draw(vertices);
+        target->draw(mesh);
 
         // put back reserves
         target->putBackIndices((size_t)(maxIndices - indexOffset));
diff --git a/src/gpu/batches/GrDrawAtlasBatch.cpp b/src/gpu/batches/GrDrawAtlasBatch.cpp
index dab5b4f..f3b497a 100644
--- a/src/gpu/batches/GrDrawAtlasBatch.cpp
+++ b/src/gpu/batches/GrDrawAtlasBatch.cpp
@@ -58,7 +58,7 @@
                                                                      this->viewMatrix(),
                                                                      this->coverageIgnored()));
     
-    target->initDraw(gp, this->pipeline());
+    target->initDraw(gp);
     
     int instanceCount = fGeoData.count();
     size_t vertexStride = gp->getVertexStride();
diff --git a/src/gpu/batches/GrDrawPathBatch.cpp b/src/gpu/batches/GrDrawPathBatch.cpp
index b115858..4a68820 100644
--- a/src/gpu/batches/GrDrawPathBatch.cpp
+++ b/src/gpu/batches/GrDrawPathBatch.cpp
@@ -23,10 +23,8 @@
     SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(),
                                                                    this->overrides(),
                                                                    this->viewMatrix()));
-    state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline());
-    GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(),
-                                        &desc, &this->stencilSettings());
-    state->gpu()->pathRendering()->drawPath(args, fPath.get());
+    state->gpu()->pathRendering()->drawPath(*this->pipeline(), *pathProc, this->stencilSettings(),
+                                            fPath.get());
 }
 
 SkString GrDrawPathRangeBatch::dumpInfo() const {
@@ -123,14 +121,13 @@
                                                                    drawMatrix,
                                                                    localMatrix));
 
-    GrProgramDesc  desc;
-    state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline());
-    GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(),
-                                       &desc, &this->stencilSettings());
-
     if (fDraws.count() == 1) {
         const InstanceData& instances = *head.fInstanceData;
-        state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), instances.indices(),
+        state->gpu()->pathRendering()->drawPaths(*this->pipeline(),
+                                                 *pathProc,
+                                                 this->stencilSettings(),
+                                                 fPathRange.get(),
+                                                 instances.indices(),
                                                  GrPathRange::kU16_PathIndexType,
                                                  instances.transformValues(),
                                                  instances.transformType(),
@@ -155,9 +152,15 @@
         }
         SkASSERT(idx == fTotalPathCount);
 
-        state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), indexStorage,
-                                                 GrPathRange::kU16_PathIndexType, transformStorage,
-                                                 this->transformType(), fTotalPathCount);
+        state->gpu()->pathRendering()->drawPaths(*this->pipeline(),
+                                                 *pathProc,
+                                                 this->stencilSettings(),
+                                                 fPathRange.get(),
+                                                 indexStorage,
+                                                 GrPathRange::kU16_PathIndexType,
+                                                 transformStorage,
+                                                 this->transformType(),
+                                                 fTotalPathCount);
     }
 }
 
diff --git a/src/gpu/batches/GrDrawVerticesBatch.cpp b/src/gpu/batches/GrDrawVerticesBatch.cpp
index 156e4b3..c76ba7d 100644
--- a/src/gpu/batches/GrDrawVerticesBatch.cpp
+++ b/src/gpu/batches/GrDrawVerticesBatch.cpp
@@ -97,7 +97,7 @@
     SkAutoTUnref<const GrGeometryProcessor> gp(
         set_vertex_attributes(hasLocalCoords, &colorOffset, &texOffset, fViewMatrix,
                               fCoverageIgnored));
-    target->initDraw(gp, this->pipeline());
+    target->initDraw(gp);
 
     size_t vertexStride = gp->getVertexStride();
 
@@ -156,15 +156,15 @@
         }
     }
 
-    GrVertices vertices;
+    GrMesh mesh;
     if (indices) {
-        vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
-                             firstIndex, fVertexCount, fIndexCount);
+        mesh.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
+                         firstIndex, fVertexCount, fIndexCount);
 
     } else {
-        vertices.init(this->primitiveType(), vertexBuffer, firstVertex, fVertexCount);
+        mesh.init(this->primitiveType(), vertexBuffer, firstVertex, fVertexCount);
     }
-    target->draw(vertices);
+    target->draw(mesh);
 }
 
 bool GrDrawVerticesBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
diff --git a/src/gpu/batches/GrNinePatch.cpp b/src/gpu/batches/GrNinePatch.cpp
index bbd2801..3ca004d 100644
--- a/src/gpu/batches/GrNinePatch.cpp
+++ b/src/gpu/batches/GrNinePatch.cpp
@@ -91,7 +91,7 @@
             return;
         }
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         size_t vertexStride = gp->getVertexStride();
         int instanceCount = fGeoData.count();
diff --git a/src/gpu/batches/GrNonAAStrokeRectBatch.cpp b/src/gpu/batches/GrNonAAStrokeRectBatch.cpp
index 6766de2..a87ab11 100644
--- a/src/gpu/batches/GrNonAAStrokeRectBatch.cpp
+++ b/src/gpu/batches/GrNonAAStrokeRectBatch.cpp
@@ -117,7 +117,7 @@
                                                      this->viewMatrix()));
         }
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         size_t vertexStride = gp->getVertexStride();
 
@@ -144,7 +144,7 @@
         SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
 
         GrPrimitiveType primType;
-        if (args.fStrokeWidth > 0) {;
+        if (args.fStrokeWidth > 0) {
             primType = kTriangleStrip_GrPrimitiveType;
             init_stroke_rect_strip(vertex, args.fRect, args.fStrokeWidth);
         } else {
@@ -157,9 +157,9 @@
             vertex[4].set(args.fRect.fLeft, args.fRect.fTop);
         }
 
-        GrVertices vertices;
-        vertices.init(primType, vertexBuffer, firstVertex, vertexCount);
-        target->draw(vertices);
+        GrMesh mesh;
+        mesh.init(primType, vertexBuffer, firstVertex, vertexCount);
+        target->draw(mesh);
     }
 
     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
diff --git a/src/gpu/batches/GrPLSPathRenderer.cpp b/src/gpu/batches/GrPLSPathRenderer.cpp
index c94eb07..348681f 100644
--- a/src/gpu/batches/GrPLSPathRenderer.cpp
+++ b/src/gpu/batches/GrPLSPathRenderer.cpp
@@ -864,7 +864,7 @@
                 pathPtr = tmpPathPtr;
             }
 
-            GrVertices grVertices;
+            GrMesh mesh;
 
             PLSVertices triVertices;
             PLSVertices quadVertices;
@@ -885,10 +885,10 @@
                 for (int i = 0; i < triVertices.count(); ++i) {
                     triVerts[i] = triVertices[i];
                 }
-                grVertices.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVertex, 
-                                triVertices.count());
-                target->initDraw(triangleProcessor, this->pipeline());
-                target->draw(grVertices);
+                mesh.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVertex,
+                          triVertices.count());
+                target->initDraw(triangleProcessor);
+                target->draw(mesh);
             }
 
             if (quadVertices.count()) {
@@ -904,10 +904,10 @@
                 for (int i = 0; i < quadVertices.count(); ++i) {
                     quadVerts[i] = quadVertices[i];
                 }
-                grVertices.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex, 
-                                quadVertices.count());
-                target->initDraw(quadProcessor, this->pipeline());
-                target->draw(grVertices);
+                mesh.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex,
+                          quadVertices.count());
+                target->initDraw(quadProcessor);
+                target->draw(mesh);
             }
 
             SkAutoTUnref<GrGeometryProcessor> finishProcessor(
@@ -933,10 +933,10 @@
             rectVerts[4] = { bounds.fRight, bounds.fTop };
             rectVerts[5] = { bounds.fRight, bounds.fBottom };
 
-            grVertices.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex, 
-                            kRectVertexCount);
-            target->initDraw(finishProcessor, this->pipeline());
-            target->draw(grVertices);
+            mesh.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex,
+                      kRectVertexCount);
+            target->initDraw(finishProcessor);
+            target->draw(mesh);
         }
     }
 
diff --git a/src/gpu/batches/GrTInstanceBatch.h b/src/gpu/batches/GrTInstanceBatch.h
index 5f9a6c5..22d4f52 100644
--- a/src/gpu/batches/GrTInstanceBatch.h
+++ b/src/gpu/batches/GrTInstanceBatch.h
@@ -96,7 +96,7 @@
             return;
         }
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         size_t vertexStride = gp->getVertexStride();
         int instanceCount = fGeoData.count();
diff --git a/src/gpu/batches/GrTessellatingPathRenderer.cpp b/src/gpu/batches/GrTessellatingPathRenderer.cpp
index 06f31cd..c00e8ec 100644
--- a/src/gpu/batches/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/batches/GrTessellatingPathRenderer.cpp
@@ -10,8 +10,8 @@
 #include "GrBatchFlushState.h"
 #include "GrBatchTest.h"
 #include "GrDefaultGeoProcFactory.h"
+#include "GrMesh.h"
 #include "GrPathUtils.h"
-#include "GrVertices.h"
 #include "GrResourceCache.h"
 #include "GrResourceProvider.h"
 #include "GrTessellator.h"
@@ -228,14 +228,15 @@
 
     void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrVertexBuffer* vb,
                       int firstVertex, int count) const {
-        target->initDraw(gp, this->pipeline());
         SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
 
         GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimitiveType
                                                               : kTriangles_GrPrimitiveType;
-        GrVertices vertices;
-        vertices.init(primitiveType, vb, firstVertex, count);
-        target->draw(vertices);
+        target->initDraw(gp);
+
+        GrMesh mesh;
+        mesh.init(primitiveType, vb, firstVertex, count);
+        target->draw(mesh);
     }
 
     bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; }
diff --git a/src/gpu/batches/GrTestBatch.h b/src/gpu/batches/GrTestBatch.h
index ee92816..3efa357 100644
--- a/src/gpu/batches/GrTestBatch.h
+++ b/src/gpu/batches/GrTestBatch.h
@@ -60,7 +60,7 @@
 
 private:
     void onPrepareDraws(Target* target) const override {
-        target->initDraw(fGeometryProcessor, this->pipeline());
+        target->initDraw(fGeometryProcessor);
         this->generateGeometry(target);
     }
 
diff --git a/src/gpu/batches/GrVertexBatch.cpp b/src/gpu/batches/GrVertexBatch.cpp
index 5897fe9..17bcf8e 100644
--- a/src/gpu/batches/GrVertexBatch.cpp
+++ b/src/gpu/batches/GrVertexBatch.cpp
@@ -36,15 +36,15 @@
     size_t ibSize = indexBuffer->gpuMemorySize();
     int maxInstancesPerDraw = static_cast<int>(ibSize / (sizeof(uint16_t) * indicesPerInstance));
 
-    fVertices.initInstanced(primType, vertexBuffer, indexBuffer,
+    fMesh.initInstanced(primType, vertexBuffer, indexBuffer,
         firstVertex, verticesPerInstance, indicesPerInstance, instancesToDraw,
         maxInstancesPerDraw);
     return vertices;
 }
 
 void GrVertexBatch::InstancedHelper::recordDraw(Target* target) {
-    SkASSERT(fVertices.instanceCount());
-    target->draw(fVertices);
+    SkASSERT(fMesh.instanceCount());
+    target->draw(fMesh);
 }
 
 void* GrVertexBatch::QuadHelper::init(Target* target, size_t vertexStride,
@@ -72,15 +72,10 @@
             fInlineUploads[currUpload++]->upload(state->uploader());
         }
         const GrVertexBatch::DrawArray& drawArray = *da.get();
-        GrProgramDesc desc;
-        const GrPipeline* pipeline = this->pipeline();
-        const GrPrimitiveProcessor* primProc = drawArray.fPrimitiveProcessor.get();
-        state->gpu()->buildProgramDesc(&desc, *primProc, *pipeline);
-        GrGpu::DrawArgs args(primProc, pipeline, &desc);
 
-        int drawCount = drawArray.fDraws.count();
-        for (int i = 0; i < drawCount; i++) {
-            state->gpu()->draw(args,  drawArray.fDraws[i]);
-        }
+        state->gpu()->draw(*this->pipeline(),
+                           *drawArray.fPrimitiveProcessor.get(),
+                           drawArray.fDraws.begin(),
+                           drawArray.fDraws.count());
     }
 }
diff --git a/src/gpu/batches/GrVertexBatch.h b/src/gpu/batches/GrVertexBatch.h
index d0daf59..16ba603 100644
--- a/src/gpu/batches/GrVertexBatch.h
+++ b/src/gpu/batches/GrVertexBatch.h
@@ -9,9 +9,9 @@
 #define GrVertexBatch_DEFINED
 
 #include "GrDrawBatch.h"
+#include "GrMesh.h"
 #include "GrPrimitiveProcessor.h"
 #include "GrPendingProgramElement.h"
-#include "GrVertices.h"
 
 #include "SkTLList.h"
 
@@ -41,7 +41,7 @@
         /** Call after init() to issue draws to the batch target.*/
         void recordDraw(Target* target);
     private:
-        GrVertices  fVertices;
+        GrMesh  fMesh;
     };
 
     static const int kVerticesPerQuad = 4;
@@ -71,7 +71,7 @@
     // primitive processor. All the draws in a DrawArray share a primitive processor and use the
     // the batch's GrPipeline.
     struct DrawArray {
-        SkSTArray<1, GrVertices, true>                      fDraws;
+        SkSTArray<1, GrMesh, true>                          fDraws;
         GrPendingProgramElement<const GrPrimitiveProcessor> fPrimitiveProcessor;
     };
 
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index 13d4a38..51507b1 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -359,7 +359,7 @@
             return;
         }
 
-        target->initDraw(gp, this->pipeline());
+        target->initDraw(gp);
 
         // useAA here means Edge AA or MSAA
         bool useAA = this->aaMode() != kBW_DashAAMode;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index f742efe..76cb1a0 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -10,13 +10,13 @@
 #include "GrGLStencilAttachment.h"
 #include "GrGLTextureRenderTarget.h"
 #include "GrGpuResourcePriv.h"
+#include "GrMesh.h"
 #include "GrPipeline.h"
 #include "GrPLSGeometryProcessor.h"
 #include "GrRenderTargetPriv.h"
 #include "GrSurfacePriv.h"
 #include "GrTexturePriv.h"
 #include "GrTypes.h"
-#include "GrVertices.h"
 #include "builders/GrGLShaderStringBuilder.h"
 #include "glsl/GrGLSL.h"
 #include "glsl/GrGLSLCaps.h"
@@ -2071,15 +2071,14 @@
     this->disableScissor();
 }
 
-bool GrGLGpu::flushGLState(const DrawArgs& args) {
+bool GrGLGpu::flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc) {
     GrXferProcessor::BlendInfo blendInfo;
-    const GrPipeline& pipeline = *args.fPipeline;
-    args.fPipeline->getXferProcessor().getBlendInfo(&blendInfo);
+    pipeline.getXferProcessor().getBlendInfo(&blendInfo);
 
     this->flushColorWrite(blendInfo.fWriteColor);
     this->flushDrawFace(pipeline.getDrawFace());
 
-    SkAutoTUnref<GrGLProgram> program(fProgramCache->refProgram(args));
+    SkAutoTUnref<GrGLProgram> program(fProgramCache->refProgram(this, pipeline, primProc));
     if (!program) {
         GrCapsDebugf(this->caps(), "Failed to create program!\n");
         return false;
@@ -2094,12 +2093,12 @@
     if (blendInfo.fWriteColor) {
         // Swizzle the blend to match what the shader will output.
         const GrSwizzle& swizzle = this->glCaps().glslCaps()->configOutputSwizzle(
-            args.fPipeline->getRenderTarget()->config());
+            pipeline.getRenderTarget()->config());
         this->flushBlend(blendInfo, swizzle);
     }
 
     SkSTArray<8, const GrTextureAccess*> textureAccesses;
-    program->setData(*args.fPrimitiveProcessor, pipeline, &textureAccesses);
+    program->setData(primProc, pipeline, &textureAccesses);
 
     int numTextureAccesses = textureAccesses.count();
     for (int i = 0; i < numTextureAccesses; i++) {
@@ -2120,20 +2119,20 @@
 }
 
 void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc,
-                            const GrNonInstancedVertices& vertices,
+                            const GrNonInstancedMesh& mesh,
                             size_t* indexOffsetInBytes) {
     GrGLVertexBuffer* vbuf;
-    vbuf = (GrGLVertexBuffer*) vertices.vertexBuffer();
+    vbuf = (GrGLVertexBuffer*) mesh.vertexBuffer();
 
     SkASSERT(vbuf);
     SkASSERT(!vbuf->isMapped());
 
     GrGLIndexBuffer* ibuf = nullptr;
-    if (vertices.isIndexed()) {
+    if (mesh.isIndexed()) {
         SkASSERT(indexOffsetInBytes);
 
         *indexOffsetInBytes = 0;
-        ibuf = (GrGLIndexBuffer*)vertices.indexBuffer();
+        ibuf = (GrGLIndexBuffer*)mesh.indexBuffer();
 
         SkASSERT(ibuf);
         SkASSERT(!ibuf->isMapped());
@@ -2147,7 +2146,7 @@
 
         GrGLsizei stride = static_cast<GrGLsizei>(primProc.getVertexStride());
 
-        size_t vertexOffsetInBytes = stride * vertices.startVertex();
+        size_t vertexOffsetInBytes = stride * mesh.startVertex();
 
         vertexOffsetInBytes += vbuf->baseOffset();
 
@@ -2170,14 +2169,6 @@
     }
 }
 
-void GrGLGpu::buildProgramDesc(GrProgramDesc* desc,
-                               const GrPrimitiveProcessor& primProc,
-                               const GrPipeline& pipeline) const {
-    if (!GrGLProgramDescBuilder::Build(desc, primProc, pipeline, *this->glCaps().glslCaps())) {
-        SkDEBUGFAIL("Failed to generate GL program descriptor");
-    }
-}
-
 void GrGLGpu::bindBuffer(GrGLuint id, GrGLenum type) {
     this->handleDirtyContext();
     switch (type) {
@@ -2918,16 +2909,18 @@
     #endif
 #endif
 
-void GrGLGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertices) {
-    if (!this->flushGLState(args)) {
+void GrGLGpu::onDraw(const GrPipeline& pipeline,
+                     const GrPrimitiveProcessor& primProc,
+                     const GrMesh* meshes,
+                     int meshCount) {
+    if (!this->flushGLState(pipeline, primProc)) {
         return;
     }
-
-    GrPixelLocalStorageState plsState = args.fPrimitiveProcessor->getPixelLocalStorageState();
-    if (!fHWPLSEnabled && plsState != 
+    GrPixelLocalStorageState plsState = primProc.getPixelLocalStorageState();
+    if (!fHWPLSEnabled && plsState !=
         GrPixelLocalStorageState::kDisabled_GrPixelLocalStorageState) {
         GL_CALL(Enable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE));
-        this->setupPixelLocalStorage(args);
+        this->setupPixelLocalStorage(pipeline, primProc);
         fHWPLSEnabled = true;
     }
     if (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState) {
@@ -2936,26 +2929,35 @@
         this->flushStencil(stencil);
     }
 
-    size_t indexOffsetInBytes = 0;
-    this->setupGeometry(*args.fPrimitiveProcessor, vertices, &indexOffsetInBytes);
+    for (int i = 0; i < meshCount; ++i) {
+        if (GrXferBarrierType barrierType = pipeline.xferBarrierType(*this->caps())) {
+            this->xferBarrier(pipeline.getRenderTarget(), barrierType);
+        }
 
-    SkASSERT((size_t)vertices.primitiveType() < SK_ARRAY_COUNT(gPrimitiveType2GLMode));
-
-    if (vertices.isIndexed()) {
-        GrGLvoid* indices =
-            reinterpret_cast<GrGLvoid*>(indexOffsetInBytes + sizeof(uint16_t) *
-                                        vertices.startIndex());
-        // info.startVertex() was accounted for by setupGeometry.
-        GL_CALL(DrawElements(gPrimitiveType2GLMode[vertices.primitiveType()],
-                             vertices.indexCount(),
-                             GR_GL_UNSIGNED_SHORT,
-                             indices));
-    } else {
-        // Pass 0 for parameter first. We have to adjust glVertexAttribPointer() to account for
-        // startVertex in the DrawElements case. So we always rely on setupGeometry to have
-        // accounted for startVertex.
-        GL_CALL(DrawArrays(gPrimitiveType2GLMode[vertices.primitiveType()], 0,
-                           vertices.vertexCount()));
+        const GrMesh& mesh = meshes[i];
+        GrMesh::Iterator iter;
+        const GrNonInstancedMesh* nonIdxMesh = iter.init(mesh);
+        do {
+            size_t indexOffsetInBytes = 0;
+            this->setupGeometry(primProc, *nonIdxMesh, &indexOffsetInBytes);
+            if (nonIdxMesh->isIndexed()) {
+                GrGLvoid* indices =
+                    reinterpret_cast<GrGLvoid*>(indexOffsetInBytes + sizeof(uint16_t) *
+                    nonIdxMesh->startIndex());
+                // info.startVertex() was accounted for by setupGeometry.
+                GL_CALL(DrawElements(gPrimitiveType2GLMode[nonIdxMesh->primitiveType()],
+                                     nonIdxMesh->indexCount(),
+                                     GR_GL_UNSIGNED_SHORT,
+                                     indices));
+            } else {
+                // Pass 0 for parameter first. We have to adjust glVertexAttribPointer() to account
+                // for startVertex in the DrawElements case. So we always rely on setupGeometry to
+                // have accounted for startVertex.
+                GL_CALL(DrawArrays(gPrimitiveType2GLMode[nonIdxMesh->primitiveType()], 0,
+                                   nonIdxMesh->vertexCount()));
+            }
+            fStats.incNumDraws();
+        } while ((nonIdxMesh = iter.next()));
     }
 
     if (fHWPLSEnabled && plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState) {
@@ -3009,13 +3011,14 @@
     }
 }
 
-void GrGLGpu::setupPixelLocalStorage(const DrawArgs& args) {
+void GrGLGpu::setupPixelLocalStorage(const GrPipeline& pipeline,
+                                     const GrPrimitiveProcessor& primProc) {
     fPLSHasBeenUsed = true;
     const SkRect& bounds = 
-            static_cast<const GrPLSGeometryProcessor*>(args.fPrimitiveProcessor)->getBounds();
+            static_cast<const GrPLSGeometryProcessor&>(primProc).getBounds();
     // setup pixel local storage -- this means capturing and storing the current framebuffer color
     // and initializing the winding counts to zero
-    GrRenderTarget* rt = args.fPipeline->getRenderTarget();
+    GrRenderTarget* rt = pipeline.getRenderTarget();
     SkScalar width = SkIntToScalar(rt->width());
     SkScalar height = SkIntToScalar(rt->height());
     // dst rect edges in NDC (-1 to 1)
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 39d5659..e365601 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -27,7 +27,7 @@
 #include "SkTypes.h"
 
 class GrPipeline;
-class GrNonInstancedVertices;
+class GrNonInstancedMesh;
 class GrSwizzle;
 
 #ifdef SK_DEVELOPER
@@ -95,10 +95,6 @@
         fHWGeometryState.notifyIndexBufferDelete(id);
     }
 
-    void buildProgramDesc(GrProgramDesc*,
-                          const GrPrimitiveProcessor&,
-                          const GrPipeline&) const override;
-
     // id and type (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, etc.) of buffer to bind
     void bindBuffer(GrGLuint id, GrGLenum type);
 
@@ -216,7 +212,10 @@
 
     void onResolveRenderTarget(GrRenderTarget* target) override;
 
-    void onDraw(const DrawArgs&, const GrNonInstancedVertices&) override;
+    void onDraw(const GrPipeline&,
+                const GrPrimitiveProcessor&,
+                const GrMesh*,
+                int meshCount) override;
 
     bool onCopySurface(GrSurface* dst,
                        GrSurface* src,
@@ -232,13 +231,13 @@
     void setTextureUnit(int unitIdx);
 
     // Flushes state from GrPipeline to GL. Returns false if the state couldn't be set.
-    bool flushGLState(const DrawArgs&);
+    bool flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc);
 
     // Sets up vertex attribute pointers and strides. On return indexOffsetInBytes gives the offset
     // an into the index buffer. It does not account for vertices.startIndex() but rather the start
     // index is relative to the returned offset.
     void setupGeometry(const GrPrimitiveProcessor&,
-                       const GrNonInstancedVertices& vertices,
+                       const GrNonInstancedMesh& mesh,
                        size_t* indexOffsetInBytes);
 
     void flushBlend(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle&);
@@ -261,7 +260,7 @@
     void stampRectUsingProgram(GrGLuint program, const SkRect& bounds, GrGLint posXformUniform, 
                                GrGLuint arrayBuffer);
 
-    void setupPixelLocalStorage(const DrawArgs& args);
+    void setupPixelLocalStorage(const GrPipeline&, const GrPrimitiveProcessor&);
 
     static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
 
@@ -272,7 +271,7 @@
 
         void reset();
         void abandon();
-        GrGLProgram* refProgram(const DrawArgs&);
+        GrGLProgram* refProgram(const GrGLGpu* gpu, const GrPipeline&, const GrPrimitiveProcessor&);
 
     private:
         enum {
diff --git a/src/gpu/gl/GrGLGpuProgramCache.cpp b/src/gpu/gl/GrGLGpuProgramCache.cpp
index df8cf60..f37264a 100644
--- a/src/gpu/gl/GrGLGpuProgramCache.cpp
+++ b/src/gpu/gl/GrGLGpuProgramCache.cpp
@@ -108,28 +108,37 @@
     return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less);
 }
 
-GrGLProgram* GrGLGpu::ProgramCache::refProgram(const DrawArgs& args) {
+GrGLProgram* GrGLGpu::ProgramCache::refProgram(const GrGLGpu* gpu,
+                                               const GrPipeline& pipeline,
+                                               const GrPrimitiveProcessor& primProc) {
 #ifdef PROGRAM_CACHE_STATS
     ++fTotalRequests;
 #endif
 
+    // Get GrGLProgramDesc
+    GrGLProgramDesc desc;
+    if (!GrGLProgramDescBuilder::Build(&desc, primProc, pipeline, *gpu->glCaps().glslCaps())) {
+        GrCapsDebugf(gpu->caps(), "Failed to gl program descriptor!\n");
+        return nullptr;
+    }
+
     Entry* entry = nullptr;
 
-    uint32_t hashIdx = args.fDesc->getChecksum();
+    uint32_t hashIdx = desc.getChecksum();
     hashIdx ^= hashIdx >> 16;
     if (kHashBits <= 8) {
         hashIdx ^= hashIdx >> 8;
     }
     hashIdx &=((1 << kHashBits) - 1);
     Entry* hashedEntry = fHashTable[hashIdx];
-    if (hashedEntry && hashedEntry->fProgram->getDesc() == *args.fDesc) {
+    if (hashedEntry && hashedEntry->fProgram->getDesc() == desc) {
         SkASSERT(hashedEntry->fProgram);
         entry = hashedEntry;
     }
 
     int entryIdx;
     if (nullptr == entry) {
-        entryIdx = this->search(*args.fDesc);
+        entryIdx = this->search(desc);
         if (entryIdx >= 0) {
             entry = fEntries[entryIdx];
 #ifdef PROGRAM_CACHE_STATS
@@ -143,7 +152,7 @@
 #ifdef PROGRAM_CACHE_STATS
         ++fCacheMisses;
 #endif
-        GrGLProgram* program = GrGLProgramBuilder::CreateProgram(args, fGpu);
+        GrGLProgram* program = GrGLProgramBuilder::CreateProgram(pipeline, primProc, desc, fGpu);
         if (nullptr == program) {
             return nullptr;
         }
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 723d73d..47274f9 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -142,13 +142,16 @@
     }
 }
 
-void GrGLPathRendering::onDrawPath(const DrawPathArgs& args, const GrPath* path) {
-    if (!this->gpu()->flushGLState(args)) {
+void GrGLPathRendering::onDrawPath(const GrPipeline& pipeline,
+                                   const GrPrimitiveProcessor& primProc,
+                                   const GrStencilSettings& stencil,
+                                   const GrPath* path) {
+    if (!this->gpu()->flushGLState(pipeline, primProc)) {
         return;
     }
     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
 
-    this->flushPathStencilSettings(*args.fStencil);
+    this->flushPathStencilSettings(stencil);
     SkASSERT(!fHWPathStencilSettings.isTwoSided());
 
     GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
@@ -167,16 +170,18 @@
     }
 }
 
-void GrGLPathRendering::onDrawPaths(const DrawPathArgs& args, const GrPathRange* pathRange,
+void GrGLPathRendering::onDrawPaths(const GrPipeline& pipeline,
+                                    const GrPrimitiveProcessor& primProc,
+                                    const GrStencilSettings& stencil, const GrPathRange* pathRange,
                                     const void* indices, PathIndexType indexType,
                                     const float transformValues[], PathTransformType transformType,
                                     int count) {
     SkDEBUGCODE(verify_floats(transformValues, gXformType2ComponentCount[transformType] * count));
 
-    if (!this->gpu()->flushGLState(args)) {
+    if (!this->gpu()->flushGLState(pipeline, primProc)) {
         return;
     }
-    this->flushPathStencilSettings(*args.fStencil);
+    this->flushPathStencilSettings(stencil);
     SkASSERT(!fHWPathStencilSettings.isTwoSided());
 
 
diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h
index c3e5317..cd4668f 100644
--- a/src/gpu/gl/GrGLPathRendering.h
+++ b/src/gpu/gl/GrGLPathRendering.h
@@ -65,9 +65,19 @@
 
 protected:
     void onStencilPath(const StencilPathArgs&, const GrPath*) override;
-    void onDrawPath(const DrawPathArgs&, const GrPath*) override;
-    void onDrawPaths(const DrawPathArgs&, const GrPathRange*, const void* indices, PathIndexType,
-                     const float transformValues[], PathTransformType, int count) override;
+    void onDrawPath(const GrPipeline&,
+                    const GrPrimitiveProcessor&,
+                    const GrStencilSettings&,
+                    const GrPath*) override;
+    void onDrawPaths(const GrPipeline&,
+                     const GrPrimitiveProcessor&,
+                     const GrStencilSettings&,
+                     const GrPathRange*,
+                     const void* indices,
+                     PathIndexType,
+                     const float transformValues[],
+                     PathTransformType,
+                     int count) override;
 private:
     /**
      * Mark certain functionality as not supported.
diff --git a/src/gpu/gl/GrGLVaryingHandler.cpp b/src/gpu/gl/GrGLVaryingHandler.cpp
index a2d4e9d..b7c8729 100644
--- a/src/gpu/gl/GrGLVaryingHandler.cpp
+++ b/src/gpu/gl/GrGLVaryingHandler.cpp
@@ -19,9 +19,9 @@
     GrGLProgramBuilder* glPB = (GrGLProgramBuilder*) fProgramBuilder;
     // This call is not used for non-NVPR backends.
     SkASSERT(glPB->gpu()->glCaps().shaderCaps()->pathRenderingSupport() &&
-             glPB->fArgs.fPrimitiveProcessor->isPathRendering() &&
-             !glPB->fArgs.fPrimitiveProcessor->willUseGeoShader() &&
-             glPB->fArgs.fPrimitiveProcessor->numAttribs() == 0);
+             glPB->fPrimProc.isPathRendering() &&
+             !glPB->fPrimProc.willUseGeoShader() &&
+             glPB->fPrimProc.numAttribs() == 0);
 #endif
     this->addVarying(name, v, fsPrecision);
     auto varyingInfo = fPathProcVaryingInfos.push_back();
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 1c5cf25..30df7a7 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -16,6 +16,7 @@
 #include "SkTraceEvent.h"
 #include "gl/GrGLGpu.h"
 #include "gl/GrGLProgram.h"
+#include "gl/GrGLProgramDesc.h"
 #include "gl/GrGLSLPrettyPrint.h"
 #include "gl/builders/GrGLShaderStringBuilder.h"
 #include "glsl/GrGLSLCaps.h"
@@ -28,12 +29,15 @@
 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
 
-GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gpu) {
+GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline,
+                                               const GrPrimitiveProcessor& primProc,
+                                               const GrGLProgramDesc& desc,
+                                               GrGLGpu* gpu) {
     GrAutoLocaleSetter als("C");
 
     // create a builder.  This will be handed off to effects so they can use it to add
     // uniforms, varyings, textures, etc
-    GrGLProgramBuilder builder(gpu, args);
+    GrGLProgramBuilder builder(gpu, pipeline, primProc, desc);
 
     // TODO: Once all stages can handle taking a float or vec4 and correctly handling them we can
     // seed correctly here
@@ -50,8 +54,11 @@
 
 /////////////////////////////////////////////////////////////////////////////
 
-GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
-    : INHERITED(args)
+GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
+                                       const GrPipeline& pipeline,
+                                       const GrPrimitiveProcessor& primProc,
+                                       const GrGLProgramDesc& desc)
+    : INHERITED(pipeline, primProc, desc)
     , fGpu(gpu)
     , fVaryingHandler(this)
     , fUniformHandler(this) {
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index a3a0fe7..f2714f3 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -17,6 +17,7 @@
 
 class GrFragmentProcessor;
 class GrGLContextInfo;
+class GrGLProgramDesc;
 class GrGLSLShaderBuilder;
 class GrGLSLCaps;
 
@@ -29,7 +30,10 @@
      * to be used.
      * @return true if generation was successful.
      */
-    static GrGLProgram* CreateProgram(const DrawArgs&, GrGLGpu*);
+    static GrGLProgram* CreateProgram(const GrPipeline&,
+                                      const GrPrimitiveProcessor&,
+                                      const GrGLProgramDesc&,
+                                      GrGLGpu*);
 
     const GrCaps* caps() const override;
     const GrGLSLCaps* glslCaps() const override;
@@ -37,7 +41,8 @@
     GrGLGpu* gpu() const { return fGpu; }
 
 private:
-    GrGLProgramBuilder(GrGLGpu*, const DrawArgs&);
+    GrGLProgramBuilder(GrGLGpu*, const GrPipeline&, const GrPrimitiveProcessor&,
+                       const GrGLProgramDesc&);
 
     bool compileAndAttachShaders(GrGLSLShaderBuilder& shader,
                                  GrGLuint programId,
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 7116d19..83b50ad 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -15,12 +15,16 @@
 
 const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
 
-GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args)
+GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrPipeline& pipeline,
+                                           const GrPrimitiveProcessor& primProc,
+                                           const GrProgramDesc& desc)
     : fVS(this)
     , fGS(this)
     , fFS(this)
     , fStageIndex(-1)
-    , fArgs(args)
+    , fPipeline(pipeline)
+    , fPrimProc(primProc)
+    , fDesc(desc)
     , fGeometryProcessor(nullptr)
     , fXferProcessor(nullptr)
     , fSamplerUniforms(4)
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index 83c004d..67d1eb6 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -27,7 +27,6 @@
 
 class GrGLSLProgramBuilder {
 public:
-    typedef GrGpu::DrawArgs DrawArgs;
     typedef GrGLSLUniformHandler::UniformHandle UniformHandle;
 
     virtual ~GrGLSLProgramBuilder() {}
@@ -35,10 +34,10 @@
     virtual const GrCaps* caps() const = 0;
     virtual const GrGLSLCaps* glslCaps() const = 0;
 
-    const GrPrimitiveProcessor& primitiveProcessor() const { return *fArgs.fPrimitiveProcessor; }
-    const GrPipeline& pipeline() const { return *fArgs.fPipeline; }
-    const GrProgramDesc& desc() const { return *fArgs.fDesc; }
-    const GrProgramDesc::KeyHeader& header() const { return fArgs.fDesc->header(); }
+    const GrPrimitiveProcessor& primitiveProcessor() const { return fPrimProc; }
+    const GrPipeline& pipeline() const { return fPipeline; }
+    const GrProgramDesc& desc() const { return fDesc; }
+    const GrProgramDesc::KeyHeader& header() const { return fDesc.header(); }
 
     void appendUniformDecls(GrShaderFlags visibility, SkString*) const;
 
@@ -82,7 +81,9 @@
 
     int fStageIndex;
 
-    const DrawArgs& fArgs;
+    const GrPipeline&           fPipeline;
+    const GrPrimitiveProcessor& fPrimProc;
+    const GrProgramDesc&        fDesc;
 
     BuiltinUniformHandles fUniformHandles;
 
@@ -91,7 +92,9 @@
     GrGLSLFragProcs fFragmentProcessors;
 
 protected:
-    explicit GrGLSLProgramBuilder(const DrawArgs& args);
+    explicit GrGLSLProgramBuilder(const GrPipeline&,
+                                  const GrPrimitiveProcessor&,
+                                  const GrProgramDesc&);
 
     void addFeature(GrShaderFlags shaders, uint32_t featureBit, const char* extensionName);
 
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index fce7173..180ba3b 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -10,11 +10,11 @@
 #include "GrContextOptions.h"
 #include "GrGeometryProcessor.h"
 #include "GrGpuResourceCacheAccess.h"
+#include "GrMesh.h"
 #include "GrPipeline.h"
 #include "GrRenderTargetPriv.h"
 #include "GrSurfacePriv.h"
 #include "GrTexturePriv.h"
-#include "GrVertices.h"
 
 #include "GrVkCommandBuffer.h"
 #include "GrVkImage.h"
@@ -650,9 +650,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrVkGpu::bindGeometry(const GrPrimitiveProcessor& primProc,
-                           const GrNonInstancedVertices& vertices) {
+                           const GrNonInstancedMesh& mesh) {
     GrVkVertexBuffer* vbuf;
-    vbuf = (GrVkVertexBuffer*)vertices.vertexBuffer();
+    vbuf = (GrVkVertexBuffer*)mesh.vertexBuffer();
     SkASSERT(vbuf);
     SkASSERT(!vbuf->isMapped());
 
@@ -665,8 +665,8 @@
 
     fCurrentCmdBuffer->bindVertexBuffer(this, vbuf);
 
-    if (vertices.isIndexed()) {
-        GrVkIndexBuffer* ibuf = (GrVkIndexBuffer*)vertices.indexBuffer();
+    if (mesh.isIndexed()) {
+        GrVkIndexBuffer* ibuf = (GrVkIndexBuffer*)mesh.indexBuffer();
         SkASSERT(ibuf);
         SkASSERT(!ibuf->isMapped());
 
@@ -681,14 +681,6 @@
     }
 }
 
-void GrVkGpu::buildProgramDesc(GrProgramDesc* desc,
-                               const GrPrimitiveProcessor& primProc,
-                               const GrPipeline& pipeline) const {
-    if (!GrVkProgramDescBuilder::Build(desc, primProc, pipeline, *this->vkCaps().glslCaps())) {
-        SkDEBUGFAIL("Failed to generate GL program descriptor");
-    }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 
 GrStencilAttachment* GrVkGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
@@ -1323,28 +1315,52 @@
     return true;
 }
 
-void GrVkGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertices) {
-    GrRenderTarget* rt = args.fPipeline->getRenderTarget();
+bool GrVkGpu::prepareDrawState(const GrPipeline& pipeline,
+                               const GrPrimitiveProcessor& primProc,
+                               GrPrimitiveType primitiveType,
+                               const GrVkRenderPass& renderPass,
+                               GrVkProgram** program) {
+    // Get GrVkProgramDesc
+    GrVkProgramDesc desc;
+    if (!GrVkProgramDescBuilder::Build(&desc, primProc, pipeline, *this->vkCaps().glslCaps())) {
+        GrCapsDebugf(this->caps(), "Failed to vk program descriptor!\n");
+        return false;
+    }
+
+    *program = GrVkProgramBuilder::CreateProgram(this,
+                                                 pipeline,
+                                                 primProc,
+                                                 primitiveType,
+                                                 desc,
+                                                 renderPass);
+    if (!program) {
+        return false;
+    }
+
+    (*program)->setData(this, primProc, pipeline);
+
+    (*program)->bind(this, fCurrentCmdBuffer);
+    return true;
+}
+
+void GrVkGpu::onDraw(const GrPipeline& pipeline,
+                     const GrPrimitiveProcessor& primProc,
+                     const GrMesh* meshes,
+                     int meshCount) {
+    if (!meshCount) {
+        return;
+    }
+    GrRenderTarget* rt = pipeline.getRenderTarget();
     GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
     const GrVkRenderPass* renderPass = vkRT->simpleRenderPass();
     SkASSERT(renderPass);
 
-    GrVkProgram* program = GrVkProgramBuilder::CreateProgram(this, args,
-                                                             vertices.primitiveType(),
-                                                             *renderPass);
-
-    if (!program) {
+    GrVkProgram* program = nullptr;
+    GrPrimitiveType primitiveType = meshes[0].primitiveType();
+    if (!this->prepareDrawState(pipeline, primProc, primitiveType, *renderPass, &program)) {
         return;
     }
 
-    program->setData(this, *args.fPrimitiveProcessor, *args.fPipeline);
-
-    fCurrentCmdBuffer->beginRenderPass(this, renderPass, *vkRT);
-
-    program->bind(this, fCurrentCmdBuffer);
-
-    this->bindGeometry(*args.fPrimitiveProcessor, vertices);
-
     // Change layout of our render target so it can be used as the color attachment
     VkImageLayout layout = vkRT->currentLayout();
     // Our color attachment is purely a destination and won't be read so don't need to flush or
@@ -1362,13 +1378,13 @@
                          false);
 
     // If we are using a stencil attachment we also need to update its layout
-    if (!args.fPipeline->getStencil().isDisabled()) {
+    if (!pipeline.getStencil().isDisabled()) {
         GrStencilAttachment* stencil = vkRT->renderTargetPriv().getStencilAttachment();
         GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil;
         VkImageLayout origDstLayout = vkStencil->currentLayout();
         VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);
         VkAccessFlags dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
-                                      VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+            VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
         VkPipelineStageFlags srcStageMask =
             GrVkMemory::LayoutToPipelineStageFlags(origDstLayout);
         VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
@@ -1381,15 +1397,53 @@
                                   false);
     }
 
-    if (vertices.isIndexed()) {
-        fCurrentCmdBuffer->drawIndexed(this,
-                                       vertices.indexCount(),
-                                       1,
-                                       vertices.startIndex(),
-                                       vertices.startVertex(),
-                                       0);
-    } else {
-        fCurrentCmdBuffer->draw(this, vertices.vertexCount(), 1, vertices.startVertex(),  0);
+    fCurrentCmdBuffer->beginRenderPass(this, renderPass, *vkRT);
+
+    for (int i = 0; i < meshCount; ++i) {
+        if (GrXferBarrierType barrierType = pipeline.xferBarrierType(*this->caps())) {
+            this->xferBarrier(pipeline.getRenderTarget(), barrierType);
+        }
+
+        const GrMesh& mesh = meshes[i];
+        GrMesh::Iterator iter;
+        const GrNonInstancedMesh* nonIdxMesh = iter.init(mesh);
+        do {
+            if (nonIdxMesh->primitiveType() != primitiveType) {
+                // Technically we don't have to call this here (since there is a safety check in
+                // program:setData but this will allow for quicker freeing of resources if the
+                // program sits in a cache for a while.
+                program->freeTempResources(this);
+                // This free will go away once we setup a program cache, and then the cache will be
+                // responsible for call freeGpuResources.
+                program->freeGPUResources(this);
+                program->unref();
+                SkDEBUGCODE(program = nullptr);
+                primitiveType = nonIdxMesh->primitiveType();
+                if (!this->prepareDrawState(pipeline, primProc, primitiveType, *renderPass,
+                                            &program)) {
+                    return;
+                }
+            }
+            SkASSERT(program);
+            this->bindGeometry(primProc, *nonIdxMesh);
+
+            if (nonIdxMesh->isIndexed()) {
+                fCurrentCmdBuffer->drawIndexed(this,
+                                               nonIdxMesh->indexCount(),
+                                               1,
+                                               nonIdxMesh->startIndex(),
+                                               nonIdxMesh->startVertex(),
+                                               0);
+            } else {
+                fCurrentCmdBuffer->draw(this,
+                                        nonIdxMesh->vertexCount(),
+                                        1,
+                                        nonIdxMesh->startVertex(),
+                                        0);
+            }
+
+            fStats.incNumDraws();
+        } while ((nonIdxMesh = iter.next()));
     }
 
     fCurrentCmdBuffer->endRenderPass(this);
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 723d714..3785b15 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -21,7 +21,7 @@
 #include "vulkan/vulkan.h"
 
 class GrPipeline;
-class GrNonInstancedVertices;
+class GrNonInstancedMesh;
 
 class GrVkBufferImpl;
 class GrVkCommandBuffer;
@@ -64,9 +64,6 @@
                               GrPixelConfig srcConfig, DrawPreference*,
                               WritePixelTempDrawInfo*) override;
 
-    void buildProgramDesc(GrProgramDesc*, const GrPrimitiveProcessor&,
-                          const GrPipeline&) const override;
-
     void discard(GrRenderTarget*) override {
         SkDebugf("discard not yet implemented for Vulkan\n");
     }
@@ -154,7 +151,10 @@
 
     void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) override;
 
-    void onDraw(const DrawArgs&, const GrNonInstancedVertices&) override;
+    void onDraw(const GrPipeline&,
+                const GrPrimitiveProcessor&,
+                const GrMesh*,
+                int meshCount) override;
 
     bool onReadPixels(GrSurface* surface,
                       int left, int top, int width, int height,
@@ -178,8 +178,14 @@
         SkDebugf("onResolveRenderTarget not yet implemented for Vulkan\n");
     }
 
+    bool prepareDrawState(const GrPipeline&,
+                          const GrPrimitiveProcessor&,
+                          GrPrimitiveType,
+                          const GrVkRenderPass&,
+                          GrVkProgram** program);
+
     // Bind vertex and index buffers
-    void bindGeometry(const GrPrimitiveProcessor&, const GrNonInstancedVertices&);
+    void bindGeometry(const GrPrimitiveProcessor&, const GrNonInstancedMesh&);
 
     // Ends and submits the current command buffer to the queue and then creates a new command
     // buffer and begins it. If sync is set to kForce_SyncQueue, the function will wait for all 
diff --git a/src/gpu/vk/GrVkProgramBuilder.cpp b/src/gpu/vk/GrVkProgramBuilder.cpp
index 06de3a0..1b56054 100644
--- a/src/gpu/vk/GrVkProgramBuilder.cpp
+++ b/src/gpu/vk/GrVkProgramBuilder.cpp
@@ -12,12 +12,14 @@
 #include "vk/GrVkProgram.h"
 
 GrVkProgram* GrVkProgramBuilder::CreateProgram(GrVkGpu* gpu,
-                                               const DrawArgs& args,
+                                               const GrPipeline& pipeline,
+                                               const GrPrimitiveProcessor& primProc,
                                                GrPrimitiveType primitiveType,
+                                               const GrVkProgramDesc& desc,
                                                const GrVkRenderPass& renderPass) {
     // create a builder.  This will be handed off to effects so they can use it to add
     // uniforms, varyings, textures, etc
-    GrVkProgramBuilder builder(gpu, args);
+    GrVkProgramBuilder builder(gpu, pipeline, primProc, desc);
 
     GrGLSLExpr4 inputColor;
     GrGLSLExpr4 inputCoverage;
@@ -27,11 +29,14 @@
         return nullptr;
     }
 
-    return builder.finalize(args, primitiveType, renderPass);
+    return builder.finalize(primitiveType, renderPass);
 }
 
-GrVkProgramBuilder::GrVkProgramBuilder(GrVkGpu* gpu, const DrawArgs& args)
-    : INHERITED(args) 
+GrVkProgramBuilder::GrVkProgramBuilder(GrVkGpu* gpu,
+                                       const GrPipeline& pipeline,
+                                       const GrPrimitiveProcessor& primProc,
+                                       const GrVkProgramDesc& desc)
+    : INHERITED(pipeline, primProc, desc) 
     , fGpu(gpu)
     , fVaryingHandler(this) 
     , fUniformHandler(this) {
@@ -135,8 +140,7 @@
     return true;
 }
 
-GrVkProgram* GrVkProgramBuilder::finalize(const DrawArgs& args,
-                                          GrPrimitiveType primitiveType,
+GrVkProgram* GrVkProgramBuilder::finalize(GrPrimitiveType primitiveType,
                                           const GrVkRenderPass& renderPass) {
     VkDescriptorSetLayout dsLayout[2];
     VkPipelineLayout pipelineLayout;
@@ -246,8 +250,8 @@
                                         &shaderStageInfo[1]));
 
     GrVkResourceProvider& resourceProvider = fGpu->resourceProvider();
-    GrVkPipeline* pipeline = resourceProvider.createPipeline(*args.fPipeline,
-                                                             *args.fPrimitiveProcessor,
+    GrVkPipeline* pipeline = resourceProvider.createPipeline(fPipeline,
+                                                             fPrimProc,
                                                              shaderStageInfo,
                                                              2,
                                                              primitiveType,
diff --git a/src/gpu/vk/GrVkProgramBuilder.h b/src/gpu/vk/GrVkProgramBuilder.h
index 83a7adf..65fe546 100644
--- a/src/gpu/vk/GrVkProgramBuilder.h
+++ b/src/gpu/vk/GrVkProgramBuilder.h
@@ -20,6 +20,7 @@
 class GrVkGpu;
 class GrVkRenderPass;
 class GrVkProgram;
+class GrVkProgramDesc;
 
 class GrVkProgramBuilder : public GrGLSLProgramBuilder {
 public:
@@ -31,8 +32,10 @@
     * @return true if generation was successful.
     */
     static GrVkProgram* CreateProgram(GrVkGpu*,
-                                      const DrawArgs&,
+                                      const GrPipeline&,
+                                      const GrPrimitiveProcessor&,
                                       GrPrimitiveType,
+                                      const GrVkProgramDesc&,
                                       const GrVkRenderPass& renderPass);
 
     const GrCaps* caps() const override;
@@ -43,11 +46,12 @@
     void finalizeFragmentOutputColor(GrGLSLShaderVar& outputColor) override;
 
 private:
-    GrVkProgramBuilder(GrVkGpu*, const DrawArgs&);
+    GrVkProgramBuilder(GrVkGpu*,
+                       const GrPipeline&,
+                       const GrPrimitiveProcessor&,
+                       const GrVkProgramDesc&);
 
-    GrVkProgram* finalize(const DrawArgs& args,
-                          GrPrimitiveType primitiveType,
-                          const GrVkRenderPass& renderPass);
+    GrVkProgram* finalize(GrPrimitiveType primitiveType, const GrVkRenderPass& renderPass);
 
     static bool CreateVkShaderModule(const GrVkGpu* gpu,
                                      VkShaderStageFlagBits stage,
@@ -63,8 +67,6 @@
     GrVkVaryingHandler        fVaryingHandler;
     GrVkUniformHandler        fUniformHandler;
 
-    SkTArray<UniformHandle>   fSamplerUniforms;
-
     typedef GrGLSLProgramBuilder INHERITED;
 };