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