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