blob: fedde703988d7be19ea1ee690da734e4251697c9 [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 }
bsalomon0fdec8a2016-07-01 06:31:25 -0700176 fBounds = devRect;
bsalomon4be9a302016-07-06 07:03:26 -0700177 fRectCnt = 1;
bsalomon0fdec8a2016-07-01 06:31:25 -0700178 }
bsalomon08d14152016-06-30 12:45:18 -0700179
bsalomon4be9a302016-07-06 07:03:26 -0700180 const char* name() const override { return "AAFillRectBatch"; }
bsalomon08d14152016-06-30 12:45:18 -0700181
182 SkString dumpInfo() const override {
183 SkString str;
bsalomon4be9a302016-07-06 07:03:26 -0700184 str.appendf("# batched: %d\n", fRectCnt);
185 const RectInfo* info = this->first();
186 for (int i = 0; i < fRectCnt; ++i) {
187 const SkRect& rect = info->rect();
bsalomonbc9b6a42016-07-01 05:35:51 -0700188 str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
bsalomon4be9a302016-07-06 07:03:26 -0700189 i, info->color(), rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
190 info = this->next(info);
bsalomon08d14152016-06-30 12:45:18 -0700191 }
192 str.append(INHERITED::dumpInfo());
193 return str;
194 }
195
196 void computePipelineOptimizations(GrInitInvariantOutput* color,
197 GrInitInvariantOutput* coverage,
198 GrBatchToXPOverrides* overrides) const override {
bsalomon0fdec8a2016-07-01 06:31:25 -0700199 // When this is called on a batch, there is only one rect
bsalomon4be9a302016-07-06 07:03:26 -0700200 color->setKnownFourComponents(this->first()->color());
bsalomonbc9b6a42016-07-01 05:35:51 -0700201 coverage->setUnknownSingleComponent();
bsalomon08d14152016-06-30 12:45:18 -0700202 }
203
204 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
bsalomon4be9a302016-07-06 07:03:26 -0700205 GrColor color;
206 if (overrides.getOverrideColorIfSet(&color)) {
207 this->first()->setColor(color);
208 }
bsalomon08d14152016-06-30 12:45:18 -0700209 fOverrides = overrides;
210 }
211
bsalomon08d14152016-06-30 12:45:18 -0700212private:
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700213 void onPrepareDraws(Target* target) const override {
bsalomon4be9a302016-07-06 07:03:26 -0700214 bool needLocalCoords = fOverrides.readsLocalCoords();
215 using namespace GrDefaultGeoProcFactory;
216
217 Color color(Color::kAttribute_Type);
218 Coverage::Type coverageType;
219 if (fOverrides.canTweakAlphaForCoverage()) {
220 coverageType = Coverage::kSolid_Type;
221 } else {
222 coverageType = Coverage::kAttribute_Type;
223 }
224 Coverage coverage(coverageType);
225 LocalCoords lc = needLocalCoords ? LocalCoords::kHasExplicit_Type
226 : LocalCoords::kUnused_Type;
227 sk_sp<GrGeometryProcessor> gp = GrDefaultGeoProcFactory::Make(color, coverage, lc,
228 SkMatrix::I());
bsalomon08d14152016-06-30 12:45:18 -0700229 if (!gp) {
230 SkDebugf("Couldn't create GrGeometryProcessor\n");
231 return;
232 }
233
234 size_t vertexStride = gp->getVertexStride();
bsalomon08d14152016-06-30 12:45:18 -0700235
bsalomonbc9b6a42016-07-01 05:35:51 -0700236 SkAutoTUnref<const GrBuffer> indexBuffer(get_index_buffer(target->resourceProvider()));
bsalomon08d14152016-06-30 12:45:18 -0700237 InstancedHelper helper;
238 void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
bsalomonbc9b6a42016-07-01 05:35:51 -0700239 indexBuffer, kVertsPerAAFillRect,
bsalomon4be9a302016-07-06 07:03:26 -0700240 kIndicesPerAAFillRect, fRectCnt);
bsalomon08d14152016-06-30 12:45:18 -0700241 if (!vertices || !indexBuffer) {
242 SkDebugf("Could not allocate vertices\n");
243 return;
244 }
245
bsalomon4be9a302016-07-06 07:03:26 -0700246 const RectInfo* info = this->first();
247 const SkMatrix* localMatrix = nullptr;
248 for (int i = 0; i < fRectCnt; i++) {
bsalomon08d14152016-06-30 12:45:18 -0700249 intptr_t verts = reinterpret_cast<intptr_t>(vertices) +
bsalomonbc9b6a42016-07-01 05:35:51 -0700250 i * kVertsPerAAFillRect * vertexStride;
bsalomon4be9a302016-07-06 07:03:26 -0700251 if (needLocalCoords) {
252 if (info->hasLocalMatrix()) {
253 localMatrix = &static_cast<const RectWithLocalMatrixInfo*>(info)->localMatrix();
254 } else {
255 localMatrix = &SkMatrix::I();
256 }
257 }
258 generate_aa_fill_rect_geometry(verts, vertexStride, info->color(),
259 info->viewMatrix(), info->rect(),
260 info->devRect(), fOverrides, localMatrix);
261 info = this->next(info);
bsalomon08d14152016-06-30 12:45:18 -0700262 }
263 helper.recordDraw(target, gp.get());
264 }
265
bsalomon08d14152016-06-30 12:45:18 -0700266 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomon4be9a302016-07-06 07:03:26 -0700267 AAFillRectBatch* that = t->cast<AAFillRectBatch>();
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700268 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
269 that->bounds(), caps)) {
270 return false;
271 }
272
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700273 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
274 // not tweaking
275 if (fOverrides.canTweakAlphaForCoverage() && !that->fOverrides.canTweakAlphaForCoverage()) {
276 fOverrides = that->fOverrides;
277 }
278
bsalomon4be9a302016-07-06 07:03:26 -0700279 fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
280 fRectCnt += that->fRectCnt;
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700281 this->joinBounds(that->bounds());
282 return true;
283 }
284
285 struct RectInfo {
bsalomon4be9a302016-07-06 07:03:26 -0700286 public:
287 RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
288 const SkRect& devRect)
289 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {}
290 bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; }
291 GrColor color() const { return fColor; }
292 const SkMatrix& viewMatrix() const { return fViewMatrix; }
293 const SkRect& rect() const { return fRect; }
294 const SkRect& devRect() const { return fDevRect; }
295
296 void setColor(GrColor color) { fColor = color; }
297 protected:
298 enum class HasLocalMatrix : uint32_t { kNo, kYes };
299
300 RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
301 const SkRect& devRect, HasLocalMatrix hasLM)
302 : fHasLocalMatrix(hasLM)
303 , fColor(color)
304 , fViewMatrix(viewMatrix)
305 , fRect(rect)
306 , fDevRect(devRect) {}
307
308 HasLocalMatrix fHasLocalMatrix;
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700309 GrColor fColor;
310 SkMatrix fViewMatrix;
311 SkRect fRect;
312 SkRect fDevRect;
313 };
314
bsalomon4be9a302016-07-06 07:03:26 -0700315 struct RectWithLocalMatrixInfo : public RectInfo {
316 public:
317 RectWithLocalMatrixInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
318 const SkRect& devRect, const SkMatrix& localMatrix)
319 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes)
320 , fLocalMatrix(localMatrix) {}
321 const SkMatrix& localMatrix() const { return fLocalMatrix; }
322 private:
benjaminwagnerd87a6b22016-07-04 11:30:01 -0700323 SkMatrix fLocalMatrix;
bsalomon0fdec8a2016-07-01 06:31:25 -0700324 };
325
bsalomon4be9a302016-07-06 07:03:26 -0700326 RectInfo* first() { return reinterpret_cast<RectInfo*>(fRectData.begin()); }
327 const RectInfo* first() const { return reinterpret_cast<const RectInfo*>(fRectData.begin()); }
328 const RectInfo* next(const RectInfo* prev) const {
329 intptr_t next = reinterpret_cast<intptr_t>(prev) +
330 (prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo)
331 : sizeof(RectInfo));
332 return reinterpret_cast<const RectInfo*>(next);
333 }
334
bsalomon08d14152016-06-30 12:45:18 -0700335 GrXPOverridesForBatch fOverrides;
bsalomon4be9a302016-07-06 07:03:26 -0700336 SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData;
337 int fRectCnt;
bsalomon08d14152016-06-30 12:45:18 -0700338
339 typedef GrVertexBatch INHERITED;
joshualitt147dc062015-08-12 11:51:46 -0700340};
341
joshualitt37eb1842015-08-12 06:36:57 -0700342namespace GrAAFillRectBatch {
joshualitt9ff64252015-08-10 09:03:51 -0700343
bsalomonabd30f52015-08-13 13:34:48 -0700344GrDrawBatch* Create(GrColor color,
345 const SkMatrix& viewMatrix,
346 const SkRect& rect,
347 const SkRect& devRect) {
bsalomon4be9a302016-07-06 07:03:26 -0700348 return new AAFillRectBatch(color, viewMatrix, rect, devRect, nullptr);
joshualitt147dc062015-08-12 11:51:46 -0700349}
350
bsalomonabd30f52015-08-13 13:34:48 -0700351GrDrawBatch* Create(GrColor color,
352 const SkMatrix& viewMatrix,
353 const SkMatrix& localMatrix,
354 const SkRect& rect,
355 const SkRect& devRect) {
bsalomon4be9a302016-07-06 07:03:26 -0700356 return new AAFillRectBatch(color, viewMatrix, rect, devRect, &localMatrix);
joshualitt9ff64252015-08-10 09:03:51 -0700357}
358
bsalomonc55271f2015-11-09 11:55:57 -0800359GrDrawBatch* Create(GrColor color,
360 const SkMatrix& viewMatrix,
361 const SkMatrix& localMatrix,
362 const SkRect& rect) {
363 SkRect devRect;
364 viewMatrix.mapRect(&devRect, rect);
365 return Create(color, viewMatrix, localMatrix, rect, devRect);
366}
367
368GrDrawBatch* CreateWithLocalRect(GrColor color,
369 const SkMatrix& viewMatrix,
370 const SkRect& rect,
371 const SkRect& localRect) {
372 SkRect devRect;
373 viewMatrix.mapRect(&devRect, rect);
374 SkMatrix localMatrix;
375 if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
376 return nullptr;
377 }
378 return Create(color, viewMatrix, localMatrix, rect, devRect);
379}
380
joshualitt37eb1842015-08-12 06:36:57 -0700381};
382
joshualitt9ff64252015-08-10 09:03:51 -0700383///////////////////////////////////////////////////////////////////////////////////////////////////
384
385#ifdef GR_TEST_UTILS
386
387#include "GrBatchTest.h"
388
bsalomonabd30f52015-08-13 13:34:48 -0700389DRAW_BATCH_TEST_DEFINE(AAFillRectBatch) {
joshualitt090ae8e2015-08-14 09:01:21 -0700390 GrColor color = GrRandomColor(random);
391 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
392 SkRect rect = GrTest::TestRect(random);
393 SkRect devRect = GrTest::TestRect(random);
394 return GrAAFillRectBatch::Create(color, viewMatrix, rect, devRect);
joshualitt147dc062015-08-12 11:51:46 -0700395}
396
bsalomonabd30f52015-08-13 13:34:48 -0700397DRAW_BATCH_TEST_DEFINE(AAFillRectBatchLocalMatrix) {
joshualitt090ae8e2015-08-14 09:01:21 -0700398 GrColor color = GrRandomColor(random);
399 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
400 SkMatrix localMatrix = GrTest::TestMatrix(random);
401 SkRect rect = GrTest::TestRect(random);
402 SkRect devRect = GrTest::TestRect(random);
403 return GrAAFillRectBatch::Create(color, viewMatrix, localMatrix, rect, devRect);
joshualitt9ff64252015-08-10 09:03:51 -0700404}
405
406#endif