| Index: src/gpu/batches/GrTInstanceBatch.h
|
| diff --git a/src/gpu/batches/GrTInstanceBatch.h b/src/gpu/batches/GrTInstanceBatch.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..420f873d2676f07c51d6714d4f843286a384e670
|
| --- /dev/null
|
| +++ b/src/gpu/batches/GrTInstanceBatch.h
|
| @@ -0,0 +1,139 @@
|
| +/*
|
| + * 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 GrTInstanceBatch_DEFINED
|
| +#define GrTInstanceBatch_DEFINED
|
| +
|
| +#include "GrVertexBatch.h"
|
| +
|
| +#include "GrBatchFlushState.h"
|
| +
|
| +/**
|
| + * GrTInstanceBatch is an optional template to help with writing batches
|
| + * To use this template, The 'Impl' must define the following statics:
|
| + * A Geometry struct
|
| + *
|
| + * static const int kVertsPerInstance
|
| + * static const int kIndicesPerInstance
|
| + *
|
| + * const char* Name()
|
| + *
|
| + * bool CanCombine(const Geometry& mine, const Geometry& theirs,
|
| + * const GrPipelineOptimizations&)
|
| + *
|
| + * const GrGeometryProcessor* CreateGP(const Geometry& seedGeometry,
|
| + * const GrPipelineOptimizations& opts)
|
| + *
|
| + * const GrIndexBuffer* GetIndexBuffer(GrResourceProvider*)
|
| + *
|
| + * Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
|
| + * const GrPipelineOptimizations& opts)
|
| + */
|
| +template <typename Impl>
|
| +class GrTInstanceBatch : public GrVertexBatch {
|
| +public:
|
| + typedef typename Impl::Geometry Geometry;
|
| +
|
| + static GrTInstanceBatch* Create() {
|
| + return SkNEW(GrTInstanceBatch);
|
| + }
|
| +
|
| + const char* name() const override { return Impl::Name(); }
|
| +
|
| + void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
|
| + // When this is called on a batch, there is only one geometry bundle
|
| + out->setKnownFourComponents(fGeoData[0].fColor);
|
| + }
|
| +
|
| + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
|
| + out->setUnknownSingleComponent();
|
| + }
|
| +
|
| + void initBatchTracker(const GrPipelineOptimizations& opt) override {
|
| + opt.getOverrideColorIfSet(&fGeoData[0].fColor);
|
| + fOpts = opt;
|
| + }
|
| +
|
| + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| +
|
| + // to avoid even the initial copy of the struct, we have a getter for the first item which
|
| + // is used to seed the batch with its initial geometry. After seeding, the client should call
|
| + // init() so the Batch can initialize itself
|
| + Geometry* geometry() { return &fGeoData[0]; }
|
| + void init() {
|
| + const Geometry& geo = fGeoData[0];
|
| + this->setBounds(geo.fDevRect);
|
| + }
|
| +
|
| +private:
|
| + GrTInstanceBatch() {
|
| + this->initClassID<GrTInstanceBatch<Impl>>();
|
| +
|
| + // Push back an initial geometry
|
| + fGeoData.push_back();
|
| + }
|
| +
|
| + void onPrepareDraws(Target* target) override {
|
| + SkAutoTUnref<const GrGeometryProcessor> gp(Impl::CreateGP(this->seedGeometry(), fOpts));
|
| + if (!gp) {
|
| + SkDebugf("Couldn't create GrGeometryProcessor\n");
|
| + return;
|
| + }
|
| +
|
| + target->initDraw(gp, this->pipeline());
|
| +
|
| + size_t vertexStride = gp->getVertexStride();
|
| + int instanceCount = fGeoData.count();
|
| +
|
| + SkAutoTUnref<const GrIndexBuffer> indexBuffer(
|
| + Impl::GetIndexBuffer(target->resourceProvider()));
|
| + InstancedHelper helper;
|
| + void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
|
| + indexBuffer, Impl::kVertsPerInstance,
|
| + Impl::kIndicesPerInstance, instanceCount);
|
| + if (!vertices || !indexBuffer) {
|
| + SkDebugf("Could not allocate vertices\n");
|
| + return;
|
| + }
|
| +
|
| + for (int i = 0; i < instanceCount; i++) {
|
| + intptr_t verts = reinterpret_cast<intptr_t>(vertices) +
|
| + i * Impl::kVertsPerInstance * vertexStride;
|
| + Impl::Tesselate(verts, vertexStride, fGeoData[i], fOpts);
|
| + }
|
| + helper.recordDraw(target);
|
| + }
|
| +
|
| + const Geometry& seedGeometry() const { return fGeoData[0]; }
|
| +
|
| + bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
|
| + GrTInstanceBatch* that = t->cast<GrTInstanceBatch>();
|
| + if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
|
| + that->bounds(), caps)) {
|
| + return false;
|
| + }
|
| +
|
| + if (!Impl::CanCombine(this->seedGeometry(), that->seedGeometry(), fOpts)) {
|
| + return false;
|
| + }
|
| +
|
| + // In the event of two batches, one who can tweak, one who cannot, we just fall back to
|
| + // not tweaking
|
| + if (fOpts.canTweakAlphaForCoverage() && !that->fOpts.canTweakAlphaForCoverage()) {
|
| + fOpts = that->fOpts;
|
| + }
|
| +
|
| + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
| + this->joinBounds(that->bounds());
|
| + return true;
|
| + }
|
| +
|
| + GrPipelineOptimizations fOpts;
|
| + SkSTArray<1, Geometry, true> fGeoData;
|
| +};
|
| +
|
| +#endif
|
|
|