| Index: src/gpu/vk/GrVkGpu.cpp | 
| diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp | 
| index fce7173effeabaa33a2f49f0ff9e687fa3ffa26f..180ba3be66b85686d0a3c2e59b32b4f1c9af3e5f 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 @@ GrRenderTarget* GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe | 
| //////////////////////////////////////////////////////////////////////////////// | 
|  | 
| 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 @@ void GrVkGpu::bindGeometry(const GrPrimitiveProcessor& primProc, | 
|  | 
| 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::bindGeometry(const GrPrimitiveProcessor& primProc, | 
| } | 
| } | 
|  | 
| -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,27 +1315,51 @@ bool GrVkGpu::onReadPixels(GrSurface* surface, | 
| return true; | 
| } | 
|  | 
| -void GrVkGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertices) { | 
| -    GrRenderTarget* rt = args.fPipeline->getRenderTarget(); | 
| -    GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt); | 
| -    const GrVkRenderPass* renderPass = vkRT->simpleRenderPass(); | 
| -    SkASSERT(renderPass); | 
| - | 
| -    GrVkProgram* program = GrVkProgramBuilder::CreateProgram(this, args, | 
| -                                                             vertices.primitiveType(), | 
| -                                                             *renderPass); | 
| +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; | 
| +        return false; | 
| } | 
|  | 
| -    program->setData(this, *args.fPrimitiveProcessor, *args.fPipeline); | 
| +    (*program)->setData(this, primProc, pipeline); | 
|  | 
| -    fCurrentCmdBuffer->beginRenderPass(this, renderPass, *vkRT); | 
| +    (*program)->bind(this, fCurrentCmdBuffer); | 
| +    return true; | 
| +} | 
|  | 
| -    program->bind(this, fCurrentCmdBuffer); | 
| +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); | 
|  | 
| -    this->bindGeometry(*args.fPrimitiveProcessor, vertices); | 
| +    GrVkProgram* program = nullptr; | 
| +    GrPrimitiveType primitiveType = meshes[0].primitiveType(); | 
| +    if (!this->prepareDrawState(pipeline, primProc, primitiveType, *renderPass, &program)) { | 
| +        return; | 
| +    } | 
|  | 
| // Change layout of our render target so it can be used as the color attachment | 
| VkImageLayout layout = vkRT->currentLayout(); | 
| @@ -1362,13 +1378,13 @@ void GrVkGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertice | 
| 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 @@ void GrVkGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertice | 
| 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); | 
|  |