Home | History | Annotate | Download | only in gpu
      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 "GrContext.h"
     11 #include "GrDrawState.h"
     12 #include "GrPathUtils.h"
     13 #include "SkString.h"
     14 #include "SkStrokeRec.h"
     15 #include "SkTLazy.h"
     16 #include "SkTraceEvent.h"
     17 
     18 
     19 GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
     20                                              bool stencilWrapOpsSupport)
     21     : fSeparateStencil(separateStencilSupport)
     22     , fStencilWrapOps(stencilWrapOpsSupport) {
     23 }
     24 
     25 
     26 ////////////////////////////////////////////////////////////////////////////////
     27 // Stencil rules for paths
     28 
     29 ////// Even/Odd
     30 
     31 GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
     32     kInvert_StencilOp,
     33     kKeep_StencilOp,
     34     kAlwaysIfInClip_StencilFunc,
     35     0xffff,
     36     0xffff,
     37     0xffff);
     38 
     39 // ok not to check clip b/c stencil pass only wrote inside clip
     40 GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
     41     kZero_StencilOp,
     42     kZero_StencilOp,
     43     kNotEqual_StencilFunc,
     44     0xffff,
     45     0x0000,
     46     0xffff);
     47 
     48 // have to check clip b/c outside clip will always be zero.
     49 GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
     50     kZero_StencilOp,
     51     kZero_StencilOp,
     52     kEqualIfInClip_StencilFunc,
     53     0xffff,
     54     0x0000,
     55     0xffff);
     56 
     57 ////// Winding
     58 
     59 // when we have separate stencil we increment front faces / decrement back faces
     60 // when we don't have wrap incr and decr we use the stencil test to simulate
     61 // them.
     62 
     63 GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
     64     kIncWrap_StencilOp,             kDecWrap_StencilOp,
     65     kKeep_StencilOp,                kKeep_StencilOp,
     66     kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
     67     0xffff,                         0xffff,
     68     0xffff,                         0xffff,
     69     0xffff,                         0xffff);
     70 
     71 // if inc'ing the max value, invert to make 0
     72 // if dec'ing zero invert to make all ones.
     73 // we can't avoid touching the stencil on both passing and
     74 // failing, so we can't resctrict ourselves to the clip.
     75 GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
     76     kInvert_StencilOp,              kInvert_StencilOp,
     77     kIncClamp_StencilOp,            kDecClamp_StencilOp,
     78     kEqual_StencilFunc,             kEqual_StencilFunc,
     79     0xffff,                         0xffff,
     80     0xffff,                         0x0000,
     81     0xffff,                         0xffff);
     82 
     83 // When there are no separate faces we do two passes to setup the winding rule
     84 // stencil. First we draw the front faces and inc, then we draw the back faces
     85 // and dec. These are same as the above two split into the incrementing and
     86 // decrementing passes.
     87 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
     88     kIncWrap_StencilOp,
     89     kKeep_StencilOp,
     90     kAlwaysIfInClip_StencilFunc,
     91     0xffff,
     92     0xffff,
     93     0xffff);
     94 
     95 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
     96     kDecWrap_StencilOp,
     97     kKeep_StencilOp,
     98     kAlwaysIfInClip_StencilFunc,
     99     0xffff,
    100     0xffff,
    101     0xffff);
    102 
    103 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
    104     kInvert_StencilOp,
    105     kIncClamp_StencilOp,
    106     kEqual_StencilFunc,
    107     0xffff,
    108     0xffff,
    109     0xffff);
    110 
    111 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
    112     kInvert_StencilOp,
    113     kDecClamp_StencilOp,
    114     kEqual_StencilFunc,
    115     0xffff,
    116     0x0000,
    117     0xffff);
    118 
    119 // Color passes are the same whether we use the two-sided stencil or two passes
    120 
    121 GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
    122     kZero_StencilOp,
    123     kZero_StencilOp,
    124     kNonZeroIfInClip_StencilFunc,
    125     0xffff,
    126     0x0000,
    127     0xffff);
    128 
    129 GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
    130     kZero_StencilOp,
    131     kZero_StencilOp,
    132     kEqualIfInClip_StencilFunc,
    133     0xffff,
    134     0x0000,
    135     0xffff);
    136 
    137 ////// Normal render to stencil
    138 
    139 // Sometimes the default path renderer can draw a path directly to the stencil
    140 // buffer without having to first resolve the interior / exterior.
    141 GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
    142     kZero_StencilOp,
    143     kIncClamp_StencilOp,
    144     kAlwaysIfInClip_StencilFunc,
    145     0xffff,
    146     0x0000,
    147     0xffff);
    148 
    149 ////////////////////////////////////////////////////////////////////////////////
    150 // Helpers for drawPath
    151 
    152 #define STENCIL_OFF     0   // Always disable stencil (even when needed)
    153 
    154 static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
    155 #if STENCIL_OFF
    156     return true;
    157 #else
    158     if (!stroke.isHairlineStyle() && !path.isInverseFillType()) {
    159         return path.isConvex();
    160     }
    161     return false;
    162 #endif
    163 }
    164 
    165 GrPathRenderer::StencilSupport GrDefaultPathRenderer::onGetStencilSupport(
    166                                                             const SkPath& path,
    167                                                             const SkStrokeRec& stroke,
    168                                                             const GrDrawTarget*) const {
    169     if (single_pass_path(path, stroke)) {
    170         return GrPathRenderer::kNoRestriction_StencilSupport;
    171     } else {
    172         return GrPathRenderer::kStencilOnly_StencilSupport;
    173     }
    174 }
    175 
    176 static inline void append_countour_edge_indices(bool hairLine,
    177                                                 uint16_t fanCenterIdx,
    178                                                 uint16_t edgeV0Idx,
    179                                                 uint16_t** indices) {
    180     // when drawing lines we're appending line segments along
    181     // the contour. When applying the other fill rules we're
    182     // drawing triangle fans around fanCenterIdx.
    183     if (!hairLine) {
    184         *((*indices)++) = fanCenterIdx;
    185     }
    186     *((*indices)++) = edgeV0Idx;
    187     *((*indices)++) = edgeV0Idx + 1;
    188 }
    189 
    190 bool GrDefaultPathRenderer::createGeom(const SkPath& path,
    191                                        const SkStrokeRec& stroke,
    192                                        SkScalar srcSpaceTol,
    193                                        GrDrawTarget* target,
    194                                        GrPrimitiveType* primType,
    195                                        int* vertexCnt,
    196                                        int* indexCnt,
    197                                        GrDrawTarget::AutoReleaseGeometry* arg) {
    198     {
    199     SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
    200     int contourCnt;
    201     int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
    202                                                   srcSpaceTol);
    203 
    204     if (maxPts <= 0) {
    205         return false;
    206     }
    207     if (maxPts > ((int)SK_MaxU16 + 1)) {
    208         GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
    209         return false;
    210     }
    211 
    212     bool indexed = contourCnt > 1;
    213 
    214     const bool isHairline = stroke.isHairlineStyle();
    215 
    216     int maxIdxs = 0;
    217     if (isHairline) {
    218         if (indexed) {
    219             maxIdxs = 2 * maxPts;
    220             *primType = kLines_GrPrimitiveType;
    221         } else {
    222             *primType = kLineStrip_GrPrimitiveType;
    223         }
    224     } else {
    225         if (indexed) {
    226             maxIdxs = 3 * maxPts;
    227             *primType = kTriangles_GrPrimitiveType;
    228         } else {
    229             *primType = kTriangleFan_GrPrimitiveType;
    230         }
    231     }
    232 
    233     target->drawState()->setDefaultVertexAttribs();
    234     if (!arg->set(target, maxPts, maxIdxs)) {
    235         return false;
    236     }
    237 
    238     uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());
    239     uint16_t* idx = idxBase;
    240     uint16_t subpathIdxStart = 0;
    241 
    242     SkPoint* base = reinterpret_cast<SkPoint*>(arg->vertices());
    243     SkASSERT(NULL != base);
    244     SkPoint* vert = base;
    245 
    246     SkPoint pts[4];
    247 
    248     bool first = true;
    249     int subpath = 0;
    250 
    251     SkPath::Iter iter(path, false);
    252 
    253     for (;;) {
    254         SkPath::Verb verb = iter.next(pts);
    255         switch (verb) {
    256             case SkPath::kConic_Verb:
    257                 SkASSERT(0);
    258                 break;
    259             case SkPath::kMove_Verb:
    260                 if (!first) {
    261                     uint16_t currIdx = (uint16_t) (vert - base);
    262                     subpathIdxStart = currIdx;
    263                     ++subpath;
    264                 }
    265                 *vert = pts[0];
    266                 vert++;
    267                 break;
    268             case SkPath::kLine_Verb:
    269                 if (indexed) {
    270                     uint16_t prevIdx = (uint16_t)(vert - base) - 1;
    271                     append_countour_edge_indices(isHairline, subpathIdxStart,
    272                                                  prevIdx, &idx);
    273                 }
    274                 *(vert++) = pts[1];
    275                 break;
    276             case SkPath::kQuad_Verb: {
    277                 // first pt of quad is the pt we ended on in previous step
    278                 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
    279                 uint16_t numPts =  (uint16_t)
    280                     GrPathUtils::generateQuadraticPoints(
    281                             pts[0], pts[1], pts[2],
    282                             srcSpaceTolSqd, &vert,
    283                             GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
    284                 if (indexed) {
    285                     for (uint16_t i = 0; i < numPts; ++i) {
    286                         append_countour_edge_indices(isHairline, subpathIdxStart,
    287                                                      firstQPtIdx + i, &idx);
    288                     }
    289                 }
    290                 break;
    291             }
    292             case SkPath::kCubic_Verb: {
    293                 // first pt of cubic is the pt we ended on in previous step
    294                 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
    295                 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
    296                                 pts[0], pts[1], pts[2], pts[3],
    297                                 srcSpaceTolSqd, &vert,
    298                                 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
    299                 if (indexed) {
    300                     for (uint16_t i = 0; i < numPts; ++i) {
    301                         append_countour_edge_indices(isHairline, subpathIdxStart,
    302                                                      firstCPtIdx + i, &idx);
    303                     }
    304                 }
    305                 break;
    306             }
    307             case SkPath::kClose_Verb:
    308                 break;
    309             case SkPath::kDone_Verb:
    310              // uint16_t currIdx = (uint16_t) (vert - base);
    311                 goto FINISHED;
    312         }
    313         first = false;
    314     }
    315 FINISHED:
    316     SkASSERT((vert - base) <= maxPts);
    317     SkASSERT((idx - idxBase) <= maxIdxs);
    318 
    319     *vertexCnt = static_cast<int>(vert - base);
    320     *indexCnt = static_cast<int>(idx - idxBase);
    321 
    322     }
    323     return true;
    324 }
    325 
    326 bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
    327                                              const SkStrokeRec& origStroke,
    328                                              GrDrawTarget* target,
    329                                              bool stencilOnly) {
    330 
    331     SkMatrix viewM = target->getDrawState().getViewMatrix();
    332     SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
    333 
    334     SkScalar hairlineCoverage;
    335     if (IsStrokeHairlineOrEquivalent(*stroke, target->getDrawState().getViewMatrix(),
    336                                      &hairlineCoverage)) {
    337         uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage *
    338                                                  target->getDrawState().getCoverage());
    339         target->drawState()->setCoverage(newCoverage);
    340 
    341         if (!stroke->isHairlineStyle()) {
    342             stroke.writable()->setHairlineStyle();
    343         }
    344     }
    345 
    346     SkScalar tol = SK_Scalar1;
    347     tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
    348 
    349     int vertexCnt;
    350     int indexCnt;
    351     GrPrimitiveType primType;
    352     GrDrawTarget::AutoReleaseGeometry arg;
    353     if (!this->createGeom(path,
    354                           *stroke,
    355                           tol,
    356                           target,
    357                           &primType,
    358                           &vertexCnt,
    359                           &indexCnt,
    360                           &arg)) {
    361         return false;
    362     }
    363 
    364     SkASSERT(NULL != target);
    365     GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
    366     GrDrawState* drawState = target->drawState();
    367     bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
    368     // face culling doesn't make sense here
    369     SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
    370 
    371     int                         passCount = 0;
    372     const GrStencilSettings*    passes[3];
    373     GrDrawState::DrawFace       drawFace[3];
    374     bool                        reverse = false;
    375     bool                        lastPassIsBounds;
    376 
    377     if (stroke->isHairlineStyle()) {
    378         passCount = 1;
    379         if (stencilOnly) {
    380             passes[0] = &gDirectToStencil;
    381         } else {
    382             passes[0] = NULL;
    383         }
    384         lastPassIsBounds = false;
    385         drawFace[0] = GrDrawState::kBoth_DrawFace;
    386     } else {
    387         if (single_pass_path(path, *stroke)) {
    388             passCount = 1;
    389             if (stencilOnly) {
    390                 passes[0] = &gDirectToStencil;
    391             } else {
    392                 passes[0] = NULL;
    393             }
    394             drawFace[0] = GrDrawState::kBoth_DrawFace;
    395             lastPassIsBounds = false;
    396         } else {
    397             switch (path.getFillType()) {
    398                 case SkPath::kInverseEvenOdd_FillType:
    399                     reverse = true;
    400                     // fallthrough
    401                 case SkPath::kEvenOdd_FillType:
    402                     passes[0] = &gEOStencilPass;
    403                     if (stencilOnly) {
    404                         passCount = 1;
    405                         lastPassIsBounds = false;
    406                     } else {
    407                         passCount = 2;
    408                         lastPassIsBounds = true;
    409                         if (reverse) {
    410                             passes[1] = &gInvEOColorPass;
    411                         } else {
    412                             passes[1] = &gEOColorPass;
    413                         }
    414                     }
    415                     drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
    416                     break;
    417 
    418                 case SkPath::kInverseWinding_FillType:
    419                     reverse = true;
    420                     // fallthrough
    421                 case SkPath::kWinding_FillType:
    422                     if (fSeparateStencil) {
    423                         if (fStencilWrapOps) {
    424                             passes[0] = &gWindStencilSeparateWithWrap;
    425                         } else {
    426                             passes[0] = &gWindStencilSeparateNoWrap;
    427                         }
    428                         passCount = 2;
    429                         drawFace[0] = GrDrawState::kBoth_DrawFace;
    430                     } else {
    431                         if (fStencilWrapOps) {
    432                             passes[0] = &gWindSingleStencilWithWrapInc;
    433                             passes[1] = &gWindSingleStencilWithWrapDec;
    434                         } else {
    435                             passes[0] = &gWindSingleStencilNoWrapInc;
    436                             passes[1] = &gWindSingleStencilNoWrapDec;
    437                         }
    438                         // which is cw and which is ccw is arbitrary.
    439                         drawFace[0] = GrDrawState::kCW_DrawFace;
    440                         drawFace[1] = GrDrawState::kCCW_DrawFace;
    441                         passCount = 3;
    442                     }
    443                     if (stencilOnly) {
    444                         lastPassIsBounds = false;
    445                         --passCount;
    446                     } else {
    447                         lastPassIsBounds = true;
    448                         drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
    449                         if (reverse) {
    450                             passes[passCount-1] = &gInvWindColorPass;
    451                         } else {
    452                             passes[passCount-1] = &gWindColorPass;
    453                         }
    454                     }
    455                     break;
    456                 default:
    457                     SkDEBUGFAIL("Unknown path fFill!");
    458                     return false;
    459             }
    460         }
    461     }
    462 
    463     SkRect devBounds;
    464     GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds);
    465 
    466     for (int p = 0; p < passCount; ++p) {
    467         drawState->setDrawFace(drawFace[p]);
    468         if (NULL != passes[p]) {
    469             *drawState->stencil() = *passes[p];
    470         }
    471 
    472         if (lastPassIsBounds && (p == passCount-1)) {
    473             if (!colorWritesWereDisabled) {
    474                 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
    475             }
    476             SkRect bounds;
    477             GrDrawState::AutoViewMatrixRestore avmr;
    478             if (reverse) {
    479                 SkASSERT(NULL != drawState->getRenderTarget());
    480                 // draw over the dev bounds (which will be the whole dst surface for inv fill).
    481                 bounds = devBounds;
    482                 SkMatrix vmi;
    483                 // mapRect through persp matrix may not be correct
    484                 if (!drawState->getViewMatrix().hasPerspective() &&
    485                     drawState->getViewInverse(&vmi)) {
    486                     vmi.mapRect(&bounds);
    487                 } else {
    488                     avmr.setIdentity(drawState);
    489                 }
    490             } else {
    491                 bounds = path.getBounds();
    492             }
    493             GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit);
    494             target->drawSimpleRect(bounds, NULL);
    495         } else {
    496             if (passCount > 1) {
    497                 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
    498             }
    499             if (indexCnt) {
    500                 target->drawIndexed(primType, 0, 0,
    501                                     vertexCnt, indexCnt, &devBounds);
    502             } else {
    503                 target->drawNonIndexed(primType, 0, vertexCnt, &devBounds);
    504             }
    505         }
    506     }
    507     return true;
    508 }
    509 
    510 bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
    511                                         const SkStrokeRec& stroke,
    512                                         const GrDrawTarget* target,
    513                                         bool antiAlias) const {
    514     // this class can draw any path with any fill but doesn't do any anti-aliasing.
    515 
    516     return !antiAlias &&
    517         (stroke.isFillStyle() ||
    518          IsStrokeHairlineOrEquivalent(stroke, target->getDrawState().getViewMatrix(), NULL));
    519 }
    520 
    521 bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
    522                                        const SkStrokeRec& stroke,
    523                                        GrDrawTarget* target,
    524                                        bool antiAlias) {
    525     return this->internalDrawPath(path,
    526                                   stroke,
    527                                   target,
    528                                   false);
    529 }
    530 
    531 void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
    532                                           const SkStrokeRec& stroke,
    533                                           GrDrawTarget* target) {
    534     SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
    535     SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
    536     this->internalDrawPath(path, stroke, target, true);
    537 }
    538