Add onPrePrepareDraws & createProgramInfo methods to GrDrawVerticesOp (take 2)

This CL also incidentally adds:

1) a GrMeshDrawOp::Target 'outputView' virtual and switches GrOpFlushState over to overriding it.

2) a createProgramInfo helper to GrSimpleMeshDrawOpHelper

Bug: skia:9455
Change-Id: I88ce51c585b1458ee79a9aaa7024190e9f19198c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/274506
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index d2d8754..822da9a 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -106,7 +106,7 @@
     GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) {
         return this->createProgramInfo(&flushState->caps(),
                                        flushState->allocator(),
-                                       flushState->view(),
+                                       flushState->outputView(),
                                        flushState->detachAppliedClip(),
                                        flushState->dstProxyView());
     }
diff --git a/gm/clockwise.cpp b/gm/clockwise.cpp
index 206a22e..1a0753f 100644
--- a/gm/clockwise.cpp
+++ b/gm/clockwise.cpp
@@ -178,7 +178,7 @@
     GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
         return this->createProgramInfo(&flushState->caps(),
                                        flushState->allocator(),
-                                       flushState->view(),
+                                       flushState->outputView(),
                                        flushState->detachAppliedClip(),
                                        flushState->dstProxyView());
     }
diff --git a/gm/fwidth_squircle.cpp b/gm/fwidth_squircle.cpp
index 1d0fd29..38dca23 100644
--- a/gm/fwidth_squircle.cpp
+++ b/gm/fwidth_squircle.cpp
@@ -186,7 +186,7 @@
     GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
         return this->createProgramInfo(&flushState->caps(),
                                        flushState->allocator(),
-                                       flushState->view(),
+                                       flushState->outputView(),
                                        flushState->detachAppliedClip(),
                                        flushState->dstProxyView());
     }
diff --git a/gm/samplelocations.cpp b/gm/samplelocations.cpp
index c3d5152..d462542 100644
--- a/gm/samplelocations.cpp
+++ b/gm/samplelocations.cpp
@@ -262,7 +262,7 @@
     GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
         return this->createProgramInfo(&flushState->caps(),
                                        flushState->allocator(),
-                                       flushState->view(),
+                                       flushState->outputView(),
                                        flushState->detachAppliedClip(),
                                        flushState->dstProxyView());
     }
diff --git a/gm/tessellation.cpp b/gm/tessellation.cpp
index e390b0d..184b98b 100644
--- a/gm/tessellation.cpp
+++ b/gm/tessellation.cpp
@@ -333,7 +333,7 @@
         }
 
         GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
-                                  state->proxy()->backendFormat(), state->view()->origin(),
+                                  state->proxy()->backendFormat(), state->outputView()->origin(),
                                   &pipeline, shader.get(), &fixedDynamicState, nullptr, 0,
                                   GrPrimitiveType::kPatches, tessellationPatchVertexCount);
 
diff --git a/src/gpu/GrOpFlushState.cpp b/src/gpu/GrOpFlushState.cpp
index 02e1608..10b84f4 100644
--- a/src/gpu/GrOpFlushState.cpp
+++ b/src/gpu/GrOpFlushState.cpp
@@ -46,7 +46,7 @@
         GrProgramInfo programInfo(this->proxy()->numSamples(),
                                   this->proxy()->numStencilSamples(),
                                   this->proxy()->backendFormat(),
-                                  this->view()->origin(),
+                                  this->outputView()->origin(),
                                   pipeline,
                                   fCurrDraw->fGeometryProcessor,
                                   fCurrDraw->fFixedDynamicState,
diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h
index 4d7c3e4..57b6247 100644
--- a/src/gpu/GrOpFlushState.h
+++ b/src/gpu/GrOpFlushState.h
@@ -71,7 +71,7 @@
         GrSwizzle outputSwizzle() const { return fSurfaceView->swizzle(); }
 
         GrOp* op() { return fOp; }
-        const GrSurfaceProxyView* view() const { return fSurfaceView; }
+        const GrSurfaceProxyView* outputView() const { return fSurfaceView; }
         GrRenderTargetProxy* proxy() const { return fRenderTargetProxy; }
         GrAppliedClip* appliedClip() { return fAppliedClip; }
         const GrAppliedClip* appliedClip() const { return fAppliedClip; }
@@ -132,7 +132,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(); }
+    const GrSurfaceProxyView* outputView() const final { return this->drawOpArgs().outputView(); }
     GrRenderTargetProxy* proxy() const final { return this->drawOpArgs().proxy(); }
     const GrAppliedClip* appliedClip() const final { return this->drawOpArgs().appliedClip(); }
     GrAppliedClip detachAppliedClip() final;
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.cpp b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
index 14d9887..b3ca13e 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.cpp
@@ -207,7 +207,7 @@
     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
