GrAAConvexPathRenderer.cpp revision a91f03165335267bda7cf04ae5ffb60c1362f017
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 "GrContext.h"
12#include "GrDrawState.h"
13#include "GrDrawTargetCaps.h"
14#include "GrEffect.h"
15#include "GrPathUtils.h"
16#include "GrTBackendEffectFactory.h"
17#include "SkString.h"
18#include "SkStrokeRec.h"
19#include "SkTrace.h"
20
21#include "gl/GrGLEffect.h"
22#include "gl/GrGLSL.h"
23
24GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
25}
26
27struct Segment {
28    enum {
29        // These enum values are assumed in member functions below.
30        kLine = 0,
31        kQuad = 1,
32    } fType;
33
34    // line uses one pt, quad uses 2 pts
35    GrPoint fPts[2];
36    // normal to edge ending at each pt
37    GrVec fNorms[2];
38    // is the corner where the previous segment meets this segment
39    // sharp. If so, fMid is a normalized bisector facing outward.
40    GrVec fMid;
41
42    int countPoints() {
43        GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
44        return fType + 1;
45    }
46    const SkPoint& endPt() const {
47        GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
48        return fPts[fType];
49    };
50    const SkPoint& endNorm() const {
51        GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
52        return fNorms[fType];
53    };
54};
55
56typedef SkTArray<Segment, true> SegmentArray;
57
58static void center_of_mass(const SegmentArray& segments, SkPoint* c) {
59    SkScalar area = 0;
60    SkPoint center = {0, 0};
61    int count = segments.count();
62    SkPoint p0 = {0, 0};
63    if (count > 2) {
64        // We translate the polygon so that the first point is at the origin.
65        // This avoids some precision issues with small area polygons far away
66        // from the origin.
67        p0 = segments[0].endPt();
68        SkPoint pi;
69        SkPoint pj;
70        // the first and last iteration of the below loop would compute
71        // zeros since the starting / ending point is (0,0). So instead we start
72        // at i=1 and make the last iteration i=count-2.
73        pj = segments[1].endPt() - p0;
74        for (int i = 1; i < count - 1; ++i) {
75            pi = pj;
76            const SkPoint pj = segments[i + 1].endPt() - p0;
77
78            SkScalar t = SkScalarMul(pi.fX, pj.fY) - SkScalarMul(pj.fX, pi.fY);
79            area += t;
80            center.fX += (pi.fX + pj.fX) * t;
81            center.fY += (pi.fY + pj.fY) * t;
82
83        }
84    }
85    // If the poly has no area then we instead return the average of
86    // its points.
87    if (SkScalarNearlyZero(area)) {
88        SkPoint avg;
89        avg.set(0, 0);
90        for (int i = 0; i < count; ++i) {
91            const SkPoint& pt = segments[i].endPt();
92            avg.fX += pt.fX;
93            avg.fY += pt.fY;
94        }
95        SkScalar denom = SK_Scalar1 / count;
96        avg.scale(denom);
97        *c = avg;
98    } else {
99        area *= 3;
100        area = SkScalarDiv(SK_Scalar1, area);
101        center.fX = SkScalarMul(center.fX, area);
102        center.fY = SkScalarMul(center.fY, area);
103        // undo the translate of p0 to the origin.
104        *c = center + p0;
105    }
106    SkASSERT(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY));
107}
108
109static void compute_vectors(SegmentArray* segments,
110                            SkPoint* fanPt,
111                            SkPath::Direction dir,
112                            int* vCount,
113                            int* iCount) {
114    center_of_mass(*segments, fanPt);
115    int count = segments->count();
116
117    // Make the normals point towards the outside
118    GrPoint::Side normSide;
119    if (dir == SkPath::kCCW_Direction) {
120        normSide = GrPoint::kRight_Side;
121    } else {
122        normSide = GrPoint::kLeft_Side;
123    }
124
125    *vCount = 0;
126    *iCount = 0;
127    // compute normals at all points
128    for (int a = 0; a < count; ++a) {
129        Segment& sega = (*segments)[a];
130        int b = (a + 1) % count;
131        Segment& segb = (*segments)[b];
132
133        const GrPoint* prevPt = &sega.endPt();
134        int n = segb.countPoints();
135        for (int p = 0; p < n; ++p) {
136            segb.fNorms[p] = segb.fPts[p] - *prevPt;
137            segb.fNorms[p].normalize();
138            segb.fNorms[p].setOrthog(segb.fNorms[p], normSide);
139            prevPt = &segb.fPts[p];
140        }
141        if (Segment::kLine == segb.fType) {
142            *vCount += 5;
143            *iCount += 9;
144        } else {
145            *vCount += 6;
146            *iCount += 12;
147        }
148    }
149
150    // compute mid-vectors where segments meet. TODO: Detect shallow corners
151    // and leave out the wedges and close gaps by stitching segments together.
152    for (int a = 0; a < count; ++a) {
153        const Segment& sega = (*segments)[a];
154        int b = (a + 1) % count;
155        Segment& segb = (*segments)[b];
156        segb.fMid = segb.fNorms[0] + sega.endNorm();
157        segb.fMid.normalize();
158        // corner wedges
159        *vCount += 4;
160        *iCount += 6;
161    }
162}
163
164struct DegenerateTestData {
165    DegenerateTestData() { fStage = kInitial; }
166    bool isDegenerate() const { return kNonDegenerate != fStage; }
167    enum {
168        kInitial,
169        kPoint,
170        kLine,
171        kNonDegenerate
172    }           fStage;
173    GrPoint     fFirstPoint;
174    GrVec       fLineNormal;
175    SkScalar    fLineC;
176};
177
178static const SkScalar kClose = (SK_Scalar1 / 16);
179static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
180
181static void update_degenerate_test(DegenerateTestData* data, const GrPoint& pt) {
182    switch (data->fStage) {
183        case DegenerateTestData::kInitial:
184            data->fFirstPoint = pt;
185            data->fStage = DegenerateTestData::kPoint;
186            break;
187        case DegenerateTestData::kPoint:
188            if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
189                data->fLineNormal = pt - data->fFirstPoint;
190                data->fLineNormal.normalize();
191                data->fLineNormal.setOrthog(data->fLineNormal);
192                data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
193                data->fStage = DegenerateTestData::kLine;
194            }
195            break;
196        case DegenerateTestData::kLine:
197            if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
198                data->fStage = DegenerateTestData::kNonDegenerate;
199            }
200        case DegenerateTestData::kNonDegenerate:
201            break;
202        default:
203            GrCrash("Unexpected degenerate test stage.");
204    }
205}
206
207static inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Direction* dir) {
208    if (!path.cheapComputeDirection(dir)) {
209        return false;
210    }
211    // check whether m reverses the orientation
212    SkASSERT(!m.hasPerspective());
213    SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) -
214                      SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY));
215    if (det2x2 < 0) {
216        *dir = SkPath::OppositeDirection(*dir);
217    }
218    return true;
219}
220
221static inline void add_line_to_segment(const SkPoint& pt,
222                                       SegmentArray* segments,
223                                       SkRect* devBounds) {
224    segments->push_back();
225    segments->back().fType = Segment::kLine;
226    segments->back().fPts[0] = pt;
227    devBounds->growToInclude(pt.fX, pt.fY);
228}
229
230static inline bool contains_inclusive(const SkRect& rect, const SkPoint& p) {
231    return p.fX >= rect.fLeft && p.fX <= rect.fRight && p.fY >= rect.fTop && p.fY <= rect.fBottom;
232}
233static inline void add_quad_segment(const SkPoint pts[3],
234                                    SegmentArray* segments,
235                                    SkRect* devBounds) {
236    if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) {
237        if (pts[0] != pts[2]) {
238            add_line_to_segment(pts[2], segments, devBounds);
239        }
240    } else {
241        segments->push_back();
242        segments->back().fType = Segment::kQuad;
243        segments->back().fPts[0] = pts[1];
244        segments->back().fPts[1] = pts[2];
245        SkASSERT(contains_inclusive(*devBounds, pts[0]));
246        devBounds->growToInclude(pts + 1, 2);
247    }
248}
249
250static inline void add_cubic_segments(const SkPoint pts[4],
251                                      SkPath::Direction dir,
252                                      SegmentArray* segments,
253                                      SkRect* devBounds) {
254    SkSTArray<15, SkPoint, true> quads;
255    GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
256    int count = quads.count();
257    for (int q = 0; q < count; q += 3) {
258        add_quad_segment(&quads[q], segments, devBounds);
259    }
260}
261
262static bool get_segments(const SkPath& path,
263                         const SkMatrix& m,
264                         SegmentArray* segments,
265                         SkPoint* fanPt,
266                         int* vCount,
267                         int* iCount,
268                         SkRect* devBounds) {
269    SkPath::Iter iter(path, true);
270    // This renderer over-emphasizes very thin path regions. We use the distance
271    // to the path from the sample to compute coverage. Every pixel intersected
272    // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
273    // notice that the sample may be close to a very thin area of the path and
274    // thus should be very light. This is particularly egregious for degenerate
275    // line paths. We detect paths that are very close to a line (zero area) and
276    // draw nothing.
277    DegenerateTestData degenerateData;
278    SkPath::Direction dir;
279    // get_direction can fail for some degenerate paths.
280    if (!get_direction(path, m, &dir)) {
281        return false;
282    }
283
284    for (;;) {
285        GrPoint pts[4];
286        SkPath::Verb verb = iter.next(pts);
287        switch (verb) {
288            case SkPath::kMove_Verb:
289                m.mapPoints(pts, 1);
290                update_degenerate_test(&degenerateData, pts[0]);
291                devBounds->set(pts->fX, pts->fY, pts->fX, pts->fY);
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, devBounds);
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, devBounds);
304                break;
305            case SkPath::kCubic_Verb: {
306                m.mapPoints(pts, 4);
307                update_degenerate_test(&degenerateData, pts[1]);
308                update_degenerate_test(&degenerateData, pts[2]);
309                update_degenerate_test(&degenerateData, pts[3]);
310                add_cubic_segments(pts, dir, segments, devBounds);
311                break;
312            };
313            case SkPath::kDone_Verb:
314                if (degenerateData.isDegenerate()) {
315                    return false;
316                } else {
317                    compute_vectors(segments, fanPt, dir, vCount, iCount);
318                    return true;
319                }
320            default:
321                break;
322        }
323    }
324}
325
326struct QuadVertex {
327    GrPoint  fPos;
328    GrPoint  fUV;
329    SkScalar fD0;
330    SkScalar fD1;
331};
332
333struct Draw {
334    Draw() : fVertexCnt(0), fIndexCnt(0) {}
335    int fVertexCnt;
336    int fIndexCnt;
337};
338
339typedef SkTArray<Draw, true> DrawArray;
340
341static void create_vertices(const SegmentArray&  segments,
342                            const SkPoint& fanPt,
343                            DrawArray*     draws,
344                            QuadVertex*    verts,
345                            uint16_t*      idxs) {
346    Draw* draw = &draws->push_back();
347    // alias just to make vert/index assignments easier to read.
348    int* v = &draw->fVertexCnt;
349    int* i = &draw->fIndexCnt;
350
351    int count = segments.count();
352    for (int a = 0; a < count; ++a) {
353        const Segment& sega = segments[a];
354        int b = (a + 1) % count;
355        const Segment& segb = segments[b];
356
357        // Check whether adding the verts for this segment to the current draw would cause index
358        // values to overflow.
359        int vCount = 4;
360        if (Segment::kLine == segb.fType) {
361            vCount += 5;
362        } else {
363            vCount += 6;
364        }
365        if (draw->fVertexCnt + vCount > (1 << 16)) {
366            verts += *v;
367            idxs += *i;
368            draw = &draws->push_back();
369            v = &draw->fVertexCnt;
370            i = &draw->fIndexCnt;
371        }
372
373        // FIXME: These tris are inset in the 1 unit arc around the corner
374        verts[*v + 0].fPos = sega.endPt();
375        verts[*v + 1].fPos = verts[*v + 0].fPos + sega.endNorm();
376        verts[*v + 2].fPos = verts[*v + 0].fPos + segb.fMid;
377        verts[*v + 3].fPos = verts[*v + 0].fPos + segb.fNorms[0];
378        verts[*v + 0].fUV.set(0,0);
379        verts[*v + 1].fUV.set(0,-SK_Scalar1);
380        verts[*v + 2].fUV.set(0,-SK_Scalar1);
381        verts[*v + 3].fUV.set(0,-SK_Scalar1);
382        verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
383        verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
384        verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
385        verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
386
387        idxs[*i + 0] = *v + 0;
388        idxs[*i + 1] = *v + 2;
389        idxs[*i + 2] = *v + 1;
390        idxs[*i + 3] = *v + 0;
391        idxs[*i + 4] = *v + 3;
392        idxs[*i + 5] = *v + 2;
393
394        *v += 4;
395        *i += 6;
396
397        if (Segment::kLine == segb.fType) {
398            verts[*v + 0].fPos = fanPt;
399            verts[*v + 1].fPos = sega.endPt();
400            verts[*v + 2].fPos = segb.fPts[0];
401
402            verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0];
403            verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0];
404
405            // we draw the line edge as a degenerate quad (u is 0, v is the
406            // signed distance to the edge)
407            SkScalar dist = fanPt.distanceToLineBetween(verts[*v + 1].fPos,
408                                                        verts[*v + 2].fPos);
409            verts[*v + 0].fUV.set(0, dist);
410            verts[*v + 1].fUV.set(0, 0);
411            verts[*v + 2].fUV.set(0, 0);
412            verts[*v + 3].fUV.set(0, -SK_Scalar1);
413            verts[*v + 4].fUV.set(0, -SK_Scalar1);
414
415            verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
416            verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
417            verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
418            verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
419            verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1;
420
421            idxs[*i + 0] = *v + 0;
422            idxs[*i + 1] = *v + 2;
423            idxs[*i + 2] = *v + 1;
424
425            idxs[*i + 3] = *v + 3;
426            idxs[*i + 4] = *v + 1;
427            idxs[*i + 5] = *v + 2;
428
429            idxs[*i + 6] = *v + 4;
430            idxs[*i + 7] = *v + 3;
431            idxs[*i + 8] = *v + 2;
432
433            *v += 5;
434            *i += 9;
435        } else {
436            GrPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
437
438            GrVec midVec = segb.fNorms[0] + segb.fNorms[1];
439            midVec.normalize();
440
441            verts[*v + 0].fPos = fanPt;
442            verts[*v + 1].fPos = qpts[0];
443            verts[*v + 2].fPos = qpts[2];
444            verts[*v + 3].fPos = qpts[0] + segb.fNorms[0];
445            verts[*v + 4].fPos = qpts[2] + segb.fNorms[1];
446            verts[*v + 5].fPos = qpts[1] + midVec;
447
448            SkScalar c = segb.fNorms[0].dot(qpts[0]);
449            verts[*v + 0].fD0 =  -segb.fNorms[0].dot(fanPt) + c;
450            verts[*v + 1].fD0 =  0.f;
451            verts[*v + 2].fD0 =  -segb.fNorms[0].dot(qpts[2]) + c;
452            verts[*v + 3].fD0 = -SK_ScalarMax/100;
453            verts[*v + 4].fD0 = -SK_ScalarMax/100;
454            verts[*v + 5].fD0 = -SK_ScalarMax/100;
455
456            c = segb.fNorms[1].dot(qpts[2]);
457            verts[*v + 0].fD1 =  -segb.fNorms[1].dot(fanPt) + c;
458            verts[*v + 1].fD1 =  -segb.fNorms[1].dot(qpts[0]) + c;
459            verts[*v + 2].fD1 =  0.f;
460            verts[*v + 3].fD1 = -SK_ScalarMax/100;
461            verts[*v + 4].fD1 = -SK_ScalarMax/100;
462            verts[*v + 5].fD1 = -SK_ScalarMax/100;
463
464            GrPathUtils::QuadUVMatrix toUV(qpts);
465            toUV.apply<6, sizeof(QuadVertex), sizeof(GrPoint)>(verts + *v);
466
467            idxs[*i + 0] = *v + 3;
468            idxs[*i + 1] = *v + 1;
469            idxs[*i + 2] = *v + 2;
470            idxs[*i + 3] = *v + 4;
471            idxs[*i + 4] = *v + 3;
472            idxs[*i + 5] = *v + 2;
473
474            idxs[*i + 6] = *v + 5;
475            idxs[*i + 7] = *v + 3;
476            idxs[*i + 8] = *v + 4;
477
478            idxs[*i +  9] = *v + 0;
479            idxs[*i + 10] = *v + 2;
480            idxs[*i + 11] = *v + 1;
481
482            *v += 6;
483            *i += 12;
484        }
485    }
486}
487
488///////////////////////////////////////////////////////////////////////////////
489
490/*
491 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
492 * two components of the vertex attribute. Coverage is based on signed
493 * distance with negative being inside, positive outside. The edge is specified in
494 * window space (y-down). If either the third or fourth component of the interpolated
495 * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
496 * attempt to trim to a portion of the infinite quad.
497 * Requires shader derivative instruction support.
498 */
499
500class QuadEdgeEffect : public GrEffect {
501public:
502
503    static GrEffectRef* Create() {
504        GR_CREATE_STATIC_EFFECT(gQuadEdgeEffect, QuadEdgeEffect, ());
505        gQuadEdgeEffect->ref();
506        return gQuadEdgeEffect;
507    }
508
509    virtual ~QuadEdgeEffect() {}
510
511    static const char* Name() { return "QuadEdge"; }
512
513    virtual void getConstantColorComponents(GrColor* color,
514                                            uint32_t* validFlags) const SK_OVERRIDE {
515        *validFlags = 0;
516    }
517
518    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
519        return GrTBackendEffectFactory<QuadEdgeEffect>::getInstance();
520    }
521
522    class GLEffect : public GrGLEffect {
523    public:
524        GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
525            : INHERITED (factory) {}
526
527        virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
528
529        virtual void emitCode(GrGLShaderBuilder* builder,
530                              const GrDrawEffect& drawEffect,
531                              EffectKey key,
532                              const char* outputColor,
533                              const char* inputColor,
534                              const TextureSamplerArray& samplers) SK_OVERRIDE {
535            GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
536            SkASSERT(NULL != vertexBuilder);
537
538            const char *vsName, *fsName;
539            const SkString* attrName =
540                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
541            builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
542
543            SkAssertResult(builder->enableFeature(
544                                              GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
545            vertexBuilder->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
546
547            // keep the derivative instructions outside the conditional
548            builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
549            builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
550            builder->fsCodeAppendf("\t\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
551            // today we know z and w are in device space. We could use derivatives
552            builder->fsCodeAppendf("\t\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
553                                    fsName);
554            builder->fsCodeAppendf ("\t\t} else {\n");
555            builder->fsCodeAppendf("\t\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
556                                   "\t\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
557                                   fsName, fsName);
558            builder->fsCodeAppendf("\t\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
559                                    fsName);
560            builder->fsCodeAppendf("\t\t\tedgeAlpha = "
561                                   "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n\t\t}\n");
562
563            SkString modulate;
564            GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
565            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
566
567            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
568        }
569
570        static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
571            return 0x0;
572        }
573
574        virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
575
576    private:
577        typedef GrGLEffect INHERITED;
578    };
579
580private:
581    QuadEdgeEffect() {
582        this->addVertexAttrib(kVec4f_GrSLType);
583    }
584
585    virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
586        return true;
587    }
588
589    GR_DECLARE_EFFECT_TEST;
590
591    typedef GrEffect INHERITED;
592};
593
594GR_DEFINE_EFFECT_TEST(QuadEdgeEffect);
595
596GrEffectRef* QuadEdgeEffect::TestCreate(SkMWCRandom* random,
597                                        GrContext*,
598                                        const GrDrawTargetCaps& caps,
599                                        GrTexture*[]) {
600    // Doesn't work without derivative instructions.
601    return caps.shaderDerivativeSupport() ? QuadEdgeEffect::Create() : NULL;
602}
603
604///////////////////////////////////////////////////////////////////////////////
605
606bool GrAAConvexPathRenderer::canDrawPath(const SkPath& path,
607                                         const SkStrokeRec& stroke,
608                                         const GrDrawTarget* target,
609                                         bool antiAlias) const {
610    return (target->caps()->shaderDerivativeSupport() && antiAlias &&
611            stroke.isFillStyle() && !path.isInverseFillType() && path.isConvex());
612}
613
614namespace {
615
616// position + edge
617extern const GrVertexAttrib gPathAttribs[] = {
618    {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
619    {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
620};
621
622};
623
624bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
625                                        const SkStrokeRec&,
626                                        GrDrawTarget* target,
627                                        bool antiAlias) {
628
629    const SkPath* path = &origPath;
630    if (path->isEmpty()) {
631        return true;
632    }
633
634    SkMatrix viewMatrix = target->getDrawState().getViewMatrix();
635    GrDrawTarget::AutoStateRestore asr;
636    if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
637        return false;
638    }
639    GrDrawState* drawState = target->drawState();
640
641    // We use the fact that SkPath::transform path does subdivision based on
642    // perspective. Otherwise, we apply the view matrix when copying to the
643    // segment representation.
644    SkPath tmpPath;
645    if (viewMatrix.hasPerspective()) {
646        origPath.transform(viewMatrix, &tmpPath);
647        path = &tmpPath;
648        viewMatrix = SkMatrix::I();
649    }
650
651    QuadVertex *verts;
652    uint16_t* idxs;
653
654    int vCount;
655    int iCount;
656    enum {
657        kPreallocSegmentCnt = 512 / sizeof(Segment),
658        kPreallocDrawCnt = 4,
659    };
660    SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
661    SkPoint fanPt;
662
663    // We can't simply use the path bounds because we may degenerate cubics to quads which produces
664    // new control points outside the original convex hull.
665    SkRect devBounds;
666    if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount, &devBounds)) {
667        return false;
668    }
669
670    // Our computed verts should all be within one pixel of the segment control points.
671    devBounds.outset(SK_Scalar1, SK_Scalar1);
672
673    drawState->setVertexAttribs<gPathAttribs>(SK_ARRAY_COUNT(gPathAttribs));
674
675    static const int kEdgeAttrIndex = 1;
676    GrEffectRef* quadEffect = QuadEdgeEffect::Create();
677    drawState->addCoverageEffect(quadEffect, kEdgeAttrIndex)->unref();
678
679    GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount);
680    if (!arg.succeeded()) {
681        return false;
682    }
683    SkASSERT(sizeof(QuadVertex) == drawState->getVertexSize());
684    verts = reinterpret_cast<QuadVertex*>(arg.vertices());
685    idxs = reinterpret_cast<uint16_t*>(arg.indices());
686
687    SkSTArray<kPreallocDrawCnt, Draw, true> draws;
688    create_vertices(segments, fanPt, &draws, verts, idxs);
689
690    // Check devBounds
691#ifdef SK_DEBUG
692    SkRect tolDevBounds = devBounds;
693    tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
694    SkRect actualBounds;
695    actualBounds.set(verts[0].fPos, verts[1].fPos);
696    for (int i = 2; i < vCount; ++i) {
697        actualBounds.growToInclude(verts[i].fPos.fX, verts[i].fPos.fY);
698    }
699    SkASSERT(tolDevBounds.contains(actualBounds));
700#endif
701
702    int vOffset = 0;
703    for (int i = 0; i < draws.count(); ++i) {
704        const Draw& draw = draws[i];
705        target->drawIndexed(kTriangles_GrPrimitiveType,
706                            vOffset,  // start vertex
707                            0,        // start index
708                            draw.fVertexCnt,
709                            draw.fIndexCnt,
710                            &devBounds);
711        vOffset += draw.fVertexCnt;
712    }
713
714    return true;
715}
716