1
2 /*
3 * Copyright 2012 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "GrAAConvexPathRenderer.h"
10
11 #include "GrAAConvexTessellator.h"
12 #include "GrBatchFlushState.h"
13 #include "GrBatchTest.h"
14 #include "GrCaps.h"
15 #include "GrContext.h"
16 #include "GrDefaultGeoProcFactory.h"
17 #include "GrGeometryProcessor.h"
18 #include "GrInvariantOutput.h"
19 #include "GrPathUtils.h"
20 #include "GrProcessor.h"
21 #include "GrPipelineBuilder.h"
22 #include "GrStrokeInfo.h"
23 #include "SkGeometry.h"
24 #include "SkPathPriv.h"
25 #include "SkString.h"
26 #include "SkTraceEvent.h"
27 #include "batches/GrVertexBatch.h"
28 #include "glsl/GrGLSLFragmentShaderBuilder.h"
29 #include "glsl/GrGLSLGeometryProcessor.h"
30 #include "glsl/GrGLSLProgramDataManager.h"
31 #include "glsl/GrGLSLUniformHandler.h"
32 #include "glsl/GrGLSLVarying.h"
33 #include "glsl/GrGLSLVertexShaderBuilder.h"
34
GrAAConvexPathRenderer()35 GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
36 }
37
38 struct Segment {
39 enum {
40 // These enum values are assumed in member functions below.
41 kLine = 0,
42 kQuad = 1,
43 } fType;
44
45 // line uses one pt, quad uses 2 pts
46 SkPoint fPts[2];
47 // normal to edge ending at each pt
48 SkVector fNorms[2];
49 // is the corner where the previous segment meets this segment
50 // sharp. If so, fMid is a normalized bisector facing outward.
51 SkVector fMid;
52
countPointsSegment53 int countPoints() {
54 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
55 return fType + 1;
56 }
endPtSegment57 const SkPoint& endPt() const {
58 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
59 return fPts[fType];
60 };
endNormSegment61 const SkPoint& endNorm() const {
62 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
63 return fNorms[fType];
64 };
65 };
66
67 typedef SkTArray<Segment, true> SegmentArray;
68
center_of_mass(const SegmentArray & segments,SkPoint * c)69 static void center_of_mass(const SegmentArray& segments, SkPoint* c) {
70 SkScalar area = 0;
71 SkPoint center = {0, 0};
72 int count = segments.count();
73 SkPoint p0 = {0, 0};
74 if (count > 2) {
75 // We translate the polygon so that the first point is at the origin.
76 // This avoids some precision issues with small area polygons far away
77 // from the origin.
78 p0 = segments[0].endPt();
79 SkPoint pi;
80 SkPoint pj;
81 // the first and last iteration of the below loop would compute
82 // zeros since the starting / ending point is (0,0). So instead we start
83 // at i=1 and make the last iteration i=count-2.
84 pj = segments[1].endPt() - p0;
85 for (int i = 1; i < count - 1; ++i) {
86 pi = pj;
87 pj = segments[i + 1].endPt() - p0;
88
89 SkScalar t = SkPoint::CrossProduct(pi, pj);
90 area += t;
91 center.fX += (pi.fX + pj.fX) * t;
92 center.fY += (pi.fY + pj.fY) * t;
93 }
94 }
95
96 // If the poly has no area then we instead return the average of
97 // its points.
98 if (SkScalarNearlyZero(area)) {
99 SkPoint avg;
100 avg.set(0, 0);
101 for (int i = 0; i < count; ++i) {
102 const SkPoint& pt = segments[i].endPt();
103 avg.fX += pt.fX;
104 avg.fY += pt.fY;
105 }
106 SkScalar denom = SK_Scalar1 / count;
107 avg.scale(denom);
108 *c = avg;
109 } else {
110 area *= 3;
111 area = SkScalarInvert(area);
112 center.scale(area);
113 // undo the translate of p0 to the origin.
114 *c = center + p0;
115 }
116 SkASSERT(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY));
117 }
118
compute_vectors(SegmentArray * segments,SkPoint * fanPt,SkPathPriv::FirstDirection dir,int * vCount,int * iCount)119 static void compute_vectors(SegmentArray* segments,
120 SkPoint* fanPt,
121 SkPathPriv::FirstDirection dir,
122 int* vCount,
123 int* iCount) {
124 center_of_mass(*segments, fanPt);
125 int count = segments->count();
126
127 // Make the normals point towards the outside
128 SkPoint::Side normSide;
129 if (dir == SkPathPriv::kCCW_FirstDirection) {
130 normSide = SkPoint::kRight_Side;
131 } else {
132 normSide = SkPoint::kLeft_Side;
133 }
134
135 *vCount = 0;
136 *iCount = 0;
137 // compute normals at all points
138 for (int a = 0; a < count; ++a) {
139 Segment& sega = (*segments)[a];
140 int b = (a + 1) % count;
141 Segment& segb = (*segments)[b];
142
143 const SkPoint* prevPt = &sega.endPt();
144 int n = segb.countPoints();
145 for (int p = 0; p < n; ++p) {
146 segb.fNorms[p] = segb.fPts[p] - *prevPt;
147 segb.fNorms[p].normalize();
148 segb.fNorms[p].setOrthog(segb.fNorms[p], normSide);
149 prevPt = &segb.fPts[p];
150 }
151 if (Segment::kLine == segb.fType) {
152 *vCount += 5;
153 *iCount += 9;
154 } else {
155 *vCount += 6;
156 *iCount += 12;
157 }
158 }
159
160 // compute mid-vectors where segments meet. TODO: Detect shallow corners
161 // and leave out the wedges and close gaps by stitching segments together.
162 for (int a = 0; a < count; ++a) {
163 const Segment& sega = (*segments)[a];
164 int b = (a + 1) % count;
165 Segment& segb = (*segments)[b];
166 segb.fMid = segb.fNorms[0] + sega.endNorm();
167 segb.fMid.normalize();
168 // corner wedges
169 *vCount += 4;
170 *iCount += 6;
171 }
172 }
173
174 struct DegenerateTestData {
DegenerateTestDataDegenerateTestData175 DegenerateTestData() { fStage = kInitial; }
isDegenerateDegenerateTestData176 bool isDegenerate() const { return kNonDegenerate != fStage; }
177 enum {
178 kInitial,
179 kPoint,
180 kLine,
181 kNonDegenerate
182 } fStage;
183 SkPoint fFirstPoint;
184 SkVector fLineNormal;
185 SkScalar fLineC;
186 };
187
188 static const SkScalar kClose = (SK_Scalar1 / 16);
189 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
190
update_degenerate_test(DegenerateTestData * data,const SkPoint & pt)191 static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
192 switch (data->fStage) {
193 case DegenerateTestData::kInitial:
194 data->fFirstPoint = pt;
195 data->fStage = DegenerateTestData::kPoint;
196 break;
197 case DegenerateTestData::kPoint:
198 if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
199 data->fLineNormal = pt - data->fFirstPoint;
200 data->fLineNormal.normalize();
201 data->fLineNormal.setOrthog(data->fLineNormal);
202 data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
203 data->fStage = DegenerateTestData::kLine;
204 }
205 break;
206 case DegenerateTestData::kLine:
207 if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
208 data->fStage = DegenerateTestData::kNonDegenerate;
209 }
210 case DegenerateTestData::kNonDegenerate:
211 break;
212 default:
213 SkFAIL("Unexpected degenerate test stage.");
214 }
215 }
216
get_direction(const SkPath & path,const SkMatrix & m,SkPathPriv::FirstDirection * dir)217 static inline bool get_direction(const SkPath& path, const SkMatrix& m,
218 SkPathPriv::FirstDirection* dir) {
219 if (!SkPathPriv::CheapComputeFirstDirection(path, dir)) {
220 return false;
221 }
222 // check whether m reverses the orientation
223 SkASSERT(!m.hasPerspective());
224 SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) -
225 SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY));
226 if (det2x2 < 0) {
227 *dir = SkPathPriv::OppositeFirstDirection(*dir);
228 }
229 return true;
230 }
231
add_line_to_segment(const SkPoint & pt,SegmentArray * segments)232 static inline void add_line_to_segment(const SkPoint& pt,
233 SegmentArray* segments) {
234 segments->push_back();
235 segments->back().fType = Segment::kLine;
236 segments->back().fPts[0] = pt;
237 }
238
add_quad_segment(const SkPoint pts[3],SegmentArray * segments)239 static inline void add_quad_segment(const SkPoint pts[3],
240 SegmentArray* segments) {
241 if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) {
242 if (pts[0] != pts[2]) {
243 add_line_to_segment(pts[2], segments);
244 }
245 } else {
246 segments->push_back();
247 segments->back().fType = Segment::kQuad;
248 segments->back().fPts[0] = pts[1];
249 segments->back().fPts[1] = pts[2];
250 }
251 }
252
add_cubic_segments(const SkPoint pts[4],SkPathPriv::FirstDirection dir,SegmentArray * segments)253 static inline void add_cubic_segments(const SkPoint pts[4],
254 SkPathPriv::FirstDirection dir,
255 SegmentArray* segments) {
256 SkSTArray<15, SkPoint, true> quads;
257 GrPathUtils::convertCubicToQuadsConstrainToTangents(pts, SK_Scalar1, dir, &quads);
258 int count = quads.count();
259 for (int q = 0; q < count; q += 3) {
260 add_quad_segment(&quads[q], segments);
261 }
262 }
263
get_segments(const SkPath & path,const SkMatrix & m,SegmentArray * segments,SkPoint * fanPt,int * vCount,int * iCount)264 static bool get_segments(const SkPath& path,
265 const SkMatrix& m,
266 SegmentArray* segments,
267 SkPoint* fanPt,
268 int* vCount,
269 int* iCount) {
270 SkPath::Iter iter(path, true);
271 // This renderer over-emphasizes very thin path regions. We use the distance
272 // to the path from the sample to compute coverage. Every pixel intersected
273 // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
274 // notice that the sample may be close to a very thin area of the path and
275 // thus should be very light. This is particularly egregious for degenerate
276 // line paths. We detect paths that are very close to a line (zero area) and
277 // draw nothing.
278 DegenerateTestData degenerateData;
279 SkPathPriv::FirstDirection dir;
280 // get_direction can fail for some degenerate paths.
281 if (!get_direction(path, m, &dir)) {
282 return false;
283 }
284
285 for (;;) {
286 SkPoint pts[4];
287 SkPath::Verb verb = iter.next(pts);
288 switch (verb) {
289 case SkPath::kMove_Verb:
290 m.mapPoints(pts, 1);
291 update_degenerate_test(°enerateData, pts[0]);
292 break;
293 case SkPath::kLine_Verb: {
294 m.mapPoints(&pts[1], 1);
295 update_degenerate_test(°enerateData, pts[1]);
296 add_line_to_segment(pts[1], segments);
297 break;
298 }
299 case SkPath::kQuad_Verb:
300 m.mapPoints(pts, 3);
301 update_degenerate_test(°enerateData, pts[1]);
302 update_degenerate_test(°enerateData, pts[2]);
303 add_quad_segment(pts, segments);
304 break;
305 case SkPath::kConic_Verb: {
306 m.mapPoints(pts, 3);
307 SkScalar weight = iter.conicWeight();
308 SkAutoConicToQuads converter;
309 const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.5f);
310 for (int i = 0; i < converter.countQuads(); ++i) {
311 update_degenerate_test(°enerateData, quadPts[2*i + 1]);
312 update_degenerate_test(°enerateData, quadPts[2*i + 2]);
313 add_quad_segment(quadPts + 2*i, segments);
314 }
315 break;
316 }
317 case SkPath::kCubic_Verb: {
318 m.mapPoints(pts, 4);
319 update_degenerate_test(°enerateData, pts[1]);
320 update_degenerate_test(°enerateData, pts[2]);
321 update_degenerate_test(°enerateData, pts[3]);
322 add_cubic_segments(pts, dir, segments);
323 break;
324 };
325 case SkPath::kDone_Verb:
326 if (degenerateData.isDegenerate()) {
327 return false;
328 } else {
329 compute_vectors(segments, fanPt, dir, vCount, iCount);
330 return true;
331 }
332 default:
333 break;
334 }
335 }
336 }
337
338 struct QuadVertex {
339 SkPoint fPos;
340 SkPoint fUV;
341 SkScalar fD0;
342 SkScalar fD1;
343 };
344
345 struct Draw {
DrawDraw346 Draw() : fVertexCnt(0), fIndexCnt(0) {}
347 int fVertexCnt;
348 int fIndexCnt;
349 };
350
351 typedef SkTArray<Draw, true> DrawArray;
352
create_vertices(const SegmentArray & segments,const SkPoint & fanPt,DrawArray * draws,QuadVertex * verts,uint16_t * idxs)353 static void create_vertices(const SegmentArray& segments,
354 const SkPoint& fanPt,
355 DrawArray* draws,
356 QuadVertex* verts,
357 uint16_t* idxs) {
358 Draw* draw = &draws->push_back();
359 // alias just to make vert/index assignments easier to read.
360 int* v = &draw->fVertexCnt;
361 int* i = &draw->fIndexCnt;
362
363 int count = segments.count();
364 for (int a = 0; a < count; ++a) {
365 const Segment& sega = segments[a];
366 int b = (a + 1) % count;
367 const Segment& segb = segments[b];
368
369 // Check whether adding the verts for this segment to the current draw would cause index
370 // values to overflow.
371 int vCount = 4;
372 if (Segment::kLine == segb.fType) {
373 vCount += 5;
374 } else {
375 vCount += 6;
376 }
377 if (draw->fVertexCnt + vCount > (1 << 16)) {
378 verts += *v;
379 idxs += *i;
380 draw = &draws->push_back();
381 v = &draw->fVertexCnt;
382 i = &draw->fIndexCnt;
383 }
384
385 // FIXME: These tris are inset in the 1 unit arc around the corner
386 verts[*v + 0].fPos = sega.endPt();
387 verts[*v + 1].fPos = verts[*v + 0].fPos + sega.endNorm();
388 verts[*v + 2].fPos = verts[*v + 0].fPos + segb.fMid;
389 verts[*v + 3].fPos = verts[*v + 0].fPos + segb.fNorms[0];
390 verts[*v + 0].fUV.set(0,0);
391 verts[*v + 1].fUV.set(0,-SK_Scalar1);
392 verts[*v + 2].fUV.set(0,-SK_Scalar1);
393 verts[*v + 3].fUV.set(0,-SK_Scalar1);
394 verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
395 verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
396 verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
397 verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
398
399 idxs[*i + 0] = *v + 0;
400 idxs[*i + 1] = *v + 2;
401 idxs[*i + 2] = *v + 1;
402 idxs[*i + 3] = *v + 0;
403 idxs[*i + 4] = *v + 3;
404 idxs[*i + 5] = *v + 2;
405
406 *v += 4;
407 *i += 6;
408
409 if (Segment::kLine == segb.fType) {
410 verts[*v + 0].fPos = fanPt;
411 verts[*v + 1].fPos = sega.endPt();
412 verts[*v + 2].fPos = segb.fPts[0];
413
414 verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0];
415 verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0];
416
417 // we draw the line edge as a degenerate quad (u is 0, v is the
418 // signed distance to the edge)
419 SkScalar dist = fanPt.distanceToLineBetween(verts[*v + 1].fPos,
420 verts[*v + 2].fPos);
421 verts[*v + 0].fUV.set(0, dist);
422 verts[*v + 1].fUV.set(0, 0);
423 verts[*v + 2].fUV.set(0, 0);
424 verts[*v + 3].fUV.set(0, -SK_Scalar1);
425 verts[*v + 4].fUV.set(0, -SK_Scalar1);
426
427 verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
428 verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
429 verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
430 verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
431 verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1;
432
433 idxs[*i + 0] = *v + 3;
434 idxs[*i + 1] = *v + 1;
435 idxs[*i + 2] = *v + 2;
436
437 idxs[*i + 3] = *v + 4;
438 idxs[*i + 4] = *v + 3;
439 idxs[*i + 5] = *v + 2;
440
441 *i += 6;
442
443 // Draw the interior fan if it exists.
444 // TODO: Detect and combine colinear segments. This will ensure we catch every case
445 // with no interior, and that the resulting shared edge uses the same endpoints.
446 if (count >= 3) {
447 idxs[*i + 0] = *v + 0;
448 idxs[*i + 1] = *v + 2;
449 idxs[*i + 2] = *v + 1;
450
451 *i += 3;
452 }
453
454 *v += 5;
455 } else {
456 SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
457
458 SkVector midVec = segb.fNorms[0] + segb.fNorms[1];
459 midVec.normalize();
460
461 verts[*v + 0].fPos = fanPt;
462 verts[*v + 1].fPos = qpts[0];
463 verts[*v + 2].fPos = qpts[2];
464 verts[*v + 3].fPos = qpts[0] + segb.fNorms[0];
465 verts[*v + 4].fPos = qpts[2] + segb.fNorms[1];
466 verts[*v + 5].fPos = qpts[1] + midVec;
467
468 SkScalar c = segb.fNorms[0].dot(qpts[0]);
469 verts[*v + 0].fD0 = -segb.fNorms[0].dot(fanPt) + c;
470 verts[*v + 1].fD0 = 0.f;
471 verts[*v + 2].fD0 = -segb.fNorms[0].dot(qpts[2]) + c;
472 verts[*v + 3].fD0 = -SK_ScalarMax/100;
473 verts[*v + 4].fD0 = -SK_ScalarMax/100;
474 verts[*v + 5].fD0 = -SK_ScalarMax/100;
475
476 c = segb.fNorms[1].dot(qpts[2]);
477 verts[*v + 0].fD1 = -segb.fNorms[1].dot(fanPt) + c;
478 verts[*v + 1].fD1 = -segb.fNorms[1].dot(qpts[0]) + c;
479 verts[*v + 2].fD1 = 0.f;
480 verts[*v + 3].fD1 = -SK_ScalarMax/100;
481 verts[*v + 4].fD1 = -SK_ScalarMax/100;
482 verts[*v + 5].fD1 = -SK_ScalarMax/100;
483
484 GrPathUtils::QuadUVMatrix toUV(qpts);
485 toUV.apply<6, sizeof(QuadVertex), sizeof(SkPoint)>(verts + *v);
486
487 idxs[*i + 0] = *v + 3;
488 idxs[*i + 1] = *v + 1;
489 idxs[*i + 2] = *v + 2;
490 idxs[*i + 3] = *v + 4;
491 idxs[*i + 4] = *v + 3;
492 idxs[*i + 5] = *v + 2;
493
494 idxs[*i + 6] = *v + 5;
495 idxs[*i + 7] = *v + 3;
496 idxs[*i + 8] = *v + 4;
497
498 *i += 9;
499
500 // Draw the interior fan if it exists.
501 // TODO: Detect and combine colinear segments. This will ensure we catch every case
502 // with no interior, and that the resulting shared edge uses the same endpoints.
503 if (count >= 3) {
504 idxs[*i + 0] = *v + 0;
505 idxs[*i + 1] = *v + 2;
506 idxs[*i + 2] = *v + 1;
507
508 *i += 3;
509 }
510
511 *v += 6;
512 }
513 }
514 }
515
516 ///////////////////////////////////////////////////////////////////////////////
517
518 /*
519 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
520 * two components of the vertex attribute. Coverage is based on signed
521 * distance with negative being inside, positive outside. The edge is specified in
522 * window space (y-down). If either the third or fourth component of the interpolated
523 * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
524 * attempt to trim to a portion of the infinite quad.
525 * Requires shader derivative instruction support.
526 */
527
528 class QuadEdgeEffect : public GrGeometryProcessor {
529 public:
530
Create(GrColor color,const SkMatrix & localMatrix,bool usesLocalCoords)531 static GrGeometryProcessor* Create(GrColor color, const SkMatrix& localMatrix,
532 bool usesLocalCoords) {
533 return new QuadEdgeEffect(color, localMatrix, usesLocalCoords);
534 }
535
~QuadEdgeEffect()536 virtual ~QuadEdgeEffect() {}
537
name() const538 const char* name() const override { return "QuadEdge"; }
539
inPosition() const540 const Attribute* inPosition() const { return fInPosition; }
inQuadEdge() const541 const Attribute* inQuadEdge() const { return fInQuadEdge; }
color() const542 GrColor color() const { return fColor; }
colorIgnored() const543 bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
localMatrix() const544 const SkMatrix& localMatrix() const { return fLocalMatrix; }
usesLocalCoords() const545 bool usesLocalCoords() const { return fUsesLocalCoords; }
546
547 class GLSLProcessor : public GrGLSLGeometryProcessor {
548 public:
GLSLProcessor()549 GLSLProcessor()
550 : fColor(GrColor_ILLEGAL) {}
551
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)552 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
553 const QuadEdgeEffect& qe = args.fGP.cast<QuadEdgeEffect>();
554 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
555 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
556 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
557
558 // emit attributes
559 varyingHandler->emitAttributes(qe);
560
561 GrGLSLVertToFrag v(kVec4f_GrSLType);
562 varyingHandler->addVarying("QuadEdge", &v);
563 vertBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.inQuadEdge()->fName);
564
565 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
566 // Setup pass through color
567 if (!qe.colorIgnored()) {
568 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
569 &fColorUniform);
570 }
571
572 // Setup position
573 this->setupPosition(vertBuilder, gpArgs, qe.inPosition()->fName);
574
575 // emit transforms
576 this->emitTransforms(vertBuilder,
577 varyingHandler,
578 uniformHandler,
579 gpArgs->fPositionVar,
580 qe.inPosition()->fName,
581 qe.localMatrix(),
582 args.fTransformsIn,
583 args.fTransformsOut);
584
585 SkAssertResult(fragBuilder->enableFeature(
586 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
587 fragBuilder->codeAppendf("float edgeAlpha;");
588
589 // keep the derivative instructions outside the conditional
590 fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn());
591 fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn());
592 fragBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn());
593 // today we know z and w are in device space. We could use derivatives
594 fragBuilder->codeAppendf("edgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);", v.fsIn(),
595 v.fsIn());
596 fragBuilder->codeAppendf ("} else {");
597 fragBuilder->codeAppendf("vec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,"
598 " 2.0*%s.x*duvdy.x - duvdy.y);",
599 v.fsIn(), v.fsIn());
600 fragBuilder->codeAppendf("edgeAlpha = (%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(),
601 v.fsIn());
602 fragBuilder->codeAppendf("edgeAlpha = "
603 "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);}");
604
605 fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
606 }
607
GenKey(const GrGeometryProcessor & gp,const GrGLSLCaps &,GrProcessorKeyBuilder * b)608 static inline void GenKey(const GrGeometryProcessor& gp,
609 const GrGLSLCaps&,
610 GrProcessorKeyBuilder* b) {
611 const QuadEdgeEffect& qee = gp.cast<QuadEdgeEffect>();
612 uint32_t key = 0;
613 key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0;
614 key |= qee.colorIgnored() ? 0x2 : 0x0;
615 b->add32(key);
616 }
617
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp)618 void setData(const GrGLSLProgramDataManager& pdman,
619 const GrPrimitiveProcessor& gp) override {
620 const QuadEdgeEffect& qe = gp.cast<QuadEdgeEffect>();
621 if (qe.color() != fColor) {
622 float c[4];
623 GrColorToRGBAFloat(qe.color(), c);
624 pdman.set4fv(fColorUniform, 1, c);
625 fColor = qe.color();
626 }
627 }
628
setTransformData(const GrPrimitiveProcessor & primProc,const GrGLSLProgramDataManager & pdman,int index,const SkTArray<const GrCoordTransform *,true> & transforms)629 void setTransformData(const GrPrimitiveProcessor& primProc,
630 const GrGLSLProgramDataManager& pdman,
631 int index,
632 const SkTArray<const GrCoordTransform*, true>& transforms) override {
633 this->setTransformDataHelper<QuadEdgeEffect>(primProc, pdman, index, transforms);
634 }
635
636 private:
637 GrColor fColor;
638 UniformHandle fColorUniform;
639
640 typedef GrGLSLGeometryProcessor INHERITED;
641 };
642
getGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const643 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
644 GLSLProcessor::GenKey(*this, caps, b);
645 }
646
createGLSLInstance(const GrGLSLCaps &) const647 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
648 return new GLSLProcessor();
649 }
650
651 private:
QuadEdgeEffect(GrColor color,const SkMatrix & localMatrix,bool usesLocalCoords)652 QuadEdgeEffect(GrColor color, const SkMatrix& localMatrix, bool usesLocalCoords)
653 : fColor(color)
654 , fLocalMatrix(localMatrix)
655 , fUsesLocalCoords(usesLocalCoords) {
656 this->initClassID<QuadEdgeEffect>();
657 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
658 fInQuadEdge = &this->addVertexAttrib(Attribute("inQuadEdge", kVec4f_GrVertexAttribType));
659 }
660
661 const Attribute* fInPosition;
662 const Attribute* fInQuadEdge;
663 GrColor fColor;
664 SkMatrix fLocalMatrix;
665 bool fUsesLocalCoords;
666
667 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
668
669 typedef GrGeometryProcessor INHERITED;
670 };
671
672 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect);
673
TestCreate(GrProcessorTestData * d)674 const GrGeometryProcessor* QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
675 // Doesn't work without derivative instructions.
676 return d->fCaps->shaderCaps()->shaderDerivativeSupport() ?
677 QuadEdgeEffect::Create(GrRandomColor(d->fRandom),
678 GrTest::TestMatrix(d->fRandom),
679 d->fRandom->nextBool()) : nullptr;
680 }
681
682 ///////////////////////////////////////////////////////////////////////////////
683
onCanDrawPath(const CanDrawPathArgs & args) const684 bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
685 return (args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
686 args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() &&
687 args.fPath->isConvex());
688 }
689
690 // extract the result vertices and indices from the GrAAConvexTessellator
extract_verts(const GrAAConvexTessellator & tess,void * vertices,size_t vertexStride,GrColor color,uint16_t * idxs,bool tweakAlphaForCoverage)691 static void extract_verts(const GrAAConvexTessellator& tess,
692 void* vertices,
693 size_t vertexStride,
694 GrColor color,
695 uint16_t* idxs,
696 bool tweakAlphaForCoverage) {
697 intptr_t verts = reinterpret_cast<intptr_t>(vertices);
698
699 for (int i = 0; i < tess.numPts(); ++i) {
700 *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i);
701 }
702
703 // Make 'verts' point to the colors
704 verts += sizeof(SkPoint);
705 for (int i = 0; i < tess.numPts(); ++i) {
706 if (tweakAlphaForCoverage) {
707 SkASSERT(SkScalarRoundToInt(255.0f * tess.coverage(i)) <= 255);
708 unsigned scale = SkScalarRoundToInt(255.0f * tess.coverage(i));
709 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
710 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
711 } else {
712 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
713 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
714 tess.coverage(i);
715 }
716 }
717
718 for (int i = 0; i < tess.numIndices(); ++i) {
719 idxs[i] = tess.index(i);
720 }
721 }
722
create_fill_gp(bool tweakAlphaForCoverage,const SkMatrix & viewMatrix,bool usesLocalCoords,bool coverageIgnored)723 static const GrGeometryProcessor* create_fill_gp(bool tweakAlphaForCoverage,
724 const SkMatrix& viewMatrix,
725 bool usesLocalCoords,
726 bool coverageIgnored) {
727 using namespace GrDefaultGeoProcFactory;
728
729 Color color(Color::kAttribute_Type);
730 Coverage::Type coverageType;
731 // TODO remove coverage if coverage is ignored
732 /*if (coverageIgnored) {
733 coverageType = Coverage::kNone_Type;
734 } else*/ if (tweakAlphaForCoverage) {
735 coverageType = Coverage::kSolid_Type;
736 } else {
737 coverageType = Coverage::kAttribute_Type;
738 }
739 Coverage coverage(coverageType);
740 LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type :
741 LocalCoords::kUnused_Type);
742 return CreateForDeviceSpace(color, coverage, localCoords, viewMatrix);
743 }
744
745 class AAConvexPathBatch : public GrVertexBatch {
746 public:
747 DEFINE_BATCH_CLASS_ID
748 struct Geometry {
749 GrColor fColor;
750 SkMatrix fViewMatrix;
751 SkPath fPath;
752 };
753
Create(const Geometry & geometry)754 static GrDrawBatch* Create(const Geometry& geometry) { return new AAConvexPathBatch(geometry); }
755
name() const756 const char* name() const override { return "AAConvexBatch"; }
757
computePipelineOptimizations(GrInitInvariantOutput * color,GrInitInvariantOutput * coverage,GrBatchToXPOverrides * overrides) const758 void computePipelineOptimizations(GrInitInvariantOutput* color,
759 GrInitInvariantOutput* coverage,
760 GrBatchToXPOverrides* overrides) const override {
761 // When this is called on a batch, there is only one geometry bundle
762 color->setKnownFourComponents(fGeoData[0].fColor);
763 coverage->setUnknownSingleComponent();
764 }
765
766 private:
initBatchTracker(const GrXPOverridesForBatch & overrides)767 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
768 // Handle any color overrides
769 if (!overrides.readsColor()) {
770 fGeoData[0].fColor = GrColor_ILLEGAL;
771 }
772 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
773
774 // setup batch properties
775 fBatch.fColorIgnored = !overrides.readsColor();
776 fBatch.fColor = fGeoData[0].fColor;
777 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
778 fBatch.fCoverageIgnored = !overrides.readsCoverage();
779 fBatch.fLinesOnly = SkPath::kLine_SegmentMask == fGeoData[0].fPath.getSegmentMasks();
780 fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage();
781 }
782
prepareLinesOnlyDraws(Target * target) const783 void prepareLinesOnlyDraws(Target* target) const {
784 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
785
786 // Setup GrGeometryProcessor
787 SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_gp(canTweakAlphaForCoverage,
788 this->viewMatrix(),
789 this->usesLocalCoords(),
790 this->coverageIgnored()));
791 if (!gp) {
792 SkDebugf("Could not create GrGeometryProcessor\n");
793 return;
794 }
795
796 target->initDraw(gp, this->pipeline());
797
798 size_t vertexStride = gp->getVertexStride();
799
800 SkASSERT(canTweakAlphaForCoverage ?
801 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
802 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
803
804 GrAAConvexTessellator tess;
805
806 int instanceCount = fGeoData.count();
807
808 for (int i = 0; i < instanceCount; i++) {
809 tess.rewind();
810
811 const Geometry& args = fGeoData[i];
812
813 if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
814 continue;
815 }
816
817 const GrVertexBuffer* vertexBuffer;
818 int firstVertex;
819
820 void* verts = target->makeVertexSpace(vertexStride, tess.numPts(), &vertexBuffer,
821 &firstVertex);
822 if (!verts) {
823 SkDebugf("Could not allocate vertices\n");
824 return;
825 }
826
827 const GrIndexBuffer* indexBuffer;
828 int firstIndex;
829
830 uint16_t* idxs = target->makeIndexSpace(tess.numIndices(), &indexBuffer, &firstIndex);
831 if (!idxs) {
832 SkDebugf("Could not allocate indices\n");
833 return;
834 }
835
836 extract_verts(tess, verts, vertexStride, args.fColor, idxs, canTweakAlphaForCoverage);
837
838 GrVertices info;
839 info.initIndexed(kTriangles_GrPrimitiveType,
840 vertexBuffer, indexBuffer,
841 firstVertex, firstIndex,
842 tess.numPts(), tess.numIndices());
843 target->draw(info);
844 }
845 }
846
onPrepareDraws(Target * target) const847 void onPrepareDraws(Target* target) const override {
848 #ifndef SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS
849 if (this->linesOnly()) {
850 this->prepareLinesOnlyDraws(target);
851 return;
852 }
853 #endif
854
855 int instanceCount = fGeoData.count();
856
857 SkMatrix invert;
858 if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
859 SkDebugf("Could not invert viewmatrix\n");
860 return;
861 }
862
863 // Setup GrGeometryProcessor
864 SkAutoTUnref<GrGeometryProcessor> quadProcessor(
865 QuadEdgeEffect::Create(this->color(), invert, this->usesLocalCoords()));
866
867 target->initDraw(quadProcessor, this->pipeline());
868
869 // TODO generate all segments for all paths and use one vertex buffer
870 for (int i = 0; i < instanceCount; i++) {
871 const Geometry& args = fGeoData[i];
872
873 // We use the fact that SkPath::transform path does subdivision based on
874 // perspective. Otherwise, we apply the view matrix when copying to the
875 // segment representation.
876 const SkMatrix* viewMatrix = &args.fViewMatrix;
877
878 // We avoid initializing the path unless we have to
879 const SkPath* pathPtr = &args.fPath;
880 SkTLazy<SkPath> tmpPath;
881 if (viewMatrix->hasPerspective()) {
882 SkPath* tmpPathPtr = tmpPath.init(*pathPtr);
883 tmpPathPtr->setIsVolatile(true);
884 tmpPathPtr->transform(*viewMatrix);
885 viewMatrix = &SkMatrix::I();
886 pathPtr = tmpPathPtr;
887 }
888
889 int vertexCount;
890 int indexCount;
891 enum {
892 kPreallocSegmentCnt = 512 / sizeof(Segment),
893 kPreallocDrawCnt = 4,
894 };
895 SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
896 SkPoint fanPt;
897
898 if (!get_segments(*pathPtr, *viewMatrix, &segments, &fanPt, &vertexCount,
899 &indexCount)) {
900 continue;
901 }
902
903 const GrVertexBuffer* vertexBuffer;
904 int firstVertex;
905
906 size_t vertexStride = quadProcessor->getVertexStride();
907 QuadVertex* verts = reinterpret_cast<QuadVertex*>(target->makeVertexSpace(
908 vertexStride, vertexCount, &vertexBuffer, &firstVertex));
909
910 if (!verts) {
911 SkDebugf("Could not allocate vertices\n");
912 return;
913 }
914
915 const GrIndexBuffer* indexBuffer;
916 int firstIndex;
917
918 uint16_t *idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
919 if (!idxs) {
920 SkDebugf("Could not allocate indices\n");
921 return;
922 }
923
924 SkSTArray<kPreallocDrawCnt, Draw, true> draws;
925 create_vertices(segments, fanPt, &draws, verts, idxs);
926
927 GrVertices vertices;
928
929 for (int j = 0; j < draws.count(); ++j) {
930 const Draw& draw = draws[j];
931 vertices.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer,
932 firstVertex, firstIndex, draw.fVertexCnt, draw.fIndexCnt);
933 target->draw(vertices);
934 firstVertex += draw.fVertexCnt;
935 firstIndex += draw.fIndexCnt;
936 }
937 }
938 }
939
geoData()940 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
941
AAConvexPathBatch(const Geometry & geometry)942 AAConvexPathBatch(const Geometry& geometry) : INHERITED(ClassID()) {
943 fGeoData.push_back(geometry);
944
945 // compute bounds
946 fBounds = geometry.fPath.getBounds();
947 geometry.fViewMatrix.mapRect(&fBounds);
948 }
949
onCombineIfPossible(GrBatch * t,const GrCaps & caps)950 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
951 AAConvexPathBatch* that = t->cast<AAConvexPathBatch>();
952 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
953 that->bounds(), caps)) {
954 return false;
955 }
956
957 if (this->color() != that->color()) {
958 return false;
959 }
960
961 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
962 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
963 return false;
964 }
965
966 if (this->linesOnly() != that->linesOnly()) {
967 return false;
968 }
969
970 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
971 // not tweaking
972 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
973 fBatch.fCanTweakAlphaForCoverage = false;
974 }
975
976 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
977 this->joinBounds(that->bounds());
978 return true;
979 }
980
color() const981 GrColor color() const { return fBatch.fColor; }
linesOnly() const982 bool linesOnly() const { return fBatch.fLinesOnly; }
usesLocalCoords() const983 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
canTweakAlphaForCoverage() const984 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
viewMatrix() const985 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
coverageIgnored() const986 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
987
988 struct BatchTracker {
989 GrColor fColor;
990 bool fUsesLocalCoords;
991 bool fColorIgnored;
992 bool fCoverageIgnored;
993 bool fLinesOnly;
994 bool fCanTweakAlphaForCoverage;
995 };
996
997 BatchTracker fBatch;
998 SkSTArray<1, Geometry, true> fGeoData;
999
1000 typedef GrVertexBatch INHERITED;
1001 };
1002
onDrawPath(const DrawPathArgs & args)1003 bool GrAAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
1004 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrAAConvexPathRenderer::onDrawPath");
1005 if (args.fPath->isEmpty()) {
1006 return true;
1007 }
1008
1009 AAConvexPathBatch::Geometry geometry;
1010 geometry.fColor = args.fColor;
1011 geometry.fViewMatrix = *args.fViewMatrix;
1012 geometry.fPath = *args.fPath;
1013
1014 SkAutoTUnref<GrDrawBatch> batch(AAConvexPathBatch::Create(geometry));
1015 args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
1016
1017 return true;
1018
1019 }
1020
1021 ///////////////////////////////////////////////////////////////////////////////////////////////////
1022
1023 #ifdef GR_TEST_UTILS
1024
DRAW_BATCH_TEST_DEFINE(AAConvexPathBatch)1025 DRAW_BATCH_TEST_DEFINE(AAConvexPathBatch) {
1026 AAConvexPathBatch::Geometry geometry;
1027 geometry.fColor = GrRandomColor(random);
1028 geometry.fViewMatrix = GrTest::TestMatrixInvertible(random);
1029 geometry.fPath = GrTest::TestPathConvex(random);
1030
1031 return AAConvexPathBatch::Create(geometry);
1032 }
1033
1034 #endif
1035