Chromium Code Reviews| Index: src/gpu/batches/GrTBatchTesselator.h |
| diff --git a/src/gpu/batches/GrTBatchTesselator.h b/src/gpu/batches/GrTBatchTesselator.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..bb5b67409cbecb4550cc3588726a95df1305954d |
| --- /dev/null |
| +++ b/src/gpu/batches/GrTBatchTesselator.h |
| @@ -0,0 +1,136 @@ |
| +/* |
| + * 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 GrTBatchTesselator_DEFINED |
| +#define GrTBatchTesselator_DEFINED |
| + |
| +#include "GrVertexBatch.h" |
| + |
| +#include "GrBatchFlushState.h" |
| + |
| +/* |
|
bsalomon
2015/08/18 15:01:46
/** (I think the double * is needed for doxygen to
|
| + * GrTBatchTesselator is an optional template to help with writing batches |
| + * To use this template, an implementation must define the following static functions: |
|
bsalomon
2015/08/18 15:01:46
referring to Base?
Base is a confusing name... it
|
| + * A Geometry struct |
| + * |
| + * 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 Base, int kVertsPerInstance, int kIndicesPerInstance> |
| +class GrTBatchTesselator : public GrVertexBatch { |
| +public: |
| + typedef typename Base::Geometry Geometry; |
| + |
| + static GrTBatchTesselator* Create() { |
| + return SkNEW(GrTBatchTesselator); |
| + } |
| + |
| + const char* name() const override { return Base::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: |
| + GrTBatchTesselator() { |
| + this->initClassID<GrTBatchTesselator<Base, kVertsPerInstance, kIndicesPerInstance>>(); |
| + |
| + // Push back an initial geometry |
| + fGeoData.push_back(); |
| + } |
| + |
| + void onPrepareDraws(Target* target) override { |
| + SkAutoTUnref<const GrGeometryProcessor> gp(Base::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( |
| + Base::GetIndexBuffer(target->resourceProvider())); |
| + InstancedHelper helper; |
| + void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, |
| + indexBuffer, kVertsPerInstance, 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 * kVertsPerInstance * vertexStride; |
| + Base::Tesselate(verts, vertexStride, fGeoData[i], fOpts); |
| + } |
| + helper.recordDraw(target); |
| + } |
| + |
| + const Geometry& seedGeometry() const { return fGeoData[0]; } |
| + |
| + bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
| + GrTBatchTesselator* that = t->cast<GrTBatchTesselator>(); |
| + if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), |
| + that->bounds(), caps)) { |
| + return false; |
| + } |
| + |
| + if (!Base::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 |