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