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