GrDrawVertices to batches
authorjoshualitt <joshualitt@chromium.org>
Fri, 7 Aug 2015 19:46:26 +0000 (12:46 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 7 Aug 2015 19:46:26 +0000 (12:46 -0700)
BUG=skia:

Review URL: https://codereview.chromium.org/1276333004

gm/beziereffects.cpp
gm/convexpolyeffect.cpp
gyp/gmslides.gypi
gyp/gpu.gypi
src/gpu/GrDrawContext.cpp
src/gpu/batches/GrDrawVerticesBatch.cpp [new file with mode: 0644]
src/gpu/batches/GrDrawVerticesBatch.h [new file with mode: 0644]
src/gpu/batches/GrTestBatch.h [moved from src/gpu/GrTestBatch.h with 100% similarity]

index d4ce0a4..17b67ee 100644 (file)
 #include "GrContext.h"
 #include "GrPathUtils.h"
 #include "GrTest.h"
-#include "GrTestBatch.h"
 #include "SkColorPriv.h"
 #include "SkDevice.h"
 #include "SkGeometry.h"
 
+#include "batches/GrTestBatch.h"
+
 #include "effects/GrBezierEffect.h"
 
 static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
index 665bfe0..ba5cc5b 100644 (file)
 #include "GrDefaultGeoProcFactory.h"
 #include "GrPathUtils.h"
 #include "GrTest.h"
-#include "GrTestBatch.h"
 #include "SkColorPriv.h"
 #include "SkDevice.h"
 #include "SkGeometry.h"
 #include "SkTLList.h"
 
+#include "batches/GrTestBatch.h"
+
 #include "effects/GrConvexPolyEffect.h"
 
 namespace skiagm {
index f9d57a7..60a2dd4 100644 (file)
@@ -20,7 +20,7 @@
         '<!@(python find.py ../gm "*.c*")',
 
         # Files needed by particular GMs
-        '../src/gpu/GrTestBatch.h',
+        '../src/gpu/batches/GrTestBatch.h',
         '../src/utils/debugger/SkDrawCommand.h',
         '../src/utils/debugger/SkDrawCommand.cpp',
         '../src/utils/debugger/SkDebugCanvas.h',
index ecb32cb..e8abc25 100644 (file)
       '<(skia_src_path)/gpu/batches/GrBatch.h',
       '<(skia_src_path)/gpu/batches/GrDrawAtlasBatch.cpp',
       '<(skia_src_path)/gpu/batches/GrDrawAtlasBatch.h',
+      '<(skia_src_path)/gpu/batches/GrDrawVerticesBatch.cpp',
+      '<(skia_src_path)/gpu/batches/GrDrawVerticesBatch.h',
       '<(skia_src_path)/gpu/batches/GrRectBatch.h',
       '<(skia_src_path)/gpu/batches/GrRectBatch.cpp',
       '<(skia_src_path)/gpu/batches/GrStrokeRectBatch.cpp',
index 5d77f85..c67f6f4 100644 (file)
@@ -10,7 +10,6 @@
 #include "GrAtlasTextContext.h"
 #include "GrBatchTest.h"
 #include "GrColor.h"
-#include "GrDefaultGeoProcFactory.h"
 #include "GrDrawContext.h"
 #include "GrOvalRenderer.h"
 #include "GrPathRenderer.h"
@@ -20,6 +19,7 @@
 
 #include "batches/GrBatch.h"
 #include "batches/GrDrawAtlasBatch.h"
+#include "batches/GrDrawVerticesBatch.h"
 #include "batches/GrStrokeRectBatch.h"
 
 #include "SkGr.h"
@@ -373,283 +373,6 @@ void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
                             localMatrix);
 }
 
