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 "GrBatch.h"
13#include "GrBatchTarget.h"
14#include "GrBatchTest.h"
15#include "GrContext.h"
16#include "GrDefaultGeoProcFactory.h"
17#include "GrDrawTargetCaps.h"
18#include "GrGeometryProcessor.h"
19#include "GrInvariantOutput.h"
20#include "GrPathUtils.h"
21#include "GrProcessor.h"
22#include "GrPipelineBuilder.h"
23#include "GrStrokeInfo.h"
24#include "SkGeometry.h"
25#include "SkString.h"
26#include "SkTraceEvent.h"
27#include "gl/GrGLProcessor.h"
28#include "gl/GrGLSL.h"
29#include "gl/GrGLGeometryProcessor.h"
30#include "gl/builders/GrGLProgramBuilder.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            const SkPoint pj = segments[i + 1].endPt() - p0;
85
86            SkScalar t = SkScalarMul(pi.fX, pj.fY) - SkScalarMul(pj.fX, pi.fY);
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.fX = SkScalarMul(center.fX, area);
110        center.fY = SkScalarMul(center.fY, 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
117static void compute_vectors(SegmentArray* segments,
118                            SkPoint* fanPt,
119                            SkPath::Direction 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    SkPoint::Side normSide;
127    if (dir == SkPath::kCCW_Direction) {
128        normSide = SkPoint::kRight_Side;
129    } else {
130        normSide = SkPoint::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            segb.fNorms[p].setOrthog(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
172struct DegenerateTestData {
173    DegenerateTestData() { fStage = kInitial; }
174    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
186static const SkScalar kClose = (SK_Scalar1 / 16);
187static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
188
189static 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 (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
197                data->fLineNormal = pt - data->fFirstPoint;
198                data->fLineNormal.normalize();
199                data->fLineNormal.setOrthog(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            SkFAIL("Unexpected degenerate test stage.");
212    }
213}
214
215static inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Direction* dir) {
216    if (!path.cheapComputeDirection(dir)) {
217        return false;
218    }
219    // check whether m reverses the orientation
220    SkASSERT(!m.hasPerspective());
221    SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) -
222                      SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY));
223    if (det2x2 < 0) {
224        *dir = SkPath::OppositeDirection(*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                                      SkPath::Direction dir,
252                                      SegmentArray* segments) {
253    SkSTArray<15, SkPoint, true> quads;
254    GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, 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    SkPath::Direction 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);
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 GrGeometryProcessor* Create(GrColor color, const SkMatrix& localMatrix) {
529        return SkNEW_ARGS(QuadEdgeEffect, (color, localMatrix));
530    }
531
532    virtual ~QuadEdgeEffect() {}
533
534    const char* name() const override { return "QuadEdge"; }
535
536    const Attribute* inPosition() const { return fInPosition; }
537    const Attribute* inQuadEdge() const { return fInQuadEdge; }
538    GrColor color() const { return fColor; }
539    const SkMatrix& localMatrix() const { return fLocalMatrix; }
540
541    class GLProcessor : public GrGLGeometryProcessor {
542    public:
543        GLProcessor(const GrGeometryProcessor&,
544                    const GrBatchTracker&)
545            : fColor(GrColor_ILLEGAL) {}
546
547        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
548            const QuadEdgeEffect& qe = args.fGP.cast<QuadEdgeEffect>();
549            GrGLGPBuilder* pb = args.fPB;
550            GrGLVertexBuilder* vsBuilder = pb->getVertexShaderBuilder();
551
552            // emit attributes
553            vsBuilder->emitAttributes(qe);
554
555            GrGLVertToFrag v(kVec4f_GrSLType);
556            args.fPB->addVarying("QuadEdge", &v);
557            vsBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.inQuadEdge()->fName);
558
559            const BatchTracker& local = args.fBT.cast<BatchTracker>();
560
561            // Setup pass through color
562            this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
563                                        &fColorUniform);
564
565            // Setup position
566            this->setupPosition(pb, gpArgs, qe.inPosition()->fName);
567
568            // emit transforms
569            this->emitTransforms(args.fPB, gpArgs->fPositionVar, qe.inPosition()->fName,
570                                 qe.localMatrix(), args.fTransformsIn, args.fTransformsOut);
571
572            GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
573
574            SkAssertResult(fsBuilder->enableFeature(
575                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
576            fsBuilder->codeAppendf("float edgeAlpha;");
577
578            // keep the derivative instructions outside the conditional
579            fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn());
580            fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn());
581            fsBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn());
582            // today we know z and w are in device space. We could use derivatives
583            fsBuilder->codeAppendf("edgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);", v.fsIn(),
584                                    v.fsIn());
585            fsBuilder->codeAppendf ("} else {");
586            fsBuilder->codeAppendf("vec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,"
587                                   "               2.0*%s.x*duvdy.x - duvdy.y);",
588                                   v.fsIn(), v.fsIn());
589            fsBuilder->codeAppendf("edgeAlpha = (%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(),
590                                    v.fsIn());
591            fsBuilder->codeAppendf("edgeAlpha = "
592                                   "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);}");
593
594            fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
595        }
596
597        static inline void GenKey(const GrGeometryProcessor& gp,
598                                  const GrBatchTracker& bt,
599                                  const GrGLSLCaps&,
600                                  GrProcessorKeyBuilder* b) {
601            const BatchTracker& local = bt.cast<BatchTracker>();
602            const QuadEdgeEffect& qee = gp.cast<QuadEdgeEffect>();
603            uint32_t key = local.fInputColorType << 16;
604            key |= local.fUsesLocalCoords && qee.localMatrix().hasPerspective() ? 0x1 : 0x0;
605            b->add32(key);
606        }
607
608        virtual void setData(const GrGLProgramDataManager& pdman,
609                             const GrPrimitiveProcessor& gp,
610                             const GrBatchTracker& bt) override {
611            const BatchTracker& local = bt.cast<BatchTracker>();
612            if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
613                GrGLfloat c[4];
614                GrColorToRGBAFloat(local.fColor, c);
615                pdman.set4fv(fColorUniform, 1, c);
616                fColor = local.fColor;
617            }
618        }
619
620        void setTransformData(const GrPrimitiveProcessor& primProc,
621                              const GrGLProgramDataManager& pdman,
622                              int index,
623                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
624            this->setTransformDataHelper<QuadEdgeEffect>(primProc, pdman, index, transforms);
625        }
626
627    private:
628        GrColor fColor;
629        UniformHandle fColorUniform;
630
631        typedef GrGLGeometryProcessor INHERITED;
632    };
633
634    virtual void getGLProcessorKey(const GrBatchTracker& bt,
635                                   const GrGLSLCaps& caps,
636                                   GrProcessorKeyBuilder* b) const override {
637        GLProcessor::GenKey(*this, bt, caps, b);
638    }
639
640    virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
641                                                     const GrGLSLCaps&) const override {
642        return SkNEW_ARGS(GLProcessor, (*this, bt));
643    }
644
645    void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const override {
646        BatchTracker* local = bt->cast<BatchTracker>();
647        local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
648        local->fUsesLocalCoords = init.fUsesLocalCoords;
649    }
650
651private:
652    QuadEdgeEffect(GrColor color, const SkMatrix& localMatrix)
653        : fColor(color)
654        , fLocalMatrix(localMatrix) {
655        this->initClassID<QuadEdgeEffect>();
656        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
657        fInQuadEdge = &this->addVertexAttrib(Attribute("inQuadEdge", kVec4f_GrVertexAttribType));
658    }
659
660    struct BatchTracker {
661        GrGPInput fInputColorType;
662        GrColor fColor;
663        bool fUsesLocalCoords;
664    };
665
666    const Attribute* fInPosition;
667    const Attribute* fInQuadEdge;
668    GrColor          fColor;
669    SkMatrix         fLocalMatrix;
670
671    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
672
673    typedef GrGeometryProcessor INHERITED;
674};
675
676GR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect);
677
678GrGeometryProcessor* QuadEdgeEffect::TestCreate(SkRandom* random,
679                                                GrContext*,
680                                                const GrDrawTargetCaps& caps,
681                                                GrTexture*[]) {
682    // Doesn't work without derivative instructions.
683    return caps.shaderCaps()->shaderDerivativeSupport() ?
684           QuadEdgeEffect::Create(GrRandomColor(random),
685                                  GrTest::TestMatrix(random)) : NULL;
686}
687
688///////////////////////////////////////////////////////////////////////////////
689
690bool GrAAConvexPathRenderer::canDrawPath(const GrDrawTarget* target,
691                                         const GrPipelineBuilder*,
692                                         const SkMatrix& viewMatrix,
693                                         const SkPath& path,
694                                         const GrStrokeInfo& stroke,
695                                         bool antiAlias) const {
696    return (target->caps()->shaderCaps()->shaderDerivativeSupport() && antiAlias &&
697            stroke.isFillStyle() && !path.isInverseFillType() && path.isConvex());
698}
699
700// extract the result vertices and indices from the GrAAConvexTessellator
701static void extract_verts(const GrAAConvexTessellator& tess,
702                          void* vertices,
703                          size_t vertexStride,
704                          GrColor color,
705                          uint16_t* idxs,
706                          bool tweakAlphaForCoverage) {
707    intptr_t verts = reinterpret_cast<intptr_t>(vertices);
708
709    for (int i = 0; i < tess.numPts(); ++i) {
710        *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i);
711    }
712
713    // Make 'verts' point to the colors
714    verts += sizeof(SkPoint);
715    for (int i = 0; i < tess.numPts(); ++i) {
716        SkASSERT(tess.depth(i) >= -0.5f && tess.depth(i) <= 0.5f);
717        if (tweakAlphaForCoverage) {
718            SkASSERT(SkScalarRoundToInt(255.0f * (tess.depth(i) + 0.5f)) <= 255);
719            unsigned scale = SkScalarRoundToInt(255.0f * (tess.depth(i) + 0.5f));
720            GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
721            *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
722        } else {
723            *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
724            *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
725                                                                    tess.depth(i) + 0.5f;
726        }
727    }
728
729    for (int i = 0; i < tess.numIndices(); ++i) {
730        idxs[i] = tess.index(i);
731    }
732}
733
734static const GrGeometryProcessor* create_fill_gp(bool tweakAlphaForCoverage,
735                                                 const SkMatrix& localMatrix) {
736    uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
737    if (!tweakAlphaForCoverage) {
738        flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
739    }
740
741    return GrDefaultGeoProcFactory::Create(flags, GrColor_WHITE, SkMatrix::I(), localMatrix);
742}
743
744class AAConvexPathBatch : public GrBatch {
745public:
746    struct Geometry {
747        GrColor fColor;
748        SkMatrix fViewMatrix;
749        SkPath fPath;
750    };
751
752    static GrBatch* Create(const Geometry& geometry) {
753        return SkNEW_ARGS(AAConvexPathBatch, (geometry));
754    }
755
756    const char* name() const override { return "AAConvexBatch"; }
757
758    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
759        // When this is called on a batch, there is only one geometry bundle
760        out->setKnownFourComponents(fGeoData[0].fColor);
761    }
762    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
763        out->setUnknownSingleComponent();
764    }
765
766    void initBatchTracker(const GrPipelineInfo& init) override {
767        // Handle any color overrides
768        if (init.fColorIgnored) {
769            fGeoData[0].fColor = GrColor_ILLEGAL;
770        } else if (GrColor_ILLEGAL != init.fOverrideColor) {
771            fGeoData[0].fColor = init.fOverrideColor;
772        }
773
774        // setup batch properties
775        fBatch.fColorIgnored = init.fColorIgnored;
776        fBatch.fColor = fGeoData[0].fColor;
777        fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
778        fBatch.fCoverageIgnored = init.fCoverageIgnored;
779        fBatch.fLinesOnly = SkPath::kLine_SegmentMask == fGeoData[0].fPath.getSegmentMasks();
780        fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage;
781    }
782
783    void generateGeometryLinesOnly(GrBatchTarget* batchTarget, const GrPipeline* pipeline) {
784        bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
785
786        SkMatrix invert;
787        if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
788            SkDebugf("Could not invert viewmatrix\n");
789            return;
790        }
791
792        // Setup GrGeometryProcessor
793        SkAutoTUnref<const GrGeometryProcessor> gp(
794                                                create_fill_gp(canTweakAlphaForCoverage, invert));
795
796        batchTarget->initDraw(gp, pipeline);
797
798        // TODO remove this when batch is everywhere
799        GrPipelineInfo init;
800        init.fColorIgnored = fBatch.fColorIgnored;
801        init.fOverrideColor = GrColor_ILLEGAL;
802        init.fCoverageIgnored = fBatch.fCoverageIgnored;
803        init.fUsesLocalCoords = this->usesLocalCoords();
804        gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
805
806        size_t vertexStride = gp->getVertexStride();
807
808        SkASSERT(canTweakAlphaForCoverage ?
809                 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
810                 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
811
812        GrAAConvexTessellator tess;
813
814        int instanceCount = fGeoData.count();
815
816        for (int i = 0; i < instanceCount; i++) {
817            tess.rewind();
818
819            Geometry& args = fGeoData[i];
820
821            if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
822                continue;
823            }
824
825            const GrVertexBuffer* vertexBuffer;
826            int firstVertex;
827
828            void* verts = batchTarget->makeVertSpace(vertexStride, tess.numPts(),
829                                                     &vertexBuffer, &firstVertex);
830            if (!verts) {
831                SkDebugf("Could not allocate vertices\n");
832                return;
833            }
834
835            const GrIndexBuffer* indexBuffer;
836            int firstIndex;
837
838            uint16_t* idxs = batchTarget->makeIndexSpace(tess.numIndices(),
839                                                        &indexBuffer, &firstIndex);
840            if (!idxs) {
841                SkDebugf("Could not allocate indices\n");
842                return;
843            }
844
845            extract_verts(tess, verts, vertexStride, args.fColor, idxs, canTweakAlphaForCoverage);
846
847            GrVertices info;
848            info.initIndexed(kTriangles_GrPrimitiveType,
849                             vertexBuffer, indexBuffer,
850                             firstVertex, firstIndex,
851                             tess.numPts(), tess.numIndices());
852            batchTarget->draw(info);
853        }
854    }
855
856    void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
857#ifndef SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS
858        if (this->linesOnly()) {
859            this->generateGeometryLinesOnly(batchTarget, pipeline);
860            return;
861        }
862#endif
863
864        int instanceCount = fGeoData.count();
865
866        SkMatrix invert;
867        if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
868            SkDebugf("Could not invert viewmatrix\n");
869            return;
870        }
871
872        // Setup GrGeometryProcessor
873        SkAutoTUnref<GrGeometryProcessor> quadProcessor(QuadEdgeEffect::Create(this->color(),
874                                                                               invert));
875
876        batchTarget->initDraw(quadProcessor, pipeline);
877
878        // TODO remove this when batch is everywhere
879        GrPipelineInfo init;
880        init.fColorIgnored = fBatch.fColorIgnored;
881        init.fOverrideColor = GrColor_ILLEGAL;
882        init.fCoverageIgnored = fBatch.fCoverageIgnored;
883        init.fUsesLocalCoords = this->usesLocalCoords();
884        quadProcessor->initBatchTracker(batchTarget->currentBatchTracker(), init);
885
886        // TODO generate all segments for all paths and use one vertex buffer
887        for (int i = 0; i < instanceCount; i++) {
888            Geometry& args = fGeoData[i];
889
890            // We use the fact that SkPath::transform path does subdivision based on
891            // perspective. Otherwise, we apply the view matrix when copying to the
892            // segment representation.
893            const SkMatrix* viewMatrix = &args.fViewMatrix;
894            if (viewMatrix->hasPerspective()) {
895                args.fPath.transform(*viewMatrix);
896                viewMatrix = &SkMatrix::I();
897            }
898
899            int vertexCount;
900            int indexCount;
901            enum {
902                kPreallocSegmentCnt = 512 / sizeof(Segment),
903                kPreallocDrawCnt = 4,
904            };
905            SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
906            SkPoint fanPt;
907
908            if (!get_segments(args.fPath, *viewMatrix, &segments, &fanPt, &vertexCount,
909                              &indexCount)) {
910                continue;
911            }
912
913            const GrVertexBuffer* vertexBuffer;
914            int firstVertex;
915
916            size_t vertexStride = quadProcessor->getVertexStride();
917            QuadVertex* verts = reinterpret_cast<QuadVertex*>(batchTarget->makeVertSpace(
918                vertexStride, vertexCount, &vertexBuffer, &firstVertex));
919
920            if (!verts) {
921                SkDebugf("Could not allocate vertices\n");
922                return;
923            }
924
925            const GrIndexBuffer* indexBuffer;
926            int firstIndex;
927
928            uint16_t *idxs = batchTarget->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
929            if (!idxs) {
930                SkDebugf("Could not allocate indices\n");
931                return;
932            }
933
934            SkSTArray<kPreallocDrawCnt, Draw, true> draws;
935            create_vertices(segments, fanPt, &draws, verts, idxs);
936
937            GrVertices vertices;
938
939            for (int i = 0; i < draws.count(); ++i) {
940                const Draw& draw = draws[i];
941                vertices.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer,
942                                     firstVertex, firstIndex, draw.fVertexCnt, draw.fIndexCnt);
943                batchTarget->draw(vertices);
944                firstVertex += draw.fVertexCnt;
945                firstIndex += draw.fIndexCnt;
946            }
947        }
948    }
949
950    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
951
952private:
953    AAConvexPathBatch(const Geometry& geometry) {
954        this->initClassID<AAConvexPathBatch>();
955        fGeoData.push_back(geometry);
956
957        // compute bounds
958        fBounds = geometry.fPath.getBounds();
959        geometry.fViewMatrix.mapRect(&fBounds);
960    }
961
962    bool onCombineIfPossible(GrBatch* t) override {
963        AAConvexPathBatch* that = t->cast<AAConvexPathBatch>();
964
965        if (this->color() != that->color()) {
966            return false;
967        }
968
969        SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
970        if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
971            return false;
972        }
973
974        if (this->linesOnly() != that->linesOnly()) {
975            return false;
976        }
977
978        // In the event of two batches, one who can tweak, one who cannot, we just fall back to
979        // not tweaking
980        if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
981            fBatch.fCanTweakAlphaForCoverage = false;
982        }
983
984        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
985        this->joinBounds(that->bounds());
986        return true;
987    }
988
989    GrColor color() const { return fBatch.fColor; }
990    bool linesOnly() const { return fBatch.fLinesOnly; }
991    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
992    bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
993    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
994
995    struct BatchTracker {
996        GrColor fColor;
997        bool fUsesLocalCoords;
998        bool fColorIgnored;
999        bool fCoverageIgnored;
1000        bool fLinesOnly;
1001        bool fCanTweakAlphaForCoverage;
1002    };
1003
1004    BatchTracker fBatch;
1005    SkSTArray<1, Geometry, true> fGeoData;
1006};
1007
1008bool GrAAConvexPathRenderer::onDrawPath(GrDrawTarget* target,
1009                                        GrPipelineBuilder* pipelineBuilder,
1010                                        GrColor color,
1011                                        const SkMatrix& vm,
1012                                        const SkPath& path,
1013                                        const GrStrokeInfo&,
1014                                        bool antiAlias) {
1015    if (path.isEmpty()) {
1016        return true;
1017    }
1018
1019    AAConvexPathBatch::Geometry geometry;
1020    geometry.fColor = color;
1021    geometry.fViewMatrix = vm;
1022    geometry.fPath = path;
1023
1024    SkAutoTUnref<GrBatch> batch(AAConvexPathBatch::Create(geometry));
1025    target->drawBatch(pipelineBuilder, batch);
1026
1027    return true;
1028
1029}
1030
1031///////////////////////////////////////////////////////////////////////////////////////////////////
1032
1033#ifdef GR_TEST_UTILS
1034
1035BATCH_TEST_DEFINE(AAConvexPathBatch) {
1036    AAConvexPathBatch::Geometry geometry;
1037    geometry.fColor = GrRandomColor(random);
1038    geometry.fViewMatrix = GrTest::TestMatrixInvertible(random);
1039    geometry.fPath = GrTest::TestPathConvex(random);
1040
1041    return AAConvexPathBatch::Create(geometry);
1042}
1043
1044#endif
1045