-                              flushState->view()->origin(),
+                              flushState->outputView()->origin(),
                               &pipeline,
                               this,
                               nullptr,
diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp
index 8499726..1a18126 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.cpp
+++ b/src/gpu/ccpr/GrCCPathProcessor.cpp
@@ -144,7 +144,7 @@
     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
-                              flushState->view()->origin(),
+                              flushState->outputView()->origin(),
                               &pipeline,
                               this,
                               fixedDynamicState,
diff --git a/src/gpu/ccpr/GrCCStroker.cpp b/src/gpu/ccpr/GrCCStroker.cpp
index 8d092d6..3484c48 100644
--- a/src/gpu/ccpr/GrCCStroker.cpp
+++ b/src/gpu/ccpr/GrCCStroker.cpp
@@ -782,7 +782,7 @@
     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
-                              flushState->view()->origin(),
+                              flushState->outputView()->origin(),
                               &pipeline,
                               &processor,
                               nullptr,
diff --git a/src/gpu/ccpr/GrStencilAtlasOp.cpp b/src/gpu/ccpr/GrStencilAtlasOp.cpp
index e56d722..40960df 100644
--- a/src/gpu/ccpr/GrStencilAtlasOp.cpp
+++ b/src/gpu/ccpr/GrStencilAtlasOp.cpp
@@ -157,7 +157,7 @@
     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                               flushState->proxy()->numStencilSamples(),
                               flushState->proxy()->backendFormat(),
-                              flushState->view()->origin(),
+                              flushState->outputView()->origin(),
                               &resolvePipeline,
                               &primProc,
                               &scissorRectState,
diff --git a/src/gpu/ops/GrDrawPathOp.cpp b/src/gpu/ops/GrDrawPathOp.cpp
index 489b7f7..e1db207 100644
--- a/src/gpu/ops/GrDrawPathOp.cpp
+++ b/src/gpu/ops/GrDrawPathOp.cpp
@@ -101,7 +101,7 @@
     GrProgramInfo programInfo(proxy->numSamples(),
                               proxy->numStencilSamples(),
                               proxy->backendFormat(),
-                              flushState->view()->origin(),
+                              flushState->outputView()->origin(),
                               pipeline,
                               pathProc.get(),
                               fixedDynamicState,
diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp
index d96999a..bc93833 100644
--- a/src/gpu/ops/GrDrawVerticesOp.cpp
+++ b/src/gpu/ops/GrDrawVerticesOp.cpp
@@ -9,6 +9,7 @@
 #include "src/gpu/GrCaps.h"
 #include "src/gpu/GrDefaultGeoProcFactory.h"
 #include "src/gpu/GrOpFlushState.h"
+#include "src/gpu/GrProgramInfo.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/ops/GrDrawVerticesOp.h"
 #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
@@ -28,7 +29,11 @@
     const char* name() const override { return "DrawVerticesOp"; }
 
     void visitProxies(const VisitProxyFunc& func) const override {
-        fHelper.visitProxies(func);
+        if (fProgramInfo) {
+            fProgramInfo->visitProxies(func);
+        } else {
+            fHelper.visitProxies(func);
+        }
     }
 
 #ifdef SK_DEBUG
@@ -46,29 +51,40 @@
         kSkColor,
     };
 
