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(&degenerateData, pts[0]);
292                 break;
293             case SkPath::kLine_Verb: {
294                 m.mapPoints(&pts[1], 1);
295                 update_degenerate_test(&degenerateData, 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(&degenerateData, pts[1]);
302                 update_degenerate_test(&degenerateData, 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(&degenerateData, quadPts[2*i + 1]);
312                     update_degenerate_test(&degenerateData, 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(&degenerateData, pts[1]);
320                 update_degenerate_test(&degenerateData, pts[2]);
321                 update_degenerate_test(&degenerateData, 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