Add onPrePrepareDraws to GrFillRectOp

In DDL-mode, this pulls the tessellation of the GrFillRectOp's vertices forward to record time.

Bug: skia:9601
Change-Id: I1a505845cc20f795d6f171b4c19d779475fdd240
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/257685
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index 050a461..ab5c833 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -185,24 +185,62 @@
     int numQuads() const final { return fQuads.count(); }
 #endif
 
-    void onPrepareDraws(Target* target) override {
-        TRACE_EVENT0("skia.gpu", TRACE_FUNC);
-
-        using Domain = GrQuadPerEdgeAA::Domain;
-        static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
-
+    VertexSpec vertexSpec() const {
         auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(fHelper.aaType(),
                                                                         fQuads.count());
 
-        VertexSpec vertexSpec(fQuads.deviceQuadType(), fColorType, fQuads.localQuadType(),
-                              fHelper.usesLocalCoords(), Domain::kNo, fHelper.aaType(),
-                              fHelper.compatibleWithCoverageAsAlpha(), indexBufferOption);
+        return VertexSpec(fQuads.deviceQuadType(), fColorType, fQuads.localQuadType(),
+                          fHelper.usesLocalCoords(), GrQuadPerEdgeAA::Domain::kNo,
+                          fHelper.aaType(),
+                          fHelper.compatibleWithCoverageAsAlpha(), indexBufferOption);
+    }
+
+    void onPrePrepareDraws(GrRecordingContext* context,
+                           const GrSurfaceProxyView*,
+                           GrAppliedClip*,
+                           const GrXferProcessor::DstProxyView&) override {
+        TRACE_EVENT0("skia.gpu", TRACE_FUNC);
+
+        SkASSERT(!fPrePreparedVertices);
+
+        SkArenaAlloc* arena = context->priv().recordTimeAllocator();
+
+        const VertexSpec vertexSpec = this->vertexSpec();
+
+        const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
+        const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
+
+        fPrePreparedVertices = arena->makeArrayDefault<char>(totalVertexSizeInBytes);
+
+        this->tessellate(vertexSpec, fPrePreparedVertices);
+    }
+
+    void tessellate(const VertexSpec& vertexSpec, char* dst) const {
+        static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
+
+        GrQuadPerEdgeAA::Tessellator tessellator(vertexSpec, dst);
+        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();
+            tessellator.append(iter.deviceQuad(), iter.localQuad(),
+                               info.fColor, kEmptyDomain, info.fAAFlags);
+        }
+    }
+
+    void onPrepareDraws(Target* target) override {
+        TRACE_EVENT0("skia.gpu", TRACE_FUNC);
+
+        const VertexSpec vertexSpec = this->vertexSpec();
+
         // Make sure that if the op thought it was a solid color, the vertex spec does not use
         // local coords.
         SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
 
         GrGeometryProcessor* gp = GrQuadPerEdgeAA::MakeProcessor(target->allocator(), vertexSpec);
-        size_t vertexSize = gp->vertexStride();
+        SkASSERT(gp->vertexStride() == vertexSpec.vertexSize());
 
         sk_sp<const GrBuffer> vertexBuffer;
         int vertexOffsetInBuffer = 0;
@@ -210,22 +248,19 @@
         const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad();
 
         // Fill the allocated vertex data
-        void* vdata = target->makeVertexSpace(vertexSize, totalNumVertices,
+        void* vdata = target->makeVertexSpace(vertexSpec.vertexSize(), totalNumVertices,
                                               &vertexBuffer, &vertexOffsetInBuffer);
         if (!vdata) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
 
-        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();
-            tessellator.append(iter.deviceQuad(), iter.localQuad(),
-                               info.fColor, kEmptyDomain, info.fAAFlags);
+        if (fPrePreparedVertices) {
+            const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices;
+
+            memcpy(vdata, fPrePreparedVertices, totalVertexSizeInBytes);
+        } else {
+            this->tessellate(vertexSpec, (char*) vdata);
         }
 
         sk_sp<const GrBuffer> indexBuffer;
@@ -336,6 +371,7 @@
 
     Helper fHelper;
     GrQuadBuffer<ColorAndAA> fQuads;
+    char* fPrePreparedVertices = nullptr;
 
     ColorType fColorType;