+    GrProgramInfo* createProgramInfo(const GrCaps*,
+                                     SkArenaAlloc*,
+                                     const GrSurfaceProxyView* outputView,
+                                     GrAppliedClip&&,
+                                     const GrXferProcessor::DstProxyView&);
+    GrProgramInfo* createProgramInfo(Target* target) {
+        return this->createProgramInfo(&target->caps(),
+                                       target->allocator(),
+                                       target->outputView(),
+                                       target->detachAppliedClip(),
+                                       target->dstProxyView());
+    }
+
+    void onPrePrepareDraws(GrRecordingContext*,
+                           const GrSurfaceProxyView* outputView,
+                           GrAppliedClip*,
+                           const GrXferProcessor::DstProxyView&) override;
     void onPrepareDraws(Target*) override;
     void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
 
-    void drawVolatile(Target*);
-    void drawNonVolatile(Target*);
+    void drawVolatile(Target*, const GrPrimitiveProcessor&);
+    void drawNonVolatile(Target*, const GrPrimitiveProcessor&);
 
-    void fillBuffers(bool hasColorAttribute,
-                     bool hasLocalCoordsAttribute,
-                     size_t vertexStride,
+    void fillBuffers(size_t vertexStride,
                      void* verts,
                      uint16_t* indices) const;
 
-    void drawVertices(Target*,
-                      const GrGeometryProcessor*,
-                      sk_sp<const GrBuffer> vertexBuffer,
-                      int firstVertex,
-                      sk_sp<const GrBuffer> indexBuffer,
-                      int firstIndex);
+    void createMesh(Target*,
+                    sk_sp<const GrBuffer> vertexBuffer,
+                    int firstVertex,
+                    sk_sp<const GrBuffer> indexBuffer,
+                    int firstIndex);
 
-    GrGeometryProcessor* makeGP(SkArenaAlloc* arena,
-                                const GrShaderCaps* shaderCaps,
-                                bool* hasColorAttribute,
-                                bool* hasLocalCoordAttribute) const;
+    GrGeometryProcessor* makeGP(SkArenaAlloc*, const GrShaderCaps*);
 
     GrPrimitiveType primitiveType() const { return fPrimitiveType; }
     bool combinablePrimitive() const {
@@ -116,6 +132,11 @@
         kRequiresPerVertexColors_Flag       = 0x1,
         kAnyMeshHasExplicitLocalCoords_Flag = 0x2,
         kHasMultipleViewMatrices_Flag       = 0x4,
+
+        // These following flags are set in makeGP
+        kHasLocalCoordAttribute_Flag        = 0x8,
+        kHasColorAttribute_Flag             = 0x10, // should always match kRequiresPerVertexColors
+        kWasCharacterized_Flag              = 0x20,
     };
 
     Helper fHelper;
@@ -129,6 +150,9 @@
     ColorArrayType fColorArrayType;
     sk_sp<GrColorSpaceXform> fColorSpaceXform;
 
+    GrMesh*        fMesh = nullptr;
+    GrProgramInfo* fProgramInfo = nullptr;
+
     typedef GrMeshDrawOp INHERITED;
 };
 
@@ -213,25 +237,20 @@
     return result;
 }
 
-GrGeometryProcessor* DrawVerticesOp::makeGP(SkArenaAlloc* arena,
-                                            const GrShaderCaps* shaderCaps,
-                                            bool* hasColorAttribute,
-                                            bool* hasLocalCoordAttribute) const {
+GrGeometryProcessor* DrawVerticesOp::makeGP(SkArenaAlloc* arena, const GrShaderCaps* shaderCaps) {
     using namespace GrDefaultGeoProcFactory;
     LocalCoords::Type localCoordsType;
     if (fHelper.usesLocalCoords()) {
         // If we have multiple view matrices we will transform the positions into device space. We
         // must then also provide untransformed positions as local coords.
         if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) {
-            *hasLocalCoordAttribute = true;
+            fFlags |= kHasLocalCoordAttribute_Flag;
             localCoordsType = LocalCoords::kHasExplicit_Type;
         } else {
-            *hasLocalCoordAttribute = false;
             localCoordsType = LocalCoords::kUsePosition_Type;
         }
     } else {
         localCoordsType = LocalCoords::kUnused_Type;
-        *hasLocalCoordAttribute = false;
     }
 
     Color color(fMeshes[0].fColor);
@@ -242,13 +261,12 @@
             color.fType = Color::kUnpremulSkColorAttribute_Type;
             color.fColorSpaceXform = fColorSpaceXform;
         }