-static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
-                                                        bool hasColors,
-                                                        int* colorOffset,
-                                                        int* texOffset,
-                                                        GrColor color,
-                                                        const SkMatrix& viewMatrix,
-                                                        bool coverageIgnored) {
-    using namespace GrDefaultGeoProcFactory;
-    *texOffset = -1;
-    *colorOffset = -1;
-    Color gpColor(color);
-    if (hasColors) {
-        gpColor.fType = Color::kAttribute_Type;
-    }
-
-    Coverage coverage(coverageIgnored ? Coverage::kNone_Type : Coverage::kSolid_Type);
-    LocalCoords localCoords(hasLocalCoords ? LocalCoords::kHasExplicit_Type :
-                                             LocalCoords::kUsePosition_Type);
-    if (hasLocalCoords && hasColors) {
-        *colorOffset = sizeof(SkPoint);
-        *texOffset = sizeof(SkPoint) + sizeof(GrColor);
-    } else if (hasLocalCoords) {
-        *texOffset = sizeof(SkPoint);
-    } else if (hasColors) {
-        *colorOffset = sizeof(SkPoint);
-    }
-    return GrDefaultGeoProcFactory::Create(gpColor, coverage, localCoords, viewMatrix);
-}
-
-class DrawVerticesBatch : public GrBatch {
-public:
-    struct Geometry {
-        GrColor fColor;
-        SkTDArray<SkPoint> fPositions;
-        SkTDArray<uint16_t> fIndices;
-        SkTDArray<GrColor> fColors;
-        SkTDArray<SkPoint> fLocalCoords;
-    };
-
-    static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
-                           const SkMatrix& viewMatrix,
-                           const SkPoint* positions, int vertexCount,
-                           const uint16_t* indices, int indexCount,
-                           const GrColor* colors, const SkPoint* localCoords,
-                           const SkRect& bounds) {
-        return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
-                                              vertexCount, indices, indexCount, colors,
-                                              localCoords, bounds));
-    }
-
-    const char* name() const override { return "DrawVerticesBatch"; }
-
-    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
-        // When this is called on a batch, there is only one geometry bundle
-        if (this->hasColors()) {
-            out->setUnknownFourComponents();
-        } else {
-            out->setKnownFourComponents(fGeoData[0].fColor);
-        }
-    }
-
-    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
-        out->setKnownSingleComponent(0xff);
-    }
-
-    void initBatchTracker(const GrPipelineInfo& 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 generateGeometry(GrBatchTarget* batchTarget) override {
-        int colorOffset = -1, texOffset = -1;
-        SkAutoTUnref<const GrGeometryProcessor> gp(
-                set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
-                                      &texOffset, this->color(), this->viewMatrix(),
-                                      this->coverageIgnored()));
-
-        batchTarget->initDraw(gp, this->pipeline());
-
-        size_t vertexStride = gp->getVertexStride();
-
-        SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
-                                                 + (this->hasColors() ? sizeof(GrColor) : 0));
-
-        int instanceCount = fGeoData.count();
-
-        const GrVertexBuffer* vertexBuffer;
-        int firstVertex;
-
-        void* verts = batchTarget->makeVertSpace(vertexStride, this->vertexCount(),
-                                                 &vertexBuffer, &firstVertex);
-
-        if (!verts) {
-            SkDebugf("Could not allocate vertices\n");
-            return;
-        }
-
-        const GrIndexBuffer* indexBuffer = NULL;
-        int firstIndex = 0;
-
-        uint16_t* indices = NULL;
-        if (this->hasIndices()) {
-            indices = batchTarget->makeIndexSpace(this->indexCount(), &indexBuffer, &firstIndex);
-
-            if (!indices) {
-                SkDebugf("Could not allocate indices\n");
-                return;
-            }
-        }
-
-        int indexOffset = 0;
-        int vertexOffset = 0;
-        for (int i = 0; i < instanceCount; i++) {
-            const Geometry& args = fGeoData[i];
-
-            // TODO we can actually cache this interleaved and then just memcopy
-            if (this->hasIndices()) {
-                for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
-                    *(indices + indexOffset) = args.fIndices[j] + vertexOffset;
-                }
-            }
-
-            for (int j = 0; j < args.fPositions.count(); ++j) {
-                *((SkPoint*)verts) = args.fPositions[j];
-                if (this->hasColors()) {
-                    *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j];
-                }
-                if (this->hasLocalCoords()) {
-                    *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j];
-                }
-                verts = (void*)((intptr_t)verts + vertexStride);
-                vertexOffset++;
-            }
-        }
-
-        GrVertices vertices;
-        if (this->hasIndices()) {
-            vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
-                                 firstIndex, this->vertexCount(), this->indexCount());
-
-        } else {
-            vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this->vertexCount());
-        }
-        batchTarget->draw(vertices);
-    }
-
-    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
-
-private:
-    DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
-                      const SkMatrix& viewMatrix,
-                      const SkPoint* positions, int vertexCount,
-                      const uint16_t* indices, int indexCount,
-                      const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds) {
-        this->initClassID<DrawVerticesBatch>();
-        SkASSERT(positions);
-
-        fBatch.fViewMatrix = viewMatrix;
-        Geometry& installedGeo = fGeoData.push_back(geometry);
-
-        installedGeo.fPositions.append(vertexCount, positions);
-        if (indices) {
-            installedGeo.fIndices.append(indexCount, indices);
-            fBatch.fHasIndices = true;
-        } else {
-            fBatch.fHasIndices = false;
-        }
-
-        if (colors) {
-            installedGeo.fColors.append(vertexCount, colors);
-            fBatch.fHasColors = true;
-        } else {
-            fBatch.fHasColors = false;
-        }
-
-        if (localCoords) {
-            installedGeo.fLocalCoords.append(vertexCount, localCoords);
-            fBatch.fHasLocalCoords = true;
-        } else {
-            fBatch.fHasLocalCoords = false;
-        }
-        fBatch.fVertexCount = vertexCount;
-        fBatch.fIndexCount = indexCount;
-        fBatch.fPrimitiveType = primitiveType;
-
-        this->setBounds(bounds);
-    }
-
-    GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
-    bool batchablePrimitiveType() const {
-        return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
-               kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
-               kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
-    }
-    GrColor color() const { return fBatch.fColor; }
-    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
-    bool colorIgnored() const { return fBatch.fColorIgnored; }
-    const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
-    bool hasColors() const { return fBatch.fHasColors; }
-    bool hasIndices() const { return fBatch.fHasIndices; }
-    bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
-    int vertexCount() const { return fBatch.fVertexCount; }
-    int indexCount() const { return fBatch.fIndexCount; }
-    bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
-
-    bool onCombineIfPossible(GrBatch* t) override {
-        if (!this->pipeline()->isEqual(*t->pipeline())) {
-            return false;
-        }
-
-        DrawVerticesBatch* that = t->cast<DrawVerticesBatch>();
-
-        if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
-            return false;
-        }
-
-        SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
-
-        // We currently use a uniform viewmatrix for this batch
-        if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
-            return false;
-        }
-
-        if (this->hasColors() != that->hasColors()) {
-            return false;
-        }
-
-        if (this->hasIndices() != that->hasIndices()) {
-            return false;
-        }
-
-        if (this->hasLocalCoords() != that->hasLocalCoords()) {
-            return false;
-        }
-
-        if (!this->hasColors() && this->color() != that->color()) {
-            return false;
-        }
-
-        if (this->color() != that->color()) {
-            fBatch.fColor = GrColor_ILLEGAL;
-        }
-        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
-        fBatch.fVertexCount += that->vertexCount();
-        fBatch.fIndexCount += that->indexCount();
-
-        this->joinBounds(that->bounds());
-        return true;
-    }
-
-    struct BatchTracker {
-        GrPrimitiveType fPrimitiveType;
-        SkMatrix fViewMatrix;
-        GrColor fColor;
-        bool fUsesLocalCoords;
-        bool fColorIgnored;
-        bool fCoverageIgnored;
-        bool fHasColors;
-        bool fHasIndices;
-        bool fHasLocalCoords;
-        int fVertexCount;
-        int fIndexCount;
-    };
-
-    BatchTracker fBatch;
-    SkSTArray<1, Geometry, true> fGeoData;
-};
-
 void GrDrawContext::drawVertices(GrRenderTarget* rt,
                                  const GrClip& clip,
                                  const GrPaint& paint,
@@ -684,12 +407,12 @@ void GrDrawContext::drawVertices(GrRenderTarget* rt,
         bounds.outset(0.5f, 0.5f);
     }
 
-    DrawVerticesBatch::Geometry geometry;
+    GrDrawVerticesBatch::Geometry geometry;
     geometry.fColor = paint.getColor();
-    SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
-                                                          positions, vertexCount, indices,
-                                                          indexCount, colors, texCoords,
-                                                          bounds));
+    SkAutoTUnref<GrBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
+                                                            positions, vertexCount, indices,
+                                                            indexCount, colors, texCoords,
+                                                            bounds));
 
     fDrawTarget->drawBatch(pipelineBuilder, batch);
 }
