Revert "Revert "Add a new non-AA rect op that does not inherit from GrLegacyMeshDrawOp.""

This reverts commit 0f353327968530506dd3dd15fca79ef59fe013f1.

Bug: skia:
Change-Id: I8def56fa55bfc70de4386bf0b7a7867f6e91c173
Reviewed-on: https://skia-review.googlesource.com/15251
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h
index 4ba87fe..0fc7b7f 100644
--- a/src/gpu/GrOpFlushState.h
+++ b/src/gpu/GrOpFlushState.h
@@ -10,6 +10,7 @@
 
 #include "GrBufferAllocPool.h"
 #include "GrGpu.h"
+#include "SkArenaAlloc.h"
 #include "ops/GrMeshDrawOp.h"
 
 class GrGpuCommandBuffer;
@@ -94,6 +95,7 @@
     void reset() {
         fVertexPool.reset();
         fIndexPool.reset();
+        fPipelines.reset();
     }
 
     /** Additional data required on a per-op basis when executing GrDrawOps. */
@@ -110,16 +112,22 @@
         return *fOpArgs;
     }
 
+    template <typename... Args>
+    GrPipeline* allocPipeline(Args... args) {
+        return fPipelines.make<GrPipeline>(std::forward<Args>(args)...);
+    }
+
 private:
-    GrGpu*                                      fGpu;
-    GrResourceProvider*                         fResourceProvider;
-    GrGpuCommandBuffer*                         fCommandBuffer;
-    GrVertexBufferAllocPool                     fVertexPool;
-    GrIndexBufferAllocPool                      fIndexPool;
-    SkSTArray<4, GrDrawOp::DeferredUploadFn>    fAsapUploads;
-    GrDrawOpUploadToken                         fLastIssuedToken;
-    GrDrawOpUploadToken                         fLastFlushedToken;
-    DrawOpArgs*                                 fOpArgs;
+    GrGpu* fGpu;
+    GrResourceProvider* fResourceProvider;
+    GrGpuCommandBuffer* fCommandBuffer;
+    GrVertexBufferAllocPool fVertexPool;
+    GrIndexBufferAllocPool fIndexPool;
+    SkSTArray<4, GrDrawOp::DeferredUploadFn> fAsapUploads;
+    GrDrawOpUploadToken fLastIssuedToken;
+    GrDrawOpUploadToken fLastFlushedToken;
+    DrawOpArgs* fOpArgs;
+    SkArenaAlloc fPipelines{sizeof(GrPipeline) * 100};
 };
 
 /**
@@ -182,6 +190,7 @@
 protected:
     GrDrawOp* op() { return fOp; }
     GrOpFlushState* state() { return fState; }
+    const GrOpFlushState* state() const { return fState; }
 
 private:
     GrOpFlushState* fState;
@@ -211,6 +220,19 @@
         this->state()->putBackVertexSpace(vertices * vertexStride);
     }
 
+    GrRenderTarget* renderTarget() const { return this->state()->drawOpArgs().fRenderTarget; }
+
+    const GrAppliedClip* clip() const { return this->state()->drawOpArgs().fAppliedClip; }
+
+    const GrXferProcessor::DstTexture& dstTexture() const {
+        return this->state()->drawOpArgs().fDstTexture;
+    }
+
+    template <typename... Args>
+    GrPipeline* allocPipeline(Args... args) {
+        return this->state()->allocPipeline(std::forward<Args>(args)...);
+    }
+
 private:
     GrMeshDrawOp* meshDrawOp() { return static_cast<GrMeshDrawOp*>(this->op()); }
     typedef GrDrawOp::Target INHERITED;
diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp
index 6c5a041..9bbeec5 100644
--- a/src/gpu/GrPaint.cpp
+++ b/src/gpu/GrPaint.cpp
@@ -12,11 +12,11 @@
 #include "effects/GrSimpleTextureEffect.h"
 
 void GrPaint::setPorterDuffXPFactory(SkBlendMode mode) {
-    fXPFactory = GrPorterDuffXPFactory::Get(mode);
+    this->setXPFactory(GrPorterDuffXPFactory::Get(mode));
 }
 
 void GrPaint::setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) {
-    fXPFactory = GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage);
+    this->setXPFactory(GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage));
 }
 
 void GrPaint::addColorTextureProcessor(GrResourceProvider* resourceProvider,
diff --git a/src/gpu/GrPaint.h b/src/gpu/GrPaint.h
index bcf6858..6fe561a 100644
--- a/src/gpu/GrPaint.h
+++ b/src/gpu/GrPaint.h
@@ -79,11 +79,14 @@
      * as such (with linear blending), and sRGB inputs to be filtered and decoded correctly.
      */
     void setGammaCorrect(bool gammaCorrect) {
-        setDisableOutputConversionToSRGB(!gammaCorrect);
-        setAllowSRGBInputs(gammaCorrect);
+        this->setDisableOutputConversionToSRGB(!gammaCorrect);
+        this->setAllowSRGBInputs(gammaCorrect);
     }
 
