blob: d40a0c9cec2c1ff965b5ebfec5d77cfb1f69084f [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
joshualittbcf33d52015-08-26 08:10:35 -07008#include "GrNonAAFillRectBatch.h"
joshualitt9c80b5f2015-08-13 10:05:51 -07009
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"
joshualitt2244c272015-08-21 10:33:15 -070014#include "GrResourceProvider.h"
joshualittae5b2c62015-08-19 08:48:41 -070015#include "GrQuad.h"
bsalomon16b99132015-08-13 14:55:50 -070016#include "GrVertexBatch.h"
joshualitt9c80b5f2015-08-13 10:05:51 -070017
bsalomon08d14152016-06-30 12:45:18 -070018static const int kVertsPerInstance = 4;
19static const int kIndicesPerInstance = 6;
joshualitt2244c272015-08-21 10:33:15 -070020
21/** We always use per-vertex colors so that rects can be batched across color changes. Sometimes
22 we have explicit local coords and sometimes not. We *could* always provide explicit local
23 coords and just duplicate the positions when the caller hasn't provided a local coord rect,
24 but we haven't seen a use case which frequently switches between local rect and no local
25 rect draws.
26
27 The vertex attrib order is always pos, color, [local coords].
28 */
bungeman06ca8ec2016-06-09 08:01:03 -070029static sk_sp<GrGeometryProcessor> make_gp(const SkMatrix& viewMatrix,
30 bool readsCoverage,
31 bool hasExplicitLocalCoords,
32 const SkMatrix* localMatrix) {
joshualitt2244c272015-08-21 10:33:15 -070033 using namespace GrDefaultGeoProcFactory;
34 Color color(Color::kAttribute_Type);
35 Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Type);
36
joshualitt8cce8f12015-08-26 06:23:39 -070037 // If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map
38 // the local rect on the cpu (in case the localMatrix also has perspective).
39 // Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect
40 // to generate vertex local coords
41 if (viewMatrix.hasPerspective()) {
42 LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type :
43 LocalCoords::kUsePosition_Type,
44 localMatrix);
bungeman06ca8ec2016-06-09 08:01:03 -070045 return GrDefaultGeoProcFactory::Make(color, coverage, localCoords, viewMatrix);
joshualitt8cce8f12015-08-26 06:23:39 -070046 } else if (hasExplicitLocalCoords) {
joshualitt2244c272015-08-21 10:33:15 -070047 LocalCoords localCoords(LocalCoords::kHasExplicit_Type);
bungeman06ca8ec2016-06-09 08:01:03 -070048 return GrDefaultGeoProcFactory::Make(color, coverage, localCoords, SkMatrix::I());
joshualitt2244c272015-08-21 10:33:15 -070049 } else {
50 LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix);
bungeman06ca8ec2016-06-09 08:01:03 -070051 return GrDefaultGeoProcFactory::MakeForDeviceSpace(color, coverage, localCoords,
52 viewMatrix);
joshualitt2244c272015-08-21 10:33:15 -070053 }
54}
55
56static void tesselate(intptr_t vertices,
57 size_t vertexStride,
58 GrColor color,
59 const SkMatrix& viewMatrix,
60 const SkRect& rect,
joshualitt8cce8f12015-08-26 06:23:39 -070061 const GrQuad* localQuad) {
joshualitt2244c272015-08-21 10:33:15 -070062 SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
63
64 positions->setRectFan(rect.fLeft, rect.fTop,
65 rect.fRight, rect.fBottom, vertexStride);
joshualitt2244c272015-08-21 10:33:15 -070066
joshualitt8cce8f12015-08-26 06:23:39 -070067 if (!viewMatrix.hasPerspective()) {
bsalomon08d14152016-06-30 12:45:18 -070068 viewMatrix.mapPointsWithStride(positions, vertexStride, kVertsPerInstance);
joshualitt8cce8f12015-08-26 06:23:39 -070069 }
70
71 // Setup local coords
joshualitt2244c272015-08-21 10:33:15 -070072 // TODO we should only do this if local coords are being read
joshualitt8cce8f12015-08-26 06:23:39 -070073 if (localQuad) {
joshualitt2244c272015-08-21 10:33:15 -070074 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
bsalomon08d14152016-06-30 12:45:18 -070075 for (int i = 0; i < kVertsPerInstance; i++) {
joshualitt8cce8f12015-08-26 06:23:39 -070076 SkPoint* coords = reinterpret_cast<SkPoint*>(vertices + kLocalOffset +
77 i * vertexStride);
78 *coords = localQuad->point(i);
joshualitt2244c272015-08-21 10:33:15 -070079 }
80 }
81
82 static const int kColorOffset = sizeof(SkPoint);
83 GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
84 for (int j = 0; j < 4; ++j) {
85 *vertColor = color;
86 vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride);
87 }
88}
89
bsalomon08d14152016-06-30 12:45:18 -070090class NonAAFillRectBatch : public GrVertexBatch {
joshualitt2244c272015-08-21 10:33:15 -070091public:
bsalomon08d14152016-06-30 12:45:18 -070092 DEFINE_BATCH_CLASS_ID
93
bsalomon9d7f1842016-07-01 08:01:36 -070094 NonAAFillRectBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
95 const SkRect* localRect, const SkMatrix* localMatrix)
96 : INHERITED(ClassID()) {
97 SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix ||
98 !localMatrix->hasPerspective()));
99 RectInfo& info = fRects.push_back();
100 info.fColor = color;
101 info.fViewMatrix = viewMatrix;
102 info.fRect = rect;
103 if (localRect && localMatrix) {
104 info.fLocalQuad.setFromMappedRect(*localRect, *localMatrix);
105 } else if (localRect) {
106 info.fLocalQuad.set(*localRect);
107 } else if (localMatrix) {
108 info.fLocalQuad.setFromMappedRect(rect, *localMatrix);
109 } else {
110 info.fLocalQuad.set(rect);
111 }
112 viewMatrix.mapRect(&fBounds, fRects[0].fRect);
113 }
bsalomon08d14152016-06-30 12:45:18 -0700114
bsalomonbc9b6a42016-07-01 05:35:51 -0700115 const char* name() const override { return "NonAAFillRectBatch"; }
bsalomon08d14152016-06-30 12:45:18 -0700116
117 SkString dumpInfo() const override {
118 SkString str;
bsalomon9d7f1842016-07-01 08:01:36 -0700119 str.appendf("# batched: %d\n", fRects.count());
120 for (int i = 0; i < fRects.count(); ++i) {
121 const RectInfo& info = fRects[i];
bsalomonbc9b6a42016-07-01 05:35:51 -0700122 str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
bsalomon9d7f1842016-07-01 08:01:36 -0700123 i, info.fColor,
124 info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight, info.fRect.fBottom);
bsalomon08d14152016-06-30 12:45:18 -0700125 }
126 str.append(INHERITED::dumpInfo());
127 return str;
128 }
129
130 void computePipelineOptimizations(GrInitInvariantOutput* color,
131 GrInitInvariantOutput* coverage,
132 GrBatchToXPOverrides* overrides) const override {
133 // When this is called on a batch, there is only one geometry bundle
bsalomon9d7f1842016-07-01 08:01:36 -0700134 color->setKnownFourComponents(fRects[0].fColor);
bsalomonbc9b6a42016-07-01 05:35:51 -0700135 coverage->setKnownSingleComponent(0xff);
bsalomon08d14152016-06-30 12:45:18 -0700136 }
137
138 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
bsalomon9d7f1842016-07-01 08:01:36 -0700139 overrides.getOverrideColorIfSet(&fRects[0].fColor);
bsalomon08d14152016-06-30 12:45:18 -0700140 fOverrides = overrides;
141 }
142
bsalomon08d14152016-06-30 12:45:18 -0700143private:
bsalomon08d14152016-06-30 12:45:18 -0700144 NonAAFillRectBatch() : INHERITED(ClassID()) {}
145
146 void onPrepareDraws(Target* target) const override {
bsalomon9d7f1842016-07-01 08:01:36 -0700147 sk_sp<GrGeometryProcessor> gp = make_gp(fRects[0].fViewMatrix, fOverrides.readsCoverage(),
bsalomonbc9b6a42016-07-01 05:35:51 -0700148 true, nullptr);
bsalomon08d14152016-06-30 12:45:18 -0700149 if (!gp) {
150 SkDebugf("Couldn't create GrGeometryProcessor\n");
151 return;
152 }
bsalomonbc9b6a42016-07-01 05:35:51 -0700153 SkASSERT(gp->getVertexStride() ==
154 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
bsalomon08d14152016-06-30 12:45:18 -0700155
156 size_t vertexStride = gp->getVertexStride();
bsalomon9d7f1842016-07-01 08:01:36 -0700157 int instanceCount = fRects.count();
bsalomon08d14152016-06-30 12:45:18 -0700158
bsalomonbc9b6a42016-07-01 05:35:51 -0700159 SkAutoTUnref<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
bsalomon08d14152016-06-30 12:45:18 -0700160 InstancedHelper helper;
161 void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
162 indexBuffer, kVertsPerInstance,
163 kIndicesPerInstance, instanceCount);
164 if (!vertices || !indexBuffer) {
165 SkDebugf("Could not allocate vertices\n");
166 return;
167 }
168
169 for (int i = 0; i < instanceCount; i++) {
170 intptr_t verts = reinterpret_cast<intptr_t>(vertices) +
171 i * kVertsPerInstance * vertexStride;
bsalomon9d7f1842016-07-01 08:01:36 -0700172 tesselate(verts, vertexStride, fRects[i].fColor, fRects[i].fViewMatrix,
173 fRects[i].fRect, &fRects[i].fLocalQuad);
bsalomon08d14152016-06-30 12:45:18 -0700174 }
175 helper.recordDraw(target, gp.get());
176 }
177
bsalomon08d14152016-06-30 12:45:18 -0700178 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
179 NonAAFillRectBatch* that = t->cast<NonAAFillRectBatch>();
180 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
181 that->bounds(), caps)) {
182 return false;
183 }
184
bsalomon08d14152016-06-30 12:45:18 -0700185 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
186 // not tweaking
187 if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) {
188 fOverrides = that->fOverrides;
189 }
190
bsalomon9d7f1842016-07-01 08:01:36 -0700191 fRects.push_back_n(that->fRects.count(), that->fRects.begin());
bsalomon08d14152016-06-30 12:45:18 -0700192 this->joinBounds(that->bounds());
193 return true;
194 }
195
bsalomon9d7f1842016-07-01 08:01:36 -0700196 struct RectInfo {
197 GrColor fColor;
198 SkMatrix fViewMatrix;
199 SkRect fRect;
200 GrQuad fLocalQuad;
201 };
202
bsalomon08d14152016-06-30 12:45:18 -0700203 GrXPOverridesForBatch fOverrides;
bsalomon9d7f1842016-07-01 08:01:36 -0700204 SkSTArray<1, RectInfo, true> fRects;
bsalomon08d14152016-06-30 12:45:18 -0700205
206 typedef GrVertexBatch INHERITED;
joshualitt2244c272015-08-21 10:33:15 -0700207};
208
joshualitt8cce8f12015-08-26 06:23:39 -0700209// We handle perspective in the local matrix or viewmatrix with special batches
bsalomon08d14152016-06-30 12:45:18 -0700210class NonAAFillRectPerspectiveBatch : public GrVertexBatch {
joshualitt2244c272015-08-21 10:33:15 -0700211public:
bsalomon08d14152016-06-30 12:45:18 -0700212 DEFINE_BATCH_CLASS_ID
213
bsalomon9d7f1842016-07-01 08:01:36 -0700214 NonAAFillRectPerspectiveBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
215 const SkRect* localRect, const SkMatrix* localMatrix)
216 : INHERITED(ClassID())
217 , fViewMatrix(viewMatrix) {
218 SkASSERT(viewMatrix.hasPerspective() || (localMatrix &&
219 localMatrix->hasPerspective()));
220 RectInfo& info = fRects.push_back();
221 info.fColor = color;
222 info.fRect = rect;
223 fHasLocalRect = SkToBool(localRect);
224 fHasLocalMatrix = SkToBool(localMatrix);
225 if (fHasLocalMatrix) {
226 fLocalMatrix = *localMatrix;
227 }
228 if (fHasLocalRect) {
229 info.fLocalRect = *localRect;
230 }
231 viewMatrix.mapRect(&fBounds, rect);
232 }
bsalomon08d14152016-06-30 12:45:18 -0700233
bsalomonbc9b6a42016-07-01 05:35:51 -0700234 const char* name() const override { return "NonAAFillRectPerspectiveBatch"; }
bsalomon08d14152016-06-30 12:45:18 -0700235
236 SkString dumpInfo() const override {
237 SkString str;
bsalomon9d7f1842016-07-01 08:01:36 -0700238 str.appendf("# batched: %d\n", fRects.count());
239 for (int i = 0; i < fRects.count(); ++i) {
240 const RectInfo& geo = fRects[0];
bsalomonbc9b6a42016-07-01 05:35:51 -0700241 str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
242 i, geo.fColor,
243 geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight, geo.fRect.fBottom);
bsalomon08d14152016-06-30 12:45:18 -0700244 }
245 str.append(INHERITED::dumpInfo());
246 return str;
247 }
248
249 void computePipelineOptimizations(GrInitInvariantOutput* color,
250 GrInitInvariantOutput* coverage,
251 GrBatchToXPOverrides* overrides) const override {
252 // When this is called on a batch, there is only one geometry bundle
bsalomon9d7f1842016-07-01 08:01:36 -0700253 color->setKnownFourComponents(fRects[0].fColor);
bsalomonbc9b6a42016-07-01 05:35:51 -0700254 coverage->setKnownSingleComponent(0xff);
bsalomon08d14152016-06-30 12:45:18 -0700255 }
256
257 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
bsalomon9d7f1842016-07-01 08:01:36 -0700258 overrides.getOverrideColorIfSet(&fRects[0].fColor);
bsalomon08d14152016-06-30 12:45:18 -0700259 fOverrides = overrides;
260 }
261
bsalomon08d14152016-06-30 12:45:18 -0700262private:
bsalomon08d14152016-06-30 12:45:18 -0700263 NonAAFillRectPerspectiveBatch() : INHERITED(ClassID()) {}
264
265 void onPrepareDraws(Target* target) const override {
bsalomon9d7f1842016-07-01 08:01:36 -0700266 sk_sp<GrGeometryProcessor> gp = make_gp(fViewMatrix, fOverrides.readsCoverage(),
267 fHasLocalRect,
268 fHasLocalMatrix ? &fLocalMatrix : nullptr);
bsalomon08d14152016-06-30 12:45:18 -0700269 if (!gp) {
270 SkDebugf("Couldn't create GrGeometryProcessor\n");
271 return;
272 }
bsalomon9d7f1842016-07-01 08:01:36 -0700273 SkASSERT(fHasLocalRect
bsalomonbc9b6a42016-07-01 05:35:51 -0700274 ? gp->getVertexStride() ==
275 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
276 : gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
bsalomon08d14152016-06-30 12:45:18 -0700277
278 size_t vertexStride = gp->getVertexStride();
bsalomon9d7f1842016-07-01 08:01:36 -0700279 int instanceCount = fRects.count();
bsalomon08d14152016-06-30 12:45:18 -0700280
bsalomonbc9b6a42016-07-01 05:35:51 -0700281 SkAutoTUnref<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
bsalomon08d14152016-06-30 12:45:18 -0700282 InstancedHelper helper;
283 void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
284 indexBuffer, kVertsPerInstance,
285 kIndicesPerInstance, instanceCount);
286 if (!vertices || !indexBuffer) {
287 SkDebugf("Could not allocate vertices\n");
288 return;
289 }
290
291 for (int i = 0; i < instanceCount; i++) {
bsalomon9d7f1842016-07-01 08:01:36 -0700292 const RectInfo& info = fRects[i];
bsalomon08d14152016-06-30 12:45:18 -0700293 intptr_t verts = reinterpret_cast<intptr_t>(vertices) +
294 i * kVertsPerInstance * vertexStride;
bsalomon9d7f1842016-07-01 08:01:36 -0700295 if (fHasLocalRect) {
296 GrQuad quad(info.fLocalRect);
297 tesselate(verts, vertexStride, info.fColor, fViewMatrix, info.fRect, &quad);
bsalomonbc9b6a42016-07-01 05:35:51 -0700298 } else {
bsalomon9d7f1842016-07-01 08:01:36 -0700299 tesselate(verts, vertexStride, info.fColor, fViewMatrix, info.fRect, nullptr);
bsalomonbc9b6a42016-07-01 05:35:51 -0700300 }
bsalomon08d14152016-06-30 12:45:18 -0700301 }
302 helper.recordDraw(target, gp.get());
303 }
304
bsalomon08d14152016-06-30 12:45:18 -0700305 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
306 NonAAFillRectPerspectiveBatch* that = t->cast<NonAAFillRectPerspectiveBatch>();
307 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
308 that->bounds(), caps)) {
309 return false;
310 }
311
bsalomonbc9b6a42016-07-01 05:35:51 -0700312 // We could batch across perspective vm changes if we really wanted to
bsalomon9d7f1842016-07-01 08:01:36 -0700313 if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
bsalomonbc9b6a42016-07-01 05:35:51 -0700314 return false;
315 }
bsalomon9d7f1842016-07-01 08:01:36 -0700316 if (fHasLocalRect != that->fHasLocalRect) {
bsalomonbc9b6a42016-07-01 05:35:51 -0700317 return false;
318 }
bsalomon9d7f1842016-07-01 08:01:36 -0700319 if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
bsalomon08d14152016-06-30 12:45:18 -0700320 return false;
321 }
322
323 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
324 // not tweaking
325 if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) {
326 fOverrides = that->fOverrides;
327 }
328
bsalomon9d7f1842016-07-01 08:01:36 -0700329 fRects.push_back_n(that->fRects.count(), that->fRects.begin());
bsalomon08d14152016-06-30 12:45:18 -0700330 this->joinBounds(that->bounds());
331 return true;
332 }
333
bsalomon9d7f1842016-07-01 08:01:36 -0700334 struct RectInfo {
335 SkRect fRect;
336 GrColor fColor;
337 SkRect fLocalRect;
338 };
339
bsalomon08d14152016-06-30 12:45:18 -0700340 GrXPOverridesForBatch fOverrides;
bsalomon9d7f1842016-07-01 08:01:36 -0700341 SkSTArray<1, RectInfo, true> fRects;
342 bool fHasLocalMatrix;
343 bool fHasLocalRect;
344 SkMatrix fLocalMatrix;
345 SkMatrix fViewMatrix;
bsalomon08d14152016-06-30 12:45:18 -0700346
347 typedef GrVertexBatch INHERITED;
joshualittae41b382015-08-19 06:54:08 -0700348};
349
bsalomonb8cbd202016-06-30 13:09:48 -0700350namespace GrNonAAFillRectBatch {
351
352GrDrawBatch* Create(GrColor color,
353 const SkMatrix& viewMatrix,
354 const SkRect& rect,
355 const SkRect* localRect,
356 const SkMatrix* localMatrix) {
bsalomon9d7f1842016-07-01 08:01:36 -0700357 return new NonAAFillRectBatch(color, viewMatrix, rect, localRect, localMatrix);
joshualitt9c80b5f2015-08-13 10:05:51 -0700358}
joshualitt3566d442015-09-18 07:12:55 -0700359
bsalomonb8cbd202016-06-30 13:09:48 -0700360GrDrawBatch* CreateWithPerspective(GrColor color,
361 const SkMatrix& viewMatrix,
362 const SkRect& rect,
363 const SkRect* localRect,
364 const SkMatrix* localMatrix) {
bsalomon9d7f1842016-07-01 08:01:36 -0700365 return new NonAAFillRectPerspectiveBatch(color, viewMatrix, rect, localRect, localMatrix);
joshualitt3566d442015-09-18 07:12:55 -0700366}
367
joshualitt9c80b5f2015-08-13 10:05:51 -0700368};
369
370///////////////////////////////////////////////////////////////////////////////////////////////////
371
372#ifdef GR_TEST_UTILS
373
374#include "GrBatchTest.h"
375
bsalomonabd30f52015-08-13 13:34:48 -0700376DRAW_BATCH_TEST_DEFINE(RectBatch) {
joshualitt2244c272015-08-21 10:33:15 -0700377 GrColor color = GrRandomColor(random);
378 SkRect rect = GrTest::TestRect(random);
379 SkRect localRect = GrTest::TestRect(random);
380 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
381 SkMatrix localMatrix = GrTest::TestMatrix(random);
joshualitt9c80b5f2015-08-13 10:05:51 -0700382
joshualitt2244c272015-08-21 10:33:15 -0700383 bool hasLocalRect = random->nextBool();
384 bool hasLocalMatrix = random->nextBool();
joshualittbcf33d52015-08-26 08:10:35 -0700385 return GrNonAAFillRectBatch::Create(color, viewMatrix, rect,
386 hasLocalRect ? &localRect : nullptr,
387 hasLocalMatrix ? &localMatrix : nullptr);
joshualitt9c80b5f2015-08-13 10:05:51 -0700388}
389
390#endif