@@ -1108,121 +831,3 @@ bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
 void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) {
     fDrawTarget->drawBatch(*pipelineBuilder, batch);
 }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef GR_TEST_UTILS
-
-static uint32_t seed_vertices(GrPrimitiveType type) {
-    switch (type) {
-        case kTriangles_GrPrimitiveType:
-        case kTriangleStrip_GrPrimitiveType:
-        case kTriangleFan_GrPrimitiveType:
-            return 3;
-        case kPoints_GrPrimitiveType:
-            return 1;
-        case kLines_GrPrimitiveType:
-        case kLineStrip_GrPrimitiveType:
-            return 2;
-    }
-    SkFAIL("Incomplete switch\n");
-    return 0;
-}
-
-static uint32_t primitive_vertices(GrPrimitiveType type) {
-    switch (type) {
-        case kTriangles_GrPrimitiveType:
-            return 3;
-        case kLines_GrPrimitiveType:
-            return 2;
-        case kTriangleStrip_GrPrimitiveType:
-        case kTriangleFan_GrPrimitiveType:
-        case kPoints_GrPrimitiveType:
-        case kLineStrip_GrPrimitiveType:
-            return 1;
-    }
-    SkFAIL("Incomplete switch\n");
-    return 0;
-}
-
-static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
-    SkPoint p;
-    p.fX = random->nextRangeScalar(min, max);
-    p.fY = random->nextRangeScalar(min, max);
-    return p;
-}
-
-static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
-                             SkRandom* random,
-                             SkTArray<SkPoint>* positions,
-                             SkTArray<SkPoint>* texCoords, bool hasTexCoords,
-                             SkTArray<GrColor>* colors, bool hasColors,
-                             SkTArray<uint16_t>* indices, bool hasIndices) {
-    for (uint32_t v = 0; v < count; v++) {
-        positions->push_back(random_point(random, min, max));
-        if (hasTexCoords) {
-            texCoords->push_back(random_point(random, min, max));
-        }
-        if (hasColors) {
-            colors->push_back(GrRandomColor(random));
-        }
-        if (hasIndices) {
-            SkASSERT(maxVertex <= SK_MaxU16);
-            indices->push_back(random->nextULessThan((uint16_t)maxVertex));
-        }
-    }
-}
-
-BATCH_TEST_DEFINE(VerticesBatch) {
-    GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
-    uint32_t primitiveCount = random->nextRangeU(1, 100);
-
-    // TODO make 'sensible' indexbuffers
-    SkTArray<SkPoint> positions;
-    SkTArray<SkPoint> texCoords;
-    SkTArray<GrColor> colors;
-    SkTArray<uint16_t> indices;
-
-    bool hasTexCoords = random->nextBool();
-    bool hasIndices = random->nextBool();
-    bool hasColors = random->nextBool();
-
-    uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
-
-    static const SkScalar kMinVertExtent = -100.f;
-    static const SkScalar kMaxVertExtent = 100.f;
-    randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
-                     random,
-                     &positions,
-                     &texCoords, hasTexCoords,
-                     &colors, hasColors,
-                     &indices, hasIndices);
-
-    for (uint32_t i = 1; i < primitiveCount; i++) {
-        randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
-                         random,
-                         &positions,
-                         &texCoords, hasTexCoords,
-                         &colors, hasColors,
-                         &indices, hasIndices);
-    }
-
-    SkMatrix viewMatrix = GrTest::TestMatrix(random);
-    SkRect bounds;
-    SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount);
-    SkASSERT(result);
-
-    viewMatrix.mapRect(&bounds);
-
-    DrawVerticesBatch::Geometry geometry;
-    geometry.fColor = GrRandomColor(random);
-    return DrawVerticesBatch::Create(geometry, type, viewMatrix,
-                                     positions.begin(), vertexCount,
-                                     indices.begin(), hasIndices ? vertexCount : 0,
-                                     colors.begin(),
-                                     texCoords.begin(),
-                                     bounds);
-}
-
-#endif
-
diff --git a/src/gpu/batches/GrDrawVerticesBatch.cpp b/src/gpu/batches/GrDrawVerticesBatch.cpp
new file mode 100644 (file)
index 0000000..d302c64
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrDrawVerticesBatch.h"
+
+#include "GrBatchTarget.h"
+#include "GrInvariantOutput.h"
+#include "GrDefaultGeoProcFactory.h"
+
+static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
+                                                        bool hasColors,
+                                                        int* colorOffset,
+                                                        int* texOffset,
+                                                        GrColor color,
+                                                        const SkMatrix& viewMatrix,
+                                                        bool coverageIgnored) {
+    using namespace GrDefaultGeoProcFactory;
+    *texOffset = -1;
+    *colorOffset = -1;
+    Color gpColor(color);
+    if (hasColors) {
+        gpColor.fType = Color::kAttribute_Type;
+    }
+
+    Coverage coverage(coverageIgnored ? Coverage::kNone_Type : Coverage::kSolid_Type);
+    LocalCoords localCoords(hasLocalCoords ? LocalCoords::kHasExplicit_Type :
+                                             LocalCoords::kUsePosition_Type);
+    if (hasLocalCoords && hasColors) {
+        *colorOffset = sizeof(SkPoint);
+        *texOffset = sizeof(SkPoint) + sizeof(GrColor);
+    } else if (hasLocalCoords) {
+        *texOffset = sizeof(SkPoint);
+    } else if (hasColors) {
+        *colorOffset = sizeof(SkPoint);
+    }
+    return GrDefaultGeoProcFactory::Create(gpColor, coverage, localCoords, viewMatrix);
+}
+
+GrDrawVerticesBatch::GrDrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
+                                         const SkMatrix& viewMatrix,
+                                         const SkPoint* positions, int vertexCount,
+                                         const uint16_t* indices, int indexCount,
+                                         const GrColor* colors, const SkPoint* localCoords,
+                                         const SkRect& bounds) {
+    this->initClassID<GrDrawVerticesBatch>();
+    SkASSERT(positions);
+
+    fBatch.fViewMatrix = viewMatrix;
+    Geometry& installedGeo = fGeoData.push_back(geometry);
+
+    installedGeo.fPositions.append(vertexCount, positions);
+    if (indices) {
+        installedGeo.fIndices.append(indexCount, indices);
+        fBatch.fHasIndices = true;
+    } else {
+        fBatch.fHasIndices = false;
+    }
+
+    if (colors) {
+        installedGeo.fColors.append(vertexCount, colors);
+        fBatch.fHasColors = true;
+    } else {
+        fBatch.fHasColors = false;
+    }
+
+    if (localCoords) {
+        installedGeo.fLocalCoords.append(vertexCount, localCoords);
+        fBatch.fHasLocalCoords = true;
+    } else {
+        fBatch.fHasLocalCoords = false;
+    }
+    fBatch.fVertexCount = vertexCount;
+    fBatch.fIndexCount = indexCount;
+    fBatch.fPrimitiveType = primitiveType;
+
+    this->setBounds(bounds);
+}
+
+void GrDrawVerticesBatch::getInvariantOutputColor(GrInitInvariantOutput* out) const {
+    // When this is called on a batch, there is only one geometry bundle
+    if (this->hasColors()) {
+        out->setUnknownFourComponents();
+    } else {
+        out->setKnownFourComponents(fGeoData[0].fColor);
+    }
+}
+
+void GrDrawVerticesBatch::getInvariantOutputCoverage(GrInitInvariantOutput* out) const {
+    out->setKnownSingleComponent(0xff);
+}
+
+void GrDrawVerticesBatch::initBatchTracker(const GrPipelineInfo& init) {
+    // 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 GrDrawVerticesBatch::generateGeometry(GrBatchTarget* batchTarget) {
+    int colorOffset = -1, texOffset = -1;
+    SkAutoTUnref<const GrGeometryProcessor> gp(
+            set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
+                                  &texOffset, this->color(), this->viewMatrix(),
+                                  this->coverageIgnored()));
+
+    batchTarget->initDraw(gp, this->pipeline());
+
+    size_t vertexStride = gp->getVertexStride();
+
+    SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
+                                             + (this->hasColors() ? sizeof(GrColor) : 0));
+
+    int instanceCount = fGeoData.count();
+
+    const GrVertexBuffer* vertexBuffer;
+    int firstVertex;
+
+    void* verts = batchTarget->makeVertSpace(vertexStride, this->vertexCount(),
+                                             &vertexBuffer, &firstVertex);
+
+    if (!verts) {
+        SkDebugf("Could not allocate vertices\n");
+        return;
+    }
+
+    const GrIndexBuffer* indexBuffer = NULL;
+    int firstIndex = 0;
+
+    uint16_t* indices = NULL;
+    if (this->hasIndices()) {
+        indices = batchTarget->makeIndexSpace(this->indexCount(), &indexBuffer, &firstIndex);
+
+        if (!indices) {
+            SkDebugf("Could not allocate indices\n");
+            return;
+        }
+    }
+
+    int indexOffset = 0;
+    int vertexOffset = 0;
+    for (int i = 0; i < instanceCount; i++) {
+        const Geometry& args = fGeoData[i];
+
+        // TODO we can actually cache this interleaved and then just memcopy
+        if (this->hasIndices()) {
+            for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
+                *(indices + indexOffset) = args.fIndices[j] + vertexOffset;
+            }
+        }
+
+        for (int j = 0; j < args.fPositions.count(); ++j) {
+            *((SkPoint*)verts) = args.fPositions[j];
+            if (this->hasColors()) {
+                *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j];
+            }
+            if (this->hasLocalCoords()) {
+                *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j];
+            }
+            verts = (void*)((intptr_t)verts + vertexStride);
+            vertexOffset++;
+        }
+    }
+
+    GrVertices vertices;
+    if (this->hasIndices()) {
+        vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
+                             firstIndex, this->vertexCount(), this->indexCount());
+
+    } else {
+        vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this->vertexCount());
+    }
+    batchTarget->draw(vertices);
+}
+
+bool GrDrawVerticesBatch::onCombineIfPossible(GrBatch* t) {
+    if (!this->pipeline()->isEqual(*t->pipeline())) {
+        return false;
+    }
+
+    GrDrawVerticesBatch* that = t->cast<GrDrawVerticesBatch>();
+
+    if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
+        return false;
+    }
+
+    SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
+
+    // We currently use a uniform viewmatrix for this batch
+    if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
+        return false;
+    }
+
+    if (this->hasColors() != that->hasColors()) {
+        return false;
+    }
+
+    if (this->hasIndices() != that->hasIndices()) {
+        return false;
+    }
+
+    if (this->hasLocalCoords() != that->hasLocalCoords()) {
+        return false;
+    }
+
+    if (!this->hasColors() && this->color() != that->color()) {
+        return false;
+    }
+
+    if (this->color() != that->color()) {
+        fBatch.fColor = GrColor_ILLEGAL;
+    }
+    fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+    fBatch.fVertexCount += that->vertexCount();
+    fBatch.fIndexCount += that->indexCount();
+
+    this->joinBounds(that->bounds());
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef GR_TEST_UTILS
+
+#include "GrBatchTest.h"
+
+static uint32_t seed_vertices(GrPrimitiveType type) {
+    switch (type) {
+        case kTriangles_GrPrimitiveType:
+        case kTriangleStrip_GrPrimitiveType:
+        case kTriangleFan_GrPrimitiveType:
+            return 3;
+        case kPoints_GrPrimitiveType:
+            return 1;
+        case kLines_GrPrimitiveType:
+        case kLineStrip_GrPrimitiveType:
+            return 2;
+    }
+    SkFAIL("Incomplete switch\n");
+    return 0;
+}
+
+static uint32_t primitive_vertices(GrPrimitiveType type) {
+    switch (type) {
+        case kTriangles_GrPrimitiveType:
+            return 3;
+        case kLines_GrPrimitiveType:
+            return 2;
+        case kTriangleStrip_GrPrimitiveType:
+        case kTriangleFan_GrPrimitiveType:
+        case kPoints_GrPrimitiveType:
+        case kLineStrip_GrPrimitiveType:
+            return 1;
+    }
+    SkFAIL("Incomplete switch\n");
+    return 0;
+}
+
+static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
+    SkPoint p;
+    p.fX = random->nextRangeScalar(min, max);
+    p.fY = random->nextRangeScalar(min, max);
+    return p;
+}
+
+static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
+                             SkRandom* random,
+                             SkTArray<SkPoint>* positions,
+                             SkTArray<SkPoint>* texCoords, bool hasTexCoords,
+                             SkTArray<GrColor>* colors, bool hasColors,
+                             SkTArray<uint16_t>* indices, bool hasIndices) {
+    for (uint32_t v = 0; v < count; v++) {
+        positions->push_back(random_point(random, min, max));
+        if (hasTexCoords) {
+            texCoords->push_back(random_point(random, min, max));
+        }
+        if (hasColors) {
+            colors->push_back(GrRandomColor(random));
+        }
+        if (hasIndices) {
+            SkASSERT(maxVertex <= SK_MaxU16);
+            indices->push_back(random->nextULessThan((uint16_t)maxVertex));
+        }
+    }
+}
+
+BATCH_TEST_DEFINE(VerticesBatch) {
+    GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
+    uint32_t primitiveCount = random->nextRangeU(1, 100);
+
+    // TODO make 'sensible' indexbuffers
+    SkTArray<SkPoint> positions;
+    SkTArray<SkPoint> texCoords;
+    SkTArray<GrColor> colors;
+    SkTArray<uint16_t> indices;
+
+    bool hasTexCoords = random->nextBool();
+    bool hasIndices = random->nextBool();
+    bool hasColors = random->nextBool();
+
+    uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
+
+    static const SkScalar kMinVertExtent = -100.f;
+    static const SkScalar kMaxVertExtent = 100.f;
+    randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
+                     random,
+                     &positions,
+                     &texCoords, hasTexCoords,
+                     &colors, hasColors,
+                     &indices, hasIndices);
+
+    for (uint32_t i = 1; i < primitiveCount; i++) {
+        randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
+                         random,
+                         &positions,
+                         &texCoords, hasTexCoords,
+                         &colors, hasColors,
+                         &indices, hasIndices);
+    }
+
+    SkMatrix viewMatrix = GrTest::TestMatrix(random);
+    SkRect bounds;
+    SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount);
+    SkASSERT(result);
+
+    viewMatrix.mapRect(&bounds);
+
+    GrDrawVerticesBatch::Geometry geometry;
+    geometry.fColor = GrRandomColor(random);
+    return GrDrawVerticesBatch::Create(geometry, type, viewMatrix,
+                                       positions.begin(), vertexCount,
+                                       indices.begin(), hasIndices ? vertexCount : 0,
+                                       colors.begin(),
+                                       texCoords.begin(),
+                                       bounds);
+}
+
+#endif
diff --git a/src/gpu/batches/GrDrawVerticesBatch.h b/src/gpu/batches/GrDrawVerticesBatch.h
new file mode 100644 (file)
index 0000000..86ce241
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDrawVerticesBatch_DEFINED
+#define GrDrawVerticesBatch_DEFINED
+
+#include "GrBatch.h"
+#include "GrColor.h"
+#include "GrTypes.h"
+#include "SkMatrix.h"
+#include "SkRect.h"
+#include "SkTDArray.h"
+
+class GrBatch;
+class GrBatchTarget;
+struct GrInitInvariantOutput;
+
+class GrDrawVerticesBatch : public GrBatch {
+public:
+    struct Geometry {
+        GrColor fColor;
+        SkTDArray<SkPoint> fPositions;
+        SkTDArray<uint16_t> fIndices;
+        SkTDArray<GrColor> fColors;
+        SkTDArray<SkPoint> fLocalCoords;
+    };
+
+    static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
+                           const SkMatrix& viewMatrix,
+                           const SkPoint* positions, int vertexCount,
+                           const uint16_t* indices, int indexCount,
+                           const GrColor* colors, const SkPoint* localCoords,
+                           const SkRect& bounds) {
+        return SkNEW_ARGS(GrDrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
+                                                vertexCount, indices, indexCount, colors,
+                                                localCoords, bounds));
+    }
+
+    const char* name() const override { return "DrawVerticesBatch"; }
+
+    void getInvariantOutputColor(GrInitInvariantOutput* out) const override;
+
+    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override;
+
+    void initBatchTracker(const GrPipelineInfo& init) override;
+
+    void generateGeometry(GrBatchTarget* batchTarget) override;
+
+    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
+
+private:
+    GrDrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
+                        const SkMatrix& viewMatrix,
+                        const SkPoint* positions, int vertexCount,
+                        const uint16_t* indices, int indexCount,
+                        const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds);
+
+    GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
+    bool batchablePrimitiveType() const {
+        return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
+               kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
+               kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
+    }
+    GrColor color() const { return fBatch.fColor; }
+    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
+    bool colorIgnored() const { return fBatch.fColorIgnored; }
+    const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
+    bool hasColors() const { return fBatch.fHasColors; }
+    bool hasIndices() const { return fBatch.fHasIndices; }
+    bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
+    int vertexCount() const { return fBatch.fVertexCount; }
+    int indexCount() const { return fBatch.fIndexCount; }
+    bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
+
+    bool onCombineIfPossible(GrBatch* t) override;
+
+    struct BatchTracker {
+        GrPrimitiveType fPrimitiveType;
+        SkMatrix fViewMatrix;
+        GrColor fColor;
+        bool fUsesLocalCoords;
+        bool fColorIgnored;
+        bool fCoverageIgnored;
+        bool fHasColors;
+        bool fHasIndices;
+        bool fHasLocalCoords;
+        int fVertexCount;
+        int fIndexCount;
+    };
+
+    BatchTracker fBatch;
+    SkSTArray<1, Geometry, true> fGeoData;
+};
+
+#endif