Home | History | Annotate | Download | only in batches
      1 /*
      2  * Copyright 2011 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 "GrDefaultPathRenderer.h"
      9 
     10 #include "GrBatchFlushState.h"
     11 #include "GrBatchTest.h"
     12 #include "GrContext.h"
     13 #include "GrDefaultGeoProcFactory.h"
     14 #include "GrPathUtils.h"
     15 #include "GrPipelineBuilder.h"
     16 #include "GrVertices.h"
     17 #include "SkGeometry.h"
     18 #include "SkString.h"
     19 #include "SkStrokeRec.h"
     20 #include "SkTLazy.h"
     21 #include "SkTraceEvent.h"
     22 
     23 #include "batches/GrRectBatchFactory.h"
     24 #include "batches/GrVertexBatch.h"
     25 
     26 GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
     27                                              bool stencilWrapOpsSupport)
     28     : fSeparateStencil(separateStencilSupport)
     29     , fStencilWrapOps(stencilWrapOpsSupport) {
     30 }
     31 
     32 
     33 ////////////////////////////////////////////////////////////////////////////////
     34 // Stencil rules for paths
     35 
     36 ////// Even/Odd
     37 
     38 GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
     39     kInvert_StencilOp,
     40     kKeep_StencilOp,
     41     kAlwaysIfInClip_StencilFunc,
     42     0xffff,
     43     0xffff,
     44     0xffff);
     45 
     46 // ok not to check clip b/c stencil pass only wrote inside clip
     47 GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
     48     kZero_StencilOp,
     49     kZero_StencilOp,
     50     kNotEqual_StencilFunc,
     51     0xffff,
     52     0x0000,
     53     0xffff);
     54 
     55 // have to check clip b/c outside clip will always be zero.
     56 GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
     57     kZero_StencilOp,
     58     kZero_StencilOp,
     59     kEqualIfInClip_StencilFunc,
     60     0xffff,
     61     0x0000,
     62     0xffff);
     63 
     64 ////// Winding
     65 
     66 // when we have separate stencil we increment front faces / decrement back faces
     67 // when we don't have wrap incr and decr we use the stencil test to simulate
     68 // them.
     69 
     70 GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
     71     kIncWrap_StencilOp,             kDecWrap_StencilOp,
     72     kKeep_StencilOp,                kKeep_StencilOp,
     73     kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
     74     0xffff,                         0xffff,
     75     0xffff,                         0xffff,
     76     0xffff,                         0xffff);
     77 
     78 // if inc'ing the max value, invert to make 0
     79 // if dec'ing zero invert to make all ones.
     80 // we can't avoid touching the stencil on both passing and
     81 // failing, so we can't resctrict ourselves to the clip.
     82 GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
     83     kInvert_StencilOp,              kInvert_StencilOp,
     84     kIncClamp_StencilOp,            kDecClamp_StencilOp,
     85     kEqual_StencilFunc,             kEqual_StencilFunc,
     86     0xffff,                         0xffff,
     87     0xffff,                         0x0000,
     88     0xffff,                         0xffff);
     89 
     90 // When there are no separate faces we do two passes to setup the winding rule
     91 // stencil. First we draw the front faces and inc, then we draw the back faces
     92 // and dec. These are same as the above two split into the incrementing and
     93 // decrementing passes.
     94 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
     95     kIncWrap_StencilOp,
     96     kKeep_StencilOp,
     97     kAlwaysIfInClip_StencilFunc,
     98     0xffff,
     99     0xffff,
    100     0xffff);
    101 
    102 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
    103     kDecWrap_StencilOp,
    104     kKeep_StencilOp,
    105     kAlwaysIfInClip_StencilFunc,
    106     0xffff,
    107     0xffff,
    108     0xffff);
    109 
    110 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
    111     kInvert_StencilOp,
    112     kIncClamp_StencilOp,
    113     kEqual_StencilFunc,
    114     0xffff,
    115     0xffff,
    116     0xffff);
    117 
    118 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
    119     kInvert_StencilOp,
    120     kDecClamp_StencilOp,
    121     kEqual_StencilFunc,
    122     0xffff,
    123     0x0000,
    124     0xffff);
    125 
    126 // Color passes are the same whether we use the two-sided stencil or two passes
    127 
    128 GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
    129     kZero_StencilOp,
    130     kZero_StencilOp,
    131     kNonZeroIfInClip_StencilFunc,
    132     0xffff,
    133     0x0000,
    134     0xffff);
    135 
    136 GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
    137     kZero_StencilOp,
    138     kZero_StencilOp,
    139     kEqualIfInClip_StencilFunc,
    140     0xffff,
    141     0x0000,
    142     0xffff);
    143 
    144 ////// Normal render to stencil
    145 
    146 // Sometimes the default path renderer can draw a path directly to the stencil
    147 // buffer without having to first resolve the interior / exterior.
    148 GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
    149     kZero_StencilOp,
    150     kIncClamp_StencilOp,
    151     kAlwaysIfInClip_StencilFunc,
    152     0xffff,
    153     0x0000,
    154     0xffff);
    155 
    156 ////////////////////////////////////////////////////////////////////////////////
    157 // Helpers for drawPath
    158 
    159 #define STENCIL_OFF     0   // Always disable stencil (even when needed)
    160 
    161 static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
    162 #if STENCIL_OFF
    163     return true;
    164 #else
    165     if (!stroke.isHairlineStyle() && !path.isInverseFillType()) {
    166         return path.isConvex();
    167     }
    168     return false;
    169 #endif
    170 }
    171 
    172 GrPathRenderer::StencilSupport
    173 GrDefaultPathRenderer::onGetStencilSupport(const SkPath& path, const GrStrokeInfo& stroke) const {
    174     if (single_pass_path(path, stroke)) {
    175         return GrPathRenderer::kNoRestriction_StencilSupport;
    176     } else {
    177         return GrPathRenderer::kStencilOnly_StencilSupport;
    178     }
    179 }
    180 
    181 static inline void append_countour_edge_indices(bool hairLine,
    182                                                 uint16_t fanCenterIdx,
    183                                                 uint16_t edgeV0Idx,
    184                                                 uint16_t** indices) {
    185     // when drawing lines we're appending line segments along
    186     // the contour. When applying the other fill rules we're
    187     // drawing triangle fans around fanCenterIdx.
    188     if (!hairLine) {
    189         *((*indices)++) = fanCenterIdx;
    190     }
    191     *((*indices)++) = edgeV0Idx;
    192     *((*indices)++) = edgeV0Idx + 1;
    193 }
    194 
    195 static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint pts[],
    196                             SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed,
    197                             bool isHairline, uint16_t subpathIdxStart, int offset, uint16_t** idx) {
    198     // first pt of quad is the pt we ended on in previous step
    199     uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1 + offset;
    200     uint16_t numPts =  (uint16_t)
    201         GrPathUtils::generateQuadraticPoints(
    202             pts[0], pts[1], pts[2],
    203             srcSpaceTolSqd, vert,
    204             GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
    205     if (indexed) {
    206         for (uint16_t i = 0; i < numPts; ++i) {
    207             append_countour_edge_indices(isHairline, subpathIdxStart,
    208                                          firstQPtIdx + i, idx);
    209         }
    210     }
    211 }
    212 
    213 class DefaultPathBatch : public GrVertexBatch {
    214 public:
    215     DEFINE_BATCH_CLASS_ID
    216 
    217     struct Geometry {
    218         GrColor fColor;
    219         SkPath fPath;
    220         SkScalar fTolerance;
    221     };
    222 
    223     static GrDrawBatch* Create(const Geometry& geometry, uint8_t coverage,
    224                                const SkMatrix& viewMatrix, bool isHairline,
    225                                const SkRect& devBounds) {
    226         return new DefaultPathBatch(geometry, coverage, viewMatrix, isHairline, devBounds);
    227     }
    228 
    229     const char* name() const override { return "DefaultPathBatch"; }
    230 
    231     void computePipelineOptimizations(GrInitInvariantOutput* color,
    232                                       GrInitInvariantOutput* coverage,
    233                                       GrBatchToXPOverrides* overrides) const override {
    234         // When this is called on a batch, there is only one geometry bundle
    235         color->setKnownFourComponents(fGeoData[0].fColor);
    236         coverage->setKnownSingleComponent(this->coverage());
    237     }
    238 
    239 private:
    240     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
    241         // Handle any color overrides
    242         if (!overrides.readsColor()) {
    243             fGeoData[0].fColor = GrColor_ILLEGAL;
    244         }
    245         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
    246 
    247         // setup batch properties
    248         fBatch.fColorIgnored = !overrides.readsColor();
    249         fBatch.fColor = fGeoData[0].fColor;
    250         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
    251         fBatch.fCoverageIgnored = !overrides.readsCoverage();
    252     }
    253 
    254     void onPrepareDraws(Target* target) const override {
    255         SkAutoTUnref<const GrGeometryProcessor> gp;
    256         {
    257             using namespace GrDefaultGeoProcFactory;
    258             Color color(this->color());
    259             Coverage coverage(this->coverage());
    260             if (this->coverageIgnored()) {
    261                 coverage.fType = Coverage::kNone_Type;
    262             }
    263             LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type :
    264                                                               LocalCoords::kUnused_Type);
    265             gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords,
    266                                                      this->viewMatrix()));
    267         }
    268 
    269         size_t vertexStride = gp->getVertexStride();
    270         SkASSERT(vertexStride == sizeof(SkPoint));
    271 
    272         target->initDraw(gp, this->pipeline());
    273 
    274         int instanceCount = fGeoData.count();
    275 
    276         // compute number of vertices
    277         int maxVertices = 0;
    278 
    279         // We will use index buffers if we have multiple paths or one path with multiple contours
    280         bool isIndexed = instanceCount > 1;
    281         for (int i = 0; i < instanceCount; i++) {
    282             const Geometry& args = fGeoData[i];
    283 
    284             int contourCount;
    285             maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount,
    286                                                             args.fTolerance);
    287 
    288             isIndexed = isIndexed || contourCount > 1;
    289         }
    290 
    291         if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) {
    292             //SkDebugf("Cannot render path (%d)\n", maxVertices);
    293             return;
    294         }
    295 
    296         // determine primitiveType
    297         int maxIndices = 0;
    298         GrPrimitiveType primitiveType;
    299         if (this->isHairline()) {
    300             if (isIndexed) {
    301                 maxIndices = 2 * maxVertices;
    302                 primitiveType = kLines_GrPrimitiveType;
    303             } else {
    304                 primitiveType = kLineStrip_GrPrimitiveType;
    305             }
    306         } else {
    307             if (isIndexed) {
    308                 maxIndices = 3 * maxVertices;
    309                 primitiveType = kTriangles_GrPrimitiveType;
    310             } else {
    311                 primitiveType = kTriangleFan_GrPrimitiveType;
    312             }
    313         }
    314 
    315         // allocate vertex / index buffers
    316         const GrVertexBuffer* vertexBuffer;
    317         int firstVertex;
    318 
    319         void* verts = target->makeVertexSpace(vertexStride, maxVertices,
    320                                               &vertexBuffer, &firstVertex);
    321 
    322         if (!verts) {
    323             SkDebugf("Could not allocate vertices\n");
    324             return;
    325         }
    326 
    327         const GrIndexBuffer* indexBuffer = nullptr;
    328         int firstIndex = 0;
    329 
    330         void* indices = nullptr;
    331         if (isIndexed) {
    332             indices = target->makeIndexSpace(maxIndices, &indexBuffer, &firstIndex);
    333 
    334             if (!indices) {
    335                 SkDebugf("Could not allocate indices\n");
    336                 return;
    337             }
    338         }
    339 
    340         // fill buffers
    341         int vertexOffset = 0;
    342         int indexOffset = 0;
    343         for (int i = 0; i < instanceCount; i++) {
    344             const Geometry& args = fGeoData[i];
    345 
    346             int vertexCnt = 0;
    347             int indexCnt = 0;
    348             if (!this->createGeom(verts,
    349                                   vertexOffset,
    350                                   indices,
    351                                   indexOffset,
    352                                   &vertexCnt,
    353                                   &indexCnt,
    354                                   args.fPath,
    355                                   args.fTolerance,
    356                                   isIndexed)) {
    357                 return;
    358             }
    359 
    360             vertexOffset += vertexCnt;
    361             indexOffset += indexCnt;
    362             SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices);
    363         }
    364 
    365         GrVertices vertices;
    366         if (isIndexed) {
    367             vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex,
    368                                  vertexOffset, indexOffset);
    369         } else {
    370             vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset);
    371         }
    372         target->draw(vertices);
    373 
    374         // put back reserves
    375         target->putBackIndices((size_t)(maxIndices - indexOffset));
    376         target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride);
    377     }
    378 
    379     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
    380 
    381     DefaultPathBatch(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix,
    382                      bool isHairline, const SkRect& devBounds)
    383         : INHERITED(ClassID()) {
    384         fBatch.fCoverage = coverage;
    385         fBatch.fIsHairline = isHairline;
    386         fBatch.fViewMatrix = viewMatrix;
    387         fGeoData.push_back(geometry);
    388 
    389         this->setBounds(devBounds);
    390 
    391         // This is b.c. hairlines are notionally infinitely thin so without expansion
    392         // two overlapping lines could be reordered even though they hit the same pixels.
    393         if (isHairline) {
    394             fBounds.outset(0.5f, 0.5f);
    395         }
    396     }
    397 
    398     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
    399         DefaultPathBatch* that = t->cast<DefaultPathBatch>();
    400         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
    401                                      that->bounds(), caps)) {
    402             return false;
    403         }
    404 
    405         if (this->color() != that->color()) {
    406             return false;
    407         }
    408 
    409         if (this->coverage() != that->coverage()) {
    410             return false;
    411         }
    412 
    413         if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
    414             return false;
    415         }
    416 
    417         if (this->isHairline() != that->isHairline()) {
    418             return false;
    419         }
    420 
    421         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
    422         this->joinBounds(that->bounds());
    423         return true;
    424     }
    425 
    426     bool createGeom(void* vertices,
    427                     size_t vertexOffset,
    428                     void* indices,
    429                     size_t indexOffset,
    430                     int* vertexCnt,
    431                     int* indexCnt,
    432                     const SkPath& path,
    433                     SkScalar srcSpaceTol,
    434                     bool isIndexed) const {
    435         {
    436             SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
    437 
    438             uint16_t indexOffsetU16 = (uint16_t)indexOffset;
    439             uint16_t vertexOffsetU16 = (uint16_t)vertexOffset;
    440 
    441             uint16_t* idxBase = reinterpret_cast<uint16_t*>(indices) + indexOffsetU16;
    442             uint16_t* idx = idxBase;
    443             uint16_t subpathIdxStart = vertexOffsetU16;
    444 
    445             SkPoint* base = reinterpret_cast<SkPoint*>(vertices) + vertexOffset;
    446             SkPoint* vert = base;
    447 
    448             SkPoint pts[4];
    449 
    450             bool first = true;
    451             int subpath = 0;
    452 
    453             SkPath::Iter iter(path, false);
    454 
    455             bool done = false;
    456             while (!done) {
    457                 SkPath::Verb verb = iter.next(pts);
    458                 switch (verb) {
    459                     case SkPath::kMove_Verb:
    460                         if (!first) {
    461                             uint16_t currIdx = (uint16_t) (vert - base) + vertexOffsetU16;
    462                             subpathIdxStart = currIdx;
    463                             ++subpath;
    464                         }
    465                         *vert = pts[0];
    466                         vert++;
    467                         break;
    468                     case SkPath::kLine_Verb:
    469                         if (isIndexed) {
    470                             uint16_t prevIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
    471                             append_countour_edge_indices(this->isHairline(), subpathIdxStart,
    472                                                          prevIdx, &idx);
    473                         }
    474                         *(vert++) = pts[1];
    475                         break;
    476                     case SkPath::kConic_Verb: {
    477                         SkScalar weight = iter.conicWeight();
    478                         SkAutoConicToQuads converter;
    479                         // Converting in src-space, hance the finer tolerance (0.25)
    480                         // TODO: find a way to do this in dev-space so the tolerance means something
    481                         const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
    482                         for (int i = 0; i < converter.countQuads(); ++i) {
    483                             add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol,
    484                                      isIndexed, this->isHairline(), subpathIdxStart,
    485                                      (int)vertexOffset, &idx);
    486                         }
    487                         break;
    488                     }
    489                     case SkPath::kQuad_Verb:
    490                         add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, isIndexed,
    491                                  this->isHairline(), subpathIdxStart, (int)vertexOffset, &idx);
    492                         break;
    493                     case SkPath::kCubic_Verb: {
    494                         // first pt of cubic is the pt we ended on in previous step
    495                         uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
    496                         uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
    497                                         pts[0], pts[1], pts[2], pts[3],
    498                                         srcSpaceTolSqd, &vert,
    499                                         GrPathUtils::cubicPointCount(pts, srcSpaceTol));
    500                         if (isIndexed) {
    501                             for (uint16_t i = 0; i < numPts; ++i) {
    502                                 append_countour_edge_indices(this->isHairline(), subpathIdxStart,
    503                                                              firstCPtIdx + i, &idx);
    504                             }
    505                         }
    506                         break;
    507                     }
    508                     case SkPath::kClose_Verb:
    509                         break;
    510                     case SkPath::kDone_Verb:
    511                         done = true;
    512                 }
    513                 first = false;
    514             }
    515 
    516             *vertexCnt = static_cast<int>(vert - base);
    517             *indexCnt = static_cast<int>(idx - idxBase);
    518 
    519         }
    520         return true;
    521     }
    522 
    523     GrColor color() const { return fBatch.fColor; }
    524     uint8_t coverage() const { return fBatch.fCoverage; }
    525     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
    526     const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
    527     bool isHairline() const { return fBatch.fIsHairline; }
    528     bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
    529 
    530     struct BatchTracker {
    531         GrColor fColor;
    532         uint8_t fCoverage;
    533         SkMatrix fViewMatrix;
    534         bool fUsesLocalCoords;
    535         bool fColorIgnored;
    536         bool fCoverageIgnored;
    537         bool fIsHairline;
    538     };
    539 
    540     BatchTracker fBatch;
    541     SkSTArray<1, Geometry, true> fGeoData;
    542 
    543     typedef GrVertexBatch INHERITED;
    544 };
    545 
    546 bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
    547                                              GrPipelineBuilder* pipelineBuilder,
    548                                              GrColor color,
    549                                              const SkMatrix& viewMatrix,
    550                                              const SkPath& path,
    551                                              const GrStrokeInfo& origStroke,
    552                                              bool stencilOnly) {
    553     SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
    554 
    555     SkScalar hairlineCoverage;
    556     uint8_t newCoverage = 0xff;
    557     if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) {
    558         newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
    559 
    560         if (!stroke->isHairlineStyle()) {
    561             stroke.writable()->setHairlineStyle();
    562         }
    563     }
    564 
    565     const bool isHairline = stroke->isHairlineStyle();
    566 
    567     // Save the current xp on the draw state so we can reset it if needed
    568     const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
    569     SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
    570     // face culling doesn't make sense here
    571     SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
    572 
    573     int                         passCount = 0;
    574     const GrStencilSettings*    passes[3];
    575     GrPipelineBuilder::DrawFace drawFace[3];
    576     bool                        reverse = false;
    577     bool                        lastPassIsBounds;
    578 
    579     if (isHairline) {
    580         passCount = 1;
    581         if (stencilOnly) {
    582             passes[0] = &gDirectToStencil;
    583         } else {
    584             passes[0] = nullptr;
    585         }
    586         lastPassIsBounds = false;
    587         drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
    588     } else {
    589         if (single_pass_path(path, *stroke)) {
    590             passCount = 1;
    591             if (stencilOnly) {
    592                 passes[0] = &gDirectToStencil;
    593             } else {
    594                 passes[0] = nullptr;
    595             }
    596             drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
    597             lastPassIsBounds = false;
    598         } else {
    599             switch (path.getFillType()) {
    600                 case SkPath::kInverseEvenOdd_FillType:
    601                     reverse = true;
    602                     // fallthrough
    603                 case SkPath::kEvenOdd_FillType:
    604                     passes[0] = &gEOStencilPass;
    605                     if (stencilOnly) {
    606                         passCount = 1;
    607                         lastPassIsBounds = false;
    608                     } else {
    609                         passCount = 2;
    610                         lastPassIsBounds = true;
    611                         if (reverse) {
    612                             passes[1] = &gInvEOColorPass;
    613                         } else {
    614                             passes[1] = &gEOColorPass;
    615                         }
    616                     }
    617                     drawFace[0] = drawFace[1] = GrPipelineBuilder::kBoth_DrawFace;
    618                     break;
    619 
    620                 case SkPath::kInverseWinding_FillType:
    621                     reverse = true;
    622                     // fallthrough
    623                 case SkPath::kWinding_FillType:
    624                     if (fSeparateStencil) {
    625                         if (fStencilWrapOps) {
    626                             passes[0] = &gWindStencilSeparateWithWrap;
    627                         } else {
    628                             passes[0] = &gWindStencilSeparateNoWrap;
    629                         }
    630                         passCount = 2;
    631                         drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
    632                     } else {
    633                         if (fStencilWrapOps) {
    634                             passes[0] = &gWindSingleStencilWithWrapInc;
    635                             passes[1] = &gWindSingleStencilWithWrapDec;
    636                         } else {
    637                             passes[0] = &gWindSingleStencilNoWrapInc;
    638                             passes[1] = &gWindSingleStencilNoWrapDec;
    639                         }
    640                         // which is cw and which is ccw is arbitrary.
    641                         drawFace[0] = GrPipelineBuilder::kCW_DrawFace;
    642                         drawFace[1] = GrPipelineBuilder::kCCW_DrawFace;
    643                         passCount = 3;
    644                     }
    645                     if (stencilOnly) {
    646                         lastPassIsBounds = false;
    647                         --passCount;
    648                     } else {
    649                         lastPassIsBounds = true;
    650                         drawFace[passCount-1] = GrPipelineBuilder::kBoth_DrawFace;
    651                         if (reverse) {
    652                             passes[passCount-1] = &gInvWindColorPass;
    653                         } else {
    654                             passes[passCount-1] = &gWindColorPass;
    655                         }
    656                     }
    657                     break;
    658                 default:
    659                     SkDEBUGFAIL("Unknown path fFill!");
    660                     return false;
    661             }
    662         }
    663     }
    664 
    665     SkScalar tol = GrPathUtils::kDefaultTolerance;
    666     SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
    667 
    668     SkRect devBounds;
    669     GetPathDevBounds(path, pipelineBuilder->getRenderTarget(), viewMatrix, &devBounds);
    670 
    671     for (int p = 0; p < passCount; ++p) {
    672         pipelineBuilder->setDrawFace(drawFace[p]);
    673         if (passes[p]) {
    674             *pipelineBuilder->stencil() = *passes[p];
    675         }
    676 
    677         if (lastPassIsBounds && (p == passCount-1)) {
    678             // Reset the XP Factory on pipelineBuilder
    679             pipelineBuilder->setXPFactory(backupXPFactory);
    680             SkRect bounds;
    681             SkMatrix localMatrix = SkMatrix::I();
    682             if (reverse) {
    683                 SkASSERT(pipelineBuilder->getRenderTarget());
    684                 // draw over the dev bounds (which will be the whole dst surface for inv fill).
    685                 bounds = devBounds;
    686                 SkMatrix vmi;
    687                 // mapRect through persp matrix may not be correct
    688                 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
    689                     vmi.mapRect(&bounds);
    690                 } else {
    691                     if (!viewMatrix.invert(&localMatrix)) {
    692                         return false;
    693                     }
    694                 }
    695             } else {
    696                 bounds = path.getBounds();
    697             }
    698             const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
    699                                                                                viewMatrix;
    700             SkAutoTUnref<GrDrawBatch> batch(
    701                     GrRectBatchFactory::CreateNonAAFill(color, viewM, bounds, nullptr,
    702                                                         &localMatrix));
    703             target->drawBatch(*pipelineBuilder, batch);
    704         } else {
    705             if (passCount > 1) {
    706                 pipelineBuilder->setDisableColorXPFactory();
    707             }
    708 
    709             DefaultPathBatch::Geometry geometry;
    710             geometry.fColor = color;
    711             geometry.fPath = path;
    712             geometry.fTolerance = srcSpaceTol;
    713 
    714             SkAutoTUnref<GrDrawBatch> batch(DefaultPathBatch::Create(geometry, newCoverage,
    715                                                                      viewMatrix, isHairline,
    716                                                                      devBounds));
    717 
    718             target->drawBatch(*pipelineBuilder, batch);
    719         }
    720     }
    721     return true;
    722 }
    723 
    724 bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
    725     // this class can draw any path with any fill but doesn't do any anti-aliasing.
    726     return !args.fAntiAlias && (args.fStroke->isFillStyle() ||
    727                                 IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix,
    728                                                              nullptr));
    729 }
    730 
    731 bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
    732     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrDefaultPathRenderer::onDrawPath");
    733     return this->internalDrawPath(args.fTarget,
    734                                   args.fPipelineBuilder,
    735                                   args.fColor,
    736                                   *args.fViewMatrix,
    737                                   *args.fPath,
    738                                   *args.fStroke,
    739                                   false);
    740 }
    741 
    742 void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
    743     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),"GrDefaultPathRenderer::onStencilPath");
    744     SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
    745     SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
    746     this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
    747                            *args.fPath, *args.fStroke, true);
    748 }
    749 
    750 ///////////////////////////////////////////////////////////////////////////////////////////////////
    751 
    752 #ifdef GR_TEST_UTILS
    753 
    754 DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) {
    755     GrColor color = GrRandomColor(random);
    756     SkMatrix viewMatrix = GrTest::TestMatrix(random);
    757 
    758     // For now just hairlines because the other types of draws require two batches.
    759     // TODO we should figure out a way to combine the stencil and cover steps into one batch
    760     GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
    761     SkPath path = GrTest::TestPath(random);
    762 
    763     // Compute srcSpaceTol
    764     SkRect bounds = path.getBounds();
    765     SkScalar tol = GrPathUtils::kDefaultTolerance;
    766     SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
    767 
    768     DefaultPathBatch::Geometry geometry;
    769     geometry.fColor = color;
    770     geometry.fPath = path;
    771     geometry.fTolerance = srcSpaceTol;
    772 
    773     viewMatrix.mapRect(&bounds);
    774     uint8_t coverage = GrRandomCoverage(random);
    775     return DefaultPathBatch::Create(geometry, coverage, viewMatrix, true, bounds);
    776 }
    777 
    778 #endif
    779