Update GrTextureOp to use index buffer offsets for draws

This should, hopefully, be faster on GL as we will only need to update the index-range for a draw rather than the offset into an vertex buffer.

Change-Id: I09e54c37262168661443fa8bf8d3b43cd8faa9db
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/251757
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index 5837a4b..3a6a492 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -205,13 +205,14 @@
         sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
         size_t vertexSize = gp->vertexStride();
 
-        sk_sp<const GrBuffer> vbuffer;
+        sk_sp<const GrBuffer> vertexBuffer;
         int vertexOffsetInBuffer = 0;
 
+        const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
+
         // Fill the allocated vertex data
-        void* vdata = target->makeVertexSpace(
-                vertexSize, fQuads.count() * vertexSpec.verticesPerQuad(),
-                &vbuffer, &vertexOffsetInBuffer);
+        void* vdata = target->makeVertexSpace(vertexSize, totalNumVertices,
+                                              &vertexBuffer, &vertexOffsetInBuffer);
         if (!vdata) {
             SkDebugf("Could not allocate vertices\n");
             return;
@@ -229,13 +230,20 @@
                     info.fColor, iter.localQuad(), kEmptyDomain, info.fAAFlags);
         }
 
+        sk_sp<const GrBuffer> indexBuffer;
+        if (vertexSpec.needsIndexBuffer()) {
+            indexBuffer = GrQuadPerEdgeAA::GetIndexBuffer(target, vertexSpec.indexBufferOption());
+            if (!indexBuffer) {
+                SkDebugf("Could not allocate indices\n");
+                return;
+            }
+        }
+
         // Configure the mesh for the vertex data
         GrMesh* mesh = target->allocMeshes(1);
-        if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, fQuads.count())) {
-            SkDebugf("Could not allocate indices\n");
-            return;
-        }
-        mesh->setVertexData(std::move(vbuffer), vertexOffsetInBuffer);
+        GrQuadPerEdgeAA::ConfigureMesh(mesh, vertexSpec, 0, fQuads.count(), totalNumVertices,
+                                       std::move(vertexBuffer), std::move(indexBuffer),
+                                       vertexOffsetInBuffer);
         target->recordDraw(std::move(gp), mesh);
     }
 
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index b9b2d65..8bdeeb8 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -131,50 +131,58 @@
     return vb.fPtr;
 }
 
