GrQuadPerEdgeAA::Tessellator owns GrVertexWriter

Change-Id: I3c8bf48dda061aa9d318b9f81f22608fdd68fcbd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/255786
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index 94142a6..e213283 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -216,17 +216,15 @@
             return;
         }
 
-        // vertices pointer advances through vdata based on Tessellate's return value
-        void* vertices = vdata;
-        GrQuadPerEdgeAA::Tessellator tessellator(vertexSpec);
+        GrQuadPerEdgeAA::Tessellator tessellator(vertexSpec, (char*) vdata);
         auto iter = fQuads.iterator();
         while(iter.next()) {
             // All entries should have local coords, or no entries should have local coords,
             // matching !helper.isTrivial() (which is more conservative than helper.usesLocalCoords)
             SkASSERT(iter.isLocalValid() != fHelper.isTrivial());
             auto info = iter.metadata();
-            vertices = tessellator.append(vertices, iter.deviceQuad(), iter.localQuad(),
-                                          info.fColor, kEmptyDomain, info.fAAFlags);
+            tessellator.append(iter.deviceQuad(), iter.localQuad(),
+                               info.fColor, kEmptyDomain, info.fAAFlags);
         }
 
         sk_sp<const GrBuffer> indexBuffer;
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index ac2961b..70a8607 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -8,7 +8,6 @@
 #include "src/gpu/ops/GrQuadPerEdgeAA.h"
 
 #include "include/private/SkVx.h"
-#include "src/gpu/GrVertexWriter.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/geometry/GrQuadUtils.h"
 #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
@@ -285,12 +284,16 @@
     return write_quad_generic;
 }
 
-Tessellator::Tessellator(const VertexSpec& spec)
+Tessellator::Tessellator(const VertexSpec& spec, char* vertices)
         : fVertexSpec(spec)
+        , fVertexWriter{vertices}
         , fWriteProc(Tessellator::GetWriteQuadProc(spec)) {}
 
