blob: e314959bfcd9c7d4ff0745ff336c2302f219f389 [file] [log] [blame]
joshualitt2ad37be2015-08-18 10:16:01 -07001/*
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 *
joshualitt2244c272015-08-21 10:33:15 -070025 * void InvariantOutputCoverage(GrInitInvariantOutput* out)
26 *
27 * void SetBounds(const Geometry& seedGeometry, SkRect* outBounds)
28 *
joshualitt2ad37be2015-08-18 10:16:01 -070029 * bool CanCombine(const Geometry& mine, const Geometry& theirs,
30 * const GrPipelineOptimizations&)
31 *
32 * const GrGeometryProcessor* CreateGP(const Geometry& seedGeometry,
33 * const GrPipelineOptimizations& opts)
34 *
35 * const GrIndexBuffer* GetIndexBuffer(GrResourceProvider*)
36 *
37 * Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
38 * const GrPipelineOptimizations& opts)
39 */
40template <typename Impl>
41class GrTInstanceBatch : public GrVertexBatch {
42public:
43 typedef typename Impl::Geometry Geometry;
44
halcanary385fe4d2015-08-26 13:07:48 -070045 static GrTInstanceBatch* Create() { return new GrTInstanceBatch; }
joshualitt2ad37be2015-08-18 10:16:01 -070046
47 const char* name() const override { return Impl::Name(); }
48
49 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
50 // When this is called on a batch, there is only one geometry bundle
51 out->setKnownFourComponents(fGeoData[0].fColor);
52 }
53
54 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
joshualitt2244c272015-08-21 10:33:15 -070055 Impl::InitInvariantOutputCoverage(out);
joshualitt2ad37be2015-08-18 10:16:01 -070056 }
57
58 void initBatchTracker(const GrPipelineOptimizations& opt) override {
59 opt.getOverrideColorIfSet(&fGeoData[0].fColor);
60 fOpts = opt;
61 }
62
63 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
64
65 // to avoid even the initial copy of the struct, we have a getter for the first item which
66 // is used to seed the batch with its initial geometry. After seeding, the client should call
67 // init() so the Batch can initialize itself
68 Geometry* geometry() { return &fGeoData[0]; }
69 void init() {
70 const Geometry& geo = fGeoData[0];
joshualitt2244c272015-08-21 10:33:15 -070071 Impl::SetBounds(geo, &fBounds);
joshualitt2ad37be2015-08-18 10:16:01 -070072 }
73
74private:
75 GrTInstanceBatch() {
76 this->initClassID<GrTInstanceBatch<Impl>>();
77
78 // Push back an initial geometry
79 fGeoData.push_back();
80 }
81
82 void onPrepareDraws(Target* target) override {
83 SkAutoTUnref<const GrGeometryProcessor> gp(Impl::CreateGP(this->seedGeometry(), fOpts));
84 if (!gp) {
85 SkDebugf("Couldn't create GrGeometryProcessor\n");
86 return;
87 }
88
89 target->initDraw(gp, this->pipeline());
90
91 size_t vertexStride = gp->getVertexStride();
92 int instanceCount = fGeoData.count();
93
94 SkAutoTUnref<const GrIndexBuffer> indexBuffer(
95 Impl::GetIndexBuffer(target->resourceProvider()));
96 InstancedHelper helper;
97 void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
98 indexBuffer, Impl::kVertsPerInstance,
99 Impl::kIndicesPerInstance, instanceCount);
100 if (!vertices || !indexBuffer) {
101 SkDebugf("Could not allocate vertices\n");
102 return;
103 }
104
105 for (int i = 0; i < instanceCount; i++) {
106 intptr_t verts = reinterpret_cast<intptr_t>(vertices) +
107 i * Impl::kVertsPerInstance * vertexStride;
108 Impl::Tesselate(verts, vertexStride, fGeoData[i], fOpts);
109 }
110 helper.recordDraw(target);
111 }
112
113 const Geometry& seedGeometry() const { return fGeoData[0]; }
114
115 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
116 GrTInstanceBatch* that = t->cast<GrTInstanceBatch>();
117 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
118 that->bounds(), caps)) {
119 return false;
120 }
121
122 if (!Impl::CanCombine(this->seedGeometry(), that->seedGeometry(), fOpts)) {
123 return false;
124 }
125
126 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
127 // not tweaking
128 if (fOpts.canTweakAlphaForCoverage() && !that->fOpts.canTweakAlphaForCoverage()) {
129 fOpts = that->fOpts;
130 }
131
132 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
133 this->joinBounds(that->bounds());
134 return true;
135 }
136
137 GrPipelineOptimizations fOpts;
138 SkSTArray<1, Geometry, true> fGeoData;
139};
140
141#endif