-        *hasColorAttribute = true;
-    } else {
-        *hasColorAttribute = false;
+        fFlags |= kHasColorAttribute_Flag;
     }
 
     const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
 
+    fFlags |= kWasCharacterized_Flag;
     return GrDefaultGeoProcFactory::Make(arena,
                                          shaderCaps,
                                          color,
@@ -257,25 +275,52 @@
                                          vm);
 }
 
+GrProgramInfo* DrawVerticesOp::createProgramInfo(
+                                            const GrCaps* caps,
+                                            SkArenaAlloc* arena,
+                                            const GrSurfaceProxyView* outputView,
+                                            GrAppliedClip&& appliedClip,
+                                            const GrXferProcessor::DstProxyView& dstProxyView) {
+    GrGeometryProcessor* gp = this->makeGP(arena, caps->shaderCaps());
+
+    return fHelper.createProgramInfo(caps, arena, outputView, std::move(appliedClip), dstProxyView,
+                                     gp, this->primitiveType());
+}
+
+void DrawVerticesOp::onPrePrepareDraws(GrRecordingContext* context,
+                                       const GrSurfaceProxyView* outputView,
+                                       GrAppliedClip* clip,
+                                       const GrXferProcessor::DstProxyView& dstProxyView) {
+    SkArenaAlloc* arena = context->priv().recordTimeAllocator();
+
+    // This is equivalent to a GrOpFlushState::detachAppliedClip
+    GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip();
+
+    fProgramInfo = this->createProgramInfo(context->priv().caps(), arena, outputView,
+                                           std::move(appliedClip), dstProxyView);
+
+    context->priv().recordProgramInfo(fProgramInfo);
+}
+
 void DrawVerticesOp::onPrepareDraws(Target* target) {
+    if (!fProgramInfo) {
+        // Note: this could be moved to onExecute if draw*Volatile were made to compute
+        // their own vertex stride and hasColorAttribute and hasLocalCoordsAttribute settings.
+        fProgramInfo = this->createProgramInfo(target);
+    }
+
     bool hasMapBufferSupport = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
     if (fMeshes[0].fVertices->isVolatile() || !hasMapBufferSupport) {
-        this->drawVolatile(target);
+        this->drawVolatile(target, fProgramInfo->primProc());
     } else {
-        this->drawNonVolatile(target);
+        this->drawNonVolatile(target, fProgramInfo->primProc());
     }
 }
 
-void DrawVerticesOp::drawVolatile(Target* target) {
-    bool hasColorAttribute;
-    bool hasLocalCoordsAttribute;
-    GrGeometryProcessor* gp = this->makeGP(target->allocator(),
-                                           target->caps().shaderCaps(),
-                                           &hasColorAttribute,
-                                           &hasLocalCoordsAttribute);
+void DrawVerticesOp::drawVolatile(Target* target, const GrPrimitiveProcessor& gp) {
 
     // Allocate buffers.
-    size_t vertexStride = gp->vertexStride();
+    size_t vertexStride = gp.vertexStride();
     sk_sp<const GrBuffer> vertexBuffer;
     int firstVertex = 0;
     void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
@@ -295,27 +340,14 @@
         }
     }
 
-    // Fill the buffers.
-    this->fillBuffers(hasColorAttribute,
-                      hasLocalCoordsAttribute,
-                      vertexStride,
-                      verts,
-                      indices);
+    this->fillBuffers(vertexStride, verts, indices);
 
-    // Draw the vertices.
-    this->drawVertices(target, gp, std::move(vertexBuffer), firstVertex, indexBuffer, firstIndex);
+    this->createMesh(target, std::move(vertexBuffer), firstVertex, indexBuffer, firstIndex);
 }
 