-void* Tessellator::append(void* vertices, const GrQuad& deviceQuad, const GrQuad& localQuad,
-                          const SkPMColor4f& color, const SkRect& uvDomain, GrQuadAAFlags aaFlags) {
+void Tessellator::append(const GrQuad& deviceQuad, const GrQuad& localQuad,
+                         const SkPMColor4f& color, const SkRect& uvDomain, GrQuadAAFlags aaFlags) {
+    // We allow Tessellator to be created with a null vertices pointer for convenience, but it is
+    // assumed it will never actually be used in those cases.
+    SkASSERT(fVertexWriter.fPtr);
     SkASSERT(deviceQuad.quadType() <= fVertexSpec.deviceQuadType());
     SkASSERT(!fVertexSpec.hasLocalCoords() || localQuad.quadType() <= fVertexSpec.localQuadType());
 
@@ -298,7 +301,6 @@
     static const float kZeroCoverage[4] = {0.f, 0.f, 0.f, 0.f};
     static const SkRect kIgnoredDomain = SkRect::MakeEmpty();
 
-    GrVertexWriter vb{vertices};
     if (fVertexSpec.usesCoverageAA()) {
         SkASSERT(fVertexSpec.coverageMode() == CoverageMode::kWithColor ||
                  fVertexSpec.coverageMode() == CoverageMode::kWithPosition);
@@ -313,11 +315,11 @@
         if (aaFlags == GrQuadAAFlags::kNone) {
             // Have to write the coverage AA vertex structure, but there's no math to be done for a
             // non-aa quad batched into a coverage AA op.
-            fWriteProc(&vb, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color,
+            fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color,
                        geomDomain, uvDomain);
             // Since we pass the same corners in, the outer vertex structure will have 0 area and
             // the coverage interpolation from 1 to 0 will not be visible.
-            fWriteProc(&vb, fVertexSpec, deviceQuad, localQuad, kZeroCoverage, color,
+            fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kZeroCoverage, color,
                        geomDomain, uvDomain);
         } else {
             // Reset the tessellation helper to match the current geometry
@@ -340,23 +342,21 @@
             // Write inner vertices first
             float coverage[4];
             fAAHelper.inset(edgeDistances, &aaDeviceQuad, &aaLocalQuad).store(coverage);
-            fWriteProc(&vb, fVertexSpec, aaDeviceQuad, aaLocalQuad, coverage, color,
+            fWriteProc(&fVertexWriter, fVertexSpec, aaDeviceQuad, aaLocalQuad, coverage, color,
                        geomDomain, uvDomain);
 
             // Then outer vertices, which use 0.f for their coverage
             fAAHelper.outset(edgeDistances, &aaDeviceQuad, &aaLocalQuad);
-            fWriteProc(&vb, fVertexSpec, aaDeviceQuad, aaLocalQuad, kZeroCoverage, color,
+            fWriteProc(&fVertexWriter, fVertexSpec, aaDeviceQuad, aaLocalQuad, kZeroCoverage, color,
                        geomDomain, uvDomain);
         }
     } else {
         // No outsetting needed, just write a single quad with full coverage
         SkASSERT(fVertexSpec.coverageMode() == CoverageMode::kNone &&
                  !fVertexSpec.requiresGeometryDomain());
-        fWriteProc(&vb, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color,
+        fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color,
                    kIgnoredDomain, uvDomain);
     }
-
-    return vb.fPtr;
 }
 
 sk_sp<const GrBuffer> GetIndexBuffer(GrMeshDrawOp::Target* target,
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.h b/src/gpu/ops/GrQuadPerEdgeAA.h
index 1ba92ca..2b99c68 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.h
+++ b/src/gpu/ops/GrQuadPerEdgeAA.h
@@ -14,6 +14,7 @@
 #include "src/gpu/GrColor.h"
 #include "src/gpu/GrGeometryProcessor.h"
 #include "src/gpu/GrSamplerState.h"
+#include "src/gpu/GrVertexWriter.h"
 #include "src/gpu/geometry/GrQuad.h"
 #include "src/gpu/geometry/GrQuadUtils.h"
 #include "src/gpu/ops/GrMeshDrawOp.h"
@@ -134,14 +135,16 @@
     // MakeProcessor and/or MakeTexturedProcessor.
     class Tessellator {
     public:
-        explicit Tessellator(const VertexSpec& spec);
+        explicit Tessellator(const VertexSpec& spec, char* vertices);
 
-        // Calculates (as needed) inset and outset geometry for anti-aliasing, and writes all
-        // necessary position and vertex attributes required by this Tessellator's VertexSpec.
-        // After appending, this will return the pointer to the next vertex in the VBO.
-        void* append(void* vertices, const GrQuad& deviceQuad, const GrQuad& localQuad,
+        // Calculates (as needed) inset and outset geometry for anti-aliasing, and appends all
+        // necessary position and vertex attributes required by this Tessellator's VertexSpec into
+        // the 'vertices' the Tessellator was called with.
+        void append(const GrQuad& deviceQuad, const GrQuad& localQuad,
                     const SkPMColor4f& color, const SkRect& uvDomain, GrQuadAAFlags aaFlags);
 
+        SkDEBUGCODE(char* vertices() const { return (char*) fVertexWriter.fPtr; })
+
     private:
         // VertexSpec defines many unique ways to write vertex attributes, which can be handled
         // generically by branching per-quad based on the VertexSpec. However, there are several
@@ -155,6 +158,7 @@
 
         GrQuadUtils::TessellationHelper fAAHelper;
         VertexSpec                      fVertexSpec;
+        GrVertexWriter                  fVertexWriter;
         WriteQuadProc                   fWriteProc;
     };
 
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 2dd9d5f..0b687dd 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -584,36 +584,30 @@
                            sk_sp<const GrBuffer> indexBuffer) {
         int totQuadsSeen = 0;
         SkDEBUGCODE(int totVerticesSeen = 0;)
-        char* dst = pVertexData;
-        const size_t vertexSize = desc->fVertexSpec.vertexSize();
+        SkDEBUGCODE(const size_t vertexSize = desc->fVertexSpec.vertexSize());
 
-        GrQuadPerEdgeAA::Tessellator tessellator(desc->fVertexSpec);
+        GrQuadPerEdgeAA::Tessellator tessellator(desc->fVertexSpec, pVertexData);
         int meshIndex = 0;
         for (const auto& op : ChainRange<TextureOp>(texOp)) {
             auto iter = op.fQuads.iterator();
             for (unsigned p = 0; p < op.fProxyCnt; ++p) {
                 GrTextureProxy* proxy = op.fViewCountPairs[p].fProxyView.asTextureProxy();
 
-                int quadCnt = op.fViewCountPairs[p].fQuadCnt;
-
-                const int meshVertexCnt = quadCnt * desc->fVertexSpec.verticesPerQuad();
-
+                const int quadCnt = op.fViewCountPairs[p].fQuadCnt;
+                SkDEBUGCODE(int meshVertexCnt = quadCnt * desc->fVertexSpec.verticesPerQuad());
                 SkASSERT(meshIndex < desc->fNumProxies);
 
-                if (dst) {
-                    int i = 0;
-                    void* v = dst;
-                    while(i < quadCnt && iter.next()) {
+                if (pVertexData) {
+                    for (int i = 0; i < quadCnt && iter.next(); ++i) {
                         SkASSERT(iter.isLocalValid());
                         const ColorDomainAndAA& info = iter.metadata();
-                        v = tessellator.append(v, iter.deviceQuad(), iter.localQuad(),
-                                               info.fColor, info.fDomainRect, info.aaFlags());
-                        i++;
+                        tessellator.append(iter.deviceQuad(), iter.localQuad(),
+                                           info.fColor, info.fDomainRect, info.aaFlags());
                     }
                     desc->setMeshProxy(meshIndex, proxy);
 
-                    SkASSERT(totVerticesSeen * vertexSize == (size_t)(dst - pVertexData));
-                    dst += vertexSize * meshVertexCnt;
+                    SkASSERT((totVerticesSeen + meshVertexCnt) * vertexSize
+                             == (size_t)(tessellator.vertices() - pVertexData));
                 }
 
                 if (meshes) {
@@ -631,10 +625,11 @@
 
             // If quad counts per proxy were calculated correctly, the entire iterator
             // should have been consumed.
-            SkASSERT(!dst || !iter.next());
+            SkASSERT(!pVertexData || !iter.next());
         }
 
-        SkASSERT(!dst || (desc->totalSizeInBytes() == (size_t)(dst - pVertexData)));
+        SkASSERT(!pVertexData ||
+                 (desc->totalSizeInBytes() == (size_t)(tessellator.vertices() - pVertexData)));
         SkASSERT(meshIndex == desc->fNumProxies);
         SkASSERT(totQuadsSeen == desc->fNumTotalQuads);
         SkASSERT(totVerticesSeen == desc->totalNumVertices());