• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrNonAAFillRectBatch.h"
9 
10 #include "GrBatchFlushState.h"
11 #include "GrColor.h"
12 #include "GrDefaultGeoProcFactory.h"
13 #include "GrPrimitiveProcessor.h"
14 #include "GrResourceProvider.h"
15 #include "GrTInstanceBatch.h"
16 #include "GrQuad.h"
17 #include "GrVertexBatch.h"
18 
19 // Common functions
20 class NonAAFillRectBatchBase {
21 public:
22     static const int kVertsPerInstance = 4;
23     static const int kIndicesPerInstance = 6;
24 
InitInvariantOutputCoverage(GrInitInvariantOutput * out)25     static void InitInvariantOutputCoverage(GrInitInvariantOutput* out) {
26         out->setKnownSingleComponent(0xff);
27     }
28 
GetIndexBuffer(GrResourceProvider * rp)29     static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* rp) {
30         return rp->refQuadIndexBuffer();
31     }
32 
33     template <typename Geometry>
SetBounds(const Geometry & geo,SkRect * outBounds)34     static void SetBounds(const Geometry& geo, SkRect* outBounds) {
35         geo.fViewMatrix.mapRect(outBounds, geo.fRect);
36     }
37 
38     template <typename Geometry>
UpdateBoundsAfterAppend(const Geometry & geo,SkRect * outBounds)39     static void UpdateBoundsAfterAppend(const Geometry& geo, SkRect* outBounds) {
40         SkRect bounds = geo.fRect;
41         geo.fViewMatrix.mapRect(&bounds);
42         outBounds->join(bounds);
43     }
44 };
45 
46 /** We always use per-vertex colors so that rects can be batched across color changes. Sometimes
47     we  have explicit local coords and sometimes not. We *could* always provide explicit local
48     coords and just duplicate the positions when the caller hasn't provided a local coord rect,
49     but we haven't seen a use case which frequently switches between local rect and no local
50     rect draws.
51 
52     The vertex attrib order is always pos, color, [local coords].
53  */
create_gp(const SkMatrix & viewMatrix,bool readsCoverage,bool hasExplicitLocalCoords,const SkMatrix * localMatrix)54 static const GrGeometryProcessor* create_gp(const SkMatrix& viewMatrix,
55                                             bool readsCoverage,
56                                             bool hasExplicitLocalCoords,
57                                             const SkMatrix* localMatrix) {
58     using namespace GrDefaultGeoProcFactory;
59     Color color(Color::kAttribute_Type);
60     Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Type);
61 
62     // If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map
63     // the local rect on the cpu (in case the localMatrix also has perspective).
64     // Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect
65     // to generate vertex local coords
66     if (viewMatrix.hasPerspective()) {
67         LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type :
68                                                          LocalCoords::kUsePosition_Type,
69                                 localMatrix);
70         return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, viewMatrix);
71     } else if (hasExplicitLocalCoords) {
72         LocalCoords localCoords(LocalCoords::kHasExplicit_Type);
73         return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I());
74     } else {
75         LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix);
76         return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, localCoords,
77                                                              viewMatrix);
78     }
79 }
80 
tesselate(intptr_t vertices,size_t vertexStride,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const GrQuad * localQuad)81 static void tesselate(intptr_t vertices,
82                       size_t vertexStride,
83                       GrColor color,
84                       const SkMatrix& viewMatrix,
85                       const SkRect& rect,
86                       const GrQuad* localQuad) {
87     SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
88 
89     positions->setRectFan(rect.fLeft, rect.fTop,
90                           rect.fRight, rect.fBottom, vertexStride);
91 
92     if (!viewMatrix.hasPerspective()) {
93         viewMatrix.mapPointsWithStride(positions, vertexStride,
94                                        NonAAFillRectBatchBase::kVertsPerInstance);
95     }
96 
97     // Setup local coords
98     // TODO we should only do this if local coords are being read
99     if (localQuad) {
100         static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
101         for (int i = 0; i < NonAAFillRectBatchBase::kVertsPerInstance; i++) {
102             SkPoint* coords = reinterpret_cast<SkPoint*>(vertices + kLocalOffset +
103                               i * vertexStride);
104             *coords = localQuad->point(i);
105         }
106     }
107 
108     static const int kColorOffset = sizeof(SkPoint);
109     GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
110     for (int j = 0; j < 4; ++j) {
111         *vertColor = color;
112         vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride);
113     }
114 }
115 
116 class NonAAFillRectBatchImp : public NonAAFillRectBatchBase {
117 public:
118     struct Geometry {
119         SkMatrix fViewMatrix;
120         SkRect fRect;
121         GrQuad fLocalQuad;
122         GrColor fColor;
123     };
124 
Name()125     static const char* Name() { return "NonAAFillRectBatch"; }
126 
DumpInfo(const Geometry & geo,int index)127     static SkString DumpInfo(const Geometry& geo, int index) {
128         SkString str;
129         str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
130                     index,
131                     geo.fColor,
132                     geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight, geo.fRect.fBottom);
133         return str;
134     }
135 
CanCombine(const Geometry & mine,const Geometry & theirs,const GrXPOverridesForBatch & overrides)136     static bool CanCombine(const Geometry& mine, const Geometry& theirs,
137                            const GrXPOverridesForBatch& overrides) {
138         return true;
139     }
140 
CreateGP(const Geometry & geo,const GrXPOverridesForBatch & overrides)141     static const GrGeometryProcessor* CreateGP(const Geometry& geo,
142                                                const GrXPOverridesForBatch& overrides) {
143         const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, overrides.readsCoverage(), true,
144                                                   nullptr);
145 
146         SkASSERT(gp->getVertexStride() ==
147                 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
148         return gp;
149     }
150 
Tesselate(intptr_t vertices,size_t vertexStride,const Geometry & geo,const GrXPOverridesForBatch & overrides)151     static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
152                           const GrXPOverridesForBatch& overrides) {
153         tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, &geo.fLocalQuad);
154     }
155 };
156 
157 // We handle perspective in the local matrix or viewmatrix with special batches
158 class NonAAFillRectBatchPerspectiveImp : public NonAAFillRectBatchBase {
159 public:
160     struct Geometry {
161         SkMatrix fViewMatrix;
162         SkMatrix fLocalMatrix;
163         SkRect fRect;
164         SkRect fLocalRect;
165         GrColor fColor;
166         bool fHasLocalMatrix;
167         bool fHasLocalRect;
168     };
169 
Name()170     static const char* Name() { return "NonAAFillRectBatchPerspective"; }
171 
DumpInfo(const Geometry & geo,int index)172     static SkString DumpInfo(const Geometry& geo, int index) {
173         SkString str;
174         str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
175                     index,
176                     geo.fColor,
177                     geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight, geo.fRect.fBottom);
178         return str;
179     }
180 
CanCombine(const Geometry & mine,const Geometry & theirs,const GrXPOverridesForBatch & overrides)181     static bool CanCombine(const Geometry& mine, const Geometry& theirs,
182                            const GrXPOverridesForBatch& overrides) {
183         // We could batch across perspective vm changes if we really wanted to
184         return mine.fViewMatrix.cheapEqualTo(theirs.fViewMatrix) &&
185                mine.fHasLocalRect == theirs.fHasLocalRect &&
186                (!mine.fHasLocalMatrix || mine.fLocalMatrix.cheapEqualTo(theirs.fLocalMatrix));
187     }
188 
CreateGP(const Geometry & geo,const GrXPOverridesForBatch & overrides)189     static const GrGeometryProcessor* CreateGP(const Geometry& geo,
190                                                const GrXPOverridesForBatch& overrides) {
191         const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, overrides.readsCoverage(),
192                                                   geo.fHasLocalRect,
193                                                   geo.fHasLocalMatrix ? &geo.fLocalMatrix :
194                                                                         nullptr);
195 
196         SkASSERT(geo.fHasLocalRect ?
197              gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) :
198              gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
199         return gp;
200     }
201 
Tesselate(intptr_t vertices,size_t vertexStride,const Geometry & geo,const GrXPOverridesForBatch & overrides)202     static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
203                           const GrXPOverridesForBatch& overrides) {
204         if (geo.fHasLocalRect) {
205             GrQuad quad(geo.fLocalRect);
206             tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, &quad);
207         } else {
208             tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect, nullptr);
209         }
210     }
211 };
212 
213 typedef GrTInstanceBatch<NonAAFillRectBatchImp> NonAAFillRectBatchSimple;
214 typedef GrTInstanceBatch<NonAAFillRectBatchPerspectiveImp> NonAAFillRectBatchPerspective;
215 
append_to_batch(NonAAFillRectBatchSimple * batch,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix)216 inline static void append_to_batch(NonAAFillRectBatchSimple* batch, GrColor color,
217                                    const SkMatrix& viewMatrix, const SkRect& rect,
218                                    const SkRect* localRect, const SkMatrix* localMatrix) {
219     SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective()));
220     NonAAFillRectBatchSimple::Geometry& geo = batch->geoData()->push_back();
221 
222     geo.fColor = color;
223     geo.fViewMatrix = viewMatrix;
224     geo.fRect = rect;
225 
226     if (localRect && localMatrix) {
227         geo.fLocalQuad.setFromMappedRect(*localRect, *localMatrix);
228     } else if (localRect) {
229         geo.fLocalQuad.set(*localRect);
230     } else if (localMatrix) {
231         geo.fLocalQuad.setFromMappedRect(rect, *localMatrix);
232     } else {
233         geo.fLocalQuad.set(rect);
234     }
235 }
236 
append_to_batch(NonAAFillRectBatchPerspective * batch,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix)237 inline static void append_to_batch(NonAAFillRectBatchPerspective* batch, GrColor color,
238                                    const SkMatrix& viewMatrix, const SkRect& rect,
239                                    const SkRect* localRect, const SkMatrix* localMatrix) {
240     SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
241     NonAAFillRectBatchPerspective::Geometry& geo = batch->geoData()->push_back();
242 
243     geo.fColor = color;
244     geo.fViewMatrix = viewMatrix;
245     geo.fRect = rect;
246     geo.fHasLocalRect = SkToBool(localRect);
247     geo.fHasLocalMatrix = SkToBool(localMatrix);
248     if (localMatrix) {
249         geo.fLocalMatrix = *localMatrix;
250     }
251     if (localRect) {
252         geo.fLocalRect = *localRect;
253     }
254 
255 }
256 
257 namespace GrNonAAFillRectBatch {
258 
Create(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix)259 GrDrawBatch* Create(GrColor color,
260                     const SkMatrix& viewMatrix,
261                     const SkRect& rect,
262                     const SkRect* localRect,
263                     const SkMatrix* localMatrix) {
264     NonAAFillRectBatchSimple* batch = NonAAFillRectBatchSimple::Create();
265     append_to_batch(batch, color, viewMatrix, rect, localRect, localMatrix);
266     batch->init();
267     return batch;
268 }
269 
CreateWithPerspective(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix)270 GrDrawBatch* CreateWithPerspective(GrColor color,
271                                    const SkMatrix& viewMatrix,
272                                    const SkRect& rect,
273                                    const SkRect* localRect,
274                                    const SkMatrix* localMatrix) {
275     NonAAFillRectBatchPerspective* batch = NonAAFillRectBatchPerspective::Create();
276     append_to_batch(batch, color, viewMatrix, rect, localRect, localMatrix);
277     batch->init();
278     return batch;
279 }
280 
Append(GrBatch * origBatch,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix)281 bool Append(GrBatch* origBatch,
282             GrColor color,
283             const SkMatrix& viewMatrix,
284             const SkRect& rect,
285             const SkRect* localRect,
286             const SkMatrix* localMatrix) {
287     bool usePerspective = viewMatrix.hasPerspective() ||
288                           (localMatrix && localMatrix->hasPerspective());
289 
290     if (usePerspective && origBatch->classID() != NonAAFillRectBatchPerspective::ClassID()) {
291         return false;
292     }
293 
294     if (!usePerspective) {
295         NonAAFillRectBatchSimple* batch = origBatch->cast<NonAAFillRectBatchSimple>();
296         append_to_batch(batch, color, viewMatrix, rect, localRect, localMatrix);
297         batch->updateBoundsAfterAppend();
298     } else {
299         NonAAFillRectBatchPerspective* batch = origBatch->cast<NonAAFillRectBatchPerspective>();
300         const NonAAFillRectBatchPerspective::Geometry& geo = batch->geoData()->back();
301 
302         if (!geo.fViewMatrix.cheapEqualTo(viewMatrix) ||
303             geo.fHasLocalRect != SkToBool(localRect) ||
304             geo.fHasLocalMatrix != SkToBool(localMatrix) ||
305             (geo.fHasLocalMatrix && !geo.fLocalMatrix.cheapEqualTo(*localMatrix))) {
306             return false;
307         }
308 
309         append_to_batch(batch, color, viewMatrix, rect, localRect, localMatrix);
310         batch->updateBoundsAfterAppend();
311     }
312 
313     return true;
314 }
315 
316 };
317 
318 ///////////////////////////////////////////////////////////////////////////////////////////////////
319 
320 #ifdef GR_TEST_UTILS
321 
322 #include "GrBatchTest.h"
323 
DRAW_BATCH_TEST_DEFINE(RectBatch)324 DRAW_BATCH_TEST_DEFINE(RectBatch) {
325     GrColor color = GrRandomColor(random);
326     SkRect rect = GrTest::TestRect(random);
327     SkRect localRect = GrTest::TestRect(random);
328     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
329     SkMatrix localMatrix = GrTest::TestMatrix(random);
330 
331     bool hasLocalRect = random->nextBool();
332     bool hasLocalMatrix = random->nextBool();
333     return GrNonAAFillRectBatch::Create(color, viewMatrix, rect,
334                                         hasLocalRect ? &localRect : nullptr,
335                                         hasLocalMatrix ? &localMatrix : nullptr);
336 }
337 
338 #endif
339