-    void setXPFactory(const GrXPFactory* xpFactory) { fXPFactory = xpFactory; }
+    void setXPFactory(const GrXPFactory* xpFactory) {
+        fXPFactory = xpFactory;
+        fTrivial &= !SkToBool(xpFactory);
+    }
 
     void setPorterDuffXPFactory(SkBlendMode mode);
 
@@ -96,6 +99,7 @@
         SkASSERT(fp);
         fUsesDistanceVectorField |= fp->usesDistanceVectorField();
         fColorFragmentProcessors.push_back(std::move(fp));
+        fTrivial = false;
     }
 
     /**
@@ -105,6 +109,7 @@
         SkASSERT(fp);
         fUsesDistanceVectorField |= fp->usesDistanceVectorField();
         fCoverageFragmentProcessors.push_back(std::move(fp));
+        fTrivial = false;
     }
 
     /**
@@ -143,6 +148,12 @@
      */
     bool isConstantBlendedColor(GrColor* constantColor) const;
 
+    /**
+     * A trivial paint is one that uses src-over and has no fragment processors.
+     * It may have variable sRGB settings.
+     **/
+    bool isTrivial() const { return fTrivial; }
+
 private:
     template <bool> class MoveOrImpl;
 
@@ -172,6 +183,7 @@
     bool fDisableOutputConversionToSRGB = false;
     bool fAllowSRGBInputs = false;
     bool fUsesDistanceVectorField = false;
+    bool fTrivial = true;
     GrColor4f fColor = GrColor4f::OpaqueWhite();
 };
 
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 3bac5f7..7fa42d0 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -90,6 +90,8 @@
      **/
     GrPipeline(GrRenderTarget*, SkBlendMode);
 
+    GrPipeline(const InitArgs& args) { this->init(args); }
+
     /** (Re)initializes a pipeline. After initialization the pipeline can be used. */
     void init(const InitArgs&);
 
diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp
index 69fa69a..db73266 100644
--- a/src/gpu/GrProcessorSet.cpp
+++ b/src/gpu/GrProcessorSet.cpp
@@ -11,6 +11,8 @@
 #include "GrXferProcessor.h"
 #include "effects/GrPorterDuffXferProcessor.h"
 