-bool ConfigureMeshIndices(GrMeshDrawOp::Target* target, GrMesh* mesh, const VertexSpec& spec,
-                          int quadCount) {
+sk_sp<const GrBuffer> GetIndexBuffer(GrMeshDrawOp::Target* target,
+                                     IndexBufferOption indexBufferOption) {
     auto resourceProvider = target->resourceProvider();
 
-    if (spec.usesCoverageAA()) {
-        SkASSERT(spec.indexBufferOption() == IndexBufferOption::kPictureFramed);
+    switch (indexBufferOption) {
+        case IndexBufferOption::kPictureFramed: return resourceProvider->refAAQuadIndexBuffer();
+        case IndexBufferOption::kIndexedRects:  return resourceProvider->refNonAAQuadIndexBuffer();
+        case IndexBufferOption::kTriStrips:     // fall through
+        default:                                return nullptr;
+    }
+}
 
-        // AA quads use 8 vertices, basically nested rectangles
-        sk_sp<const GrGpuBuffer> ibuffer = resourceProvider->refAAQuadIndexBuffer();
-        if (!ibuffer) {
-            return false;
-        }
 
-        mesh->setPrimitiveType(GrPrimitiveType::kTriangles);
-        mesh->setIndexedPatterned(std::move(ibuffer),
-                                  GrResourceProvider::NumIndicesPerAAQuad(),
-                                  GrResourceProvider::NumVertsPerAAQuad(),
-                                  quadCount,
-                                  GrResourceProvider::MaxNumAAQuads());
-    } else {
-        // Non-AA quads use 4 vertices, and regular triangle strip layout
-        if (quadCount > 1) {
-            SkASSERT(spec.indexBufferOption() == IndexBufferOption::kIndexedRects);
+void ConfigureMesh(GrMesh* mesh, const VertexSpec& spec,
+                   int runningQuadCount, int quadsInDraw, int maxVerts,
+                   sk_sp<const GrBuffer> vertexBuffer,
+                   sk_sp<const GrBuffer> indexBuffer, int absVertBufferOffset) {
+    SkASSERT(vertexBuffer);
 
-            sk_sp<const GrGpuBuffer> ibuffer = resourceProvider->refNonAAQuadIndexBuffer();
-            if (!ibuffer) {
-                return false;
-            }
+    if (spec.indexBufferOption() == IndexBufferOption::kTriStrips) {
+        SkASSERT(!indexBuffer);
 
-            mesh->setPrimitiveType(GrPrimitiveType::kTriangles);
-            mesh->setIndexedPatterned(std::move(ibuffer),
-                                      GrResourceProvider::NumIndicesPerNonAAQuad(),
-                                      GrResourceProvider::NumVertsPerNonAAQuad(),
-                                      quadCount,
-                                      GrResourceProvider::MaxNumNonAAQuads());
-        } else {
-            SkASSERT(spec.indexBufferOption() != IndexBufferOption::kPictureFramed);
-
-            mesh->setPrimitiveType(GrPrimitiveType::kTriangleStrip);
-            mesh->setNonIndexedNonInstanced(4);
-        }
+        mesh->setPrimitiveType(GrPrimitiveType::kTriangleStrip);
+        mesh->setNonIndexedNonInstanced(4);
+        int offset = absVertBufferOffset +
+                                    runningQuadCount * GrResourceProvider::NumVertsPerNonAAQuad();
+        mesh->setVertexData(std::move(vertexBuffer), offset);
+        return;
     }
 
-    return true;
+    SkASSERT(spec.indexBufferOption() == IndexBufferOption::kPictureFramed ||
+             spec.indexBufferOption() == IndexBufferOption::kIndexedRects);
+    SkASSERT(indexBuffer);
+
+    int baseIndex, numIndicesToDraw;
+
+    if (spec.indexBufferOption() == IndexBufferOption::kPictureFramed) {
+        SkASSERT(runningQuadCount + quadsInDraw <= GrResourceProvider::MaxNumAAQuads());
+        // AA uses 8 vertices and 30 indices per quad, basically nested rectangles
+        baseIndex = runningQuadCount * GrResourceProvider::NumIndicesPerAAQuad();
+        numIndicesToDraw = quadsInDraw * GrResourceProvider::NumIndicesPerAAQuad();
+    } else {
+        SkASSERT(runningQuadCount + quadsInDraw <= GrResourceProvider::MaxNumNonAAQuads());
+        // Non-AA uses 4 vertices and 6 indices per quad
+        baseIndex = runningQuadCount * GrResourceProvider::NumIndicesPerNonAAQuad();
+        numIndicesToDraw = quadsInDraw * GrResourceProvider::NumIndicesPerNonAAQuad();
+    }
+
+    mesh->setPrimitiveType(GrPrimitiveType::kTriangles);
+    mesh->setIndexed(std::move(indexBuffer), numIndicesToDraw, baseIndex, 0, maxVerts-1,
+                     GrPrimitiveRestart::kNo);
+    mesh->setVertexData(std::move(vertexBuffer), absVertBufferOffset);
 }
 
 ////////////////// VertexSpec Implementation
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.h b/src/gpu/ops/GrQuadPerEdgeAA.h
index 1a37de4..427e19c 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.h
+++ b/src/gpu/ops/GrQuadPerEdgeAA.h
@@ -96,6 +96,9 @@
         CoverageMode coverageMode() const;
         size_t vertexSize() const;
 
+        bool needsIndexBuffer() const { return this->indexBufferOption() !=
+                                               IndexBufferOption::kTriStrips; }
+
     private:
         static_assert(GrQuad::kTypeCount <= 4, "GrQuad::Type doesn't fit in 2 bits");
         static_assert(kColorTypeCount <= 4, "Color doesn't fit in 2 bits");
@@ -134,13 +137,23 @@
                      const SkPMColor4f& color, const GrQuad& localQuad, const SkRect& domain,
                      GrQuadAAFlags aa);
 
-    // The mesh will have its index data configured to meet the expectations of the Tessellate()
-    // function, but it the calling code must handle filling a vertex buffer via Tessellate() and
-    // then assigning it to the returned mesh.
+    // This method will return the correct index buffer for the specified indexBufferOption.
+    // It will, correctly, return nullptr if the indexBufferOption is kTriStrips.
+    sk_sp<const GrBuffer> GetIndexBuffer(GrMeshDrawOp::Target*, IndexBufferOption);
+
+    // This method will configure the vertex and index data of the provided 'mesh' to comply
+    // with the indexing method specified in the vertexSpec. It is up to the calling code
+    // to allocate and fill in the vertex data and acquire the correct indexBuffer if it is needed.
     //
-    // Returns false if the index data could not be allocated.
-    bool ConfigureMeshIndices(GrMeshDrawOp::Target* target, GrMesh* mesh, const VertexSpec& spec,
-                              int quadCount);
+    // @param runningQuadCount  the number of quads already stored in 'vertexBuffer' and
+    //                          'indexBuffer' e.g., different GrMeshes have already been placed in
+    //                          the buffers to allow dynamic state changes.
+    // @param quadCount         the number of quads that will be drawn by the provided 'mesh'.
+    //                          A subsequent ConfigureMesh call would the use
+    //                          'runningQuadCount' + 'quadCount' for its new 'runningQuadCount'.
+    void ConfigureMesh(GrMesh* mesh, const VertexSpec&, int runningQuadCount, int quadCount,
+                       int maxVerts, sk_sp<const GrBuffer> vertexBuffer,
+                       sk_sp<const GrBuffer> indexBuffer, int absVertBufferOffset);
 
 } // namespace GrQuadPerEdgeAA
 
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 7f5c593..d66aea8 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -538,10 +538,10 @@
 
     static bool FillInData(TextureOp* texOp, PrePreparedDesc* desc,
                            char* pVertexData, GrMesh* meshes, int absBufferOffset,
-                           sk_sp<const GrBuffer> vertexBuffer, Target* target) {
-        SkDEBUGCODE(int totQuadsSeen = 0;)
+                           sk_sp<const GrBuffer> vertexBuffer,
+                           sk_sp<const GrBuffer> indexBuffer) {
+        int totQuadsSeen = 0;
         SkDEBUGCODE(int totVerticesSeen = 0;)
-        int localVertexOffsetInBuffer = 0;
         char* dst = pVertexData;
         const size_t vertexSize = desc->fVertexSpec.vertexSize();
 
@@ -552,10 +552,8 @@
                 GrTextureProxy* proxy = op.fViewCountPairs[p].fProxyView.asTextureProxy();
 
                 int quadCnt = op.fViewCountPairs[p].fQuadCnt;
-                SkDEBUGCODE(totQuadsSeen += quadCnt;)
 
-                int meshVertexCnt = quadCnt * desc->fVertexSpec.verticesPerQuad();
-                SkDEBUGCODE(totVerticesSeen += meshVertexCnt);
+                const int meshVertexCnt = quadCnt * desc->fVertexSpec.verticesPerQuad();
 
                 SkASSERT(meshIndex < desc->fNumProxies);
 
@@ -563,23 +561,21 @@
                     Tess(dst, desc->fVertexSpec, proxy, &iter, quadCnt, op.filter());
                     desc->setMeshProxy(meshIndex, proxy);
 
-                    SkASSERT(localVertexOffsetInBuffer * vertexSize == (size_t)(dst - pVertexData));
+                    SkASSERT(totVerticesSeen * vertexSize == (size_t)(dst - pVertexData));
                     dst += vertexSize * meshVertexCnt;
                 }
 
                 if (meshes) {
-                    if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, &(meshes[meshIndex]),
-                                                               desc->fVertexSpec, quadCnt)) {
-                        SkDebugf("Could not allocate indices");
-                        return false;
-                    }
-                    meshes[meshIndex].setVertexData(vertexBuffer,
-                                                    localVertexOffsetInBuffer + absBufferOffset);
+                    GrQuadPerEdgeAA::ConfigureMesh(&(meshes[meshIndex]), desc->fVertexSpec,
+                                                   totQuadsSeen, quadCnt, desc->totalNumVertices(),
+                                                   vertexBuffer, indexBuffer, absBufferOffset);
                 }
 
                 ++meshIndex;
 