-void DrawVerticesOp::drawNonVolatile(Target* target) {
+void DrawVerticesOp::drawNonVolatile(Target* target, const GrPrimitiveProcessor& gp) {
     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
 
-    bool hasColorAttribute;
-    bool hasLocalCoordsAttribute;
-    GrGeometryProcessor* gp = this->makeGP(target->allocator(),
-                                           target->caps().shaderCaps(),
-                                            &hasColorAttribute,
-                                            &hasLocalCoordsAttribute);
-
     SkASSERT(fMeshes.count() == 1); // Non-volatile meshes should never combine.
 
     // Get the resource provider.
@@ -338,12 +370,12 @@
 
     // Draw using the cached buffers if possible.
     if (vertexBuffer && (!this->isIndexed() || indexBuffer)) {
-        this->drawVertices(target, gp, std::move(vertexBuffer), 0, std::move(indexBuffer), 0);
+        this->createMesh(target, std::move(vertexBuffer), 0, std::move(indexBuffer), 0);
         return;
     }
 
     // Allocate vertex buffer.
-    size_t vertexStride = gp->vertexStride();
+    size_t vertexStride = gp.vertexStride();
     vertexBuffer = rp->createBuffer(
             fVertexCount * vertexStride, GrGpuBufferType::kVertex, kStatic_GrAccessPattern);
     void* verts = vertexBuffer ? vertexBuffer->map() : nullptr;
@@ -364,14 +396,8 @@
         }
     }
 
-    // Fill the buffers.
-    this->fillBuffers(hasColorAttribute,
-                      hasLocalCoordsAttribute,
-                      vertexStride,
-                      verts,
-                      indices);
+    this->fillBuffers(vertexStride, verts, indices);
 
-    // Unmap the buffers.
     vertexBuffer->unmap();
     if (indexBuffer) {
         indexBuffer->unmap();
@@ -382,15 +408,15 @@
     rp->assignUniqueKeyToResource(indexKey, indexBuffer.get());
 
     // Draw the vertices.
-    this->drawVertices(target, gp, std::move(vertexBuffer), 0, std::move(indexBuffer), 0);
+    this->createMesh(target, std::move(vertexBuffer), 0, std::move(indexBuffer), 0);
 }
 
-void DrawVerticesOp::fillBuffers(bool hasColorAttribute,
-                                 bool hasLocalCoordsAttribute,
-                                 size_t vertexStride,
-                                 void* verts,
-                                 uint16_t* indices) const {
+void DrawVerticesOp::fillBuffers(size_t vertexStride, void* verts, uint16_t* indices) const {
     int instanceCount = fMeshes.count();
+    bool hasColorAttribute = SkToBool(fFlags & kHasColorAttribute_Flag);
+    bool hasLocalCoordsAttribute = SkToBool(fFlags & kHasLocalCoordAttribute_Flag);
+    SkASSERT(fFlags & kWasCharacterized_Flag);
+    SkASSERT(hasColorAttribute == this->requiresPerVertexColors());
 
     // Copy data into the buffers.
     int vertexOffset = 0;
@@ -477,27 +503,28 @@
     }
 }
 
-void DrawVerticesOp::drawVertices(Target* target,
-                                  const GrGeometryProcessor* gp,
-                                  sk_sp<const GrBuffer> vertexBuffer,
-                                  int firstVertex,
-                                  sk_sp<const GrBuffer> indexBuffer,
-                                  int firstIndex) {
-    GrMesh* mesh = target->allocMesh();
+void DrawVerticesOp::createMesh(Target* target,
+                                sk_sp<const GrBuffer> vertexBuffer,
+                                int firstVertex,
+                                sk_sp<const GrBuffer> indexBuffer,
+                                int firstIndex) {
+    SkASSERT(!fMesh);
+
+    fMesh = target->allocMesh();
     if (this->isIndexed()) {
-        mesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertexCount - 1,
+        fMesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertexCount - 1,
                          GrPrimitiveRestart::kNo);
     } else {
-        mesh->setNonIndexedNonInstanced(fVertexCount);
+        fMesh->setNonIndexedNonInstanced(fVertexCount);
     }
-    mesh->setVertexData(std::move(vertexBuffer), firstVertex);
-    target->recordDraw(gp, mesh, 1, this->primitiveType());
+    fMesh->setVertexData(std::move(vertexBuffer), firstVertex);
 }
 
 void DrawVerticesOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
