Reland "Move setupGeometry() from GrGLGpu to GrGLOpsRenderPass"

This is a reland of b67081f9cb4444c5430075c0822c78c3f9adeefe

Original change's description:
> Move setupGeometry() from GrGLGpu to GrGLOpsRenderPass
> 
> Change-Id: I8788b96e07216be738c0ce1babb810b05bf46694
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/273696
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Chris Dalton <csmartdalton@google.com>

Change-Id: Ic30c9e1b1d9a3ae29623ff8239b9b1d7b2dad273
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/274057
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index fbc6ff5..92820b7 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1765,6 +1765,7 @@
 
 void GrGLGpu::flushScissorRect(const SkIRect& scissor, int rtWidth, int rtHeight,
                                GrSurfaceOrigin rtOrigin) {
+    SkASSERT(fHWScissorSettings.fEnabled == TriState::kYes_TriState);
     auto nativeScissor = GrNativeRect::MakeRelativeTo(rtOrigin, rtHeight, scissor);
     if (fHWScissorSettings.fRect != nativeScissor) {
         GL_CALL(Scissor(nativeScissor.fX, nativeScissor.fY, nativeScissor.fWidth,
@@ -1813,14 +1814,11 @@
 #endif
 }
 
-bool GrGLGpu::flushGLState(GrRenderTarget* renderTarget, const GrProgramInfo& programInfo) {
+bool GrGLGpu::flushGLState(GrRenderTarget* renderTarget,
+                                         const GrProgramInfo& programInfo) {
     this->handleDirtyContext();
 
-    if (GrPrimitiveType::kPatches == programInfo.primitiveType()) {
-        this->flushPatchVertexCount(programInfo.tessellationPatchVertexCount());
-    }
-
-    sk_sp<GrGLProgram> program(fProgramCache->findOrCreateProgram(renderTarget, programInfo));
+    sk_sp<GrGLProgram> program = fProgramCache->findOrCreateProgram(renderTarget, programInfo);
     if (!program) {
         GrCapsDebugf(this->caps(), "Failed to create program!\n");
         return false;
@@ -1828,6 +1826,10 @@
 
     this->flushProgram(std::move(program));
 
+    if (GrPrimitiveType::kPatches == programInfo.primitiveType()) {
+        this->flushPatchVertexCount(programInfo.tessellationPatchVertexCount());
+    }
+
     // Swizzle the blend to match what the shader will output.
     this->flushBlendAndColorWrite(programInfo.pipeline().getXferProcessor().getBlendInfo(),
                                   programInfo.pipeline().outputSwizzle());
@@ -1885,54 +1887,6 @@
     fHWProgramID = id;
 }
 
-void GrGLGpu::setupGeometry(const GrBuffer* indexBuffer,
-                            const GrBuffer* vertexBuffer,
-                            int baseVertex,
-                            const GrBuffer* instanceBuffer,
-                            int baseInstance,
-                            GrPrimitiveRestart enablePrimitiveRestart) {
-    SkASSERT((enablePrimitiveRestart == GrPrimitiveRestart::kNo) || indexBuffer);
-
-    GrGLAttribArrayState* attribState;
-    if (indexBuffer) {
-        SkASSERT(indexBuffer->isCpuBuffer() ||
-                 !static_cast<const GrGpuBuffer*>(indexBuffer)->isMapped());
-        attribState = fHWVertexArrayState.bindInternalVertexArray(this, indexBuffer);
-    } else {
-        attribState = fHWVertexArrayState.bindInternalVertexArray(this);
-    }
-
-    int numAttribs = fHWProgram->numVertexAttributes() + fHWProgram->numInstanceAttributes();
-    attribState->enableVertexArrays(this, numAttribs, enablePrimitiveRestart);
-
-    if (int vertexStride = fHWProgram->vertexStride()) {
-        SkASSERT(vertexBuffer);
-        SkASSERT(vertexBuffer->isCpuBuffer() ||
-                 !static_cast<const GrGpuBuffer*>(vertexBuffer)->isMapped());
-        size_t bufferOffset = baseVertex * static_cast<size_t>(vertexStride);
-        for (int i = 0; i < fHWProgram->numVertexAttributes(); ++i) {
-            const auto& attrib = fHWProgram->vertexAttribute(i);
-            static constexpr int kDivisor = 0;
-            attribState->set(this, attrib.fLocation, vertexBuffer, attrib.fCPUType, attrib.fGPUType,
-                             vertexStride, bufferOffset + attrib.fOffset, kDivisor);
-        }
-    }
-    if (int instanceStride = fHWProgram->instanceStride()) {
-        SkASSERT(instanceBuffer);
-        SkASSERT(instanceBuffer->isCpuBuffer() ||
-                 !static_cast<const GrGpuBuffer*>(instanceBuffer)->isMapped());
-        size_t bufferOffset = baseInstance * static_cast<size_t>(instanceStride);
-        int attribIdx = fHWProgram->numVertexAttributes();
-        for (int i = 0; i < fHWProgram->numInstanceAttributes(); ++i, ++attribIdx) {
-            const auto& attrib = fHWProgram->instanceAttribute(i);
-            static constexpr int kDivisor = 1;
-            attribState->set(this, attrib.fLocation, instanceBuffer, attrib.fCPUType,
-                             attrib.fGPUType, instanceStride, bufferOffset + attrib.fOffset,
-                             kDivisor);
-        }
-    }
-}
-
 GrGLenum GrGLGpu::bindBuffer(GrGpuBufferType type, const GrBuffer* buffer) {
     this->handleDirtyContext();
 
@@ -2325,6 +2279,8 @@
 }
 
 GrGLenum GrGLGpu::prepareToDraw(GrPrimitiveType primitiveType) {
+    fStats.incNumDraws();
+
     if (this->glCaps().requiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines() &&
         GrIsPrimTypeLines(primitiveType) && !GrIsPrimTypeLines(fLastPrimitiveType)) {
         GL_CALL(Enable(GR_GL_CULL_FACE));
@@ -2352,72 +2308,40 @@
     SK_ABORT("invalid GrPrimitiveType");
 }
 
-void GrGLGpu::draw(GrPrimitiveType primitiveType, const GrBuffer* vertexBuffer, int vertexCount,
-                   int baseVertex) {
+void GrGLGpu::drawArrays(GrPrimitiveType primitiveType, GrGLint baseVertex, GrGLsizei vertexCount) {
+    SkASSERT(!this->glCaps().drawArraysBaseVertexIsBroken() || 0 == baseVertex);
     GrGLenum glPrimType = this->prepareToDraw(primitiveType);
-    if (this->glCaps().drawArraysBaseVertexIsBroken()) {
-        this->setupGeometry(nullptr, vertexBuffer, baseVertex, nullptr, 0, GrPrimitiveRestart::kNo);
-        GL_CALL(DrawArrays(glPrimType, 0, vertexCount));
-    } else {
-        this->setupGeometry(nullptr, vertexBuffer, 0, nullptr, 0, GrPrimitiveRestart::kNo);
-        GL_CALL(DrawArrays(glPrimType, baseVertex, vertexCount));
-    }
-    fStats.incNumDraws();
+    GL_CALL(DrawArrays(glPrimType, baseVertex, vertexCount));
 }
 
-static const GrGLvoid* element_ptr(const GrBuffer* indexBuffer, int baseIndex) {
-    size_t baseOffset = baseIndex * sizeof(uint16_t);
-    if (indexBuffer->isCpuBuffer()) {
-        return static_cast<const GrCpuBuffer*>(indexBuffer)->data() + baseOffset;
-    } else {
-        return reinterpret_cast<const GrGLvoid*>(baseOffset);
-    }
+void GrGLGpu::drawElements(GrPrimitiveType primitiveType, GrGLsizei indexCount, GrGLenum indexType,
+                           const void* indices) {
+    GrGLenum glPrimType = this->prepareToDraw(primitiveType);
+    GL_CALL(DrawElements(glPrimType, indexCount, indexType, indices));
 }
 
-void GrGLGpu::drawIndexed(GrPrimitiveType primitiveType, const GrBuffer* indexBuffer,
-                          int indexCount, int baseIndex, GrPrimitiveRestart primitiveRestart,
-                          uint16_t minIndexValue, uint16_t maxIndexValue,
-                          const GrBuffer* vertexBuffer, int baseVertex) {
+void GrGLGpu::drawRangeElements(GrPrimitiveType primitiveType, GrGLuint minIndexValue,
+                                GrGLuint maxIndexValue, GrGLsizei indexCount, GrGLenum indexType,
+                                const void* indices) {
+    SkASSERT(this->glCaps().drawRangeElementsSupport());
     GrGLenum glPrimType = this->prepareToDraw(primitiveType);
-    const GrGLvoid* elementPtr = element_ptr(indexBuffer, baseIndex);
-    this->setupGeometry(indexBuffer, vertexBuffer, baseVertex, nullptr, 0, primitiveRestart);
-    if (this->glCaps().drawRangeElementsSupport()) {
-        GL_CALL(DrawRangeElements(glPrimType, minIndexValue, maxIndexValue, indexCount,
-                                  GR_GL_UNSIGNED_SHORT, elementPtr));
-    } else {
-        GL_CALL(DrawElements(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT, elementPtr));
-    }
-    fStats.incNumDraws();
+    GL_CALL(DrawRangeElements(glPrimType, minIndexValue, maxIndexValue, indexCount, indexType,
+                              indices));
 }
 
-void GrGLGpu::drawInstanced(GrPrimitiveType primitiveType, const GrBuffer* instanceBuffer,
-                            int instanceCount, int baseInstance, const GrBuffer* vertexBuffer,
-                            int vertexCount, int baseVertex) {
+void GrGLGpu::drawArraysInstanced(GrPrimitiveType primitiveType, GrGLint baseVertex,
+                                  GrGLsizei vertexCount, GrGLsizei instanceCount) {
+    SkASSERT(instanceCount <= this->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount));
     GrGLenum glPrimType = this->prepareToDraw(primitiveType);
-    int maxInstances = this->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
-    for (int i = 0; i < instanceCount; i += maxInstances) {
-        this->setupGeometry(nullptr, vertexBuffer, 0, instanceBuffer, baseInstance + i,
-                            GrPrimitiveRestart::kNo);
-        GL_CALL(DrawArraysInstanced(glPrimType, baseVertex, vertexCount,
-                                    std::min(instanceCount - i, maxInstances)));
-        fStats.incNumDraws();
-    }
+    GL_CALL(DrawArraysInstanced(glPrimType, baseVertex, vertexCount, instanceCount));
 }
 
-void GrGLGpu::drawIndexedInstanced(
-        GrPrimitiveType primitiveType, const GrBuffer* indexBuffer, int indexCount, int baseIndex,
-        GrPrimitiveRestart primitiveRestart, const GrBuffer* instanceBuffer, int instanceCount,
-        int baseInstance, const GrBuffer* vertexBuffer, int baseVertex) {
+void GrGLGpu::drawElementsInstanced(GrPrimitiveType primitiveType, GrGLsizei indexCount,
+                                    GrGLenum indexType, const void* indices,
+                                    GrGLsizei instanceCount) {
+    SkASSERT(instanceCount <= this->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount));
     GrGLenum glPrimType = this->prepareToDraw(primitiveType);
-    const GrGLvoid* elementPtr = element_ptr(indexBuffer, baseIndex);
-    int maxInstances = this->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
-    for (int i = 0; i < instanceCount; i += maxInstances) {
-        this->setupGeometry(indexBuffer, vertexBuffer, baseVertex,
-                            instanceBuffer, baseInstance + i, primitiveRestart);
-        GL_CALL(DrawElementsInstanced(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT, elementPtr,
-                                      std::min(instanceCount - i, maxInstances)));
-        fStats.incNumDraws();
-    }
+    GL_CALL(DrawElementsInstanced(glPrimType, indexCount, indexType, indices, instanceCount));
 }
 
 void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
@@ -3922,6 +3846,7 @@
 
 GrGLAttribArrayState* GrGLGpu::HWVertexArrayState::bindInternalVertexArray(GrGLGpu* gpu,
                                                                            const GrBuffer* ibuf) {
+    SkASSERT(!ibuf || ibuf->isCpuBuffer() || !static_cast<const GrGpuBuffer*>(ibuf)->isMapped());
     GrGLAttribArrayState* attribState;
 
     if (gpu->glCaps().isCoreProfile()) {
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index f6cc07c..fef400e 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -76,23 +76,46 @@
     // Flushes state from GrProgramInfo to GL. Returns false if the state couldn't be set.
     bool flushGLState(GrRenderTarget*, const GrProgramInfo&);
     void flushScissorRect(const SkIRect&, int rtWidth, int rtHeight, GrSurfaceOrigin);
-    void bindTextures(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline,
-                      const GrSurfaceProxy* const primProcTextures[] = nullptr) {
-        fHWProgram->bindTextures(primProc, pipeline, primProcTextures);
+
+    // Returns the last program bound by flushGLState(), or nullptr if a different program has since
+    // been put into use via some other method (e.g., resetContext, copySurfaceAsDraw).
+    // The returned GrGLProgram can be used for binding textures and vertex attributes.
+    GrGLProgram* currentProgram() {
+        this->handleDirtyContext();
+        return fHWProgram.get();
     }
 
-    // These methods issue draws using the current GL state. The client must call flushGLState,
-    // followed by flushScissorRect and/or bindTextures if applicable, before using these method.
-    void draw(GrPrimitiveType, const GrBuffer* vertexBuffer, int vertexCount, int baseVertex);
-    void drawIndexed(GrPrimitiveType, const GrBuffer* indexBuffer, int indexCount, int baseIndex,
-                     GrPrimitiveRestart, uint16_t minIndexValue, uint16_t maxIndexValue,
-                     const GrBuffer* vertexBuffer, int baseVertex);
-    void drawInstanced(GrPrimitiveType, const GrBuffer* instanceBuffer, int instanceCount, int
-                       baseInstance, const GrBuffer* vertexBuffer, int vertexCount, int baseVertex);
-    void drawIndexedInstanced(GrPrimitiveType, const GrBuffer* indexBuffer, int indexCount,
-                              int baseIndex, GrPrimitiveRestart, const GrBuffer* instanceBuffer,
-                              int instanceCount, int baseInstance, const GrBuffer* vertexBuffer,
-                              int baseVertex);
+    // Binds the vertex array that should be used for internal draws, enables 'numAttribs' vertex
+    // arrays, and flushes the desired primitive restart settings. If an index buffer is provided,
+    // it will be bound to the vertex array. Otherwise the index buffer binding will be left
+    // unchanged.
+    //
+    // NOTE: This binds the default VAO (ID=zero) unless we are on a core profile, in which case we
+    // use a dummy array instead.
+    GrGLAttribArrayState* bindInternalVertexArray(const GrBuffer* indexBuffer, int numAttribs,
+                                                  GrPrimitiveRestart primitiveRestart) {
+        auto* attribState = fHWVertexArrayState.bindInternalVertexArray(this, indexBuffer);
+        attribState->enableVertexArrays(this, numAttribs, primitiveRestart);
+        return attribState;
+    }
+    GrGLAttribArrayState* bindInternalVertexArray(const GrBuffer* indexBuffer, GrPrimitiveRestart);
+
+    // These methods invoke their GL namesakes, with added bookkeeping and assertions. The caller is
+    // responsible to ensure the desired GL state is configured before calling:
+    //
+    //   - Call flushGLState()
+    //   - If scissor test got enabled, call flushScissorRect()
+    //   - If the pipeline has textures, call currentProgram()->bindTextures()
+    //   - Setup index and attrib arrays via currentProgram()
+    void drawArrays(GrPrimitiveType, GrGLint baseVertex, GrGLsizei vertexCount);
+    void drawElements(GrPrimitiveType, GrGLsizei indexCount, GrGLenum indexType,
+                      const void* indices);
+    void drawRangeElements(GrPrimitiveType, GrGLuint minIndexValue, GrGLuint maxIndexValue,
+                           GrGLsizei indexCount, GrGLenum indexType, const void* indices);
+    void drawArraysInstanced(GrPrimitiveType, GrGLint baseVertex, GrGLsizei vertexCount,
+                             GrGLsizei instanceCount);
+    void drawElementsInstanced(GrPrimitiveType, GrGLsizei indexCount, GrGLenum indexType,
+                               const void* indices, GrGLsizei instanceCount);
 
     // The GrGLOpsRenderPass does not buffer up draws before submitting them to the gpu.
     // Thus this is the implementation of the clear call for the corresponding passthrough function
@@ -293,14 +316,6 @@
     // Version for programs that aren't GrGLProgram.
     void flushProgram(GrGLuint);
 
-    // Sets up vertex/instance attribute pointers and strides.
-    void setupGeometry(const GrBuffer* indexBuffer,
-                       const GrBuffer* vertexBuffer,
-                       int baseVertex,
-                       const GrBuffer* instanceBuffer,
-                       int baseInstance,
-                       GrPrimitiveRestart);
-
     // Applies any necessary workarounds and returns the GL primitive type to use in draw calls.
     GrGLenum prepareToDraw(GrPrimitiveType primitiveType);
 
@@ -568,7 +583,7 @@
          * state. This binds the default VAO (ID=zero) unless we are on a core profile, in which
          * case we use a dummy array instead.
          *
-         * If an index buffer is privided, it will be bound to the vertex array. Otherwise the
+         * If an index buffer is provided, it will be bound to the vertex array. Otherwise the
          * index buffer binding will be left unchanged.
          *
          * The returned GrGLAttribArrayState should be used to set vertex attribute arrays.
diff --git a/src/gpu/gl/GrGLOpsRenderPass.cpp b/src/gpu/gl/GrGLOpsRenderPass.cpp
index 60af18e..27c8a11 100644
--- a/src/gpu/gl/GrGLOpsRenderPass.cpp
+++ b/src/gpu/gl/GrGLOpsRenderPass.cpp
@@ -38,36 +38,112 @@
 bool GrGLOpsRenderPass::onBindTextures(const GrPrimitiveProcessor& primProc,
                                        const GrPipeline& pipeline,
                                        const GrSurfaceProxy* const primProcTextures[]) {
-    fGpu->bindTextures(primProc, pipeline, primProcTextures);
+    GrGLProgram* program = fGpu->currentProgram();
+    if (!program) {
+        return false;
+    }
+    program->bindTextures(primProc, pipeline, primProcTextures);
     return true;
 }
 
+void GrGLOpsRenderPass::setupGeometry(const GrBuffer* indexBuffer, const GrBuffer* vertexBuffer,
+                                      int baseVertex, const GrBuffer* instanceBuffer,
+                                      int baseInstance, GrPrimitiveRestart primitiveRestart) {
+    SkASSERT((primitiveRestart == GrPrimitiveRestart::kNo) || indexBuffer);
+    GrGLProgram* program = fGpu->currentProgram();
+    if (!program) {
+        return;
+    }
+
+    int numAttribs = program->numVertexAttributes() + program->numInstanceAttributes();
+    auto* attribState = fGpu->bindInternalVertexArray(indexBuffer, numAttribs, primitiveRestart);
+
+    if (int vertexStride = program->vertexStride()) {
+        SkASSERT(vertexBuffer);
+        SkASSERT(vertexBuffer->isCpuBuffer() ||
+                 !static_cast<const GrGpuBuffer*>(vertexBuffer)->isMapped());
+        size_t bufferOffset = baseVertex * static_cast<size_t>(vertexStride);
+        for (int i = 0; i < program->numVertexAttributes(); ++i) {
+            const auto& attrib = program->vertexAttribute(i);
+            static constexpr int kDivisor = 0;
+            attribState->set(fGpu, attrib.fLocation, vertexBuffer, attrib.fCPUType, attrib.fGPUType,
+                             vertexStride, bufferOffset + attrib.fOffset, kDivisor);
+        }
+    }
+    if (int instanceStride = program->instanceStride()) {
+        SkASSERT(instanceBuffer);
+        SkASSERT(instanceBuffer->isCpuBuffer() ||
+                 !static_cast<const GrGpuBuffer*>(instanceBuffer)->isMapped());
+        size_t bufferOffset = baseInstance * static_cast<size_t>(instanceStride);
+        int attribIdx = program->numVertexAttributes();
+        for (int i = 0; i < program->numInstanceAttributes(); ++i, ++attribIdx) {
+            const auto& attrib = program->instanceAttribute(i);
+            static constexpr int kDivisor = 1;
+            attribState->set(fGpu, attrib.fLocation, instanceBuffer, attrib.fCPUType,
+                             attrib.fGPUType, instanceStride, bufferOffset + attrib.fOffset,
+                             kDivisor);
+        }
+    }
+}
+
+static const GrGLvoid* get_gl_index_ptr(const GrBuffer* indexBuffer, int baseIndex) {
+    size_t baseOffset = baseIndex * sizeof(uint16_t);
+    if (indexBuffer->isCpuBuffer()) {
+        return static_cast<const GrCpuBuffer*>(indexBuffer)->data() + baseOffset;
+    } else {
+        return reinterpret_cast<const GrGLvoid*>(baseOffset);
+    }
+}
+
 void GrGLOpsRenderPass::onDraw(const GrBuffer* vertexBuffer, int vertexCount, int baseVertex) {
-    fGpu->draw(fPrimitiveType, vertexBuffer, vertexCount, baseVertex);
+    if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
+        this->setupGeometry(nullptr, vertexBuffer, baseVertex, nullptr, 0, GrPrimitiveRestart::kNo);
+        fGpu->drawArrays(fPrimitiveType, 0, vertexCount);
+        return;
+    }
+
+    this->setupGeometry(nullptr, vertexBuffer, 0, nullptr, 0, GrPrimitiveRestart::kNo);
+    fGpu->drawArrays(fPrimitiveType, baseVertex, vertexCount);
 }
 
 void GrGLOpsRenderPass::onDrawIndexed(const GrBuffer* indexBuffer, int indexCount, int baseIndex,
                                       GrPrimitiveRestart primitiveRestart, uint16_t minIndexValue,
                                       uint16_t maxIndexValue, const GrBuffer* vertexBuffer,
                                       int baseVertex) {
-    fGpu->drawIndexed(fPrimitiveType, indexBuffer, indexCount, baseIndex, primitiveRestart,
-                      minIndexValue, maxIndexValue, vertexBuffer, baseVertex);
+    const GrGLvoid* indexPtr = get_gl_index_ptr(indexBuffer, baseIndex);
+    this->setupGeometry(indexBuffer, vertexBuffer, baseVertex, nullptr, 0, primitiveRestart);
+    if (fGpu->glCaps().drawRangeElementsSupport()) {
+        fGpu->drawRangeElements(fPrimitiveType, minIndexValue, maxIndexValue, indexCount,
+                                GR_GL_UNSIGNED_SHORT, indexPtr);
+    } else {
+        fGpu->drawElements(fPrimitiveType, indexCount, GR_GL_UNSIGNED_SHORT, indexPtr);
+    }
 }
 
 void GrGLOpsRenderPass::onDrawInstanced(const GrBuffer* instanceBuffer, int instanceCount,
                                         int baseInstance, const GrBuffer* vertexBuffer,
                                         int vertexCount, int baseVertex) {
-    fGpu->drawInstanced(fPrimitiveType, instanceBuffer, instanceCount, baseInstance, vertexBuffer,
-                      vertexCount, baseVertex);
+    int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
+    for (int i = 0; i < instanceCount; i += maxInstances) {
+        this->setupGeometry(nullptr, vertexBuffer, 0, instanceBuffer, baseInstance + i,
+                            GrPrimitiveRestart::kNo);
+        fGpu->drawArraysInstanced(fPrimitiveType, baseVertex, vertexCount,
+                                  std::min(instanceCount - i, maxInstances));
+    }
 }
 
 void GrGLOpsRenderPass::onDrawIndexedInstanced(
         const GrBuffer* indexBuffer, int indexCount, int baseIndex,
         GrPrimitiveRestart primitiveRestart, const GrBuffer* instanceBuffer, int instanceCount,
         int baseInstance, const GrBuffer* vertexBuffer, int baseVertex) {
-    fGpu->drawIndexedInstanced(fPrimitiveType, indexBuffer, indexCount, baseIndex, primitiveRestart,
-                               instanceBuffer, instanceCount, baseInstance, vertexBuffer,
-                               baseVertex);
+    const GrGLvoid* indexPtr = get_gl_index_ptr(indexBuffer, baseIndex);
+    int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
+    for (int i = 0; i < instanceCount; i += maxInstances) {
+        this->setupGeometry(indexBuffer, vertexBuffer, baseVertex,
+                            instanceBuffer, baseInstance + i, primitiveRestart);
+        fGpu->drawElementsInstanced(fPrimitiveType, indexCount, GR_GL_UNSIGNED_SHORT, indexPtr,
+                                    std::min(instanceCount - i, maxInstances));
+    }
 }
 
 void GrGLOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) {
diff --git a/src/gpu/gl/GrGLOpsRenderPass.h b/src/gpu/gl/GrGLOpsRenderPass.h
index e79558d..5e4faef 100644
--- a/src/gpu/gl/GrGLOpsRenderPass.h
+++ b/src/gpu/gl/GrGLOpsRenderPass.h
@@ -49,6 +49,10 @@
 private:
     GrGpu* gpu() override { return fGpu; }
 
+    void setupGeometry(const GrBuffer* indexBuffer, const GrBuffer* vertexBuffer, int baseVertex,
+                       const GrBuffer* instanceBuffer, int baseInstance,
+                       GrPrimitiveRestart enablePrimitiveRestart);
+
     bool onBindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) override;
     void onSetScissorRect(const SkIRect& scissor) override;
     bool onBindTextures(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline,
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index abbd9d2..2d910a8 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -122,7 +122,8 @@
         this->gpu()->flushScissorRect(programInfo.fixedScissor(), renderTarget->width(),
                                       renderTarget->height(), programInfo.origin());
     }
-    this->gpu()->bindTextures(programInfo.primProc(), programInfo.pipeline());
+    this->gpu()->currentProgram()->bindTextures(
+            programInfo.primProc(), programInfo.pipeline(), nullptr);
 
     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);