1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef GrTInstanceBatch_DEFINED 9 #define GrTInstanceBatch_DEFINED 10 11 #include "GrVertexBatch.h" 12 13 #include "GrBatchFlushState.h" 14 15 /** 16 * GrTInstanceBatch is an optional template to help with writing batches 17 * To use this template, The 'Impl' must define the following statics: 18 * A Geometry struct 19 * 20 * static const int kVertsPerInstance 21 * static const int kIndicesPerInstance 22 * 23 * const char* Name() 24 * 25 * void InvariantOutputCoverage(GrInitInvariantOutput* out) 26 * 27 * void SetBounds(const Geometry& seedGeometry, SkRect* outBounds) 28 * 29 * void UpdateBoundsAfterAppend(const Geometry& lastGeometry, SkRect* currentBounds) 30 * 31 * bool CanCombine(const Geometry& mine, const Geometry& theirs, 32 * const GrXPOverridesForBatch&) 33 * 34 * const GrGeometryProcessor* CreateGP(const Geometry& seedGeometry, 35 * const GrXPOverridesForBatch& overrides) 36 * 37 * const GrIndexBuffer* GetIndexBuffer(GrResourceProvider*) 38 * 39 * Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo, 40 * const GrXPOverridesForBatch& overrides) 41 */ 42 template <typename Impl> 43 class GrTInstanceBatch : public GrVertexBatch { 44 public: 45 DEFINE_BATCH_CLASS_ID 46 47 typedef typename Impl::Geometry Geometry; 48 Create()49 static GrTInstanceBatch* Create() { return new GrTInstanceBatch; } 50 name()51 const char* name() const override { return Impl::Name(); } 52 dumpInfo()53 SkString dumpInfo() const override { 54 SkString str; 55 for (int i = 0; i < fGeoData.count(); ++i) { 56 str.append(Impl::DumpInfo(fGeoData[i], i)); 57 } 58 str.append(INHERITED::dumpInfo()); 59 return str; 60 } 61 computePipelineOptimizations(GrInitInvariantOutput * color,GrInitInvariantOutput * coverage,GrBatchToXPOverrides * overrides)62 void computePipelineOptimizations(GrInitInvariantOutput* color, 63 GrInitInvariantOutput* coverage, 64 GrBatchToXPOverrides* overrides) const override { 65 // When this is called on a batch, there is only one geometry bundle 66 color->setKnownFourComponents(fGeoData[0].fColor); 67 Impl::InitInvariantOutputCoverage(coverage); 68 } 69 initBatchTracker(const GrXPOverridesForBatch & overrides)70 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { 71 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); 72 fOverrides = overrides; 73 } 74 geoData()75 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } 76 77 // After seeding, the client should call init() so the Batch can initialize itself init()78 void init() { 79 const Geometry& geo = fGeoData[0]; 80 Impl::SetBounds(geo, &fBounds); 81 } 82 updateBoundsAfterAppend()83 void updateBoundsAfterAppend() { 84 const Geometry& geo = fGeoData.back(); 85 Impl::UpdateBoundsAfterAppend(geo, &fBounds); 86 } 87 88 private: GrTInstanceBatch()89 GrTInstanceBatch() : INHERITED(ClassID()) {} 90 onPrepareDraws(Target * target)91 void onPrepareDraws(Target* target) const override { 92 SkAutoTUnref<const GrGeometryProcessor> gp(Impl::CreateGP(this->seedGeometry(), 93 fOverrides)); 94 if (!gp) { 95 SkDebugf("Couldn't create GrGeometryProcessor\n"); 96 return; 97 } 98 99 target->initDraw(gp, this->pipeline()); 100 101 size_t vertexStride = gp->getVertexStride(); 102 int instanceCount = fGeoData.count(); 103 104 SkAutoTUnref<const GrIndexBuffer> indexBuffer( 105 Impl::GetIndexBuffer(target->resourceProvider())); 106 InstancedHelper helper; 107 void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, 108 indexBuffer, Impl::kVertsPerInstance, 109 Impl::kIndicesPerInstance, instanceCount); 110 if (!vertices || !indexBuffer) { 111 SkDebugf("Could not allocate vertices\n"); 112 return; 113 } 114 115 for (int i = 0; i < instanceCount; i++) { 116 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + 117 i * Impl::kVertsPerInstance * vertexStride; 118 Impl::Tesselate(verts, vertexStride, fGeoData[i], fOverrides); 119 } 120 helper.recordDraw(target); 121 } 122 seedGeometry()123 const Geometry& seedGeometry() const { return fGeoData[0]; } 124 onCombineIfPossible(GrBatch * t,const GrCaps & caps)125 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { 126 GrTInstanceBatch* that = t->cast<GrTInstanceBatch>(); 127 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), 128 that->bounds(), caps)) { 129 return false; 130 } 131 132 if (!Impl::CanCombine(this->seedGeometry(), that->seedGeometry(), fOverrides)) { 133 return false; 134 } 135 136 // In the event of two batches, one who can tweak, one who cannot, we just fall back to 137 // not tweaking 138 if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) { 139 fOverrides = that->fOverrides; 140 } 141 142 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); 143 this->joinBounds(that->bounds()); 144 return true; 145 } 146 147 GrXPOverridesForBatch fOverrides; 148 SkSTArray<1, Geometry, true> fGeoData; 149 150 typedef GrVertexBatch INHERITED; 151 }; 152 153 #endif 154