-    auto pipeline = fHelper.createPipeline(flushState);
+    SkASSERT(fProgramInfo);
 
-    flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline);
+    flushState->opsRenderPass()->bindPipeline(*fProgramInfo, chainBounds);
+    flushState->opsRenderPass()->drawMeshes(*fProgramInfo, fMesh, 1);
 }
 
 GrOp::CombineResult DrawVerticesOp::onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*,
diff --git a/src/gpu/ops/GrFillRRectOp.cpp b/src/gpu/ops/GrFillRRectOp.cpp
index 5156509..fefd688 100644
--- a/src/gpu/ops/GrFillRRectOp.cpp
+++ b/src/gpu/ops/GrFillRRectOp.cpp
@@ -102,7 +102,7 @@
     GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) {
         return this->createProgramInfo(&flushState->caps(),
                                        flushState->allocator(),
-                                       flushState->view(),
+                                       flushState->outputView(),
                                        flushState->detachAppliedClip(),
                                        flushState->dstProxyView());
     }
diff --git a/src/gpu/ops/GrMeshDrawOp.h b/src/gpu/ops/GrMeshDrawOp.h
index db492af..0ac8b61 100644
--- a/src/gpu/ops/GrMeshDrawOp.h
+++ b/src/gpu/ops/GrMeshDrawOp.h
@@ -191,6 +191,7 @@
     }
 
     virtual GrRenderTargetProxy* proxy() const = 0;