-                localVertexOffsetInBuffer += meshVertexCnt;
+                totQuadsSeen += quadCnt;
+                SkDEBUGCODE(totVerticesSeen += meshVertexCnt);
+                SkASSERT(totQuadsSeen * desc->fVertexSpec.verticesPerQuad() == totVerticesSeen);
             }
 
             // If quad counts per proxy were calculated correctly, the entire iterator
@@ -722,6 +718,16 @@
             return;
         }
 
+        sk_sp<const GrBuffer> indexBuffer;
+        if (desc.fVertexSpec.needsIndexBuffer()) {
+            indexBuffer = GrQuadPerEdgeAA::GetIndexBuffer(target,
+                                                          desc.fVertexSpec.indexBufferOption());
+            if (!indexBuffer) {
+                SkDebugf("Could not allocate indices\n");
+                return;
+            }
+        }
+
         // Note: this allocation is always in the flush-time arena (i.e., the flushState)
         GrMesh* meshes = target->allocMeshes(desc.fNumProxies);
 
@@ -731,11 +737,11 @@
             // The above memcpy filled in the vertex data - just call FillInData to fill in the
             // mesh data
             result = FillInData(this, &desc, nullptr, meshes, vertexOffsetInBuffer,
-                                std::move(vbuffer), target);
+                                std::move(vbuffer), std::move(indexBuffer));
         } else {
             // Fills in both vertex data and mesh data
             result = FillInData(this, &desc, (char*) vdata, meshes, vertexOffsetInBuffer,
-                                std::move(vbuffer), target);
+                                std::move(vbuffer), std::move(indexBuffer));
         }
 
         if (!result) {