Revert "fill rect batch refactor into separate batches"

This reverts commit ae41b3834301444cf27b8aa729b8ad36666bdc08.

TBR=bsalomon@google.com
BUG=skia:

Review URL: https://codereview.chromium.org/1301203002
diff --git a/src/gpu/batches/GrBWFillRectBatch.cpp b/src/gpu/batches/GrBWFillRectBatch.cpp
index 5c14aae..f9ba268 100644
--- a/src/gpu/batches/GrBWFillRectBatch.cpp
+++ b/src/gpu/batches/GrBWFillRectBatch.cpp
@@ -12,275 +12,229 @@
 #include "GrDefaultGeoProcFactory.h"
 #include "GrPrimitiveProcessor.h"
 #include "GrQuad.h"
-#include "GrResourceProvider.h"
-#include "GrTInstanceBatch.h"
 #include "GrVertexBatch.h"
 
-// Common functions
-class BWFillRectBatchBase {
+class GrBatchFlushState;
+class SkMatrix;
+struct SkRect;
+
+class BWFillRectBatch : public GrVertexBatch {
 public:
-    static const int kVertsPerInstance = 4;
-    static const int kIndicesPerInstance = 6;
+    struct Geometry {
+        SkMatrix fViewMatrix;
+        SkRect fRect;
+        SkRect fLocalRect;
+        SkMatrix fLocalMatrix;
+        GrColor fColor;
+        bool fHasLocalRect;
+        bool fHasLocalMatrix;
+    };
 
-    static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* rp) {
-        return rp->refQuadIndexBuffer();
+    static GrDrawBatch* Create(const Geometry& geometry) {
+        return SkNEW_ARGS(BWFillRectBatch, (geometry));
     }
 
-    template <typename Geometry>
-    static void SetBounds(const Geometry& geo, SkRect* outBounds) {
-        geo.fViewMatrix.mapRect(outBounds, geo.fRect);
+    const char* name() const override { return "RectBatch"; }
+
+    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
+        // When this is called on a batch, there is only one geometry bundle
+        out->setKnownFourComponents(fGeoData[0].fColor);
     }
-};
 
-/** We always use per-vertex colors so that rects can be batched 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 color param is used to determine whether the opaque hint can be set on the draw state.
-    The caller must populate the vertex colors itself.
-
-    The vertex attrib order is always pos, color, [local coords].
- */
-static const GrGeometryProcessor* create_gp(const SkMatrix& viewMatrix,
-                                            bool readsCoverage,
-                                            bool hasExplicitLocalCoords,
-                                            const SkMatrix* localMatrix) {
-    using namespace GrDefaultGeoProcFactory;
-    Color color(Color::kAttribute_Type);
-    Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Type);
-
-    // if we have a local rect, then we apply the localMatrix directly to the localRect to
-    // generate vertex local coords
-    if (hasExplicitLocalCoords) {
-        LocalCoords localCoords(LocalCoords::kHasExplicit_Type);
-        return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I());
-    } else {
-        LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix ? localMatrix : NULL);
-        return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, localCoords,
-                                                             viewMatrix);
+    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
+        out->setKnownSingleComponent(0xff);
     }
-}
 
