Add ClockwiseTestOp::onPrePrepare

This is a trial balloon for the pulling forward of GrProgramInfo to DDL-record time

Bug: skia:9455
Change-Id: Icabf27fcf7169f12b0655ee23f98dafa7c770add
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/253099
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/gm/clockwise.cpp b/gm/clockwise.cpp
index 6fe1e99..f96e958 100644
--- a/gm/clockwise.cpp
+++ b/gm/clockwise.cpp
@@ -80,18 +80,25 @@
 
 class ClockwiseTestProcessor : public GrGeometryProcessor {
 public:
+    static sk_sp<GrGeometryProcessor> Make(bool readSkFragCoord) {
+        return sk_sp<GrGeometryProcessor>(new ClockwiseTestProcessor(readSkFragCoord));
+    }
+
+    const char* name() const final { return "ClockwiseTestProcessor"; }
+
+    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
+        b->add32(fReadSkFragCoord);
+    }
+
+    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
+
+private:
     ClockwiseTestProcessor(bool readSkFragCoord)
             : GrGeometryProcessor(kClockwiseTestProcessor_ClassID)
             , fReadSkFragCoord(readSkFragCoord) {
         this->setVertexAttributes(&gVertex, 1);
     }
-    const char* name() const override { return "ClockwiseTestProcessor"; }
-    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
-        b->add32(fReadSkFragCoord);
-    }
-    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
 
-private:
     const bool fReadSkFragCoord;
 
     friend class GLSLClockwiseTestProcessor;
@@ -147,6 +154,32 @@
                                       bool hasMixedSampledCoverage, GrClampType) override {
         return GrProcessorSet::EmptySetAnalysis();
     }
+
+    void onPrePrepare(GrRecordingContext* context,
+                      const GrSurfaceProxyView* dstView,
+                      const GrAppliedClip*) final {
+        // We're going to create the GrProgramInfo (and the GrPipeline it relies on) in the
+        // DDL-record-time arena.
+        SkArenaAlloc* arena = context->priv().opPODAllocator();
+
+        // Not POD! It has some sk_sp's buried inside it!
+        GrPipeline* pipeline = arena->make<GrPipeline>(GrScissorTest::kDisabled, SkBlendMode::kPlus,
+                                                       dstView->swizzle());
+
+        // This is allocated in the processor memory pool!?!
+        fGeomProc = ClockwiseTestProcessor::Make(fReadSkFragCoord);
+
+        // The programInfo is POD
+        GrRenderTargetProxy* dstProxy = dstView->asRenderTargetProxy();
+        fProgramInfo = arena->make<GrProgramInfo>(dstProxy->numSamples(),
+                                                  dstProxy->numStencilSamples(),
+                                                  dstView->origin(),
+                                                  *pipeline,
+                                                  *fGeomProc,
+                                                  nullptr, nullptr, 0,
+                                                  GrPrimitiveType::kTriangleStrip);
+    }
+
     void onPrepare(GrOpFlushState* flushState) override {
         SkPoint vertices[4] = {
             {100, fY},
@@ -157,32 +190,55 @@
         fVertexBuffer = flushState->resourceProvider()->createBuffer(
                 sizeof(vertices), GrGpuBufferType::kVertex, kStatic_GrAccessPattern, vertices);
     }
+
     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
         if (!fVertexBuffer) {
             return;
         }
-        GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kPlus,
-                            flushState->drawOpArgs().outputSwizzle());
+
         GrMesh mesh(GrPrimitiveType::kTriangleStrip);
         mesh.setNonIndexedNonInstanced(4);
         mesh.setVertexData(std::move(fVertexBuffer));
 
-        ClockwiseTestProcessor primProc(fReadSkFragCoord);
+        if (fProgramInfo) {
+            flushState->opsRenderPass()->draw(*fProgramInfo, &mesh, 1,
+                                              SkRect::MakeXYWH(0, fY, 100, 100));
+        } else {
+            const GrSurfaceProxyView* dstView = flushState->view();
 
-        GrProgramInfo programInfo(flushState->proxy()->numSamples(),
-                                  flushState->proxy()->numStencilSamples(),
-                                  flushState->drawOpArgs().origin(),
-                                  pipeline,
-                                  primProc,
-                                  nullptr, nullptr, 0,
-                                  GrPrimitiveType::kTriangleStrip);
+            GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kPlus,
+                                dstView->swizzle());
 
-        flushState->opsRenderPass()->draw(programInfo, &mesh, 1, SkRect::MakeXYWH(0, fY, 100, 100));
+            // This is allocated in the processor memory pool!?!
+            sk_sp<GrPrimitiveProcessor> gp = ClockwiseTestProcessor::Make(fReadSkFragCoord);
+
+            GrProgramInfo programInfo(dstView->asRenderTargetProxy()->numSamples(),
+                                      dstView->asRenderTargetProxy()->numStencilSamples(),
+                                      dstView->origin(),
+                                      pipeline,
+                                      *gp,
+                                      nullptr, nullptr, 0,
+                                      GrPrimitiveType::kTriangleStrip);
+
+            flushState->opsRenderPass()->draw(programInfo, &mesh, 1,
+                                              SkRect::MakeXYWH(0, fY, 100, 100));
+
+        }
+
     }
 
