Allow Tessellator to operate on provided GrQuads

To facilitate this, the GrQuadBuffer::Iter's local GrQuads that are
modified on each next() are now allowed to be operated on for the AA
inset/outsetting. Previously this required additional GrQuads on the
stack to hold the results, and additional guards for accessing localQuad()
when the entry didn't have actual coords.

With this change, a 2D op should have its device and src GrQuads' Ws
set to 1 once, and then they are completely ignored for all iteration
and tessellation, without any more redundant initialization. In all
likelihood we won't see the needle move on powerful platforms, but may
help lower end devices.

Change-Id: I457205786766403a760918e779d36ba056d69cde
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/256097
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/samplecode/SampleDegenerateQuads.cpp b/samplecode/SampleDegenerateQuads.cpp
index ef89053..3d48cec 100644
--- a/samplecode/SampleDegenerateQuads.cpp
+++ b/samplecode/SampleDegenerateQuads.cpp
@@ -422,7 +422,7 @@
 
         float vertices[56]; // 2 quads, with x, y, coverage, and geometry domain (7 floats x 8 vert)
         GrQuadPerEdgeAA::Tessellator tessellator(kSpec, (char*) vertices);
-        tessellator.append(quad, GrQuad(SkRect::MakeEmpty()), {1.f, 1.f, 1.f, 1.f},
+        tessellator.append(&quad, nullptr, {1.f, 1.f, 1.f, 1.f},
                            SkRect::MakeEmpty(), flags);
 
         // The first quad in vertices is the inset, then the outset, but they
diff --git a/src/gpu/geometry/GrQuadBuffer.h b/src/gpu/geometry/GrQuadBuffer.h
index a2aed13..c7309d4 100644
--- a/src/gpu/geometry/GrQuadBuffer.h
+++ b/src/gpu/geometry/GrQuadBuffer.h
@@ -71,14 +71,16 @@
 
         const T& metadata() const { this->validate(); return *(fBuffer->metadata(fCurrentEntry)); }
 
-        const GrQuad& deviceQuad() const { this->validate(); return fDeviceQuad; }
+        // The returned pointer is mutable so that the object can be used for scratch calculations
+        // during op preparation. However, any changes are not persisted in the GrQuadBuffer and
+        // subsequent calls to next() will overwrite the state of the GrQuad.
+        GrQuad* deviceQuad() { this->validate(); return &fDeviceQuad; }
 
-        // If isLocalValid() returns false, this returns an empty quad (all 0s) so that localQuad()
-        // can be called without triggering any sanitizers, for convenience when some other state
-        // ensures that the quad will eventually not be used.
-        const GrQuad& localQuad() const {
+        // If isLocalValid() returns false, this returns nullptr. Otherwise, the returned pointer
+        // is mutable in the same manner as deviceQuad().
+        GrQuad* localQuad() {
             this->validate();
-            return fLocalQuad;
+            return this->isLocalValid() ? &fLocalQuad : nullptr;
         }
 
         bool isLocalValid() const {
@@ -341,10 +343,8 @@
     coords = fBuffer->unpackQuad(static_cast<GrQuad::Type>(h->fDeviceType), coords, &fDeviceQuad);
     if (h->fHasLocals) {
         coords = fBuffer->unpackQuad(static_cast<GrQuad::Type>(h->fLocalType), coords, &fLocalQuad);
-    } else {
-        static const GrQuad kEmptyLocal(SkRect::MakeEmpty());
-        fLocalQuad = kEmptyLocal;
-    }
+    } // else localQuad() will return a nullptr so no need to reset fLocalQuad
+
     // At this point, coords points to the start of the next entry
     fNextEntry = static_cast<const char*>(static_cast<const void*>(coords));
     SkASSERT((fNextEntry - fCurrentEntry) == fBuffer->entrySize(h));
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index 0b35528..050a461 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -29,9 +29,10 @@
 using ColorType = GrQuadPerEdgeAA::ColorType;
 
 #ifdef SK_DEBUG
-static SkString dump_quad_info(int index, const GrQuad& deviceQuad,
-                               const GrQuad& localQuad, const SkPMColor4f& color,
+static SkString dump_quad_info(int index, const GrQuad* deviceQuad,
+                               const GrQuad* localQuad, const SkPMColor4f& color,
                                GrQuadAAFlags aaFlags) {
+    GrQuad safeLocal = localQuad ? *localQuad : GrQuad();
     SkString str;
     str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
                 "  device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
@@ -43,14 +44,14 @@
                 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
                 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
                 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
-                deviceQuad.x(0), deviceQuad.y(0), deviceQuad.w(0),
-                deviceQuad.x(1), deviceQuad.y(1), deviceQuad.w(1),
-                deviceQuad.x(2), deviceQuad.y(2), deviceQuad.w(2),
-                deviceQuad.x(3), deviceQuad.y(3), deviceQuad.w(3),
-                localQuad.x(0), localQuad.y(0), localQuad.w(0),
-                localQuad.x(1), localQuad.y(1), localQuad.w(1),
-                localQuad.x(2), localQuad.y(2), localQuad.w(2),
-                localQuad.x(3), localQuad.y(3), localQuad.w(3));
+                deviceQuad->x(0), deviceQuad->y(0), deviceQuad->w(0),
+                deviceQuad->x(1), deviceQuad->y(1), deviceQuad->w(1),
+                deviceQuad->x(2), deviceQuad->y(2), deviceQuad->w(2),
+                deviceQuad->x(3), deviceQuad->y(3), deviceQuad->w(3),
+                safeLocal.x(0), safeLocal.y(0), safeLocal.w(0),
+                safeLocal.x(1), safeLocal.y(1), safeLocal.w(1),
+                safeLocal.x(2), safeLocal.y(2), safeLocal.w(2),
+                safeLocal.x(3), safeLocal.y(3), safeLocal.w(3));
     return str;
 }
 #endif
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index ca0c7c0..2726c24 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -23,16 +23,19 @@
 // Generic WriteQuadProc that can handle any VertexSpec. It writes the 4 vertices in triangle strip
 // order, although the data per-vertex is dependent on the VertexSpec.
 static void write_quad_generic(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
-                               const GrQuad& deviceQuad, const GrQuad& localQuad,
+                               const GrQuad* deviceQuad, const GrQuad* localQuad,
                                const float coverage[4], const SkPMColor4f& color,
                                const SkRect& geomDomain, const SkRect& texDomain) {
     static constexpr auto If = GrVertexWriter::If<float>;
+
+    SkASSERT(!spec.hasLocalCoords() || localQuad);
+
     GrQuadPerEdgeAA::CoverageMode mode = spec.coverageMode();
     for (int i = 0; i < 4; ++i) {
         // save position, this is a float2 or float3 or float4 depending on the combination of
         // perspective and coverage mode.
-        vb->write(deviceQuad.x(i), deviceQuad.y(i),
-                  If(spec.deviceQuadType() == GrQuad::Type::kPerspective, deviceQuad.w(i)),
+        vb->write(deviceQuad->x(i), deviceQuad->y(i),
+                  If(spec.deviceQuadType() == GrQuad::Type::kPerspective, deviceQuad->w(i)),
                   If(mode == GrQuadPerEdgeAA::CoverageMode::kWithPosition, coverage[i]));
 
         // save color
@@ -45,8 +48,8 @@
 
         // save local position
         if (spec.hasLocalCoords()) {
-            vb->write(localQuad.x(i), localQuad.y(i),
-                      If(spec.localQuadType() == GrQuad::Type::kPerspective, localQuad.w(i)));
+            vb->write(localQuad->x(i), localQuad->y(i),
+                      If(spec.localQuadType() == GrQuad::Type::kPerspective, localQuad->w(i)));
         }
 
         // save the geometry domain
@@ -67,7 +70,7 @@
 // 2D (XY), no explicit coverage, vertex color, no locals, no geometry domain, no texture domain
 // This represents simple, solid color or shader, non-AA (or AA with cov. as alpha) rects.
 static void write_2d_color(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
-                           const GrQuad& deviceQuad, const GrQuad& localQuad,
+                           const GrQuad* deviceQuad, const GrQuad* localQuad,
                            const float coverage[4], const SkPMColor4f& color,
                            const SkRect& geomDomain, const SkRect& texDomain) {
     // Assert assumptions about VertexSpec
@@ -78,20 +81,23 @@
     SkASSERT(spec.hasVertexColors());
     SkASSERT(!spec.requiresGeometryDomain());
     SkASSERT(!spec.hasDomain());
+    // We don't assert that localQuad == nullptr, since it is possible for GrFillRectOp to
+    // accumulate local coords conservatively (paint not trivial), and then after analysis realize
+    // the processors don't need local coordinates.
 
     bool wide = spec.colorType() == GrQuadPerEdgeAA::ColorType::kHalf;
     for (int i = 0; i < 4; ++i) {
         // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything
         SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithColor ||
                  coverage[i] == 1.f);
-        vb->write(deviceQuad.x(i), deviceQuad.y(i), GrVertexColor(color * coverage[i], wide));
+        vb->write(deviceQuad->x(i), deviceQuad->y(i), GrVertexColor(color * coverage[i], wide));
     }
 }
 
 // 2D (XY), no explicit coverage, UV locals, no color, no geometry domain, no texture domain
 // This represents opaque, non AA, textured rects
 static void write_2d_uv(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
-                        const GrQuad& deviceQuad, const GrQuad& localQuad,
+                        const GrQuad* deviceQuad, const GrQuad* localQuad,
                         const float coverage[4], const SkPMColor4f& color,
                         const SkRect& geomDomain, const SkRect& texDomain) {
     // Assert assumptions about VertexSpec
@@ -101,16 +107,17 @@
     SkASSERT(!spec.hasVertexColors());
     SkASSERT(!spec.requiresGeometryDomain());
     SkASSERT(!spec.hasDomain());
+    SkASSERT(localQuad);
 
     for (int i = 0; i < 4; ++i) {
-        vb->write(deviceQuad.x(i), deviceQuad.y(i), localQuad.x(i), localQuad.y(i));
+        vb->write(deviceQuad->x(i), deviceQuad->y(i), localQuad->x(i), localQuad->y(i));
     }
 }
 
 // 2D (XY), no explicit coverage, UV locals, vertex color, no geometry or texture domains
 // This represents transparent, non AA (or AA with cov. as alpha), textured rects
 static void write_2d_color_uv(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
-                              const GrQuad& deviceQuad, const GrQuad& localQuad,
+                              const GrQuad* deviceQuad, const GrQuad* localQuad,
                               const float coverage[4], const SkPMColor4f& color,
                               const SkRect& geomDomain, const SkRect& texDomain) {
     // Assert assumptions about VertexSpec
@@ -121,21 +128,22 @@
     SkASSERT(spec.hasVertexColors());
     SkASSERT(!spec.requiresGeometryDomain());
     SkASSERT(!spec.hasDomain());
+    SkASSERT(localQuad);
 
     bool wide = spec.colorType() == GrQuadPerEdgeAA::ColorType::kHalf;
     for (int i = 0; i < 4; ++i) {
         // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything
         SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithColor ||
                  coverage[i] == 1.f);
-        vb->write(deviceQuad.x(i), deviceQuad.y(i), GrVertexColor(color * coverage[i], wide),
-                  localQuad.x(i), localQuad.y(i));
+        vb->write(deviceQuad->x(i), deviceQuad->y(i), GrVertexColor(color * coverage[i], wide),
+                  localQuad->x(i), localQuad->y(i));
     }
 }
 
 // 2D (XY), explicit coverage, UV locals, no color, no geometry domain, no texture domain
 // This represents opaque, AA, textured rects
 static void write_2d_cov_uv(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
-                            const GrQuad& deviceQuad, const GrQuad& localQuad,
+                            const GrQuad* deviceQuad, const GrQuad* localQuad,
                             const float coverage[4], const SkPMColor4f& color,
                             const SkRect& geomDomain, const SkRect& texDomain) {
     // Assert assumptions about VertexSpec
@@ -145,9 +153,11 @@
     SkASSERT(!spec.hasVertexColors());
     SkASSERT(!spec.requiresGeometryDomain());
     SkASSERT(!spec.hasDomain());
+    SkASSERT(localQuad);
 
     for (int i = 0; i < 4; ++i) {
-        vb->write(deviceQuad.x(i), deviceQuad.y(i), coverage[i], localQuad.x(i), localQuad.y(i));
+        vb->write(deviceQuad->x(i), deviceQuad->y(i), coverage[i],
+                  localQuad->x(i), localQuad->y(i));
     }
 }
 
@@ -160,7 +170,7 @@
 // 2D (XY), no explicit coverage, UV locals, no color, tex domain but no geometry domain
 // This represents opaque, non AA, textured rects with strict uv sampling
 static void write_2d_uv_strict(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
-                               const GrQuad& deviceQuad, const GrQuad& localQuad,
+                               const GrQuad* deviceQuad, const GrQuad* localQuad,
                                const float coverage[4], const SkPMColor4f& color,
                                const SkRect& geomDomain, const SkRect& texDomain) {
     // Assert assumptions about VertexSpec
@@ -170,16 +180,17 @@
     SkASSERT(!spec.hasVertexColors());
     SkASSERT(!spec.requiresGeometryDomain());
     SkASSERT(spec.hasDomain());
+    SkASSERT(localQuad);
 
     for (int i = 0; i < 4; ++i) {
-        vb->write(deviceQuad.x(i), deviceQuad.y(i), localQuad.x(i), localQuad.y(i), texDomain);
+        vb->write(deviceQuad->x(i), deviceQuad->y(i), localQuad->x(i), localQuad->y(i), texDomain);
     }
 }
 
 // 2D (XY), no explicit coverage, UV locals, vertex color, tex domain but no geometry domain
 // This represents transparent, non AA (or AA with cov. as alpha), textured rects with strict sample
 static void write_2d_color_uv_strict(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
-                                     const GrQuad& deviceQuad, const GrQuad& localQuad,
+                                     const GrQuad* deviceQuad, const GrQuad* localQuad,
                                      const float coverage[4], const SkPMColor4f& color,
                                      const SkRect& geomDomain, const SkRect& texDomain) {
     // Assert assumptions about VertexSpec
@@ -190,21 +201,22 @@
     SkASSERT(spec.hasVertexColors());
     SkASSERT(!spec.requiresGeometryDomain());
     SkASSERT(spec.hasDomain());
+    SkASSERT(localQuad);
 
     bool wide = spec.colorType() == GrQuadPerEdgeAA::ColorType::kHalf;
     for (int i = 0; i < 4; ++i) {
         // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything
         SkASSERT(spec.coverageMode() == GrQuadPerEdgeAA::CoverageMode::kWithColor ||
                  coverage[i] == 1.f);
-        vb->write(deviceQuad.x(i), deviceQuad.y(i), GrVertexColor(color * coverage[i], wide),
-                  localQuad.x(i), localQuad.y(i), texDomain);
+        vb->write(deviceQuad->x(i), deviceQuad->y(i), GrVertexColor(color * coverage[i], wide),
+                  localQuad->x(i), localQuad->y(i), texDomain);
     }
 }
 
 // 2D (XY), explicit coverage, UV locals, no color, tex domain but no geometry domain
 // This represents opaque, AA, textured rects with strict uv sampling
 static void write_2d_cov_uv_strict(GrVertexWriter* vb, const GrQuadPerEdgeAA::VertexSpec& spec,
-                                   const GrQuad& deviceQuad, const GrQuad& localQuad,
+                                   const GrQuad* deviceQuad, const GrQuad* localQuad,
                                    const float coverage[4], const SkPMColor4f& color,
                                    const SkRect& geomDomain, const SkRect& texDomain) {
     // Assert assumptions about VertexSpec
@@ -214,10 +226,11 @@
     SkASSERT(!spec.hasVertexColors());
     SkASSERT(!spec.requiresGeometryDomain());
     SkASSERT(spec.hasDomain());
+    SkASSERT(localQuad);
 
     for (int i = 0; i < 4; ++i) {
-        vb->write(deviceQuad.x(i), deviceQuad.y(i), coverage[i],
-                  localQuad.x(i), localQuad.y(i), texDomain);
+        vb->write(deviceQuad->x(i), deviceQuad->y(i), coverage[i],
+                  localQuad->x(i), localQuad->y(i), texDomain);
     }
 }
 
@@ -289,13 +302,14 @@
         , fVertexWriter{vertices}
         , fWriteProc(Tessellator::GetWriteQuadProc(spec)) {}
 
-void Tessellator::append(const GrQuad& deviceQuad, const GrQuad& localQuad,
+void Tessellator::append(GrQuad* deviceQuad, 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());
+    SkASSERT(deviceQuad->quadType() <= fVertexSpec.deviceQuadType());
+    SkASSERT(localQuad || !fVertexSpec.hasLocalCoords());
+    SkASSERT(!fVertexSpec.hasLocalCoords() || localQuad->quadType() <= fVertexSpec.localQuadType());
 
     static const float kFullCoverage[4] = {1.f, 1.f, 1.f, 1.f};
     static const float kZeroCoverage[4] = {0.f, 0.f, 0.f, 0.f};
@@ -308,7 +322,7 @@
         // a geometry domain if corners are not right angles
         SkRect geomDomain;
         if (fVertexSpec.requiresGeometryDomain()) {
-            geomDomain = deviceQuad.bounds();
+            geomDomain = deviceQuad->bounds();
             geomDomain.outset(0.5f, 0.5f); // account for AA expansion
         }
 
@@ -323,7 +337,7 @@
                        geomDomain, uvDomain);
         } else {
             // Reset the tessellation helper to match the current geometry
-            fAAHelper.reset(deviceQuad, fVertexSpec.hasLocalCoords() ? &localQuad : nullptr);
+            fAAHelper.reset(*deviceQuad, localQuad);
 
             // Edge inset/outset distance ordered LBTR, set to 0.5 for a half pixel if the AA flag
             // is turned on, or 0.0 if the edge is not anti-aliased.
@@ -337,17 +351,15 @@
                                   (aaFlags & GrQuadAAFlags::kRight)  ? 0.5f : 0.f };
             }
 
