Add FwidthSquircleTestOp::onPrePrepare

This CL also introduces creating the geometryProcessor in the arena (which bypasses the GrProcessor memory pool).

Bug: skia:9455
Change-Id: Ia9d5c0d886ea918d9e4209078a1f7e8595234d0e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/254963
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/gm/fwidth_squircle.cpp b/gm/fwidth_squircle.cpp
index 7429664..f761783 100644
--- a/gm/fwidth_squircle.cpp
+++ b/gm/fwidth_squircle.cpp
@@ -65,19 +65,30 @@
 
 class FwidthSquircleTestProcessor : public GrGeometryProcessor {
 public:
+    static GrGeometryProcessor* Make(SkArenaAlloc* arena, const SkMatrix& viewMatrix) {
+        return arena->make<FwidthSquircleTestProcessor>(viewMatrix);
+    }
+
+    const char* name() const override { return "FwidthSquircleTestProcessor"; }
+
+    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {}
+
+    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
+
+private:
+    friend class ::SkArenaAlloc; // for access to ctor
+
     FwidthSquircleTestProcessor(const SkMatrix& viewMatrix)
             : GrGeometryProcessor(kFwidthSquircleTestProcessor_ClassID)
             , fViewMatrix(viewMatrix) {
         this->setVertexAttributes(&gVertex, 1);
     }
-    const char* name() const override { return "FwidthSquircleTestProcessor"; }
-    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {}
-    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
 
-private:
     const SkMatrix fViewMatrix;
 
     class Impl;
+
+    typedef GrGeometryProcessor INHERITED;
 };
 
 class FwidthSquircleTestProcessor::Impl : public GrGLSLGeometryProcessor {
@@ -153,11 +164,37 @@
 
     const char* name() const override { return "FwidthSquircleTestOp"; }
     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
-    GrProcessorSet::Analysis finalize(
-            const GrCaps&, const GrAppliedClip*, bool hasMixedSampledCoverage, GrClampType) override {
+    GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
+                                      bool hasMixedSampledCoverage, GrClampType) override {
         return GrProcessorSet::EmptySetAnalysis();
     }
-    void onPrepare(GrOpFlushState* flushState) override {
+
+    void onPrePrepare(GrRecordingContext* context,
+                      const GrSurfaceProxyView* dstView,
+                      const GrAppliedClip*) final {
+        // We're going to create the GrProgramInfo (and the GrPipeline and geometry processor
+        // it relies on) in the DDL-record-time arena.
+        SkArenaAlloc* arena = context->priv().recordTimeAllocator();
+
+        // Not POD! It has some sk_sp's buried inside it!
+        GrPipeline* pipeline = arena->make<GrPipeline>(GrScissorTest::kDisabled,
+                                                       SkBlendMode::kSrcOver,
+                                                       dstView->swizzle());
+
+        GrPrimitiveProcessor* geomProc = FwidthSquircleTestProcessor::Make(arena, fViewMatrix);
+
+        // The programInfo is POD
+        GrRenderTargetProxy* dstProxy = dstView->asRenderTargetProxy();
+        fProgramInfo = arena->make<GrProgramInfo>(dstProxy->numSamples(),
+                                                  dstProxy->numStencilSamples(),
+                                                  dstView->origin(),
+                                                  pipeline,
+                                                  geomProc,
+                                                  nullptr, nullptr, 0,
+                                                  GrPrimitiveType::kTriangleStrip);
+    }
+
+    void onPrepare(GrOpFlushState* flushState) final {
         SkPoint vertices[4] = {
             {-1, -1},
             {+1, -1},
@@ -167,35 +204,58 @@
         fVertexBuffer = flushState->resourceProvider()->createBuffer(
                 sizeof(vertices), GrGpuBufferType::kVertex, kStatic_GrAccessPattern, vertices);
     }
-    void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
+
+    void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) final {
         if (!fVertexBuffer) {
             return;
         }
-        GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kSrcOver,
-                            flushState->drawOpArgs().outputSwizzle());
-
-        FwidthSquircleTestProcessor primProc(fViewMatrix);
-
-        GrProgramInfo programInfo(flushState->proxy()->numSamples(),
-                                  flushState->proxy()->numStencilSamples(),
-                                  flushState->drawOpArgs().origin(),
-                                  &pipeline,
-                                  &primProc,
-                                  nullptr, nullptr, 0,
-                                  GrPrimitiveType::kTriangleStrip);
 
         GrMesh mesh(GrPrimitiveType::kTriangleStrip);
         mesh.setNonIndexedNonInstanced(4);
         mesh.setVertexData(std::move(fVertexBuffer));
-        flushState->opsRenderPass()->draw(programInfo, &mesh, 1, SkRect::MakeIWH(kWidth, kHeight));
+
+        if (fProgramInfo) {
+            flushState->opsRenderPass()->draw(*fProgramInfo, &mesh, 1,
+                                              SkRect::MakeIWH(kWidth, kHeight));
+        } else {
+            const GrSurfaceProxyView* dstView = flushState->view();
+
+            GrPipeline pipeline(GrScissorTest::kDisabled,
+                                SkBlendMode::kSrcOver,
+                                dstView->swizzle());
+
+            GrGeometryProcessor* gp = FwidthSquircleTestProcessor::Make(flushState->allocator(),
+                                                                        fViewMatrix);
+
+            GrProgramInfo programInfo(dstView->asRenderTargetProxy()->numSamples(),
+                                      dstView->asRenderTargetProxy()->numStencilSamples(),
+                                      dstView->origin(),
+                                      &pipeline,
+                                      gp,
+                                      nullptr, nullptr, 0,
+                                      GrPrimitiveType::kTriangleStrip);
+
+            flushState->opsRenderPass()->draw(programInfo, &mesh, 1,
+                                              SkRect::MakeIWH(kWidth, kHeight));
+        }
     }
 
-    sk_sp<GrBuffer> fVertexBuffer;
-    const SkMatrix fViewMatrix;
     static const int kWidth = 200;
     static const int kHeight = 200;
 
+    sk_sp<GrBuffer> fVertexBuffer;
+    const SkMatrix  fViewMatrix;
+
+    // The program info (and both the GrPipeline and GrPrimitiveProcessor it relies on), when
+    // allocated, are allocated in the ddl-record-time arena. It is the arena's job to free up
+    // their memory so we just have a bare programInfo pointer here. We don't even store the
+    // GrPipeline and GrPrimitiveProcessor pointers here bc they are guaranteed to have the
+    // same lifetime as the program info.
+    GrProgramInfo*  fProgramInfo = nullptr;
+
     friend class ::GrOpMemoryPool; // for ctor
+
+    typedef GrDrawOp INHERITED;
 };
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////