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