-static void tesselate(intptr_t vertices,
-                      size_t vertexStride,
-                      GrColor color,
-                      const SkMatrix& viewMatrix,
-                      const SkRect& rect,
-                      const SkRect* localRect,
-                      const SkMatrix* localMatrix) {
-    SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
+    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
-    positions->setRectFan(rect.fLeft, rect.fTop,
-                          rect.fRight, rect.fBottom, vertexStride);
-    viewMatrix.mapPointsWithStride(positions, vertexStride, BWFillRectBatchBase::kVertsPerInstance);
+private:
+    BWFillRectBatch(const Geometry& geometry) {
+        this->initClassID<BWFillRectBatch>();
+        fGeoData.push_back(geometry);
 
-    // TODO we should only do this if local coords are being read
-    if (localRect) {
-        static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
-        SkPoint* coords = reinterpret_cast<SkPoint*>(vertices + kLocalOffset);
-        coords->setRectFan(localRect->fLeft, localRect->fTop,
-                           localRect->fRight, localRect->fBottom,
-                           vertexStride);
-        if (localMatrix) {
-            localMatrix->mapPointsWithStride(coords, vertexStride,
-                                             BWFillRectBatchBase::kVertsPerInstance);
+        fBounds = geometry.fRect;
+        geometry.fViewMatrix.mapRect(&fBounds);
+    }
+
+    GrColor color() const { return fBatch.fColor; }
+    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
+    bool colorIgnored() const { return fBatch.fColorIgnored; }
+    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
+    const SkMatrix& localMatrix() const { return fGeoData[0].fLocalMatrix; }
+    bool hasLocalRect() const { return fGeoData[0].fHasLocalRect; }
+    bool hasLocalMatrix() const { return fGeoData[0].fHasLocalMatrix; }
+    bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
+
+    void initBatchTracker(const GrPipelineOptimizations& init) override {
+        // Handle any color overrides
+        if (!init.readsColor()) {
+            fGeoData[0].fColor = GrColor_ILLEGAL;
+        }
+        init.getOverrideColorIfSet(&fGeoData[0].fColor);
+
+        // setup batch properties
+        fBatch.fColorIgnored = !init.readsColor();
+        fBatch.fColor = fGeoData[0].fColor;
+        fBatch.fUsesLocalCoords = init.readsLocalCoords();
+        fBatch.fCoverageIgnored = !init.readsCoverage();
+    }
+
+    void onPrepareDraws(Target* target) override {
+        SkAutoTUnref<const GrGeometryProcessor> gp(this->createRectGP());
+        if (!gp) {
+            SkDebugf("Could not create GrGeometryProcessor\n");
+            return;
+        }
+
+        target->initDraw(gp, this->pipeline());
+
+        int instanceCount = fGeoData.count();
+        size_t vertexStride = gp->getVertexStride();
+        SkASSERT(this->hasLocalRect() ?
+                 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) :
+                 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
+        QuadHelper helper;
+        void* vertices = helper.init(target, vertexStride, instanceCount);
+
+        if (!vertices) {
+            return;
+        }
+
+        for (int i = 0; i < instanceCount; i++) {
+            const Geometry& geom = fGeoData[i];
+
+            intptr_t offset = reinterpret_cast<intptr_t>(vertices) +
+                              kVerticesPerQuad * i * vertexStride;
+            SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
+
+            positions->setRectFan(geom.fRect.fLeft, geom.fRect.fTop,
+                                  geom.fRect.fRight, geom.fRect.fBottom, vertexStride);
+            geom.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVerticesPerQuad);
+
+            // TODO we should only do this if local coords are being read
+            if (geom.fHasLocalRect) {
+                static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
+                SkPoint* coords = reinterpret_cast<SkPoint*>(offset + kLocalOffset);
+                coords->setRectFan(geom.fLocalRect.fLeft, geom.fLocalRect.fTop,
+                                   geom.fLocalRect.fRight, geom.fLocalRect.fBottom,
+                                   vertexStride);
+                if (geom.fHasLocalMatrix) {
+                    geom.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVerticesPerQuad);
+                }
+            }
+
+            static const int kColorOffset = sizeof(SkPoint);
+            GrColor* vertColor = reinterpret_cast<GrColor*>(offset + kColorOffset);
+            for (int j = 0; j < 4; ++j) {
+                *vertColor = geom.fColor;
+                vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride);
+            }
+        }
+
+        helper.recordDraw(target);
+    }
+
+    bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
+        BWFillRectBatch* that = t->cast<BWFillRectBatch>();
+        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
+                                    that->bounds(), caps)) {
+            return false;
+        }
+
+        if (this->hasLocalRect() != that->hasLocalRect()) {
+            return false;
+        }
+
+        SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
+        if (!this->hasLocalRect() && this->usesLocalCoords()) {
+            if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
+                return false;
+            }
+
+            if (this->hasLocalMatrix() != that->hasLocalMatrix()) {
+                return false;
+            }
+
+            if (this->hasLocalMatrix() && !this->localMatrix().cheapEqualTo(that->localMatrix())) {
+                return false;
+            }
+        }
+
+        if (this->color() != that->color()) {
+            fBatch.fColor = GrColor_ILLEGAL;
+        }
+        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+        this->joinBounds(that->bounds());
+        return true;
+    }
+
+
+    /** We always use per-vertex colors so that rects can be batched 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 color param is used to determine whether the opaque hint can be set on the draw state.
+        The caller must populate the vertex colors itself.
+
+        The vertex attrib order is always pos, color, [local coords].
+     */
+    const GrGeometryProcessor* createRectGP() const {
+        using namespace GrDefaultGeoProcFactory;
+        Color color(Color::kAttribute_Type);
+        Coverage coverage(this->coverageIgnored() ? Coverage::kNone_Type : Coverage::kSolid_Type);
+
+        // if we have a local rect, then we apply the localMatrix directly to the localRect to
+        // generate vertex local coords
+        if (this->hasLocalRect()) {
+            LocalCoords localCoords(LocalCoords::kHasExplicit_Type);
+            return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I());
+        } else {
+            LocalCoords localCoords(LocalCoords::kUsePosition_Type,
+                                    this->hasLocalMatrix() ? &this->localMatrix() : NULL);
+            return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, localCoords,
+                                                                 this->viewMatrix());
         }
     }
 