-    sk_sp<GrBuffer> fVertexBuffer;
-    const bool fReadSkFragCoord;
-    const float fY;
+    sk_sp<GrBuffer>                fVertexBuffer;
+    const bool                     fReadSkFragCoord;
+    const float                    fY;
+
+    // This is allocated in the processor memory pool so we need to hold an sk_sp
+    sk_sp<GrPrimitiveProcessor>    fGeomProc;
+
+    // The program info (and the GrPipeline 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 program info pointer here. We don't even store the GrPipeline's pointer bc it is
+    // guaranteed to have the same lifetime as the program info.
+    GrProgramInfo*                 fProgramInfo = nullptr;
 
     friend class ::GrOpMemoryPool; // for ctor
 };
diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h
index d33f466..37ba109 100644
--- a/src/gpu/GrOpFlushState.h
+++ b/src/gpu/GrOpFlushState.h
@@ -72,6 +72,7 @@
         GrSwizzle outputSwizzle() const { return fSurfaceView->swizzle(); }
 
         GrOp* op() { return fOp; }
+        const GrSurfaceProxyView* view() const { return fSurfaceView; }
         GrRenderTargetProxy* proxy() const { return fRenderTargetProxy; }
         GrAppliedClip* appliedClip() { return fAppliedClip; }
         const GrAppliedClip* appliedClip() const { return fAppliedClip; }
@@ -129,6 +130,7 @@
                                     int* actualIndexCount) final;
     void putBackIndices(int indexCount) final;
     void putBackVertices(int vertices, size_t vertexStride) final;
+    const GrSurfaceProxyView* view() const { return this->drawOpArgs().view(); }
     GrRenderTargetProxy* proxy() const final { return this->drawOpArgs().proxy(); }
     const GrAppliedClip* appliedClip() final { return this->drawOpArgs().appliedClip(); }
     GrAppliedClip detachAppliedClip() final;
diff --git a/src/gpu/GrOpsTask.cpp b/src/gpu/GrOpsTask.cpp
index 6181995..4a1146e 100644
--- a/src/gpu/GrOpsTask.cpp
+++ b/src/gpu/GrOpsTask.cpp
@@ -408,7 +408,7 @@
 
     for (const auto& chain : fOpChains) {
         if (chain.shouldExecute()) {
-            chain.head()->prePrepare(context, chain.appliedClip());
+            chain.head()->prePrepare(context, &fTargetView, chain.appliedClip());
         }
     }
 }
@@ -440,6 +440,12 @@
                                           chain.dstProxyView());
 
             flushState->setOpArgs(&opArgs);
+
+            // Temporary debugging helper: for debugging prePrepare w/o going through DDLs
+            // Delete once most of the GrOps have an onPrePrepare.
+            // chain.head()->prePrepare(flushState->gpu()->getContext(), &fTargetView,
+            //                          chain.appliedClip());
+
             // GrOp::prePrepare may or may not have been called at this point
             chain.head()->prepare(flushState);
             flushState->setOpArgs(nullptr);
diff --git a/src/gpu/ops/GrMeshDrawOp.h b/src/gpu/ops/GrMeshDrawOp.h
index d0d8436..75bb184 100644
--- a/src/gpu/ops/GrMeshDrawOp.h
+++ b/src/gpu/ops/GrMeshDrawOp.h
@@ -87,13 +87,17 @@
     }
 
 private:
-    void onPrePrepare(GrRecordingContext* context, const GrAppliedClip* clip) final {
-        this->onPrePrepareDraws(context, clip);
+    void onPrePrepare(GrRecordingContext* context,
+                      const GrSurfaceProxyView* dstView,
+                      const GrAppliedClip* clip) final {
+        this->onPrePrepareDraws(context, dstView, clip);
     }
     void onPrepare(GrOpFlushState* state) final;
 
     // Only the GrTextureOp currently overrides this virtual
-    virtual void onPrePrepareDraws(GrRecordingContext*, const GrAppliedClip*) {}
+    virtual void onPrePrepareDraws(GrRecordingContext*,
+                                   const GrSurfaceProxyView*,
+                                   const GrAppliedClip*) {}
 
     virtual void onPrepareDraws(Target*) = 0;
     typedef GrDrawOp INHERITED;
diff --git a/src/gpu/ops/GrOp.h b/src/gpu/ops/GrOp.h
index 9a250a3..7dfa7bc 100644
--- a/src/gpu/ops/GrOp.h
+++ b/src/gpu/ops/GrOp.h
@@ -159,8 +159,8 @@
      * onPrePrepare must be prepared to handle both cases (when onPrePrepare has been called
      * ahead of time and when it has not been called).
      */
-    void prePrepare(GrRecordingContext* context, GrAppliedClip* clip) {
-        this->onPrePrepare(context, clip);
+    void prePrepare(GrRecordingContext* context, GrSurfaceProxyView* dstView, GrAppliedClip* clip) {
+        this->onPrePrepare(context, dstView, clip);
     }
 
     /**
@@ -292,7 +292,8 @@
     }
 
     // Only GrMeshDrawOp currently overrides this virtual
-    virtual void onPrePrepare(GrRecordingContext*, const GrAppliedClip*) {}
+    virtual void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView*,
+                              const GrAppliedClip*) {}
     virtual void onPrepare(GrOpFlushState*) = 0;
     // If this op is chained then chainBounds is the union of the bounds of all ops in the chain.
     // Otherwise, this op's bounds.
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index b9d3e6a..070221b 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -515,7 +515,9 @@
         }
     }
 
-    void onPrePrepareDraws(GrRecordingContext* context, const GrAppliedClip* clip) override {
+    void onPrePrepareDraws(GrRecordingContext* context,
+                           const GrSurfaceProxyView* dstView,
+                           const GrAppliedClip* clip) override {
         TRACE_EVENT0("skia.gpu", TRACE_FUNC);
 
         SkDEBUGCODE(this->validate();)