blob: f9ba2685eb731d3baf00548460f8e255d55df237 [file] [log] [blame]
joshualitt9c80b5f2015-08-13 10:05:51 -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#include "GrBWFillRectBatch.h"
9
bsalomon75398562015-08-17 12:55:38 -070010#include "GrBatchFlushState.h"
joshualitt9c80b5f2015-08-13 10:05:51 -070011#include "GrColor.h"
12#include "GrDefaultGeoProcFactory.h"
13#include "GrPrimitiveProcessor.h"
joshualittae5b2c62015-08-19 08:48:41 -070014#include "GrQuad.h"
bsalomon16b99132015-08-13 14:55:50 -070015#include "GrVertexBatch.h"
joshualitt9c80b5f2015-08-13 10:05:51 -070016
joshualitt87e47522015-08-20 07:22:42 -070017class GrBatchFlushState;
18class SkMatrix;
19struct SkRect;
20
21class BWFillRectBatch : public GrVertexBatch {
joshualittae41b382015-08-19 06:54:08 -070022public:
joshualitt87e47522015-08-20 07:22:42 -070023 struct Geometry {
24 SkMatrix fViewMatrix;
25 SkRect fRect;
26 SkRect fLocalRect;
27 SkMatrix fLocalMatrix;
28 GrColor fColor;
29 bool fHasLocalRect;
30 bool fHasLocalMatrix;
31 };
joshualitt9c80b5f2015-08-13 10:05:51 -070032
joshualitt87e47522015-08-20 07:22:42 -070033 static GrDrawBatch* Create(const Geometry& geometry) {
34 return SkNEW_ARGS(BWFillRectBatch, (geometry));
joshualittae41b382015-08-19 06:54:08 -070035 }
36
joshualitt87e47522015-08-20 07:22:42 -070037 const char* name() const override { return "RectBatch"; }
38
39 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
40 // When this is called on a batch, there is only one geometry bundle
41 out->setKnownFourComponents(fGeoData[0].fColor);
joshualittae41b382015-08-19 06:54:08 -070042 }
joshualittae41b382015-08-19 06:54:08 -070043
joshualitt87e47522015-08-20 07:22:42 -070044 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
45 out->setKnownSingleComponent(0xff);
joshualittae41b382015-08-19 06:54:08 -070046 }
joshualittae41b382015-08-19 06:54:08 -070047
joshualitt87e47522015-08-20 07:22:42 -070048 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
joshualittae41b382015-08-19 06:54:08 -070049
joshualitt87e47522015-08-20 07:22:42 -070050private:
51 BWFillRectBatch(const Geometry& geometry) {
52 this->initClassID<BWFillRectBatch>();
53 fGeoData.push_back(geometry);
joshualittae41b382015-08-19 06:54:08 -070054
joshualitt87e47522015-08-20 07:22:42 -070055 fBounds = geometry.fRect;
56 geometry.fViewMatrix.mapRect(&fBounds);
57 }
58
59 GrColor color() const { return fBatch.fColor; }
60 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
61 bool colorIgnored() const { return fBatch.fColorIgnored; }
62 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
63 const SkMatrix& localMatrix() const { return fGeoData[0].fLocalMatrix; }
64 bool hasLocalRect() const { return fGeoData[0].fHasLocalRect; }
65 bool hasLocalMatrix() const { return fGeoData[0].fHasLocalMatrix; }
66 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
67
68 void initBatchTracker(const GrPipelineOptimizations& init) override {
69 // Handle any color overrides
70 if (!init.readsColor()) {
71 fGeoData[0].fColor = GrColor_ILLEGAL;
72 }
73 init.getOverrideColorIfSet(&fGeoData[0].fColor);
74
75 // setup batch properties
76 fBatch.fColorIgnored = !init.readsColor();
77 fBatch.fColor = fGeoData[0].fColor;
78 fBatch.fUsesLocalCoords = init.readsLocalCoords();
79 fBatch.fCoverageIgnored = !init.readsCoverage();
80 }
81
82 void onPrepareDraws(Target* target) override {
83 SkAutoTUnref<const GrGeometryProcessor> gp(this->createRectGP());
84 if (!gp) {
85 SkDebugf("Could not create GrGeometryProcessor\n");
86 return;
87 }
88
89 target->initDraw(gp, this->pipeline());
90
91 int instanceCount = fGeoData.count();
92 size_t vertexStride = gp->getVertexStride();
93 SkASSERT(this->hasLocalRect() ?
94 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) :
95 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
96 QuadHelper helper;
97 void* vertices = helper.init(target, vertexStride, instanceCount);
98
99 if (!vertices) {
100 return;
101 }
102
103 for (int i = 0; i < instanceCount; i++) {
104 const Geometry& geom = fGeoData[i];
105
106 intptr_t offset = reinterpret_cast<intptr_t>(vertices) +
107 kVerticesPerQuad * i * vertexStride;
108 SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
109
110 positions->setRectFan(geom.fRect.fLeft, geom.fRect.fTop,
111 geom.fRect.fRight, geom.fRect.fBottom, vertexStride);
112 geom.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVerticesPerQuad);
113
114 // TODO we should only do this if local coords are being read
115 if (geom.fHasLocalRect) {
116 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
117 SkPoint* coords = reinterpret_cast<SkPoint*>(offset + kLocalOffset);
118 coords->setRectFan(geom.fLocalRect.fLeft, geom.fLocalRect.fTop,
119 geom.fLocalRect.fRight, geom.fLocalRect.fBottom,
120 vertexStride);
121 if (geom.fHasLocalMatrix) {
122 geom.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVerticesPerQuad);
123 }
124 }
125
126 static const int kColorOffset = sizeof(SkPoint);
127 GrColor* vertColor = reinterpret_cast<GrColor*>(offset + kColorOffset);
128 for (int j = 0; j < 4; ++j) {
129 *vertColor = geom.fColor;
130 vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride);
131 }
132 }
133
134 helper.recordDraw(target);
135 }
136
137 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
138 BWFillRectBatch* that = t->cast<BWFillRectBatch>();
139 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
140 that->bounds(), caps)) {
141 return false;
142 }
143
144 if (this->hasLocalRect() != that->hasLocalRect()) {
145 return false;
146 }
147
148 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
149 if (!this->hasLocalRect() && this->usesLocalCoords()) {
150 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
151 return false;
152 }
153
154 if (this->hasLocalMatrix() != that->hasLocalMatrix()) {
155 return false;
156 }
157
158 if (this->hasLocalMatrix() && !this->localMatrix().cheapEqualTo(that->localMatrix())) {
159 return false;
160 }
161 }
162
163 if (this->color() != that->color()) {
164 fBatch.fColor = GrColor_ILLEGAL;
165 }
166 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
167 this->joinBounds(that->bounds());
168 return true;
169 }
170
171
172 /** We always use per-vertex colors so that rects can be batched across color changes. Sometimes
173 we have explicit local coords and sometimes not. We *could* always provide explicit local
174 coords and just duplicate the positions when the caller hasn't provided a local coord rect,
175 but we haven't seen a use case which frequently switches between local rect and no local
176 rect draws.
177
178 The color param is used to determine whether the opaque hint can be set on the draw state.
179 The caller must populate the vertex colors itself.
180
181 The vertex attrib order is always pos, color, [local coords].
182 */
183 const GrGeometryProcessor* createRectGP() const {
184 using namespace GrDefaultGeoProcFactory;
185 Color color(Color::kAttribute_Type);
186 Coverage coverage(this->coverageIgnored() ? Coverage::kNone_Type : Coverage::kSolid_Type);
187
188 // if we have a local rect, then we apply the localMatrix directly to the localRect to
189 // generate vertex local coords
190 if (this->hasLocalRect()) {
191 LocalCoords localCoords(LocalCoords::kHasExplicit_Type);
192 return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I());
193 } else {
194 LocalCoords localCoords(LocalCoords::kUsePosition_Type,
195 this->hasLocalMatrix() ? &this->localMatrix() : NULL);
196 return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, localCoords,
197 this->viewMatrix());
joshualittae41b382015-08-19 06:54:08 -0700198 }
199 }
200
joshualitt87e47522015-08-20 07:22:42 -0700201 struct BatchTracker {
joshualittae41b382015-08-19 06:54:08 -0700202 GrColor fColor;
joshualitt87e47522015-08-20 07:22:42 -0700203 bool fUsesLocalCoords;
204 bool fColorIgnored;
205 bool fCoverageIgnored;
joshualittae41b382015-08-19 06:54:08 -0700206 };
207
joshualitt87e47522015-08-20 07:22:42 -0700208 BatchTracker fBatch;
209 SkSTArray<1, Geometry, true> fGeoData;
joshualittae41b382015-08-19 06:54:08 -0700210};
211
joshualitt9c80b5f2015-08-13 10:05:51 -0700212namespace GrBWFillRectBatch {
bsalomonabd30f52015-08-13 13:34:48 -0700213GrDrawBatch* Create(GrColor color,
214 const SkMatrix& viewMatrix,
215 const SkRect& rect,
216 const SkRect* localRect,
217 const SkMatrix* localMatrix) {
joshualitt87e47522015-08-20 07:22:42 -0700218 BWFillRectBatch::Geometry geometry;
219 geometry.fColor = color;
220 geometry.fViewMatrix = viewMatrix;
221 geometry.fRect = rect;
222
223 if (localRect) {
224 geometry.fHasLocalRect = true;
225 geometry.fLocalRect = *localRect;
joshualitt9c80b5f2015-08-13 10:05:51 -0700226 } else {
joshualitt87e47522015-08-20 07:22:42 -0700227 geometry.fHasLocalRect = false;
joshualitt9c80b5f2015-08-13 10:05:51 -0700228 }
joshualitt87e47522015-08-20 07:22:42 -0700229
230 if (localMatrix) {
231 geometry.fHasLocalMatrix = true;
232 geometry.fLocalMatrix = *localMatrix;
233 } else {
234 geometry.fHasLocalMatrix = false;
235 }
236
237 return BWFillRectBatch::Create(geometry);
joshualitt9c80b5f2015-08-13 10:05:51 -0700238}
239};
240
241///////////////////////////////////////////////////////////////////////////////////////////////////
242
243#ifdef GR_TEST_UTILS
244
245#include "GrBatchTest.h"
246
bsalomonabd30f52015-08-13 13:34:48 -0700247DRAW_BATCH_TEST_DEFINE(RectBatch) {
joshualitt87e47522015-08-20 07:22:42 -0700248 BWFillRectBatch::Geometry geometry;
249 geometry.fColor = GrRandomColor(random);
joshualitt9c80b5f2015-08-13 10:05:51 -0700250
joshualitt87e47522015-08-20 07:22:42 -0700251 geometry.fRect = GrTest::TestRect(random);
252 geometry.fHasLocalRect = random->nextBool();
253
254 if (geometry.fHasLocalRect) {
255 geometry.fViewMatrix = GrTest::TestMatrixInvertible(random);
256 geometry.fLocalRect = GrTest::TestRect(random);
257 } else {
258 geometry.fViewMatrix = GrTest::TestMatrix(random);
259 }
260
261 geometry.fHasLocalMatrix = random->nextBool();
262 if (geometry.fHasLocalMatrix) {
263 geometry.fLocalMatrix = GrTest::TestMatrix(random);
264 }
265
266 return BWFillRectBatch::Create(geometry);
joshualitt9c80b5f2015-08-13 10:05:51 -0700267}
268
269#endif