-    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 BWFillRectBatchNoLocalMatrixImp : public BWFillRectBatchBase {
-public:
-    struct Geometry {
-        SkMatrix fViewMatrix;
-        SkRect fRect;
+    struct BatchTracker {
         GrColor fColor;
+        bool fUsesLocalCoords;
+        bool fColorIgnored;
+        bool fCoverageIgnored;
     };
 
-    static const char* Name() { return "BWFillRectBatchNoLocalMatrix"; }
-
-    static bool CanCombine(const Geometry& mine, const Geometry& theirs,
-                           const GrPipelineOptimizations& opts) {
-        // We apply the viewmatrix to the rect points on the cpu.  However, if the pipeline uses
-        // local coords then we won't be able to batch.  We could actually upload the viewmatrix
-        // using vertex attributes in these cases, but haven't investigated that
-        return !opts.readsLocalCoords() || mine.fViewMatrix.cheapEqualTo(theirs.fViewMatrix);
-    }
-
-    static const GrGeometryProcessor* CreateGP(const Geometry& geo,
-                                               const GrPipelineOptimizations& opts) {
-        const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCoverage(), false,
-                                                  NULL);
-
-        SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
-        return gp;
-    }
-
-    static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
-                          const GrPipelineOptimizations& opts) {
-        tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, NULL, NULL);
-    }
+    BatchTracker fBatch;
+    SkSTArray<1, Geometry, true> fGeoData;
 };
 
