| /* |
| * 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() |
| * |
| * void InvariantOutputCoverage(GrInitInvariantOutput* out) |
| * |
| * void SetBounds(const Geometry& seedGeometry, SkRect* outBounds) |
| * |
| * void UpdateBoundsAfterAppend(const Geometry& lastGeometry, SkRect* currentBounds) |
| * |
| * bool CanCombine(const Geometry& mine, const Geometry& theirs, |
| * const GrXPOverridesForBatch&) |
| * |
| * const GrGeometryProcessor* CreateGP(const Geometry& seedGeometry, |
| * const GrXPOverridesForBatch& overrides) |
| * |
| * const GrIndexBuffer* GetIndexBuffer(GrResourceProvider*) |
| * |
| * Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo, |
| * const GrXPOverridesForBatch& overrides) |
| */ |
| template <typename Impl> |
| class GrTInstanceBatch : public GrVertexBatch { |
| public: |
| DEFINE_BATCH_CLASS_ID |
| |
| typedef typename Impl::Geometry Geometry; |
| |
| static GrTInstanceBatch* Create() { return new GrTInstanceBatch; } |
| |
| const char* name() const override { return Impl::Name(); } |
| |
| SkString dumpInfo() const override { |
| SkString str; |
| for (int i = 0; i < fGeoData.count(); ++i) { |
| str.append(Impl::DumpInfo(fGeoData[i], i)); |
| } |
| str.append(INHERITED::dumpInfo()); |
| return str; |
| } |
| |
| void computePipelineOptimizations(GrInitInvariantOutput* color, |
| GrInitInvariantOutput* coverage, |
| GrBatchToXPOverrides* overrides) const override { |
| // When this is called on a batch, there is only one geometry bundle |
| color->setKnownFourComponents(fGeoData[0].fColor); |
| Impl::InitInvariantOutputCoverage(coverage); |
| overrides->fUsePLSDstRead = false; |
| } |
| |
| void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
| overrides.getOverrideColorIfSet(&fGeoData[0].fColor); |
| fOverrides = overrides; |
| } |
| |
| SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } |
| |
| // After seeding, the client should call init() so the Batch can initialize itself |
| void init() { |
| const Geometry& geo = fGeoData[0]; |
| Impl::SetBounds(geo, &fBounds); |
| } |
| |
| void updateBoundsAfterAppend() { |
| const Geometry& geo = fGeoData.back(); |
| Impl::UpdateBoundsAfterAppend(geo, &fBounds); |
| } |
| |
| private: |
| GrTInstanceBatch() : INHERITED(ClassID()) {} |
| |
| void onPrepareDraws(Target* target) const override { |
| SkAutoTUnref<const GrGeometryProcessor> gp(Impl::CreateGP(this->seedGeometry(), |
| fOverrides)); |
| 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], fOverrides); |
| } |
| 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(), fOverrides)) { |
| return false; |
| } |
| |
| // In the event of two batches, one who can tweak, one who cannot, we just fall back to |
| // not tweaking |
| if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) { |
| fOverrides = that->fOverrides; |
| } |
| |
| fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); |
| this->joinBounds(that->bounds()); |
| return true; |
| } |
| |
| GrXPOverridesForBatch fOverrides; |
| SkSTArray<1, Geometry, true> fGeoData; |
| |
| typedef GrVertexBatch INHERITED; |
| }; |
| |
| #endif |