blob: c8804daacfa6268d4a243067623e8cd9bcf0ba1c [file] [log] [blame]
joshualitt9ff64252015-08-10 09:03: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 "GrAAFillRectBatch.h"
9
bsalomon08d14152016-06-30 12:45:18 -070010#include "GrBatchFlushState.h"
joshualitt37eb1842015-08-12 06:36:57 -070011#include "GrColor.h"
joshualitt9ff64252015-08-10 09:03:51 -070012#include "GrDefaultGeoProcFactory.h"
13#include "GrResourceKey.h"
14#include "GrResourceProvider.h"
joshualitt37eb1842015-08-12 06:36:57 -070015#include "GrTypes.h"
bsalomon4be9a302016-07-06 07:03:26 -070016#include "GrVertexBatch.h"
joshualitt37eb1842015-08-12 06:36:57 -070017#include "SkMatrix.h"
18#include "SkRect.h"
joshualitt9ff64252015-08-10 09:03:51 -070019
20GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
21
22static void set_inset_fan(SkPoint* pts, size_t stride,
23 const SkRect& r, SkScalar dx, SkScalar dy) {
24 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
25 r.fRight - dx, r.fBottom - dy, stride);
26}
27
joshualitt27801bf2015-08-12 12:52:47 -070028static const int kNumAAFillRectsInIndexBuffer = 256;
29static const int kVertsPerAAFillRect = 8;
30static const int kIndicesPerAAFillRect = 30;
31
cdalton397536c2016-03-25 12:15:03 -070032const GrBuffer* get_index_buffer(GrResourceProvider* resourceProvider) {
joshualitt27801bf2015-08-12 12:52:47 -070033 GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
34
35 static const uint16_t gFillAARectIdx[] = {
36 0, 1, 5, 5, 4, 0,
37 1, 2, 6, 6, 5, 1,
38 2, 3, 7, 7, 6, 2,
39 3, 0, 4, 4, 7, 3,
40 4, 5, 6, 6, 7, 4,
41 };
42 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect);
43 return resourceProvider->findOrCreateInstancedIndexBuffer(gFillAARectIdx,
44 kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer, kVertsPerAAFillRect,
45 gAAFillRectIndexBufferKey);
46}
47
joshualittcd47b712015-08-18 07:25:38 -070048static void generate_aa_fill_rect_geometry(intptr_t verts,
49 size_t vertexStride,
50 GrColor color,
51 const SkMatrix& viewMatrix,
52 const SkRect& rect,
53 const SkRect& devRect,
ethannicholasff210322015-11-24 12:10:10 -080054 const GrXPOverridesForBatch& overrides,
joshualittcd47b712015-08-18 07:25:38 -070055 const SkMatrix* localMatrix) {
56 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
57 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
58
robertphillips0851d2d2016-06-02 05:21:34 -070059 SkScalar inset;
joshualittcd47b712015-08-18 07:25:38 -070060
61 if (viewMatrix.rectStaysRect()) {
robertphillips0851d2d2016-06-02 05:21:34 -070062 inset = SkMinScalar(devRect.width(), SK_Scalar1);
63 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
64
joshualittcd47b712015-08-18 07:25:38 -070065 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
66 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
67 } else {
68 // compute transformed (1, 0) and (0, 1) vectors
69 SkVector vec[2] = {
70 { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] },
71 { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] }
72 };
73
robertphillips0851d2d2016-06-02 05:21:34 -070074 SkScalar len1 = SkPoint::Normalize(&vec[0]);
joshualittcd47b712015-08-18 07:25:38 -070075 vec[0].scale(SK_ScalarHalf);
robertphillips0851d2d2016-06-02 05:21:34 -070076 SkScalar len2 = SkPoint::Normalize(&vec[1]);
joshualittcd47b712015-08-18 07:25:38 -070077 vec[1].scale(SK_ScalarHalf);
78
robertphillips0851d2d2016-06-02 05:21:34 -070079 inset = SkMinScalar(len1 * rect.width(), SK_Scalar1);
80 inset = SK_ScalarHalf * SkMinScalar(inset, len2 * rect.height());
81
joshualittcd47b712015-08-18 07:25:38 -070082 // create the rotated rect
83 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
84 rect.fRight, rect.fBottom, vertexStride);
85 viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
86
87 // Now create the inset points and then outset the original
88 // rotated points
89
90 // TL
91 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
92 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
93 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
94 // BL
95 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
96 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
97 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
98 // BR
99 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
100 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
101 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
102 // TR
103 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
104 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
105 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
106 }
107
108 if (localMatrix) {
109 SkMatrix invViewMatrix;
110 if (!viewMatrix.invert(&invViewMatrix)) {
bsalomon4be9a302016-07-06 07:03:26 -0700111 SkDebugf("View matrix is non-invertible, local coords will be wrong.");
joshualittcd47b712015-08-18 07:25:38 -0700112 invViewMatrix = SkMatrix::I();
113 }
114 SkMatrix localCoordMatrix;
115 localCoordMatrix.setConcat(*localMatrix, invViewMatrix);
116 SkPoint* fan0Loc = reinterpret_cast<SkPoint*>(verts + sizeof(SkPoint) + sizeof(GrColor));
117 localCoordMatrix.mapPointsWithStride(fan0Loc, fan0Pos, vertexStride, 8);
118 }
119
ethannicholasff210322015-11-24 12:10:10 -0800120 bool tweakAlphaForCoverage = overrides.canTweakAlphaForCoverage();
joshualittcd47b712015-08-18 07:25:38 -0700121
122 // Make verts point to vertex color and then set all the color and coverage vertex attrs
123 // values.
124 verts += sizeof(SkPoint);
125
126 // The coverage offset is always the last vertex attribute
127 intptr_t coverageOffset = vertexStride - sizeof(GrColor) - sizeof(SkPoint);
128 for (int i = 0; i < 4; ++i) {
129 if (tweakAlphaForCoverage) {
130 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
131 } else {
132 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
133 *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = 0;
134 }
135 }
136
137 int scale;
138 if (inset < SK_ScalarHalf) {
139 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
140 SkASSERT(scale >= 0 && scale <= 255);
141 } else {
142 scale = 0xff;
143 }
144
145 verts += 4 * vertexStride;
146
147 float innerCoverage = GrNormalizeByteToFloat(scale);
148 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
149
150 for (int i = 0; i < 4; ++i) {
151 if (tweakAlphaForCoverage) {
152 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
153 } else {
154 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
155 *reinterpret_cast<float*>(verts + i * vertexStride +
156 coverageOffset) = innerCoverage;
157 }
158 }
159}
bsalomon4be9a302016-07-06 07:03:26 -0700160class AAFillRectBatch : public GrVertexBatch {
joshualitt2ad37be2015-08-18 10:16:01 -0700161public:
Brian Salomon25a88092016-12-01 09:36:50 -0500162 DEFINE_OP_CLASS_ID
bsalomon4be9a302016-07-06 07:03:26 -0700163
164 AAFillRectBatch(GrColor color,
165 const SkMatrix& viewMatrix,
166 const SkRect& rect,
167 const SkRect& devRect,
168 const SkMatrix* localMatrix) : INHERITED(ClassID()) {
169 if (localMatrix) {
170 void* mem = fRectData.push_back_n(sizeof(RectWithLocalMatrixInfo));
171 new (mem) RectWithLocalMatrixInfo(color, viewMatrix, rect, devRect, *localMatrix);
172 } else {
173 void* mem = fRectData.push_back_n(sizeof(RectInfo));
174 new (mem) RectInfo(color, viewMatrix, rect, devRect);
175 }
bsalomon88cf17d2016-07-08 06:40:56 -0700176 IsZeroArea zeroArea = (!rect.width() || !rect.height()) ? IsZeroArea::kYes
177 : IsZeroArea::kNo;
178 this->setBounds(devRect, HasAABloat::kYes, zeroArea);
bsalomon4be9a302016-07-06 07:03:26 -0700179 fRectCnt = 1;
bsalomon0fdec8a2016-07-01 06:31:25 -0700180 }
bsalomon08d14152016-06-30 12:45:18 -0700181
bsalomon4be9a302016-07-06 07:03:26 -0700182 const char* name() const override { return "AAFillRectBatch"; }
bsalomon08d14152016-06-30 12:45:18 -0700183
184 SkString dumpInfo() const override {
185 SkString str;
bsalomon4be9a302016-07-06 07:03:26 -0700186 str.appendf("# batched: %d\n", fRectCnt);
187 const RectInfo* info = this->first();
188 for (int i = 0; i < fRectCnt; ++i) {
189 const SkRect& rect = info->rect();
bsalomonbc9b6a42016-07-01 05:35:51 -0700190 str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
bsalomon4be9a302016-07-06 07:03:26 -0700191 i, info->color(), rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
192 info = this->next(info);
bsalomon08d14152016-06-30 12:45:18 -0700193 }
Brian Salomon7c3e7182016-12-01 09:35:30 -0500194 str.append(DumpPipelineInfo(*this->pipeline()));
bsalomon08d14152016-06-30 12:45:18 -0700195 str.append(INHERITED::dumpInfo());
196 return str;
197 }
198
199 void computePipelineOptimizations(GrInitInvariantOutput* color,
200 GrInitInvariantOutput* coverage,
201 GrBatchToXPOverrides* overrides) const override {
bsalomon0fdec8a2016-07-01 06:31:25 -0700202 // When this is called on a batch, there is only one rect
bsalomon4be9a302016-07-06 07:03:26 -0700203 color->setKnownFourComponents(this->first()->color());
bsalomonbc9b6a42016-07-01 05:35:51 -0700204 coverage->setUnknownSingleComponent();
bsalomon08d14152016-06-30 12:45:18 -0700205 }
206
207 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
bsalomon4be9a302016-07-06 07:03:26 -0700208 GrColor color;
209 if (overrides.getOverrideColorIfSet(&color)) {
210 this->first()->setColor(color);
211 }
bsalomon08d14152016-06-30 12:45:18 -0700212 fOverrides = overrides;
213 }
214
bsalomon08d14152016-06-30 12:45:18 -0700215private:
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700216 void onPrepareDraws(Target* target) const override {
bsalomon4be9a302016-07-06 07:03:26 -0700217 bool needLocalCoords = fOverrides.readsLocalCoords();
218 using namespace GrDefaultGeoProcFactory;
219
220 Color color(Color::kAttribute_Type);
221 Coverage::Type coverageType;
222 if (fOverrides.canTweakAlphaForCoverage()) {
223 coverageType = Coverage::kSolid_Type;
224 } else {
225 coverageType = Coverage::kAttribute_Type;
226 }
227 Coverage coverage(coverageType);
228 LocalCoords lc = needLocalCoords ? LocalCoords::kHasExplicit_Type
229 : LocalCoords::kUnused_Type;
230 sk_sp<GrGeometryProcessor> gp = GrDefaultGeoProcFactory::Make(color, coverage, lc,
231 SkMatrix::I());
bsalomon08d14152016-06-30 12:45:18 -0700232 if (!gp) {
233 SkDebugf("Couldn't create GrGeometryProcessor\n");
234 return;
235 }
236
237 size_t vertexStride = gp->getVertexStride();
bsalomon08d14152016-06-30 12:45:18 -0700238
Hal Canary144caf52016-11-07 17:57:18 -0500239 sk_sp<const GrBuffer> indexBuffer(get_index_buffer(target->resourceProvider()));
bsalomon08d14152016-06-30 12:45:18 -0700240 InstancedHelper helper;
241 void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
Hal Canary144caf52016-11-07 17:57:18 -0500242 indexBuffer.get(), kVertsPerAAFillRect,
bsalomon4be9a302016-07-06 07:03:26 -0700243 kIndicesPerAAFillRect, fRectCnt);
bsalomon08d14152016-06-30 12:45:18 -0700244 if (!vertices || !indexBuffer) {
245 SkDebugf("Could not allocate vertices\n");
246 return;
247 }
248
bsalomon4be9a302016-07-06 07:03:26 -0700249 const RectInfo* info = this->first();
250 const SkMatrix* localMatrix = nullptr;
251 for (int i = 0; i < fRectCnt; i++) {
bsalomon08d14152016-06-30 12:45:18 -0700252 intptr_t verts = reinterpret_cast<intptr_t>(vertices) +
bsalomonbc9b6a42016-07-01 05:35:51 -0700253 i * kVertsPerAAFillRect * vertexStride;
bsalomon4be9a302016-07-06 07:03:26 -0700254 if (needLocalCoords) {
255 if (info->hasLocalMatrix()) {
256 localMatrix = &static_cast<const RectWithLocalMatrixInfo*>(info)->localMatrix();
257 } else {
258 localMatrix = &SkMatrix::I();
259 }
260 }
261 generate_aa_fill_rect_geometry(verts, vertexStride, info->color(),
262 info->viewMatrix(), info->rect(),
263 info->devRect(), fOverrides, localMatrix);
264 info = this->next(info);
bsalomon08d14152016-06-30 12:45:18 -0700265 }
266 helper.recordDraw(target, gp.get());
267 }
268
Brian Salomon25a88092016-12-01 09:36:50 -0500269 bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
bsalomon4be9a302016-07-06 07:03:26 -0700270 AAFillRectBatch* that = t->cast<AAFillRectBatch>();
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700271 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
272 that->bounds(), caps)) {
273 return false;
274 }
275
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700276 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
277 // not tweaking
278 if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) {
279 fOverrides = that->fOverrides;
280 }
281
bsalomon4be9a302016-07-06 07:03:26 -0700282 fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
283 fRectCnt += that->fRectCnt;
bsalomon88cf17d2016-07-08 06:40:56 -0700284 this->joinBounds(*that);
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700285 return true;
286 }
287
288 struct RectInfo {
bsalomon4be9a302016-07-06 07:03:26 -0700289 public:
290 RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
291 const SkRect& devRect)
292 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {}
293 bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; }
294 GrColor color() const { return fColor; }
295 const SkMatrix& viewMatrix() const { return fViewMatrix; }
296 const SkRect& rect() const { return fRect; }
297 const SkRect& devRect() const { return fDevRect; }
298
299 void setColor(GrColor color) { fColor = color; }
300 protected:
301 enum class HasLocalMatrix : uint32_t { kNo, kYes };
302
303 RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
304 const SkRect& devRect, HasLocalMatrix hasLM)
305 : fHasLocalMatrix(hasLM)
306 , fColor(color)
307 , fViewMatrix(viewMatrix)
308 , fRect(rect)
309 , fDevRect(devRect) {}
310
311 HasLocalMatrix fHasLocalMatrix;
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700312 GrColor fColor;
313 SkMatrix fViewMatrix;
314 SkRect fRect;
315 SkRect fDevRect;
316 };
317
bsalomon4be9a302016-07-06 07:03:26 -0700318 struct RectWithLocalMatrixInfo : public RectInfo {
319 public:
320 RectWithLocalMatrixInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
321 const SkRect& devRect, const SkMatrix& localMatrix)
322 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes)
323 , fLocalMatrix(localMatrix) {}
324 const SkMatrix& localMatrix() const { return fLocalMatrix; }
325 private:
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700326 SkMatrix fLocalMatrix;
bsalomon0fdec8a2016-07-01 06:31:25 -0700327 };
328
bsalomon4be9a302016-07-06 07:03:26 -0700329 RectInfo* first() { return reinterpret_cast<RectInfo*>(fRectData.begin()); }
330 const RectInfo* first() const { return reinterpret_cast<const RectInfo*>(fRectData.begin()); }
331 const RectInfo* next(const RectInfo* prev) const {
332 intptr_t next = reinterpret_cast<intptr_t>(prev) +
333 (prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo)
334 : sizeof(RectInfo));
335 return reinterpret_cast<const RectInfo*>(next);
336 }
337
bsalomon08d14152016-06-30 12:45:18 -0700338 GrXPOverridesForBatch fOverrides;
bsalomon4be9a302016-07-06 07:03:26 -0700339 SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData;
340 int fRectCnt;
bsalomon08d14152016-06-30 12:45:18 -0700341
342 typedef GrVertexBatch INHERITED;
joshualitt147dc062015-08-12 11:51:46 -0700343};
344
joshualitt37eb1842015-08-12 06:36:57 -0700345namespace GrAAFillRectBatch {
joshualitt9ff64252015-08-10 09:03:51 -0700346
bsalomonabd30f52015-08-13 13:34:48 -0700347GrDrawBatch* Create(GrColor color,
348 const SkMatrix& viewMatrix,
349 const SkRect& rect,
350 const SkRect& devRect) {
bsalomon4be9a302016-07-06 07:03:26 -0700351 return new AAFillRectBatch(color, viewMatrix, rect, devRect, nullptr);
joshualitt147dc062015-08-12 11:51:46 -0700352}
353
bsalomonabd30f52015-08-13 13:34:48 -0700354GrDrawBatch* Create(GrColor color,
355 const SkMatrix& viewMatrix,
356 const SkMatrix& localMatrix,
357 const SkRect& rect,
358 const SkRect& devRect) {
bsalomon4be9a302016-07-06 07:03:26 -0700359 return new AAFillRectBatch(color, viewMatrix, rect, devRect, &localMatrix);
joshualitt9ff64252015-08-10 09:03:51 -0700360}
361
bsalomonc55271f2015-11-09 11:55:57 -0800362GrDrawBatch* Create(GrColor color,
363 const SkMatrix& viewMatrix,
364 const SkMatrix& localMatrix,
365 const SkRect& rect) {
366 SkRect devRect;
367 viewMatrix.mapRect(&devRect, rect);
368 return Create(color, viewMatrix, localMatrix, rect, devRect);
369}
370
371GrDrawBatch* CreateWithLocalRect(GrColor color,
372 const SkMatrix& viewMatrix,
373 const SkRect& rect,
374 const SkRect& localRect) {
375 SkRect devRect;
376 viewMatrix.mapRect(&devRect, rect);
377 SkMatrix localMatrix;
378 if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
379 return nullptr;
380 }
381 return Create(color, viewMatrix, localMatrix, rect, devRect);
382}
383
joshualitt37eb1842015-08-12 06:36:57 -0700384};
385
joshualitt9ff64252015-08-10 09:03:51 -0700386///////////////////////////////////////////////////////////////////////////////////////////////////
387
388#ifdef GR_TEST_UTILS
389
390#include "GrBatchTest.h"
391
bsalomonabd30f52015-08-13 13:34:48 -0700392DRAW_BATCH_TEST_DEFINE(AAFillRectBatch) {
joshualitt090ae8e2015-08-14 09:01:21 -0700393 GrColor color = GrRandomColor(random);
394 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
395 SkRect rect = GrTest::TestRect(random);
396 SkRect devRect = GrTest::TestRect(random);
397 return GrAAFillRectBatch::Create(color, viewMatrix, rect, devRect);
joshualitt147dc062015-08-12 11:51:46 -0700398}
399
bsalomonabd30f52015-08-13 13:34:48 -0700400DRAW_BATCH_TEST_DEFINE(AAFillRectBatchLocalMatrix) {
joshualitt090ae8e2015-08-14 09:01:21 -0700401 GrColor color = GrRandomColor(random);
402 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
403 SkMatrix localMatrix = GrTest::TestMatrix(random);
404 SkRect rect = GrTest::TestRect(random);
405 SkRect devRect = GrTest::TestRect(random);
406 return GrAAFillRectBatch::Create(color, viewMatrix, localMatrix, rect, devRect);
joshualitt9ff64252015-08-10 09:03:51 -0700407}
408
409#endif