blob: 964610788d7ca5a7a33ed6d427bfef3458674741 [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
joshualitt37eb1842015-08-12 06:36:57 -070010#include "GrColor.h"
joshualitt9ff64252015-08-10 09:03:51 -070011#include "GrDefaultGeoProcFactory.h"
12#include "GrResourceKey.h"
13#include "GrResourceProvider.h"
joshualitt2ad37be2015-08-18 10:16:01 -070014#include "GrTInstanceBatch.h"
joshualitt37eb1842015-08-12 06:36:57 -070015#include "GrTypes.h"
16#include "SkMatrix.h"
17#include "SkRect.h"
joshualitt9ff64252015-08-10 09:03:51 -070018
19GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
20
21static 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
joshualitt27801bf2015-08-12 12:52:47 -070027static const int kNumAAFillRectsInIndexBuffer = 256;
28static const int kVertsPerAAFillRect = 8;
29static const int kIndicesPerAAFillRect = 30;
30
31const 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
joshualittcd47b712015-08-18 07:25:38 -070047static const GrGeometryProcessor* create_fill_rect_gp(
48 const SkMatrix& viewMatrix,
49 const GrPipelineOptimizations& opts,
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 (opts.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(opts.readsLocalCoords() ? localCoordsType :
71 LocalCoords::kUnused_Type);
72 return CreateForDeviceSpace(color, coverage, localCoords, viewMatrix);
73 }
74}
75
76static 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 GrPipelineOptimizations& opts,
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 = opts.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
joshualitt2ad37be2015-08-18 10:16:01 -0700184// Common functions
185class AAFillRectBatchBase {
186public:
187 static const int kVertsPerInstance = kVertsPerAAFillRect;
188 static const int kIndicesPerInstance = kIndicesPerAAFillRect;
189
joshualitt2244c272015-08-21 10:33:15 -0700190 static void InitInvariantOutputCoverage(GrInitInvariantOutput* out) {
191 out->setUnknownSingleComponent();
192 }
193
194 static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* rp) {
joshualitt2ad37be2015-08-18 10:16:01 -0700195 return get_index_buffer(rp);
196 }
joshualitt2244c272015-08-21 10:33:15 -0700197
198 template <class Geometry>
199 static void SetBounds(const Geometry& geo, SkRect* outBounds) {
200 *outBounds = geo.fDevRect;
201 }
joshualittaa37a962015-09-18 13:03:25 -0700202
203 template <class Geometry>
204 static void UpdateBoundsAfterAppend(const Geometry& geo, SkRect* outBounds) {
205 outBounds->join(geo.fDevRect);
206 }
joshualitt2ad37be2015-08-18 10:16:01 -0700207};
208
209class AAFillRectBatchNoLocalMatrixImp : public AAFillRectBatchBase {
joshualitt147dc062015-08-12 11:51:46 -0700210public:
211 struct Geometry {
212 SkMatrix fViewMatrix;
joshualitt40ac15a2015-08-14 08:45:39 -0700213 SkRect fRect;
joshualitt147dc062015-08-12 11:51:46 -0700214 SkRect fDevRect;
215 GrColor fColor;
216 };
217
joshualitt2244c272015-08-21 10:33:15 -0700218 static const char* Name() { return "AAFillRectBatchNoLocalMatrix"; }
joshualitt2ad37be2015-08-18 10:16:01 -0700219
joshualitt2244c272015-08-21 10:33:15 -0700220 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
221 const GrPipelineOptimizations& opts) {
joshualitt147dc062015-08-12 11:51:46 -0700222 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
223 // local coords then we won't be able to batch. We could actually upload the viewmatrix
224 // using vertex attributes in these cases, but haven't investigated that
joshualittcd47b712015-08-18 07:25:38 -0700225 return !opts.readsLocalCoords() || mine.fViewMatrix.cheapEqualTo(theirs.fViewMatrix);
joshualitt147dc062015-08-12 11:51:46 -0700226 }
227
joshualitt2244c272015-08-21 10:33:15 -0700228 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
229 const GrPipelineOptimizations& opts) {
joshualittcd47b712015-08-18 07:25:38 -0700230 const GrGeometryProcessor* gp =
231 create_fill_rect_gp(geo.fViewMatrix, opts,
232 GrDefaultGeoProcFactory::LocalCoords::kUsePosition_Type);
233
234 SkASSERT(opts.canTweakAlphaForCoverage() ?
235 gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
236 gp->getVertexStride() ==
237 sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
238 return gp;
joshualitt147dc062015-08-12 11:51:46 -0700239 }
240
joshualitt2244c272015-08-21 10:33:15 -0700241 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
242 const GrPipelineOptimizations& opts) {
joshualittcd47b712015-08-18 07:25:38 -0700243 generate_aa_fill_rect_geometry(vertices, vertexStride,
244 geo.fColor, geo.fViewMatrix, geo.fRect, geo.fDevRect, opts,
halcanary96fcdcc2015-08-27 07:41:13 -0700245 nullptr);
joshualitt147dc062015-08-12 11:51:46 -0700246 }
joshualitt147dc062015-08-12 11:51:46 -0700247};
248
joshualitt2ad37be2015-08-18 10:16:01 -0700249class AAFillRectBatchLocalMatrixImp : public AAFillRectBatchBase {
joshualitt147dc062015-08-12 11:51:46 -0700250public:
251 struct Geometry {
252 SkMatrix fViewMatrix;
253 SkMatrix fLocalMatrix;
joshualitt40ac15a2015-08-14 08:45:39 -0700254 SkRect fRect;
joshualitt147dc062015-08-12 11:51:46 -0700255 SkRect fDevRect;
256 GrColor fColor;
257 };
258
joshualitt2244c272015-08-21 10:33:15 -0700259 static const char* Name() { return "AAFillRectBatchLocalMatrix"; }
joshualitt2ad37be2015-08-18 10:16:01 -0700260
joshualitt2244c272015-08-21 10:33:15 -0700261 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
262 const GrPipelineOptimizations&) {
joshualitt147dc062015-08-12 11:51:46 -0700263 return true;
264 }
265
joshualitt2244c272015-08-21 10:33:15 -0700266 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
267 const GrPipelineOptimizations& opts) {
joshualittcd47b712015-08-18 07:25:38 -0700268 const GrGeometryProcessor* gp =
269 create_fill_rect_gp(geo.fViewMatrix, opts,
270 GrDefaultGeoProcFactory::LocalCoords::kHasExplicit_Type);
271
272 SkASSERT(opts.canTweakAlphaForCoverage() ?
273 gp->getVertexStride() ==
274 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) :
275 gp->getVertexStride() ==
276 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordCoverage));
277 return gp;
joshualitt147dc062015-08-12 11:51:46 -0700278 }
279
joshualitt2244c272015-08-21 10:33:15 -0700280 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
281 const GrPipelineOptimizations& opts) {
joshualittcd47b712015-08-18 07:25:38 -0700282 generate_aa_fill_rect_geometry(vertices, vertexStride,
283 geo.fColor, geo.fViewMatrix, geo.fRect, geo.fDevRect, opts,
284 &geo.fLocalMatrix);
joshualitt147dc062015-08-12 11:51:46 -0700285 }
286};
287
joshualitt2ad37be2015-08-18 10:16:01 -0700288typedef GrTInstanceBatch<AAFillRectBatchNoLocalMatrixImp> AAFillRectBatchNoLocalMatrix;
289typedef GrTInstanceBatch<AAFillRectBatchLocalMatrixImp> AAFillRectBatchLocalMatrix;
joshualitt147dc062015-08-12 11:51:46 -0700290
joshualittaa37a962015-09-18 13:03:25 -0700291inline static void append_to_batch(AAFillRectBatchNoLocalMatrix* batch, GrColor color,
292 const SkMatrix& viewMatrix, const SkRect& rect,
293 const SkRect& devRect) {
294 AAFillRectBatchNoLocalMatrix::Geometry& geo = batch->geoData()->push_back();
295 geo.fColor = color;
296 geo.fViewMatrix = viewMatrix;
297 geo.fRect = rect;
298 geo.fDevRect = devRect;
299}
300
301inline static void append_to_batch(AAFillRectBatchLocalMatrix* batch, GrColor color,
302 const SkMatrix& viewMatrix, const SkMatrix& localMatrix,
303 const SkRect& rect, const SkRect& devRect) {
304 AAFillRectBatchLocalMatrix::Geometry& geo = batch->geoData()->push_back();
305 geo.fColor = color;
306 geo.fViewMatrix = viewMatrix;
307 geo.fLocalMatrix = localMatrix;
308 geo.fRect = rect;
309 geo.fDevRect = devRect;
310}
311
joshualitt37eb1842015-08-12 06:36:57 -0700312namespace GrAAFillRectBatch {
joshualitt9ff64252015-08-10 09:03:51 -0700313
bsalomonabd30f52015-08-13 13:34:48 -0700314GrDrawBatch* Create(GrColor color,
315 const SkMatrix& viewMatrix,
316 const SkRect& rect,
317 const SkRect& devRect) {
joshualitt147dc062015-08-12 11:51:46 -0700318 AAFillRectBatchNoLocalMatrix* batch = AAFillRectBatchNoLocalMatrix::Create();
joshualittaa37a962015-09-18 13:03:25 -0700319 append_to_batch(batch, color, viewMatrix, rect, devRect);
joshualitt147dc062015-08-12 11:51:46 -0700320 batch->init();
321 return batch;
322}
323
bsalomonabd30f52015-08-13 13:34:48 -0700324GrDrawBatch* Create(GrColor color,
325 const SkMatrix& viewMatrix,
326 const SkMatrix& localMatrix,
327 const SkRect& rect,
328 const SkRect& devRect) {
joshualitt147dc062015-08-12 11:51:46 -0700329 AAFillRectBatchLocalMatrix* batch = AAFillRectBatchLocalMatrix::Create();
joshualittaa37a962015-09-18 13:03:25 -0700330 append_to_batch(batch, color, viewMatrix, localMatrix, rect, devRect);
joshualitt147dc062015-08-12 11:51:46 -0700331 batch->init();
332 return batch;
joshualitt9ff64252015-08-10 09:03:51 -0700333}
334
bsalomonc55271f2015-11-09 11:55:57 -0800335GrDrawBatch* Create(GrColor color,
336 const SkMatrix& viewMatrix,
337 const SkMatrix& localMatrix,
338 const SkRect& rect) {
339 SkRect devRect;
340 viewMatrix.mapRect(&devRect, rect);
341 return Create(color, viewMatrix, localMatrix, rect, devRect);
342}
343
344GrDrawBatch* CreateWithLocalRect(GrColor color,
345 const SkMatrix& viewMatrix,
346 const SkRect& rect,
347 const SkRect& localRect) {
348 SkRect devRect;
349 viewMatrix.mapRect(&devRect, rect);
350 SkMatrix localMatrix;
351 if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
352 return nullptr;
353 }
354 return Create(color, viewMatrix, localMatrix, rect, devRect);
355}
356
joshualittaa37a962015-09-18 13:03:25 -0700357void Append(GrBatch* origBatch,
358 GrColor color,
359 const SkMatrix& viewMatrix,
360 const SkRect& rect,
361 const SkRect& devRect) {
362 AAFillRectBatchNoLocalMatrix* batch = origBatch->cast<AAFillRectBatchNoLocalMatrix>();
363 append_to_batch(batch, color, viewMatrix, rect, devRect);
364 batch->updateBoundsAfterAppend();
365}
366
367void Append(GrBatch* origBatch,
368 GrColor color,
369 const SkMatrix& viewMatrix,
370 const SkMatrix& localMatrix,
371 const SkRect& rect,
372 const SkRect& devRect) {
373 AAFillRectBatchLocalMatrix* batch = origBatch->cast<AAFillRectBatchLocalMatrix>();
374 append_to_batch(batch, color, viewMatrix, localMatrix, rect, devRect);
375 batch->updateBoundsAfterAppend();
376}
377
joshualitt37eb1842015-08-12 06:36:57 -0700378};
379
joshualitt9ff64252015-08-10 09:03:51 -0700380///////////////////////////////////////////////////////////////////////////////////////////////////
381
382#ifdef GR_TEST_UTILS
383
384#include "GrBatchTest.h"
385
bsalomonabd30f52015-08-13 13:34:48 -0700386DRAW_BATCH_TEST_DEFINE(AAFillRectBatch) {
joshualitt090ae8e2015-08-14 09:01:21 -0700387 GrColor color = GrRandomColor(random);
388 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
389 SkRect rect = GrTest::TestRect(random);
390 SkRect devRect = GrTest::TestRect(random);
391 return GrAAFillRectBatch::Create(color, viewMatrix, rect, devRect);
joshualitt147dc062015-08-12 11:51:46 -0700392}
393
bsalomonabd30f52015-08-13 13:34:48 -0700394DRAW_BATCH_TEST_DEFINE(AAFillRectBatchLocalMatrix) {
joshualitt090ae8e2015-08-14 09:01:21 -0700395 GrColor color = GrRandomColor(random);
396 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
397 SkMatrix localMatrix = GrTest::TestMatrix(random);
398 SkRect rect = GrTest::TestRect(random);
399 SkRect devRect = GrTest::TestRect(random);
400 return GrAAFillRectBatch::Create(color, viewMatrix, localMatrix, rect, devRect);
joshualitt9ff64252015-08-10 09:03:51 -0700401}
402
403#endif