+const GrProcessorSet GrProcessorSet::gEmpty{GrProcessorSet::Empty::kEmpty};
+
 GrProcessorSet::GrProcessorSet(GrPaint&& paint) : fXP(paint.getXPFactory()) {
     fFlags = 0;
     if (paint.numColorFragmentProcessors() <= kMaxColorProcessors) {
diff --git a/src/gpu/GrProcessorSet.h b/src/gpu/GrProcessorSet.h
index 6ebb00b..56cbee1 100644
--- a/src/gpu/GrProcessorSet.h
+++ b/src/gpu/GrProcessorSet.h
@@ -18,6 +18,10 @@
 class GrXPFactory;
 
 class GrProcessorSet : private SkNoncopyable {
+private:
+    // Arbitrary constructor arg for empty set and analysis
+    enum class Empty { kEmpty };
+
 public:
     GrProcessorSet(GrPaint&& paint);
 
@@ -80,6 +84,14 @@
         }
 
     private:
+        constexpr Analysis(Empty)
+                : fUsesLocalCoords(false)
+                , fCompatibleWithCoverageAsAlpha(true)
+                , fRequiresDstTexture(false)
+                , fCanCombineOverlappedStencilAndCover(true)
+                , fRequiresBarrierBetweenOverlappingDraws(false)
+                , fIsInitialized(true)
+                , fInputColorType(kOriginal_InputColorType) {}
         enum InputColorType : uint32_t {
             kOriginal_InputColorType,
             kOverridden_InputColorType,
@@ -122,7 +134,13 @@
 
     bool isFinalized() const { return SkToBool(kFinalized_Flag & fFlags); }
 
+    static const GrProcessorSet& EmptySet() { return gEmpty; }
+    static constexpr const Analysis EmptySetAnalysis() { return Analysis(Empty::kEmpty); }
+
 private:
+    GrProcessorSet(Empty) : fXP((const GrXferProcessor*)nullptr), fFlags(kFinalized_Flag) {}
+    static const GrProcessorSet gEmpty;
+
     // This absurdly large limit allows Analysis and this to pack fields together.
     static constexpr int kMaxColorProcessors = UINT8_MAX;
 
@@ -130,6 +148,7 @@
 
     union XP {
         XP(const GrXPFactory* factory) : fFactory(factory) {}
+        XP(const GrXferProcessor* processor) : fProcessor(processor) {}
         const GrXPFactory* fFactory;
         const GrXferProcessor* fProcessor;
     };
@@ -141,7 +160,7 @@
 
     SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors;
     XP fXP;
-    uint8_t fColorFragmentProcessorCnt;
+    uint8_t fColorFragmentProcessorCnt = 0;
     uint8_t fFragmentProcessorOffset = 0;
     uint8_t fFlags;
 };
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 6e72441..e21522f 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "GrRenderTargetContext.h"
+#include "../private/GrAuditTrail.h"
 #include "GrAppliedClip.h"
 #include "GrColor.h"
 #include "GrContextPriv.h"
@@ -27,10 +28,11 @@
 #include "ops/GrClearOp.h"
 #include "ops/GrClearStencilClipOp.h"
 #include "ops/GrDiscardOp.h"
-#include "ops/GrDrawOp.h"
 #include "ops/GrDrawAtlasOp.h"
+#include "ops/GrDrawOp.h"
 #include "ops/GrDrawVerticesOp.h"
 #include "ops/GrLatticeOp.h"
+#include "ops/GrNewNonAAFillRectOp.h"
 #include "ops/GrOp.h"
 #include "ops/GrOvalOpFactory.h"
 #include "ops/GrRectOpFactory.h"
@@ -39,7 +41,6 @@
 #include "ops/GrStencilPathOp.h"
 #include "text/GrAtlasTextContext.h"
 #include "text/GrStencilAndCoverTextContext.h"
-#include "../private/GrAuditTrail.h"
 
 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
 #define ASSERT_SINGLE_OWNER \
@@ -1275,7 +1276,13 @@
                                                 const GrUserStencilSettings* ss,
                                                 GrAAType hwOrNoneAAType) {
     SkASSERT(GrAAType::kCoverage != hwOrNoneAAType);
-    SkASSERT(hwOrNoneAAType == GrAAType::kNone || this->isStencilBufferMultisampled());
+    SkASSERT(GrAAType::kNone == hwOrNoneAAType || this->isStencilBufferMultisampled());
+    if (!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective())) {
+        std::unique_ptr<GrDrawOp> op = GrNewNonAAFillRectOp::Make(
+                std::move(paint), viewMatrix, rect, localRect, localMatrix, hwOrNoneAAType, ss);
+        this->addDrawOp(clip, std::move(op));
+        return;
+    }
     std::unique_ptr<GrLegacyMeshDrawOp> op = GrRectOpFactory::MakeNonAAFill(
             paint.getColor(), viewMatrix, rect, localRect, localMatrix);
     GrPipelineBuilder pipelineBuilder(std::move(paint), hwOrNoneAAType);
diff --git a/src/gpu/ops/GrMeshDrawOp.cpp b/src/gpu/ops/GrMeshDrawOp.cpp
index 92571d6..ee7c0a5 100644
--- a/src/gpu/ops/GrMeshDrawOp.cpp
+++ b/src/gpu/ops/GrMeshDrawOp.cpp
@@ -67,8 +67,6 @@
 }
 
 void GrMeshDrawOp::onExecute(GrOpFlushState* state) {
-    SkASSERT(!state->drawOpArgs().fAppliedClip);
-    SkASSERT(!state->drawOpArgs().fDstTexture.texture());
     int currUploadIdx = 0;
     int currMeshIdx = 0;
 
diff --git a/src/gpu/ops/GrNewNonAAFillRectOp.cpp b/src/gpu/ops/GrNewNonAAFillRectOp.cpp
new file mode 100644
index 0000000..15e025a
--- /dev/null
+++ b/src/gpu/ops/GrNewNonAAFillRectOp.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrNewNonAAFillRectOp.h"
+#include "GrAppliedClip.h"
+#include "GrColor.h"
+#include "GrDefaultGeoProcFactory.h"
+#include "GrMeshDrawOp.h"
+#include "GrOpFlushState.h"
+#include "GrPrimitiveProcessor.h"
+#include "GrQuad.h"
+#include "GrResourceProvider.h"
+#include "GrSimpleMeshDrawOpHelper.h"
+#include "SkMatrixPriv.h"
+
+static const int kVertsPerRect = 4;
+static const int kIndicesPerRect = 6;
+
+/** We always use per-vertex colors so that rects can be combined across color changes. Sometimes
+    we  have explicit local coords and sometimes not. We *could* always provide explicit local
+    coords and just duplicate the positions when the caller hasn't provided a local coord rect,
+    but we haven't seen a use case which frequently switches between local rect and no local
+    rect draws.
+
+    The vertex attrib order is always pos, color, [local coords].
+ */
+static sk_sp<GrGeometryProcessor> make_gp() {
+    using namespace GrDefaultGeoProcFactory;
+    return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type,
+                                         LocalCoords::kHasExplicit_Type, SkMatrix::I());
+}
+
+static void tesselate(intptr_t vertices,
+                      size_t vertexStride,
+                      GrColor color,
+                      const SkMatrix* viewMatrix,
+                      const SkRect& rect,
+                      const GrQuad* localQuad) {
+    SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
+
+    positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
+
+    if (viewMatrix) {
+        SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerRect);
+    }
+
+    // Setup local coords
+    // TODO we should only do this if local coords are being read
+    if (localQuad) {
+        static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
+        for (int i = 0; i < kVertsPerRect; i++) {
+            SkPoint* coords =
+                    reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride);
+            *coords = localQuad->point(i);
+        }
+    }
+
+    static const int kColorOffset = sizeof(SkPoint);
+    GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
+    for (int j = 0; j < 4; ++j) {
+        *vertColor = color;
+        vertColor = (GrColor*)((intptr_t)vertColor + vertexStride);
+    }
+}
+
+class NewNonAAFillRectOp final : public GrMeshDrawOp {
+private:
+    using Helper = GrSimpleMeshDrawOpHelperWithStencil;
+
+public:
+    DEFINE_OP_CLASS_ID
+    NewNonAAFillRectOp() = delete;
+
+    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
+                                          const SkRect& rect, const SkRect* localRect,
+                                          const SkMatrix* localMatrix, GrAAType aaType,
+                                          const GrUserStencilSettings* stencilSettings) {
+        SkASSERT(GrAAType::kCoverage != aaType);
+        return Helper::FactoryHelper<NewNonAAFillRectOp>(std::move(paint), viewMatrix, rect,
+                                                         localRect, localMatrix, aaType,
+                                                         stencilSettings);
+    }
+
+    const char* name() const override { return "NonAAFillRectOp"; }
+
+    SkString dumpInfo() const override {
+        SkString str;
+        str.append(GrMeshDrawOp::dumpInfo());
+        str.appendf("# combined: %d\n", fRects.count());
+        for (int i = 0; i < fRects.count(); ++i) {
+            const RectInfo& info = fRects[i];
+            str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
+                        info.fColor, info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight,
+                        info.fRect.fBottom);
+        }
+        return str;
+    }
+
+    bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
+        GrColor* color = &fRects.front().fColor;
+        return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
+    }
+
+    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
+
+    NewNonAAFillRectOp(const Helper::MakeArgs& args, GrColor color, const SkMatrix& viewMatrix,
+                       const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix,
+                       GrAAType aaType, const GrUserStencilSettings* stencilSettings)
+            : INHERITED(ClassID()), fHelper(args, aaType, stencilSettings) {
+        SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective()));
+        RectInfo& info = fRects.push_back();
+        info.fColor = color;
+        info.fViewMatrix = viewMatrix;
+        info.fRect = rect;
+        if (localRect && localMatrix) {
+            info.fLocalQuad.setFromMappedRect(*localRect, *localMatrix);
+        } else if (localRect) {
+            info.fLocalQuad.set(*localRect);
+        } else if (localMatrix) {
+            info.fLocalQuad.setFromMappedRect(rect, *localMatrix);
+        } else {
+            info.fLocalQuad.set(rect);
+        }
+        this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
+    }
+
+private:
+    void onPrepareDraws(Target* target) const override {
+        sk_sp<GrGeometryProcessor> gp = make_gp();
+        if (!gp) {
+            SkDebugf("Couldn't create GrGeometryProcessor\n");
+            return;
+        }
+        SkASSERT(gp->getVertexStride() ==
+                 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
+
+        size_t vertexStride = gp->getVertexStride();
+        int rectCount = fRects.count();
+
+        sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
+        PatternHelper helper;
+        void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
+                                     indexBuffer.get(), kVertsPerRect, kIndicesPerRect, rectCount);
+        if (!vertices || !indexBuffer) {
+            SkDebugf("Could not allocate vertices\n");
+            return;
+        }
+
+        for (int i = 0; i < rectCount; i++) {
+            intptr_t verts =
+                    reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
+            tesselate(verts, vertexStride, fRects[i].fColor, &fRects[i].fViewMatrix,
+                      fRects[i].fRect, &fRects[i].fLocalQuad);
+        }
+        helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
+    }
+
+    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+        NewNonAAFillRectOp* that = t->cast<NewNonAAFillRectOp>();
+        if (!fHelper.isCompatible(that->fHelper)) {
+            return false;
+        }
+        fRects.push_back_n(that->fRects.count(), that->fRects.begin());
+        this->joinBounds(*that);
+        return true;
+    }
+
+    struct RectInfo {
+        GrColor fColor;
+        SkMatrix fViewMatrix;
+        SkRect fRect;
+        GrQuad fLocalQuad;
+    };
+
+    Helper fHelper;
+    SkSTArray<1, RectInfo, true> fRects;
+    typedef GrMeshDrawOp INHERITED;
+};
+
+namespace GrNewNonAAFillRectOp {
+
+std::unique_ptr<GrDrawOp> Make(GrPaint&& paint,
+                               const SkMatrix& viewMatrix,
+                               const SkRect& rect,
+                               const SkRect* localRect,
+                               const SkMatrix* localMatrix,
+                               GrAAType aaType,
+                               const GrUserStencilSettings* stencilSettings) {
+    return NewNonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, localRect, localMatrix,
+                                    aaType, stencilSettings);
+}
+};  // namespace GrNewNonAAFillRectOp
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/ops/GrNewNonAAFillRectOp.h b/src/gpu/ops/GrNewNonAAFillRectOp.h
new file mode 100644
index 0000000..8f78707
--- /dev/null
+++ b/src/gpu/ops/GrNewNonAAFillRectOp.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrNewNonAAFillRectOp_DEFINED
+#define GrNewNonAAFillRectOp_DEFINED
+
+#include <memory>
+#include "GrColor.h"
+
+class GrDrawOp;
+class GrPaint;
+class SkMatrix;
+struct SkRect;
+struct GrUserStencilSettings;
+enum class GrAAType : unsigned;
+
+namespace GrNewNonAAFillRectOp {
+std::unique_ptr<GrDrawOp> Make(GrPaint&&,
+                               const SkMatrix& viewMatrix,
+                               const SkRect& rect,
+                               const SkRect* localRect,
+                               const SkMatrix* localMatrix,
+                               GrAAType,
+                               const GrUserStencilSettings* = nullptr);
+};
+
+#endif
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
new file mode 100644
index 0000000..f64f9ec
--- /dev/null
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrSimpleMeshDrawOpHelper_DEFINED
+#define GrSimpleMeshDrawOpHelper_DEFINED
+
+#include "GrAppliedClip.h"
+#include "GrOpFlushState.h"
+#include "GrPipeline.h"
+#include "GrProcessorSet.h"
+#include "GrUserStencilSettings.h"
+
+/**
+ * This class can be used to help implement simple mesh draw ops. It reduces the amount of
+ * boilerplate code to type and also provides a mechanism for optionally allocating space for a
+ * GrProcessorSet based on a GrPaint. It is intended to be used by ops that construct a single
+ * GrPipeline for a uniform primitive color and a GrPaint.
+ */
+class GrSimpleMeshDrawOpHelper {
+public:
+    struct MakeArgs;
+
+    /**
+     * This can be used by a Op class to perform allocation and initialization such that a
+     * GrProcessorSet (if required) is allocated at the same time as the Op instance. It requires
+     * that Op implements a constructor of the form:
+     *      Op(MakeArgs, GrColor, OpArgs...)
+     * which is public or made accessible via 'friend'.
+     */
+    template <typename Op, typename... OpArgs>
+    static std::unique_ptr<GrDrawOp> FactoryHelper(GrPaint&& paint, OpArgs... opArgs);
+
+    GrSimpleMeshDrawOpHelper(const MakeArgs& args, GrAAType aaType,
+                             GrUserStencilSettings* stencilSettings = nullptr)
+            : fProcessors(args.fProcessorSet)
+            , fPipelineFlags(args.fSRGBFlags)
+            , fAAType((int)aaType) {
+        SkASSERT(!stencilSettings);
+        if (GrAATypeIsHW(aaType)) {
+            fPipelineFlags |= GrPipeline::kHWAntialias_Flag;
+        }
+    }
+
+    ~GrSimpleMeshDrawOpHelper() {
+        if (fProcessors) {
+            fProcessors->~GrProcessorSet();
+        }
+    }
+
+    GrSimpleMeshDrawOpHelper() = delete;
+    GrSimpleMeshDrawOpHelper(const GrSimpleMeshDrawOpHelper&) = delete;
+    GrSimpleMeshDrawOpHelper& operator=(const GrSimpleMeshDrawOpHelper&) = delete;
+
+    GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const {
+        return GrAATypeIsHW((this->aaType())) ? GrDrawOp::FixedFunctionFlags::kUsesHWAA
+                                              : GrDrawOp::FixedFunctionFlags::kNone;
+    }
+
+    bool isCompatible(const GrSimpleMeshDrawOpHelper& that) const {
+        if (SkToBool(fProcessors) != SkToBool(that.fProcessors)) {
+            return false;
+        }
+        if (SkToBool(fProcessors) && *fProcessors != *that.fProcessors) {
+            return false;
+        }
+        return fPipelineFlags == that.fPipelineFlags && fAAType == that.fAAType;
+    }
+
+    bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip,
+                              GrProcessorAnalysisCoverage geometryCoverage, GrColor* color) {
+        if (fProcessors) {
+            GrProcessorAnalysisCoverage coverage = geometryCoverage;
+            if (GrProcessorAnalysisCoverage::kNone == coverage) {
+                coverage = clip->clipCoverageFragmentProcessor()
+                                   ? GrProcessorAnalysisCoverage::kSingleChannel
+                                   : GrProcessorAnalysisCoverage::kNone;
+            }
+            bool isMixedSamples = this->aaType() == GrAAType::kMixedSamples;
+            GrProcessorSet::Analysis analysis =
+                    fProcessors->finalize(*color, coverage, clip, isMixedSamples, caps, color);
+            return analysis.requiresDstTexture();
+        } else {
+            return GrProcessorSet::EmptySetAnalysis().requiresDstTexture();
+        }
+    }
+
+    GrPipeline* makePipeline(GrMeshDrawOp::Target* target) const {
+        return target->allocPipeline(this->pipelineInitArgs(target));
+    }
+
+    struct MakeArgs {
+    private:
+        MakeArgs() = default;
+
+        GrProcessorSet* fProcessorSet;
+        uint32_t fSRGBFlags;
+
+        friend class GrSimpleMeshDrawOpHelper;
+    };
+
+protected:
+    GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
+    uint32_t pipelineFlags() const { return fPipelineFlags; }
+    const GrProcessorSet& processors() const {
+        return fProcessors ? *fProcessors : GrProcessorSet::EmptySet();
+    }
+
+    GrPipeline::InitArgs pipelineInitArgs(GrMeshDrawOp::Target* target) const {
+        GrPipeline::InitArgs args;
+        args.fFlags = this->pipelineFlags();
+        args.fProcessors = &this->processors();
+        args.fRenderTarget = target->renderTarget();
+        args.fAppliedClip = target->clip();
+        args.fDstTexture = target->dstTexture();
+        args.fCaps = &target->caps();
+        return args;
+    }
+
+private:
+    GrProcessorSet* fProcessors;
+    unsigned fPipelineFlags : 8;
+    unsigned fAAType : 2;
+};
+
+/**
+ * This class extends GrSimpleMeshDrawOpHelper to support an optional GrUserStencilSettings. This
+ * uses private inheritance because it non-virtually overrides methods in the base class and should
+ * never be used with a GrSimpleMeshDrawOpHelper pointer or reference.
+ */
+class GrSimpleMeshDrawOpHelperWithStencil : private GrSimpleMeshDrawOpHelper {
+public:
+    using MakeArgs = GrSimpleMeshDrawOpHelper::MakeArgs;
+
+    // using declarations can't be templated, so this is a pass through function instead.
+    template <typename Op, typename... OpArgs>
+    static std::unique_ptr<GrDrawOp> FactoryHelper(GrPaint&& paint, OpArgs... opArgs) {
+        return GrSimpleMeshDrawOpHelper::FactoryHelper<Op, OpArgs...>(
+                std::move(paint), std::forward<OpArgs>(opArgs)...);
+    }
+
+    GrSimpleMeshDrawOpHelperWithStencil(const MakeArgs& args, GrAAType aaType,
+                                         const GrUserStencilSettings* stencilSettings)
+            : INHERITED(args, aaType)
+            , fStencilSettings(stencilSettings ? stencilSettings
+                                               : &GrUserStencilSettings::kUnused) {}
+
+    GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const {
+        GrDrawOp::FixedFunctionFlags flags = INHERITED::fixedFunctionFlags();
+        if (fStencilSettings != &GrUserStencilSettings::kUnused) {
+            flags |= GrDrawOp::FixedFunctionFlags::kUsesStencil;
+        }
+        return flags;
+    }
+
+    using GrSimpleMeshDrawOpHelper::xpRequiresDstTexture;
+
+    bool isCompatible(const GrSimpleMeshDrawOpHelperWithStencil& that) const {
+        return INHERITED::isCompatible(that) && fStencilSettings == that.fStencilSettings;
+    }
+
+    GrPipeline* makePipeline(GrMeshDrawOp::Target* target) const {
+        auto args = INHERITED::pipelineInitArgs(target);
+        args.fUserStencil = fStencilSettings;
+        return target->allocPipeline(args);
+    }
+
+private:
+    const GrUserStencilSettings* fStencilSettings;
+    typedef GrSimpleMeshDrawOpHelper INHERITED;
+};
+
+template <typename Op, typename... OpArgs>
+std::unique_ptr<GrDrawOp> GrSimpleMeshDrawOpHelper::FactoryHelper(GrPaint&& paint,
+                                                                  OpArgs... opArgs) {
+    MakeArgs makeArgs;
+    makeArgs.fSRGBFlags = GrPipeline::SRGBFlagsFromPaint(paint);
+    GrColor color = paint.getColor();
+    if (paint.isTrivial()) {
+        makeArgs.fProcessorSet = nullptr;
+        return std::unique_ptr<GrDrawOp>(new Op(makeArgs, color, std::forward<OpArgs>(opArgs)...));
+    } else {
+        char* mem = (char*)GrOp::operator new(sizeof(Op) + sizeof(GrProcessorSet));
+        char* setMem = mem + sizeof(Op);
+        makeArgs.fProcessorSet = new (setMem) GrProcessorSet(std::move(paint));
+        return std::unique_ptr<GrDrawOp>(
+                new (mem) Op(makeArgs, color, std::forward<OpArgs>(opArgs)...));
+    }
+}
+
+#endif