-            GrQuad aaDeviceQuad, aaLocalQuad;
-
             // Write inner vertices first
             float coverage[4];
-            fAAHelper.inset(edgeDistances, &aaDeviceQuad, &aaLocalQuad).store(coverage);
-            fWriteProc(&fVertexWriter, fVertexSpec, aaDeviceQuad, aaLocalQuad, coverage, color,
+            fAAHelper.inset(edgeDistances, deviceQuad, localQuad).store(coverage);
+            fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, coverage, color,
                        geomDomain, uvDomain);
 
             // Then outer vertices, which use 0.f for their coverage
-            fAAHelper.outset(edgeDistances, &aaDeviceQuad, &aaLocalQuad);
-            fWriteProc(&fVertexWriter, fVertexSpec, aaDeviceQuad, aaLocalQuad, kZeroCoverage, color,
+            fAAHelper.outset(edgeDistances, deviceQuad, localQuad);
+            fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kZeroCoverage, color,
                        geomDomain, uvDomain);
         }
     } else {
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.h b/src/gpu/ops/GrQuadPerEdgeAA.h
index 8a77fa7..35a18fd 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.h
+++ b/src/gpu/ops/GrQuadPerEdgeAA.h
@@ -139,8 +139,10 @@
 
         // 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,
+        // the 'vertices' the Tessellator was called with. The insetting and outsetting may
+        // damage the provided GrQuads (as this is intended to work with GrQuadBuffer::Iter).
+        // 'localQuad' can be null if the VertexSpec does not use local coords.
+        void append(GrQuad* deviceQuad, GrQuad* localQuad,
                     const SkPMColor4f& color, const SkRect& uvDomain, GrQuadAAFlags aaFlags);
 
         SkDEBUGCODE(char* vertices() const { return (char*) fVertexWriter.fPtr; })
@@ -151,7 +153,7 @@
         // specs that appear in the wild far more frequently, so they use explicit WriteQuadProcs
         // that have no branches.
         typedef void (*WriteQuadProc)(GrVertexWriter* vertices, const VertexSpec& spec,
-                                      const GrQuad& deviceQuad, const GrQuad& localQuad,
+                                      const GrQuad* deviceQuad, const GrQuad* localQuad,
                                       const float coverage[4], const SkPMColor4f& color,
                                       const SkRect& geomDomain, const SkRect& texDomain);
         static WriteQuadProc GetWriteQuadProc(const VertexSpec& spec);
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 73f1f55..a1b6c41 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -238,8 +238,8 @@
                         static_cast<int>(fFilter));
             int i = 0;
             while(i < fViewCountPairs[p].fQuadCnt && iter.next()) {
-                const GrQuad& quad = iter.deviceQuad();
-                const GrQuad& uv = iter.localQuad();
+                const GrQuad* quad = iter.deviceQuad();
+                GrQuad uv = iter.isLocalValid() ? *(iter.localQuad()) : GrQuad();
                 const ColorDomainAndAA& info = iter.metadata();
                 str.appendf(
                         "%d: Color: 0x%08x, Domain(%d): [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n"
@@ -247,8 +247,8 @@
                         "  Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n",
                         i, info.fColor.toBytes_RGBA(), fDomain, info.fDomainRect.fLeft,
                         info.fDomainRect.fTop, info.fDomainRect.fRight, info.fDomainRect.fBottom,
-                        quad.point(0).fX, quad.point(0).fY, quad.point(1).fX, quad.point(1).fY,
-                        quad.point(2).fX, quad.point(2).fY, quad.point(3).fX, quad.point(3).fY,
+                        quad->point(0).fX, quad->point(0).fY, quad->point(1).fX, quad->point(1).fY,
+                        quad->point(2).fX, quad->point(2).fY, quad->point(3).fX, quad->point(3).fY,
                         uv.point(0).fX, uv.point(0).fY, uv.point(1).fX, uv.point(1).fY,
                         uv.point(2).fX, uv.point(2).fY, uv.point(3).fX, uv.point(3).fY);
 
diff --git a/tests/GrQuadBufferTest.cpp b/tests/GrQuadBufferTest.cpp
index 928438f..c6ba08f 100644
--- a/tests/GrQuadBufferTest.cpp
+++ b/tests/GrQuadBufferTest.cpp
@@ -112,16 +112,17 @@
     auto iter = buffer.iterator();
     while(iter.next()) {
         // Each entry always has the device quad
-        assert_quad_eq(r, expectedDeviceQuads[i], iter.deviceQuad());
+        assert_quad_eq(r, expectedDeviceQuads[i], *iter.deviceQuad());
         assert_metadata_eq(r, {2 * i, 3.f * i}, iter.metadata());
 
         if (i % 2 == 0) {
             // Confirm local quads included on even entries
             ASSERT(iter.isLocalValid());
-            assert_quad_eq(r, expectedLocalQuads[i], iter.localQuad());
+            assert_quad_eq(r, expectedLocalQuads[i], *iter.localQuad());
         } else {
             // Should not have locals
             ASSERT(!iter.isLocalValid());
+            ASSERT(!iter.localQuad());
         }
 
         i++;
@@ -161,25 +162,27 @@
     while(iter.next()) {
         if (i < kQuadCount) {
             // First half should match original buffer1
-            assert_quad_eq(r, quadsA[i], iter.deviceQuad());
+            assert_quad_eq(r, quadsA[i], *iter.deviceQuad());
             assert_metadata_eq(r, {i, 2.f * i}, iter.metadata());
             if (i % 2 == 0) {
                 ASSERT(iter.isLocalValid());
-                assert_quad_eq(r, quadsB[i], iter.localQuad());
+                assert_quad_eq(r, quadsB[i], *iter.localQuad());
             } else {
                 ASSERT(!iter.isLocalValid());
+                ASSERT(!iter.localQuad());
             }
 
         } else {
             // Second half should match buffer2
             int j = i - kQuadCount;
-            assert_quad_eq(r, quadsB[j], iter.deviceQuad());
+            assert_quad_eq(r, quadsB[j], *iter.deviceQuad());
             assert_metadata_eq(r, {2 * j, 0.5f * j}, iter.metadata());
             if (j % 2 == 0) {
                 ASSERT(!iter.isLocalValid());
+                ASSERT(!iter.localQuad());
             } else {
                 ASSERT(iter.isLocalValid());
-                assert_quad_eq(r, quadsA[j], iter.localQuad());
+                assert_quad_eq(r, quadsA[j], *iter.localQuad());
             }
         }
 
@@ -221,12 +224,13 @@
         assert_metadata_eq(r, {2 * i, 0.5f * i}, iter.metadata());
 
         // Quad coordinates are unchanged
-        assert_quad_eq(r, quad, iter.deviceQuad());
+        assert_quad_eq(r, quad, *iter.deviceQuad());
         if (i % 2 == 0) {
             ASSERT(iter.isLocalValid());
-            assert_quad_eq(r, quad, iter.localQuad());
+            assert_quad_eq(r, quad, *iter.localQuad());
         } else {
             ASSERT(!iter.isLocalValid());
+            ASSERT(!iter.localQuad());
         }
         i++;
     }