-class BWFillRectBatchLocalMatrixImp : public BWFillRectBatchBase {
-public:
-    struct Geometry {
-        SkMatrix fViewMatrix;
-        SkMatrix fLocalMatrix;
-        SkRect fRect;
-        GrColor fColor;
-    };
-
-    static const char* Name() { return "BWFillRectBatchLocalMatrix"; }
-
-    static bool CanCombine(const Geometry& mine, const Geometry& theirs,
-                           const GrPipelineOptimizations& opts) {
-        // We apply the viewmatrix to the rect points on the cpu.  However, if the pipeline uses
-        // local coords then we won't be able to batch.  We could actually upload the viewmatrix
-        // using vertex attributes in these cases, but haven't investigated that
-        return !opts.readsLocalCoords() || mine.fViewMatrix.cheapEqualTo(theirs.fViewMatrix);
-    }
-
-    static const GrGeometryProcessor* CreateGP(const Geometry& geo,
-                                               const GrPipelineOptimizations& opts) {
-        const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCoverage(), false,
-                                                  &geo.fLocalMatrix);
-
-        SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
-        return gp;
-    }
-
-    static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
-                          const GrPipelineOptimizations& opts) {
-        tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, NULL,
-                  &geo.fLocalMatrix);
-    }
-};
-
-class BWFillRectBatchLocalRectImp : public BWFillRectBatchBase {
-public:
-    struct Geometry {
-        SkMatrix fViewMatrix;
-        SkRect fRect;
-        SkRect fLocalRect;
-        GrColor fColor;
-    };
-
-    static const char* Name() { return "BWFillRectBatchLocalRect"; }
-
-    static bool CanCombine(const Geometry& mine, const Geometry& theirs,
-                           const GrPipelineOptimizations& opts) {
-        return true;
-    }
-
-    static const GrGeometryProcessor* CreateGP(const Geometry& geo,
-                                               const GrPipelineOptimizations& opts) {
-        const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCoverage(), true,
-                                                  NULL);
-
-        SkASSERT(gp->getVertexStride() ==
-                sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
-        return gp;
-    }
-
-    static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
-                          const GrPipelineOptimizations& opts) {
-        tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, &geo.fLocalRect,
-                  NULL);
-    }
-};
-
-class BWFillRectBatchLocalMatrixLocalRectImp : public BWFillRectBatchBase {
-public:
-    struct Geometry {
-        SkMatrix fViewMatrix;
-        SkMatrix fLocalMatrix;
-        SkRect fRect;
-        SkRect fLocalRect;
-        GrColor fColor;
-    };
-
-    static const char* Name() { return "BWFillRectBatchLocalMatrixLocalRect"; }
-
-    static bool CanCombine(const Geometry& mine, const Geometry& theirs,
-                           const GrPipelineOptimizations& opts) {
-        return true;
-    }
-
-    static const GrGeometryProcessor* CreateGP(const Geometry& geo,
-                                               const GrPipelineOptimizations& opts) {
-        const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCoverage(), true,
-                                                  NULL);
-
-        SkASSERT(gp->getVertexStride() ==
-                sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
-        return gp;
-    }
-
-    static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
-                          const GrPipelineOptimizations& opts) {
-        tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, &geo.fLocalRect,
-                  &geo.fLocalMatrix);
-    }
-};
-
-typedef GrTInstanceBatch<BWFillRectBatchNoLocalMatrixImp> BWFillRectBatchSimple;
-typedef GrTInstanceBatch<BWFillRectBatchLocalMatrixImp> BWFillRectBatchLocalMatrix;
-typedef GrTInstanceBatch<BWFillRectBatchLocalRectImp> BWFillRectBatchLocalRect;
-typedef GrTInstanceBatch<BWFillRectBatchLocalMatrixLocalRectImp> BWFillRectBatchLocalMatrixLocalRect;
-
 namespace GrBWFillRectBatch {
 GrDrawBatch* Create(GrColor color,
                     const SkMatrix& viewMatrix,
                     const SkRect& rect,
                     const SkRect* localRect,
                     const SkMatrix* localMatrix) {
-    // TODO bubble these up as separate calls
-    if (localRect && localMatrix) {
-        BWFillRectBatchLocalMatrixLocalRect* batch = BWFillRectBatchLocalMatrixLocalRect::Create();
-        BWFillRectBatchLocalMatrixLocalRect::Geometry& geo = *batch->geometry();
-        geo.fColor = color;
-        geo.fViewMatrix = viewMatrix;
-        geo.fLocalMatrix = *localMatrix;
-        geo.fRect = rect;
-        geo.fLocalRect = *localRect;
-        batch->init();
-        return batch;
-    } else if (localRect) {
-        BWFillRectBatchLocalRect* batch = BWFillRectBatchLocalRect::Create();
-        BWFillRectBatchLocalRect::Geometry& geo = *batch->geometry();
-        geo.fColor = color;
-        geo.fViewMatrix = viewMatrix;
-        geo.fRect = rect;
-        geo.fLocalRect = *localRect;
-        batch->init();
-        return batch;
-    } else if (localMatrix) {
-        BWFillRectBatchLocalMatrix* batch = BWFillRectBatchLocalMatrix::Create();
-        BWFillRectBatchLocalMatrix::Geometry& geo = *batch->geometry();
-        geo.fColor = color;
-        geo.fViewMatrix = viewMatrix;
-        geo.fLocalMatrix = *localMatrix;
-        geo.fRect = rect;
-        batch->init();
-        return batch;
+    BWFillRectBatch::Geometry geometry;
+    geometry.fColor = color;
+    geometry.fViewMatrix = viewMatrix;
+    geometry.fRect = rect;
+
+    if (localRect) {
+        geometry.fHasLocalRect = true;
+        geometry.fLocalRect = *localRect;
     } else {
-        BWFillRectBatchSimple* batch = BWFillRectBatchSimple::Create();
-        BWFillRectBatchSimple::Geometry& geo = *batch->geometry();
-        geo.fColor = color;
-        geo.fViewMatrix = viewMatrix;
-        geo.fRect = rect;
-        batch->init();
-        return batch;
+        geometry.fHasLocalRect = false;
     }
+
+    if (localMatrix) {
+        geometry.fHasLocalMatrix = true;
+        geometry.fLocalMatrix = *localMatrix;
+    } else {
+        geometry.fHasLocalMatrix = false;
+    }
+
+    return BWFillRectBatch::Create(geometry);
 }
 };
 
@@ -291,16 +245,25 @@
 #include "GrBatchTest.h"
 
 DRAW_BATCH_TEST_DEFINE(RectBatch) {
-    GrColor color = GrRandomColor(random);
-    SkRect rect = GrTest::TestRect(random);
-    SkRect localRect = GrTest::TestRect(random);
-    SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
-    SkMatrix localMatrix = GrTest::TestMatrix(random);
+    BWFillRectBatch::Geometry geometry;
+    geometry.fColor = GrRandomColor(random);
 
-    bool hasLocalRect = random->nextBool();
-    bool hasLocalMatrix = random->nextBool();
-    return GrBWFillRectBatch::Create(color, viewMatrix, rect, hasLocalRect ? &localRect : nullptr,
-                                     hasLocalMatrix ? &localMatrix : nullptr);
+    geometry.fRect = GrTest::TestRect(random);
+    geometry.fHasLocalRect = random->nextBool();
+
+    if (geometry.fHasLocalRect) {
+        geometry.fViewMatrix = GrTest::TestMatrixInvertible(random);
+        geometry.fLocalRect = GrTest::TestRect(random);
+    } else {
+        geometry.fViewMatrix = GrTest::TestMatrix(random);
+    }
+
+    geometry.fHasLocalMatrix = random->nextBool();
+    if (geometry.fHasLocalMatrix) {
+        geometry.fLocalMatrix = GrTest::TestMatrix(random);
+    }
+
+    return BWFillRectBatch::Create(geometry);
 }
 
 #endif