blob: 4f93adf07429c5d7a0c930f1fa477339886f80d1 [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:
bsalomon08d14152016-06-30 12:45:18 -0700162 DEFINE_BATCH_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 }
194 str.append(INHERITED::dumpInfo());
195 return str;
196 }
197
198 void computePipelineOptimizations(GrInitInvariantOutput* color,
199 GrInitInvariantOutput* coverage,
200 GrBatchToXPOverrides* overrides) const override {
bsalomon0fdec8a2016-07-01 06:31:25 -0700201 // When this is called on a batch, there is only one rect
bsalomon4be9a302016-07-06 07:03:26 -0700202 color->setKnownFourComponents(this->first()->color());
bsalomonbc9b6a42016-07-01 05:35:51 -0700203 coverage->setUnknownSingleComponent();
bsalomon08d14152016-06-30 12:45:18 -0700204 }
205
206 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
bsalomon4be9a302016-07-06 07:03:26 -0700207 GrColor color;
208 if (overrides.getOverrideColorIfSet(&color)) {
209 this->first()->setColor(color);
210 }
bsalomon08d14152016-06-30 12:45:18 -0700211 fOverrides = overrides;
212 }
213
bsalomon08d14152016-06-30 12:45:18 -0700214private:
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700215 void onPrepareDraws(Target* target) const override {
bsalomon4be9a302016-07-06 07:03:26 -0700216 bool needLocalCoords = fOverrides.readsLocalCoords();
217 using namespace GrDefaultGeoProcFactory;
218
219 Color color(Color::kAttribute_Type);
220 Coverage::Type coverageType;
221 if (fOverrides.canTweakAlphaForCoverage()) {
222 coverageType = Coverage::kSolid_Type;
223 } else {
224 coverageType = Coverage::kAttribute_Type;
225 }
226 Coverage coverage(coverageType);
227 LocalCoords lc = needLocalCoords ? LocalCoords::kHasExplicit_Type
228 : LocalCoords::kUnused_Type;
229 sk_sp<GrGeometryProcessor> gp = GrDefaultGeoProcFactory::Make(color, coverage, lc,
230 SkMatrix::I());
bsalomon08d14152016-06-30 12:45:18 -0700231 if (!gp) {
232 SkDebugf("Couldn't create GrGeometryProcessor\n");
233 return;
234 }
235
236 size_t vertexStride = gp->getVertexStride();
bsalomon08d14152016-06-30 12:45:18 -0700237
bsalomonbc9b6a42016-07-01 05:35:51 -0700238 SkAutoTUnref<const GrBuffer> indexBuffer(get_index_buffer(target->resourceProvider()));
bsalomon08d14152016-06-30 12:45:18 -0700239 InstancedHelper helper;
240 void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
bsalomonbc9b6a42016-07-01 05:35:51 -0700241 indexBuffer, kVertsPerAAFillRect,
bsalomon4be9a302016-07-06 07:03:26 -0700242 kIndicesPerAAFillRect, fRectCnt);
bsalomon08d14152016-06-30 12:45:18 -0700243 if (!vertices || !indexBuffer) {
244 SkDebugf("Could not allocate vertices\n");
245 return;
246 }
247
bsalomon4be9a302016-07-06 07:03:26 -0700248 const RectInfo* info = this->first();
249 const SkMatrix* localMatrix = nullptr;
250 for (int i = 0; i < fRectCnt; i++) {
bsalomon08d14152016-06-30 12:45:18 -0700251 intptr_t verts = reinterpret_cast<intptr_t>(vertices) +
bsalomonbc9b6a42016-07-01 05:35:51 -0700252 i * kVertsPerAAFillRect * vertexStride;
bsalomon4be9a302016-07-06 07:03:26 -0700253 if (needLocalCoords) {
254 if (info->hasLocalMatrix()) {
255 localMatrix = &static_cast<const RectWithLocalMatrixInfo*>(info)->localMatrix();
256 } else {
257 localMatrix = &SkMatrix::I();
258 }
259 }
260 generate_aa_fill_rect_geometry(verts, vertexStride, info->color(),
261 info->viewMatrix(), info->rect(),
262 info->devRect(), fOverrides, localMatrix);
263 info = this->next(info);
bsalomon08d14152016-06-30 12:45:18 -0700264 }
265 helper.recordDraw(target, gp.get());
266 }
267
bsalomon08d14152016-06-30 12:45:18 -0700268 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomon4be9a302016-07-06 07:03:26 -0700269 AAFillRectBatch* that = t->cast<AAFillRectBatch>();
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700270 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
271 that->bounds(), caps)) {
272 return false;
273 }
274
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700275 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
276 // not tweaking
277 if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) {
278 fOverrides = that->fOverrides;
279 }
280
bsalomon4be9a302016-07-06 07:03:26 -0700281 fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
282 fRectCnt += that->fRectCnt;
bsalomon88cf17d2016-07-08 06:40:56 -0700283 this->joinBounds(*that);
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700284 return true;
285 }
286
287 struct RectInfo {
bsalomon4be9a302016-07-06 07:03:26 -0700288 public:
289 RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
290 const SkRect& devRect)
291 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {}
292 bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; }
293 GrColor color() const { return fColor; }
294 const SkMatrix& viewMatrix() const { return fViewMatrix; }
295 const SkRect& rect() const { return fRect; }
296 const SkRect& devRect() const { return fDevRect; }
297
298 void setColor(GrColor color) { fColor = color; }
299 protected:
300 enum class HasLocalMatrix : uint32_t { kNo, kYes };
301
302 RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
303 const SkRect& devRect, HasLocalMatrix hasLM)
304 : fHasLocalMatrix(hasLM)
305 , fColor(color)
306 , fViewMatrix(viewMatrix)
307 , fRect(rect)
308 , fDevRect(devRect) {}
309
310 HasLocalMatrix fHasLocalMatrix;
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700311 GrColor fColor;
312 SkMatrix fViewMatrix;
313 SkRect fRect;
314 SkRect fDevRect;
315 };
316
bsalomon4be9a302016-07-06 07:03:26 -0700317 struct RectWithLocalMatrixInfo : public RectInfo {
318 public:
319 RectWithLocalMatrixInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
320 const SkRect& devRect, const SkMatrix& localMatrix)
321 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes)
322 , fLocalMatrix(localMatrix) {}
323 const SkMatrix& localMatrix() const { return fLocalMatrix; }
324 private:
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700325 SkMatrix fLocalMatrix;
bsalomon0fdec8a2016-07-01 06:31:25 -0700326 };
327
bsalomon4be9a302016-07-06 07:03:26 -0700328 RectInfo* first() { return reinterpret_cast<RectInfo*>(fRectData.begin()); }
329 const RectInfo* first() const { return reinterpret_cast<const RectInfo*>(fRectData.begin()); }
330 const RectInfo* next(const RectInfo* prev) const {
331 intptr_t next = reinterpret_cast<intptr_t>(prev) +
332 (prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo)
333 : sizeof(RectInfo));
334 return reinterpret_cast<const RectInfo*>(next);
335 }
336
bsalomon08d14152016-06-30 12:45:18 -0700337 GrXPOverridesForBatch fOverrides;
bsalomon4be9a302016-07-06 07:03:26 -0700338 SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData;
339 int fRectCnt;
bsalomon08d14152016-06-30 12:45:18 -0700340
341 typedef GrVertexBatch INHERITED;
joshualitt147dc062015-08-12 11:51:46 -0700342};
343
joshualitt37eb1842015-08-12 06:36:57 -0700344namespace GrAAFillRectBatch {
joshualitt9ff64252015-08-10 09:03:51 -0700345
bsalomonabd30f52015-08-13 13:34:48 -0700346GrDrawBatch* Create(GrColor color,
347 const SkMatrix& viewMatrix,
348 const SkRect& rect,
349 const SkRect& devRect) {
bsalomon4be9a302016-07-06 07:03:26 -0700350 return new AAFillRectBatch(color, viewMatrix, rect, devRect, nullptr);
joshualitt147dc062015-08-12 11:51:46 -0700351}
352
bsalomonabd30f52015-08-13 13:34:48 -0700353GrDrawBatch* Create(GrColor color,
354 const SkMatrix& viewMatrix,
355 const SkMatrix& localMatrix,
356 const SkRect& rect,
357 const SkRect& devRect) {
bsalomon4be9a302016-07-06 07:03:26 -0700358 return new AAFillRectBatch(color, viewMatrix, rect, devRect, &localMatrix);
joshualitt9ff64252015-08-10 09:03:51 -0700359}
360
bsalomonc55271f2015-11-09 11:55:57 -0800361GrDrawBatch* Create(GrColor color,
362 const SkMatrix& viewMatrix,
363 const SkMatrix& localMatrix,
364 const SkRect& rect) {
365 SkRect devRect;
366 viewMatrix.mapRect(&devRect, rect);
367 return Create(color, viewMatrix, localMatrix, rect, devRect);
368}
369
370GrDrawBatch* CreateWithLocalRect(GrColor color,
371 const SkMatrix& viewMatrix,
372 const SkRect& rect,
373 const SkRect& localRect) {
374 SkRect devRect;
375 viewMatrix.mapRect(&devRect, rect);
376 SkMatrix localMatrix;
377 if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
378 return nullptr;
379 }
380 return Create(color, viewMatrix, localMatrix, rect, devRect);
381}
382
joshualitt37eb1842015-08-12 06:36:57 -0700383};
384
joshualitt9ff64252015-08-10 09:03:51 -0700385///////////////////////////////////////////////////////////////////////////////////////////////////
386
387#ifdef GR_TEST_UTILS
388
389#include "GrBatchTest.h"
390
bsalomonabd30f52015-08-13 13:34:48 -0700391DRAW_BATCH_TEST_DEFINE(AAFillRectBatch) {
joshualitt090ae8e2015-08-14 09:01:21 -0700392 GrColor color = GrRandomColor(random);
393 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
394 SkRect rect = GrTest::TestRect(random);
395 SkRect devRect = GrTest::TestRect(random);
396 return GrAAFillRectBatch::Create(color, viewMatrix, rect, devRect);
joshualitt147dc062015-08-12 11:51:46 -0700397}
398
bsalomonabd30f52015-08-13 13:34:48 -0700399DRAW_BATCH_TEST_DEFINE(AAFillRectBatchLocalMatrix) {
joshualitt090ae8e2015-08-14 09:01:21 -0700400 GrColor color = GrRandomColor(random);
401 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
402 SkMatrix localMatrix = GrTest::TestMatrix(random);
403 SkRect rect = GrTest::TestRect(random);
404 SkRect devRect = GrTest::TestRect(random);
405 return GrAAFillRectBatch::Create(color, viewMatrix, localMatrix, rect, devRect);
joshualitt9ff64252015-08-10 09:03:51 -0700406}
407
408#endif