+    virtual const GrSurfaceProxyView* outputView() const = 0;
 
     virtual const GrAppliedClip* appliedClip() const = 0;
     virtual GrAppliedClip detachAppliedClip() = 0;
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
index f978a10..69e8279 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
@@ -136,7 +136,7 @@
                                                 const GrUserStencilSettings* stencilSettings) {
     return CreatePipeline(&flushState->caps(),
                           flushState->allocator(),
-                          flushState->view(),
+                          flushState->outputView(),
                           flushState->detachAppliedClip(),
                           flushState->dstProxyView(),
                           std::move(processorSet),
@@ -147,7 +147,7 @@
 const GrPipeline* GrSimpleMeshDrawOpHelper::createPipeline(GrOpFlushState* flushState) {
     return CreatePipeline(&flushState->caps(),
                           flushState->allocator(),
-                          flushState->view(),
+                          flushState->outputView(),
                           flushState->detachAppliedClip(),
                           flushState->dstProxyView(),
                           this->detachProcessorSet(),
@@ -196,6 +196,25 @@
     return tmp;
 }
 
+GrProgramInfo* GrSimpleMeshDrawOpHelper::createProgramInfo(
+                                            const GrCaps* caps,
+                                            SkArenaAlloc* arena,
+                                            const GrSurfaceProxyView* outputView,
+                                            GrAppliedClip&& appliedClip,
+                                            const GrXferProcessor::DstProxyView& dstProxyView,
+                                            GrGeometryProcessor* gp,
+                                            GrPrimitiveType primType) {
+    return CreateProgramInfo(caps,
+                             arena,
+                             outputView,
+                             std::move(appliedClip),
+                             dstProxyView,
+                             gp,
+                             this->detachProcessorSet(),
+                             primType,
+                             this->pipelineFlags());
+}
+
 #ifdef SK_DEBUG
 static void dump_pipeline_flags(GrPipeline::InputFlags flags, SkString* result) {
     if (GrPipeline::InputFlags::kNone != flags) {
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
index 39b74b3..3916736 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -157,6 +157,14 @@
                                             const GrUserStencilSettings*
                                                                 = &GrUserStencilSettings::kUnused);
 
+    GrProgramInfo* createProgramInfo(const GrCaps*,
+                                     SkArenaAlloc*,
+                                     const GrSurfaceProxyView* outputView,
+                                     GrAppliedClip&&,
+                                     const GrXferProcessor::DstProxyView&,
+                                     GrGeometryProcessor*,
+                                     GrPrimitiveType);
+
     GrProcessorSet detachProcessorSet() {
         return fProcessors ? std::move(*fProcessors) : GrProcessorSet::MakeEmptySet();
     }
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.cpp b/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.cpp
index 3317631..a336fa6 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.cpp
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.cpp
@@ -11,7 +11,7 @@
         GrOpFlushState* flushState) {
     return GrSimpleMeshDrawOpHelper::CreatePipeline(&flushState->caps(),
                                                     flushState->allocator(),
-                                                    flushState->view(),
+                                                    flushState->outputView(),
                                                     flushState->detachAppliedClip(),
                                                     flushState->dstProxyView(),
                                                     this->detachProcessorSet(),
diff --git a/src/gpu/tessellate/GrDrawAtlasPathOp.cpp b/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
index 34740d1..e0dfa11 100644
--- a/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
+++ b/src/gpu/tessellate/GrDrawAtlasPathOp.cpp
@@ -180,8 +180,8 @@
     SkASSERT(shader.instanceStride() == Instance::Stride(fUsesLocalCoords));
 
     GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
-                              state->proxy()->backendFormat(), state->view()->origin(), &pipeline,
-                              &shader, &fixedDynamicState, nullptr, 0,
+                              state->proxy()->backendFormat(), state->outputView()->origin(),
+                              &pipeline, &shader, &fixedDynamicState, nullptr, 0,
                               GrPrimitiveType::kTriangleStrip);
 
     GrMesh mesh;
diff --git a/src/gpu/tessellate/GrPathShader.h b/src/gpu/tessellate/GrPathShader.h
index e5a1f0f..5d23bc1 100644
--- a/src/gpu/tessellate/GrPathShader.h
+++ b/src/gpu/tessellate/GrPathShader.h
@@ -45,7 +45,7 @@
                    const GrPipeline::FixedDynamicState* fixedDynamicState, const GrMesh& mesh,
                    const SkRect& bounds) {
         GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
-                                  state->proxy()->backendFormat(), state->view()->origin(),
+                                  state->proxy()->backendFormat(), state->outputView()->origin(),
                                   pipeline, this, fixedDynamicState, nullptr, 0,
                                   fPrimitiveType, fTessellationPatchVertexCount);
         state->opsRenderPass()->bindPipeline(programInfo, bounds);
diff --git a/tests/GrMeshTest.cpp b/tests/GrMeshTest.cpp
index 8142aa8..375a4c3 100644
--- a/tests/GrMeshTest.cpp
+++ b/tests/GrMeshTest.cpp
@@ -441,7 +441,7 @@
     GrProgramInfo programInfo(fState->proxy()->numSamples(),
                               fState->proxy()->numStencilSamples(),
                               fState->proxy()->backendFormat(),
-                              fState->view()->origin(),
+                              fState->outputView()->origin(),
                               pipeline,
                               mtp,
                               nullptr, nullptr, 0, primitiveType);
diff --git a/tests/GrPipelineDynamicStateTest.cpp b/tests/GrPipelineDynamicStateTest.cpp
index a5ce0a2..961b63b 100644
--- a/tests/GrPipelineDynamicStateTest.cpp
+++ b/tests/GrPipelineDynamicStateTest.cpp
@@ -163,7 +163,7 @@
         GrProgramInfo programInfo(flushState->proxy()->numSamples(),
                                   flushState->proxy()->numStencilSamples(),
                                   flushState->proxy()->backendFormat(),
-                                  flushState->view()->origin(),
+                                  flushState->outputView()->origin(),
                                   &pipeline,
                                   geomProc,
                                   nullptr,
diff --git a/tools/gpu/TestOps.cpp b/tools/gpu/TestOps.cpp
index 41a1c7e..bec5c58 100644
--- a/tools/gpu/TestOps.cpp
+++ b/tools/gpu/TestOps.cpp
@@ -110,7 +110,7 @@
     GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) {
         return this->createProgramInfo(&flushState->caps(),
                                        flushState->allocator(),
-                                       flushState->view(),
+                                       flushState->outputView(),
                                        flushState->detachAppliedClip(),
                                        flushState->dstProxyView());
     }