blob: 5c14aae25f0c20258016fbed9733eefdba92d297 [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"
joshualittae41b382015-08-19 06:54:08 -070015#include "GrResourceProvider.h"
16#include "GrTInstanceBatch.h"
bsalomon16b99132015-08-13 14:55:50 -070017#include "GrVertexBatch.h"
joshualitt9c80b5f2015-08-13 10:05:51 -070018
joshualittae41b382015-08-19 06:54:08 -070019// Common functions
20class BWFillRectBatchBase {
21public:
22 static const int kVertsPerInstance = 4;
23 static const int kIndicesPerInstance = 6;
joshualitt9c80b5f2015-08-13 10:05:51 -070024
joshualittae41b382015-08-19 06:54:08 -070025 static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* rp) {
26 return rp->refQuadIndexBuffer();
27 }
28
29 template <typename Geometry>
30 static void SetBounds(const Geometry& geo, SkRect* outBounds) {
31 geo.fViewMatrix.mapRect(outBounds, geo.fRect);
32 }
33};
34
35/** We always use per-vertex colors so that rects can be batched across color changes. Sometimes
36 we have explicit local coords and sometimes not. We *could* always provide explicit local
37 coords and just duplicate the positions when the caller hasn't provided a local coord rect,
38 but we haven't seen a use case which frequently switches between local rect and no local
39 rect draws.
40
41 The color param is used to determine whether the opaque hint can be set on the draw state.
42 The caller must populate the vertex colors itself.
43
44 The vertex attrib order is always pos, color, [local coords].
45 */
46static const GrGeometryProcessor* create_gp(const SkMatrix& viewMatrix,
47 bool readsCoverage,
48 bool hasExplicitLocalCoords,
49 const SkMatrix* localMatrix) {
50 using namespace GrDefaultGeoProcFactory;
51 Color color(Color::kAttribute_Type);
52 Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Type);
53
54 // if we have a local rect, then we apply the localMatrix directly to the localRect to
55 // generate vertex local coords
56 if (hasExplicitLocalCoords) {
57 LocalCoords localCoords(LocalCoords::kHasExplicit_Type);
58 return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I());
59 } else {
60 LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix ? localMatrix : NULL);
61 return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, localCoords,
62 viewMatrix);
63 }
64}
65
66static void tesselate(intptr_t vertices,
67 size_t vertexStride,
68 GrColor color,
69 const SkMatrix& viewMatrix,
70 const SkRect& rect,
71 const SkRect* localRect,
72 const SkMatrix* localMatrix) {
73 SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
74
75 positions->setRectFan(rect.fLeft, rect.fTop,
76 rect.fRight, rect.fBottom, vertexStride);
77 viewMatrix.mapPointsWithStride(positions, vertexStride, BWFillRectBatchBase::kVertsPerInstance);
78
79 // TODO we should only do this if local coords are being read
80 if (localRect) {
81 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
82 SkPoint* coords = reinterpret_cast<SkPoint*>(vertices + kLocalOffset);
83 coords->setRectFan(localRect->fLeft, localRect->fTop,
84 localRect->fRight, localRect->fBottom,
85 vertexStride);
86 if (localMatrix) {
87 localMatrix->mapPointsWithStride(coords, vertexStride,
88 BWFillRectBatchBase::kVertsPerInstance);
89 }
90 }
91
92 static const int kColorOffset = sizeof(SkPoint);
93 GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
94 for (int j = 0; j < 4; ++j) {
95 *vertColor = color;
96 vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride);
97 }
98}
99
100class BWFillRectBatchNoLocalMatrixImp : public BWFillRectBatchBase {
101public:
102 struct Geometry {
103 SkMatrix fViewMatrix;
104 SkRect fRect;
105 GrColor fColor;
106 };
107
108 static const char* Name() { return "BWFillRectBatchNoLocalMatrix"; }
109
110 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
111 const GrPipelineOptimizations& opts) {
112 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
113 // local coords then we won't be able to batch. We could actually upload the viewmatrix
114 // using vertex attributes in these cases, but haven't investigated that
115 return !opts.readsLocalCoords() || mine.fViewMatrix.cheapEqualTo(theirs.fViewMatrix);
116 }
117
118 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
119 const GrPipelineOptimizations& opts) {
120 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCoverage(), false,
121 NULL);
122
123 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
124 return gp;
125 }
126
127 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
128 const GrPipelineOptimizations& opts) {
129 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, NULL, NULL);
130 }
131};
132
133class BWFillRectBatchLocalMatrixImp : public BWFillRectBatchBase {
134public:
135 struct Geometry {
136 SkMatrix fViewMatrix;
137 SkMatrix fLocalMatrix;
138 SkRect fRect;
139 GrColor fColor;
140 };
141
142 static const char* Name() { return "BWFillRectBatchLocalMatrix"; }
143
144 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
145 const GrPipelineOptimizations& opts) {
146 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
147 // local coords then we won't be able to batch. We could actually upload the viewmatrix
148 // using vertex attributes in these cases, but haven't investigated that
149 return !opts.readsLocalCoords() || mine.fViewMatrix.cheapEqualTo(theirs.fViewMatrix);
150 }
151
152 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
153 const GrPipelineOptimizations& opts) {
154 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCoverage(), false,
155 &geo.fLocalMatrix);
156
157 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
158 return gp;
159 }
160
161 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
162 const GrPipelineOptimizations& opts) {
163 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, NULL,
164 &geo.fLocalMatrix);
165 }
166};
167
168class BWFillRectBatchLocalRectImp : public BWFillRectBatchBase {
joshualitt9c80b5f2015-08-13 10:05:51 -0700169public:
170 struct Geometry {
171 SkMatrix fViewMatrix;
172 SkRect fRect;
173 SkRect fLocalRect;
joshualitt9c80b5f2015-08-13 10:05:51 -0700174 GrColor fColor;
joshualitt9c80b5f2015-08-13 10:05:51 -0700175 };
176
joshualittae41b382015-08-19 06:54:08 -0700177 static const char* Name() { return "BWFillRectBatchLocalRect"; }
joshualitt9c80b5f2015-08-13 10:05:51 -0700178
joshualittae41b382015-08-19 06:54:08 -0700179 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
180 const GrPipelineOptimizations& opts) {
joshualitt9c80b5f2015-08-13 10:05:51 -0700181 return true;
182 }
183
joshualittae41b382015-08-19 06:54:08 -0700184 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
185 const GrPipelineOptimizations& opts) {
186 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCoverage(), true,
187 NULL);
joshualitt9c80b5f2015-08-13 10:05:51 -0700188
joshualittae41b382015-08-19 06:54:08 -0700189 SkASSERT(gp->getVertexStride() ==
190 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
191 return gp;
joshualitt9c80b5f2015-08-13 10:05:51 -0700192 }
193
joshualittae41b382015-08-19 06:54:08 -0700194 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
195 const GrPipelineOptimizations& opts) {
196 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, &geo.fLocalRect,
197 NULL);
198 }
199};
200
201class BWFillRectBatchLocalMatrixLocalRectImp : public BWFillRectBatchBase {
202public:
203 struct Geometry {
204 SkMatrix fViewMatrix;
205 SkMatrix fLocalMatrix;
206 SkRect fRect;
207 SkRect fLocalRect;
joshualitt9c80b5f2015-08-13 10:05:51 -0700208 GrColor fColor;
joshualitt9c80b5f2015-08-13 10:05:51 -0700209 };
210
joshualittae41b382015-08-19 06:54:08 -0700211 static const char* Name() { return "BWFillRectBatchLocalMatrixLocalRect"; }
212
213 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
214 const GrPipelineOptimizations& opts) {
215 return true;
216 }
217
218 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
219 const GrPipelineOptimizations& opts) {
220 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCoverage(), true,
221 NULL);
222
223 SkASSERT(gp->getVertexStride() ==
224 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
225 return gp;
226 }
227
228 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
229 const GrPipelineOptimizations& opts) {
230 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, &geo.fLocalRect,
231 &geo.fLocalMatrix);
232 }
joshualitt9c80b5f2015-08-13 10:05:51 -0700233};
234
joshualittae41b382015-08-19 06:54:08 -0700235typedef GrTInstanceBatch<BWFillRectBatchNoLocalMatrixImp> BWFillRectBatchSimple;
236typedef GrTInstanceBatch<BWFillRectBatchLocalMatrixImp> BWFillRectBatchLocalMatrix;
237typedef GrTInstanceBatch<BWFillRectBatchLocalRectImp> BWFillRectBatchLocalRect;
238typedef GrTInstanceBatch<BWFillRectBatchLocalMatrixLocalRectImp> BWFillRectBatchLocalMatrixLocalRect;
239
joshualitt9c80b5f2015-08-13 10:05:51 -0700240namespace GrBWFillRectBatch {
bsalomonabd30f52015-08-13 13:34:48 -0700241GrDrawBatch* Create(GrColor color,
242 const SkMatrix& viewMatrix,
243 const SkRect& rect,
244 const SkRect* localRect,
245 const SkMatrix* localMatrix) {
joshualittae41b382015-08-19 06:54:08 -0700246 // TODO bubble these up as separate calls
247 if (localRect && localMatrix) {
248 BWFillRectBatchLocalMatrixLocalRect* batch = BWFillRectBatchLocalMatrixLocalRect::Create();
249 BWFillRectBatchLocalMatrixLocalRect::Geometry& geo = *batch->geometry();
250 geo.fColor = color;
251 geo.fViewMatrix = viewMatrix;
252 geo.fLocalMatrix = *localMatrix;
253 geo.fRect = rect;
254 geo.fLocalRect = *localRect;
255 batch->init();
256 return batch;
257 } else if (localRect) {
258 BWFillRectBatchLocalRect* batch = BWFillRectBatchLocalRect::Create();
259 BWFillRectBatchLocalRect::Geometry& geo = *batch->geometry();
260 geo.fColor = color;
261 geo.fViewMatrix = viewMatrix;
262 geo.fRect = rect;
263 geo.fLocalRect = *localRect;
264 batch->init();
265 return batch;
266 } else if (localMatrix) {
267 BWFillRectBatchLocalMatrix* batch = BWFillRectBatchLocalMatrix::Create();
268 BWFillRectBatchLocalMatrix::Geometry& geo = *batch->geometry();
269 geo.fColor = color;
270 geo.fViewMatrix = viewMatrix;
271 geo.fLocalMatrix = *localMatrix;
272 geo.fRect = rect;
273 batch->init();
274 return batch;
joshualitt9c80b5f2015-08-13 10:05:51 -0700275 } else {
joshualittae41b382015-08-19 06:54:08 -0700276 BWFillRectBatchSimple* batch = BWFillRectBatchSimple::Create();
277 BWFillRectBatchSimple::Geometry& geo = *batch->geometry();
278 geo.fColor = color;
279 geo.fViewMatrix = viewMatrix;
280 geo.fRect = rect;
281 batch->init();
282 return batch;
joshualitt9c80b5f2015-08-13 10:05:51 -0700283 }
joshualitt9c80b5f2015-08-13 10:05:51 -0700284}
285};
286
287///////////////////////////////////////////////////////////////////////////////////////////////////
288
289#ifdef GR_TEST_UTILS
290
291#include "GrBatchTest.h"
292
bsalomonabd30f52015-08-13 13:34:48 -0700293DRAW_BATCH_TEST_DEFINE(RectBatch) {
joshualittae41b382015-08-19 06:54:08 -0700294 GrColor color = GrRandomColor(random);
295 SkRect rect = GrTest::TestRect(random);
296 SkRect localRect = GrTest::TestRect(random);
297 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
298 SkMatrix localMatrix = GrTest::TestMatrix(random);
joshualitt9c80b5f2015-08-13 10:05:51 -0700299
joshualittae41b382015-08-19 06:54:08 -0700300 bool hasLocalRect = random->nextBool();
301 bool hasLocalMatrix = random->nextBool();
302 return GrBWFillRectBatch::Create(color, viewMatrix, rect, hasLocalRect ? &localRect : nullptr,
303 hasLocalMatrix ? &localMatrix : nullptr);
joshualitt9c80b5f2015-08-13 10:05:51 -0700304}
305
306#endif