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