1 /*
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
10 #include "GrColor.h"
11 #include "GrDefaultGeoProcFactory.h"
12 #include "GrResourceKey.h"
13 #include "GrResourceProvider.h"
14 #include "GrTInstanceBatch.h"
15 #include "GrTypes.h"
16 #include "SkMatrix.h"
17 #include "SkRect.h"
18
19 GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
20
set_inset_fan(SkPoint * pts,size_t stride,const SkRect & r,SkScalar dx,SkScalar dy)21 static void set_inset_fan(SkPoint* pts, size_t stride,
22 const SkRect& r, SkScalar dx, SkScalar dy) {
23 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
24 r.fRight - dx, r.fBottom - dy, stride);
25 }
26
27 static const int kNumAAFillRectsInIndexBuffer = 256;
28 static const int kVertsPerAAFillRect = 8;
29 static const int kIndicesPerAAFillRect = 30;
30
get_index_buffer(GrResourceProvider * resourceProvider)31 const GrIndexBuffer* get_index_buffer(GrResourceProvider* resourceProvider) {
32 GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
33
34 static const uint16_t gFillAARectIdx[] = {
35 0, 1, 5, 5, 4, 0,
36 1, 2, 6, 6, 5, 1,
37 2, 3, 7, 7, 6, 2,
38 3, 0, 4, 4, 7, 3,
39 4, 5, 6, 6, 7, 4,
40 };
41 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect);
42 return resourceProvider->findOrCreateInstancedIndexBuffer(gFillAARectIdx,
43 kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer, kVertsPerAAFillRect,
44 gAAFillRectIndexBufferKey);
45 }
46
create_fill_rect_gp(const SkMatrix & viewMatrix,const GrXPOverridesForBatch & overrides,GrDefaultGeoProcFactory::LocalCoords::Type localCoordsType)47 static const GrGeometryProcessor* create_fill_rect_gp(
48 const SkMatrix& viewMatrix,
49 const GrXPOverridesForBatch& overrides,
50 GrDefaultGeoProcFactory::LocalCoords::Type localCoordsType) {
51 using namespace GrDefaultGeoProcFactory;
52
53 Color color(Color::kAttribute_Type);
54 Coverage::Type coverageType;
55 // TODO remove coverage if coverage is ignored
56 /*if (coverageIgnored) {
57 coverageType = Coverage::kNone_Type;
58 } else*/ if (overrides.canTweakAlphaForCoverage()) {
59 coverageType = Coverage::kSolid_Type;
60 } else {
61 coverageType = Coverage::kAttribute_Type;
62 }
63 Coverage coverage(coverageType);
64
65 // We assume the caller has inverted the viewmatrix
66 if (LocalCoords::kHasExplicit_Type == localCoordsType) {
67 LocalCoords localCoords(localCoordsType);
68 return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I());
69 } else {
70 LocalCoords localCoords(overrides.readsLocalCoords() ? localCoordsType :
71 LocalCoords::kUnused_Type);
72 return CreateForDeviceSpace(color, coverage, localCoords, viewMatrix);
73 }
74 }
75
generate_aa_fill_rect_geometry(intptr_t verts,size_t vertexStride,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & devRect,const GrXPOverridesForBatch & overrides,const SkMatrix * localMatrix)76 static void generate_aa_fill_rect_geometry(intptr_t verts,
77 size_t vertexStride,
78 GrColor color,
79 const SkMatrix& viewMatrix,
80 const SkRect& rect,
81 const SkRect& devRect,
82 const GrXPOverridesForBatch& overrides,
83 const SkMatrix* localMatrix) {
84 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
85 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
86
87 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
88 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
89
90 if (viewMatrix.rectStaysRect()) {
91 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
92 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
93 } else {
94 // compute transformed (1, 0) and (0, 1) vectors
95 SkVector vec[2] = {
96 { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] },
97 { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] }
98 };
99
100 vec[0].normalize();
101 vec[0].scale(SK_ScalarHalf);
102 vec[1].normalize();
103 vec[1].scale(SK_ScalarHalf);
104
105 // create the rotated rect
106 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
107 rect.fRight, rect.fBottom, vertexStride);
108 viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
109
110 // Now create the inset points and then outset the original
111 // rotated points
112
113 // TL
114 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
115 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
116 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
117 // BL
118 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
119 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
120 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
121 // BR
122 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
123 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
124 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
125 // TR
126 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
127 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
128 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
129 }
130
131 if (localMatrix) {
132 SkMatrix invViewMatrix;
133 if (!viewMatrix.invert(&invViewMatrix)) {
134 SkASSERT(false);
135 invViewMatrix = SkMatrix::I();
136 }
137 SkMatrix localCoordMatrix;
138 localCoordMatrix.setConcat(*localMatrix, invViewMatrix);
139 SkPoint* fan0Loc = reinterpret_cast<SkPoint*>(verts + sizeof(SkPoint) + sizeof(GrColor));
140 localCoordMatrix.mapPointsWithStride(fan0Loc, fan0Pos, vertexStride, 8);
141 }
142
143 bool tweakAlphaForCoverage = overrides.canTweakAlphaForCoverage();
144
145 // Make verts point to vertex color and then set all the color and coverage vertex attrs
146 // values.
147 verts += sizeof(SkPoint);
148
149 // The coverage offset is always the last vertex attribute
150 intptr_t coverageOffset = vertexStride - sizeof(GrColor) - sizeof(SkPoint);
151 for (int i = 0; i < 4; ++i) {
152 if (tweakAlphaForCoverage) {
153 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
154 } else {
155 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
156 *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = 0;
157 }
158 }
159
160 int scale;
161 if (inset < SK_ScalarHalf) {
162 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
163 SkASSERT(scale >= 0 && scale <= 255);
164 } else {
165 scale = 0xff;
166 }
167
168 verts += 4 * vertexStride;
169
170 float innerCoverage = GrNormalizeByteToFloat(scale);
171 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
172
173 for (int i = 0; i < 4; ++i) {
174 if (tweakAlphaForCoverage) {
175 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
176 } else {
177 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
178 *reinterpret_cast<float*>(verts + i * vertexStride +
179 coverageOffset) = innerCoverage;
180 }
181 }
182 }
183
184 // Common functions
185 class AAFillRectBatchBase {
186 public:
187 static const int kVertsPerInstance = kVertsPerAAFillRect;
188 static const int kIndicesPerInstance = kIndicesPerAAFillRect;
189
InitInvariantOutputCoverage(GrInitInvariantOutput * out)190 static void InitInvariantOutputCoverage(GrInitInvariantOutput* out) {
191 out->setUnknownSingleComponent();
192 }
193
GetIndexBuffer(GrResourceProvider * rp)194 static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* rp) {
195 return get_index_buffer(rp);
196 }
197
198 template <class Geometry>
SetBounds(const Geometry & geo,SkRect * outBounds)199 static void SetBounds(const Geometry& geo, SkRect* outBounds) {
200 *outBounds = geo.fDevRect;
201 }
202
203 template <class Geometry>
UpdateBoundsAfterAppend(const Geometry & geo,SkRect * outBounds)204 static void UpdateBoundsAfterAppend(const Geometry& geo, SkRect* outBounds) {
205 outBounds->join(geo.fDevRect);
206 }
207 };
208
209 class AAFillRectBatchNoLocalMatrixImp : public AAFillRectBatchBase {
210 public:
211 struct Geometry {
212 SkMatrix fViewMatrix;
213 SkRect fRect;
214 SkRect fDevRect;
215 GrColor fColor;
216 };
217
Name()218 static const char* Name() { return "AAFillRectBatchNoLocalMatrix"; }
219
DumpInfo(const Geometry & geo,int index)220 static SkString DumpInfo(const Geometry& geo, int index) {
221 SkString str;
222 str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
223 index,
224 geo.fColor,
225 geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight, geo.fRect.fBottom);
226 return str;
227 }
228
CanCombine(const Geometry & mine,const Geometry & theirs,const GrXPOverridesForBatch & overrides)229 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
230 const GrXPOverridesForBatch& overrides) {
231 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
232 // local coords then we won't be able to batch. We could actually upload the viewmatrix
233 // using vertex attributes in these cases, but haven't investigated that
234 return !overrides.readsLocalCoords() || mine.fViewMatrix.cheapEqualTo(theirs.fViewMatrix);
235 }
236
CreateGP(const Geometry & geo,const GrXPOverridesForBatch & overrides)237 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
238 const GrXPOverridesForBatch& overrides) {
239 const GrGeometryProcessor* gp =
240 create_fill_rect_gp(geo.fViewMatrix, overrides,
241 GrDefaultGeoProcFactory::LocalCoords::kUsePosition_Type);
242
243 SkASSERT(overrides.canTweakAlphaForCoverage() ?
244 gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
245 gp->getVertexStride() ==
246 sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
247 return gp;
248 }
249
Tesselate(intptr_t vertices,size_t vertexStride,const Geometry & geo,const GrXPOverridesForBatch & overrides)250 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
251 const GrXPOverridesForBatch& overrides) {
252 generate_aa_fill_rect_geometry(vertices, vertexStride,
253 geo.fColor, geo.fViewMatrix, geo.fRect, geo.fDevRect,
254 overrides, nullptr);
255 }
256 };
257
258 class AAFillRectBatchLocalMatrixImp : public AAFillRectBatchBase {
259 public:
260 struct Geometry {
261 SkMatrix fViewMatrix;
262 SkMatrix fLocalMatrix;
263 SkRect fRect;
264 SkRect fDevRect;
265 GrColor fColor;
266 };
267
Name()268 static const char* Name() { return "AAFillRectBatchLocalMatrix"; }
269
DumpInfo(const Geometry & geo,int index)270 static SkString DumpInfo(const Geometry& geo, int index) {
271 SkString str;
272 str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
273 index,
274 geo.fColor,
275 geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight, geo.fRect.fBottom);
276 return str;
277 }
278
CanCombine(const Geometry & mine,const Geometry & theirs,const GrXPOverridesForBatch & overrides)279 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
280 const GrXPOverridesForBatch& overrides) {
281 return true;
282 }
283
CreateGP(const Geometry & geo,const GrXPOverridesForBatch & overrides)284 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
285 const GrXPOverridesForBatch& overrides) {
286 const GrGeometryProcessor* gp =
287 create_fill_rect_gp(geo.fViewMatrix, overrides,
288 GrDefaultGeoProcFactory::LocalCoords::kHasExplicit_Type);
289
290 SkASSERT(overrides.canTweakAlphaForCoverage() ?
291 gp->getVertexStride() ==
292 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) :
293 gp->getVertexStride() ==
294 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordCoverage));
295 return gp;
296 }
297
Tesselate(intptr_t vertices,size_t vertexStride,const Geometry & geo,const GrXPOverridesForBatch & overrides)298 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
299 const GrXPOverridesForBatch& overrides) {
300 generate_aa_fill_rect_geometry(vertices, vertexStride,
301 geo.fColor, geo.fViewMatrix, geo.fRect, geo.fDevRect,
302 overrides, &geo.fLocalMatrix);
303 }
304 };
305
306 typedef GrTInstanceBatch<AAFillRectBatchNoLocalMatrixImp> AAFillRectBatchNoLocalMatrix;
307 typedef GrTInstanceBatch<AAFillRectBatchLocalMatrixImp> AAFillRectBatchLocalMatrix;
308
append_to_batch(AAFillRectBatchNoLocalMatrix * batch,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & devRect)309 inline static void append_to_batch(AAFillRectBatchNoLocalMatrix* batch, GrColor color,
310 const SkMatrix& viewMatrix, const SkRect& rect,
311 const SkRect& devRect) {
312 AAFillRectBatchNoLocalMatrix::Geometry& geo = batch->geoData()->push_back();
313 geo.fColor = color;
314 geo.fViewMatrix = viewMatrix;
315 geo.fRect = rect;
316 geo.fDevRect = devRect;
317 }
318
append_to_batch(AAFillRectBatchLocalMatrix * batch,GrColor color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect,const SkRect & devRect)319 inline static void append_to_batch(AAFillRectBatchLocalMatrix* batch, GrColor color,
320 const SkMatrix& viewMatrix, const SkMatrix& localMatrix,
321 const SkRect& rect, const SkRect& devRect) {
322 AAFillRectBatchLocalMatrix::Geometry& geo = batch->geoData()->push_back();
323 geo.fColor = color;
324 geo.fViewMatrix = viewMatrix;
325 geo.fLocalMatrix = localMatrix;
326 geo.fRect = rect;
327 geo.fDevRect = devRect;
328 }
329
330 namespace GrAAFillRectBatch {
331
Create(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & devRect)332 GrDrawBatch* Create(GrColor color,
333 const SkMatrix& viewMatrix,
334 const SkRect& rect,
335 const SkRect& devRect) {
336 AAFillRectBatchNoLocalMatrix* batch = AAFillRectBatchNoLocalMatrix::Create();
337 append_to_batch(batch, color, viewMatrix, rect, devRect);
338 batch->init();
339 return batch;
340 }
341
Create(GrColor color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect,const SkRect & devRect)342 GrDrawBatch* Create(GrColor color,
343 const SkMatrix& viewMatrix,
344 const SkMatrix& localMatrix,
345 const SkRect& rect,
346 const SkRect& devRect) {
347 AAFillRectBatchLocalMatrix* batch = AAFillRectBatchLocalMatrix::Create();
348 append_to_batch(batch, color, viewMatrix, localMatrix, rect, devRect);
349 batch->init();
350 return batch;
351 }
352
Create(GrColor color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect)353 GrDrawBatch* Create(GrColor color,
354 const SkMatrix& viewMatrix,
355 const SkMatrix& localMatrix,
356 const SkRect& rect) {
357 SkRect devRect;
358 viewMatrix.mapRect(&devRect, rect);
359 return Create(color, viewMatrix, localMatrix, rect, devRect);
360 }
361
CreateWithLocalRect(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & localRect)362 GrDrawBatch* CreateWithLocalRect(GrColor color,
363 const SkMatrix& viewMatrix,
364 const SkRect& rect,
365 const SkRect& localRect) {
366 SkRect devRect;
367 viewMatrix.mapRect(&devRect, rect);
368 SkMatrix localMatrix;
369 if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
370 return nullptr;
371 }
372 return Create(color, viewMatrix, localMatrix, rect, devRect);
373 }
374
Append(GrBatch * origBatch,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & devRect)375 void Append(GrBatch* origBatch,
376 GrColor color,
377 const SkMatrix& viewMatrix,
378 const SkRect& rect,
379 const SkRect& devRect) {
380 AAFillRectBatchNoLocalMatrix* batch = origBatch->cast<AAFillRectBatchNoLocalMatrix>();
381 append_to_batch(batch, color, viewMatrix, rect, devRect);
382 batch->updateBoundsAfterAppend();
383 }
384
Append(GrBatch * origBatch,GrColor color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect,const SkRect & devRect)385 void Append(GrBatch* origBatch,
386 GrColor color,
387 const SkMatrix& viewMatrix,
388 const SkMatrix& localMatrix,
389 const SkRect& rect,
390 const SkRect& devRect) {
391 AAFillRectBatchLocalMatrix* batch = origBatch->cast<AAFillRectBatchLocalMatrix>();
392 append_to_batch(batch, color, viewMatrix, localMatrix, rect, devRect);
393 batch->updateBoundsAfterAppend();
394 }
395
396 };
397
398 ///////////////////////////////////////////////////////////////////////////////////////////////////
399
400 #ifdef GR_TEST_UTILS
401
402 #include "GrBatchTest.h"
403
DRAW_BATCH_TEST_DEFINE(AAFillRectBatch)404 DRAW_BATCH_TEST_DEFINE(AAFillRectBatch) {
405 GrColor color = GrRandomColor(random);
406 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
407 SkRect rect = GrTest::TestRect(random);
408 SkRect devRect = GrTest::TestRect(random);
409 return GrAAFillRectBatch::Create(color, viewMatrix, rect, devRect);
410 }
411
DRAW_BATCH_TEST_DEFINE(AAFillRectBatchLocalMatrix)412 DRAW_BATCH_TEST_DEFINE(AAFillRectBatchLocalMatrix) {
413 GrColor color = GrRandomColor(random);
414 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
415 SkMatrix localMatrix = GrTest::TestMatrix(random);
416 SkRect rect = GrTest::TestRect(random);
417 SkRect devRect = GrTest::TestRect(random);
418 return GrAAFillRectBatch::Create(color, viewMatrix, localMatrix, rect, devRect);
419 }
420
421 #endif
422