blob: 8760896604c60c2d99cfc224cbee6c09f1884bb5 [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
190 inline static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* rp) {
191 return get_index_buffer(rp);
192 }
193};
194
195class AAFillRectBatchNoLocalMatrixImp : public AAFillRectBatchBase {
joshualitt147dc062015-08-12 11:51:46 -0700196public:
197 struct Geometry {
198 SkMatrix fViewMatrix;
joshualitt40ac15a2015-08-14 08:45:39 -0700199 SkRect fRect;
joshualitt147dc062015-08-12 11:51:46 -0700200 SkRect fDevRect;
201 GrColor fColor;
202 };
203
joshualitt2ad37be2015-08-18 10:16:01 -0700204 inline static const char* Name() { return "AAFillRectBatchNoLocalMatrix"; }
205
joshualittcd47b712015-08-18 07:25:38 -0700206 inline static bool CanCombine(const Geometry& mine, const Geometry& theirs,
207 const GrPipelineOptimizations& opts) {
joshualitt147dc062015-08-12 11:51:46 -0700208 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
209 // local coords then we won't be able to batch. We could actually upload the viewmatrix
210 // using vertex attributes in these cases, but haven't investigated that
joshualittcd47b712015-08-18 07:25:38 -0700211 return !opts.readsLocalCoords() || mine.fViewMatrix.cheapEqualTo(theirs.fViewMatrix);
joshualitt147dc062015-08-12 11:51:46 -0700212 }
213
joshualittcd47b712015-08-18 07:25:38 -0700214 inline static const GrGeometryProcessor* CreateGP(const Geometry& geo,
215 const GrPipelineOptimizations& opts) {
216 const GrGeometryProcessor* gp =
217 create_fill_rect_gp(geo.fViewMatrix, opts,
218 GrDefaultGeoProcFactory::LocalCoords::kUsePosition_Type);
219
220 SkASSERT(opts.canTweakAlphaForCoverage() ?
221 gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
222 gp->getVertexStride() ==
223 sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
224 return gp;
joshualitt147dc062015-08-12 11:51:46 -0700225 }
226
joshualittcd47b712015-08-18 07:25:38 -0700227 inline static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
228 const GrPipelineOptimizations& opts) {
229 generate_aa_fill_rect_geometry(vertices, vertexStride,
230 geo.fColor, geo.fViewMatrix, geo.fRect, geo.fDevRect, opts,
231 NULL);
joshualitt147dc062015-08-12 11:51:46 -0700232 }
joshualitt147dc062015-08-12 11:51:46 -0700233};
234
joshualitt2ad37be2015-08-18 10:16:01 -0700235class AAFillRectBatchLocalMatrixImp : public AAFillRectBatchBase {
joshualitt147dc062015-08-12 11:51:46 -0700236public:
237 struct Geometry {
238 SkMatrix fViewMatrix;
239 SkMatrix fLocalMatrix;
joshualitt40ac15a2015-08-14 08:45:39 -0700240 SkRect fRect;
joshualitt147dc062015-08-12 11:51:46 -0700241 SkRect fDevRect;
242 GrColor fColor;
243 };
244
joshualitt2ad37be2015-08-18 10:16:01 -0700245 inline static const char* Name() { return "AAFillRectBatchLocalMatrix"; }
246
joshualittcd47b712015-08-18 07:25:38 -0700247 inline static bool CanCombine(const Geometry& mine, const Geometry& theirs,
248 const GrPipelineOptimizations&) {
joshualitt147dc062015-08-12 11:51:46 -0700249 return true;
250 }
251
joshualittcd47b712015-08-18 07:25:38 -0700252 inline static const GrGeometryProcessor* CreateGP(const Geometry& geo,
253 const GrPipelineOptimizations& opts) {
254 const GrGeometryProcessor* gp =
255 create_fill_rect_gp(geo.fViewMatrix, opts,
256 GrDefaultGeoProcFactory::LocalCoords::kHasExplicit_Type);
257
258 SkASSERT(opts.canTweakAlphaForCoverage() ?
259 gp->getVertexStride() ==
260 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) :
261 gp->getVertexStride() ==
262 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordCoverage));
263 return gp;
joshualitt147dc062015-08-12 11:51:46 -0700264 }
265
joshualittcd47b712015-08-18 07:25:38 -0700266 inline static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry& geo,
267 const GrPipelineOptimizations& opts) {
268 generate_aa_fill_rect_geometry(vertices, vertexStride,
269 geo.fColor, geo.fViewMatrix, geo.fRect, geo.fDevRect, opts,
270 &geo.fLocalMatrix);
joshualitt147dc062015-08-12 11:51:46 -0700271 }
272};
273
joshualitt2ad37be2015-08-18 10:16:01 -0700274typedef GrTInstanceBatch<AAFillRectBatchNoLocalMatrixImp> AAFillRectBatchNoLocalMatrix;
275typedef GrTInstanceBatch<AAFillRectBatchLocalMatrixImp> AAFillRectBatchLocalMatrix;
joshualitt147dc062015-08-12 11:51:46 -0700276
joshualitt37eb1842015-08-12 06:36:57 -0700277namespace GrAAFillRectBatch {
joshualitt9ff64252015-08-10 09:03:51 -0700278
bsalomonabd30f52015-08-13 13:34:48 -0700279GrDrawBatch* Create(GrColor color,
280 const SkMatrix& viewMatrix,
281 const SkRect& rect,
282 const SkRect& devRect) {
joshualitt147dc062015-08-12 11:51:46 -0700283 AAFillRectBatchNoLocalMatrix* batch = AAFillRectBatchNoLocalMatrix::Create();
284 AAFillRectBatchNoLocalMatrix::Geometry& geo = *batch->geometry();
285 geo.fColor = color;
286 geo.fViewMatrix = viewMatrix;
joshualitt40ac15a2015-08-14 08:45:39 -0700287 geo.fRect = rect;
joshualitt147dc062015-08-12 11:51:46 -0700288 geo.fDevRect = devRect;
289 batch->init();
290 return batch;
291}
292
bsalomonabd30f52015-08-13 13:34:48 -0700293GrDrawBatch* Create(GrColor color,
294 const SkMatrix& viewMatrix,
295 const SkMatrix& localMatrix,
296 const SkRect& rect,
297 const SkRect& devRect) {
joshualitt147dc062015-08-12 11:51:46 -0700298 AAFillRectBatchLocalMatrix* batch = AAFillRectBatchLocalMatrix::Create();
299 AAFillRectBatchLocalMatrix::Geometry& geo = *batch->geometry();
300 geo.fColor = color;
301 geo.fViewMatrix = viewMatrix;
302 geo.fLocalMatrix = localMatrix;
joshualitt40ac15a2015-08-14 08:45:39 -0700303 geo.fRect = rect;
joshualitt147dc062015-08-12 11:51:46 -0700304 geo.fDevRect = devRect;
305 batch->init();
306 return batch;
joshualitt9ff64252015-08-10 09:03:51 -0700307}
308
joshualitt37eb1842015-08-12 06:36:57 -0700309};
310
joshualitt9ff64252015-08-10 09:03:51 -0700311///////////////////////////////////////////////////////////////////////////////////////////////////
312
313#ifdef GR_TEST_UTILS
314
315#include "GrBatchTest.h"
316
bsalomonabd30f52015-08-13 13:34:48 -0700317DRAW_BATCH_TEST_DEFINE(AAFillRectBatch) {
joshualitt090ae8e2015-08-14 09:01:21 -0700318 GrColor color = GrRandomColor(random);
319 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
320 SkRect rect = GrTest::TestRect(random);
321 SkRect devRect = GrTest::TestRect(random);
322 return GrAAFillRectBatch::Create(color, viewMatrix, rect, devRect);
joshualitt147dc062015-08-12 11:51:46 -0700323}
324
bsalomonabd30f52015-08-13 13:34:48 -0700325DRAW_BATCH_TEST_DEFINE(AAFillRectBatchLocalMatrix) {
joshualitt090ae8e2015-08-14 09:01:21 -0700326 GrColor color = GrRandomColor(random);
327 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
328 SkMatrix localMatrix = GrTest::TestMatrix(random);
329 SkRect rect = GrTest::TestRect(random);
330 SkRect devRect = GrTest::TestRect(random);
331 return GrAAFillRectBatch::Create(color, viewMatrix, localMatrix, rect, devRect);
joshualitt9ff64252015-08-10 09:03:51 -0700332}
333
334#endif