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 "SkTrace.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     SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
    200 
    201     SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
    202     int contourCnt;
    203     int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
    204                                                   srcSpaceTol);
    205 
    206     if (maxPts <= 0) {
    207         return false;
    208     }
    209     if (maxPts > ((int)SK_MaxU16 + 1)) {
    210         GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
    211         return false;
    212     }
    213 
    214     bool indexed = contourCnt > 1;
    215 
    216     const bool isHairline = stroke.isHairlineStyle();
    217 
    218     int maxIdxs = 0;
    219     if (isHairline) {
    220         if (indexed) {
    221             maxIdxs = 2 * maxPts;
    222             *primType = kLines_GrPrimitiveType;
    223         } else {
    224             *primType = kLineStrip_GrPrimitiveType;
    225         }
    226     } else {
    227         if (indexed) {
    228             maxIdxs = 3 * maxPts;
    229             *primType = kTriangles_GrPrimitiveType;
    230         } else {
    231             *primType = kTriangleFan_GrPrimitiveType;
    232         }
    233     }
    234 
    235     target->drawState()->setDefaultVertexAttribs();
    236     if (!arg->set(target, maxPts, maxIdxs)) {
    237         return false;
    238     }
    239 
    240     uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());
    241     uint16_t* idx = idxBase;
    242     uint16_t subpathIdxStart = 0;
    243 
    244     GrPoint* base = reinterpret_cast<GrPoint*>(arg->vertices());
    245     SkASSERT(NULL != base);
    246     GrPoint* vert = base;
    247 
    248     GrPoint pts[4];
    249 
    250     bool first = true;
    251     int subpath = 0;
    252 
    253     SkPath::Iter iter(path, false);
    254 
    255     for (;;) {
    256         SkPath::Verb verb = iter.next(pts);
    257         switch (verb) {
    258             case SkPath::kConic_Verb:
    259                 SkASSERT(0);
    260                 break;
    261             case SkPath::kMove_Verb:
    262                 if (!first) {
    263                     uint16_t currIdx = (uint16_t) (vert - base);
    264                     subpathIdxStart = currIdx;
    265                     ++subpath;
    266                 }
    267                 *vert = pts[0];
    268                 vert++;
    269                 break;
    270             case SkPath::kLine_Verb:
    271                 if (indexed) {
    272                     uint16_t prevIdx = (uint16_t)(vert - base) - 1;
    273                     append_countour_edge_indices(isHairline, subpathIdxStart,
    274                                                  prevIdx, &idx);
    275                 }
    276                 *(vert++) = pts[1];
    277                 break;
    278             case SkPath::kQuad_Verb: {
    279                 // first pt of quad is the pt we ended on in previous step
    280                 uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
    281                 uint16_t numPts =  (uint16_t)
    282                     GrPathUtils::generateQuadraticPoints(
    283                             pts[0], pts[1], pts[2],
    284                             srcSpaceTolSqd, &vert,
    285                             GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
    286                 if (indexed) {
    287                     for (uint16_t i = 0; i < numPts; ++i) {
    288                         append_countour_edge_indices(isHairline, subpathIdxStart,
    289                                                      firstQPtIdx + i, &idx);
    290                     }
    291                 }
    292                 break;
    293             }
    294             case SkPath::kCubic_Verb: {
    295                 // first pt of cubic is the pt we ended on in previous step
    296                 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
    297                 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
    298                                 pts[0], pts[1], pts[2], pts[3],
    299                                 srcSpaceTolSqd, &vert,
    300                                 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
    301                 if (indexed) {
    302                     for (uint16_t i = 0; i < numPts; ++i) {
    303                         append_countour_edge_indices(isHairline, subpathIdxStart,
    304                                                      firstCPtIdx + i, &idx);
    305                     }
    306                 }
    307                 break;
    308             }
    309             case SkPath::kClose_Verb:
    310                 break;
    311             case SkPath::kDone_Verb:
    312              // uint16_t currIdx = (uint16_t) (vert - base);
    313                 goto FINISHED;
    314         }
    315         first = false;
    316     }
    317 FINISHED:
    318     SkASSERT((vert - base) <= maxPts);
    319     SkASSERT((idx - idxBase) <= maxIdxs);
    320 
    321     *vertexCnt = static_cast<int>(vert - base);
    322     *indexCnt = static_cast<int>(idx - idxBase);
    323 
    324     }
    325     return true;
    326 }
    327 
    328 bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
    329                                              const SkStrokeRec& origStroke,
    330                                              GrDrawTarget* target,
    331                                              bool stencilOnly) {
    332 
    333     SkMatrix viewM = target->getDrawState().getViewMatrix();
    334     SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
    335 
    336     SkScalar hairlineCoverage;
    337     if (IsStrokeHairlineOrEquivalent(*stroke, target->getDrawState().getViewMatrix(),
    338                                      &hairlineCoverage)) {
    339         uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage *
    340                                                  target->getDrawState().getCoverage());
    341         target->drawState()->setCoverage(newCoverage);
    342 
    343         if (!stroke->isHairlineStyle()) {
    344             stroke.writable()->setHairlineStyle();
    345         }
    346     }
    347 
    348     SkScalar tol = SK_Scalar1;
    349     tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
    350 
    351     int vertexCnt;
    352     int indexCnt;
    353     GrPrimitiveType primType;
    354     GrDrawTarget::AutoReleaseGeometry arg;
    355     if (!this->createGeom(path,
    356                           *stroke,
    357                           tol,
    358                           target,
    359                           &primType,
    360                           &vertexCnt,
    361                           &indexCnt,
    362                           &arg)) {
    363         return false;
    364     }
    365 
    366     SkASSERT(NULL != target);
    367     GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
    368     GrDrawState* drawState = target->drawState();
    369     bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
    370     // face culling doesn't make sense here
    371     SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
    372 
    373     int                         passCount = 0;
    374     const GrStencilSettings*    passes[3];
    375     GrDrawState::DrawFace       drawFace[3];
    376     bool                        reverse = false;
    377     bool                        lastPassIsBounds;
    378 
    379     if (stroke->isHairlineStyle()) {
    380         passCount = 1;
    381         if (stencilOnly) {
    382             passes[0] = &gDirectToStencil;
    383         } else {
    384             passes[0] = NULL;
    385         }
    386         lastPassIsBounds = false;
    387         drawFace[0] = GrDrawState::kBoth_DrawFace;
    388     } else {
    389         if (single_pass_path(path, *stroke)) {
    390             passCount = 1;
    391             if (stencilOnly) {
    392                 passes[0] = &gDirectToStencil;
    393             } else {
    394                 passes[0] = NULL;
    395             }
    396             drawFace[0] = GrDrawState::kBoth_DrawFace;
    397             lastPassIsBounds = false;
    398         } else {
    399             switch (path.getFillType()) {
    400                 case SkPath::kInverseEvenOdd_FillType:
    401                     reverse = true;
    402                     // fallthrough
    403                 case SkPath::kEvenOdd_FillType:
    404                     passes[0] = &gEOStencilPass;
    405                     if (stencilOnly) {
    406                         passCount = 1;
    407                         lastPassIsBounds = false;
    408                     } else {
    409                         passCount = 2;
    410                         lastPassIsBounds = true;
    411                         if (reverse) {
    412                             passes[1] = &gInvEOColorPass;
    413                         } else {
    414                             passes[1] = &gEOColorPass;
    415                         }
    416                     }
    417                     drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
    418                     break;
    419 
    420                 case SkPath::kInverseWinding_FillType:
    421                     reverse = true;
    422                     // fallthrough
    423                 case SkPath::kWinding_FillType:
    424                     if (fSeparateStencil) {
    425                         if (fStencilWrapOps) {
    426                             passes[0] = &gWindStencilSeparateWithWrap;
    427                         } else {
    428                             passes[0] = &gWindStencilSeparateNoWrap;
    429                         }
    430                         passCount = 2;
    431                         drawFace[0] = GrDrawState::kBoth_DrawFace;
    432                     } else {
    433                         if (fStencilWrapOps) {
    434                             passes[0] = &gWindSingleStencilWithWrapInc;
    435                             passes[1] = &gWindSingleStencilWithWrapDec;
    436                         } else {
    437                             passes[0] = &gWindSingleStencilNoWrapInc;
    438                             passes[1] = &gWindSingleStencilNoWrapDec;
    439                         }
    440                         // which is cw and which is ccw is arbitrary.
    441                         drawFace[0] = GrDrawState::kCW_DrawFace;
    442                         drawFace[1] = GrDrawState::kCCW_DrawFace;
    443                         passCount = 3;
    444                     }
    445                     if (stencilOnly) {
    446                         lastPassIsBounds = false;
    447                         --passCount;
    448                     } else {
    449                         lastPassIsBounds = true;
    450                         drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
    451                         if (reverse) {
    452                             passes[passCount-1] = &gInvWindColorPass;
    453                         } else {
    454                             passes[passCount-1] = &gWindColorPass;
    455                         }
    456                     }
    457                     break;
    458                 default:
    459                     SkDEBUGFAIL("Unknown path fFill!");
    460                     return false;
    461             }
    462         }
    463     }
    464 
    465     SkRect devBounds;
    466     GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds);
    467 
    468     for (int p = 0; p < passCount; ++p) {
    469         drawState->setDrawFace(drawFace[p]);
    470         if (NULL != passes[p]) {
    471             *drawState->stencil() = *passes[p];
    472         }
    473 
    474         if (lastPassIsBounds && (p == passCount-1)) {
    475             if (!colorWritesWereDisabled) {
    476                 drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
    477             }
    478             SkRect bounds;
    479             GrDrawState::AutoViewMatrixRestore avmr;
    480             if (reverse) {
    481                 SkASSERT(NULL != drawState->getRenderTarget());
    482                 // draw over the dev bounds (which will be the whole dst surface for inv fill).
    483                 bounds = devBounds;
    484                 SkMatrix vmi;
    485                 // mapRect through persp matrix may not be correct
    486                 if (!drawState->getViewMatrix().hasPerspective() &&
    487                     drawState->getViewInverse(&vmi)) {
    488                     vmi.mapRect(&bounds);
    489                 } else {
    490                     avmr.setIdentity(drawState);
    491                 }
    492             } else {
    493                 bounds = path.getBounds();
    494             }
    495             GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit);
    496             target->drawSimpleRect(bounds, NULL);
    497         } else {
    498             if (passCount > 1) {
    499                 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
    500             }
    501             if (indexCnt) {
    502                 target->drawIndexed(primType, 0, 0,
    503                                     vertexCnt, indexCnt, &devBounds);
    504             } else {
    505                 target->drawNonIndexed(primType, 0, vertexCnt, &devBounds);
    506             }
    507         }
    508     }
    509     return true;
    510 }
    511 
    512 bool GrDefaultPathRenderer::canDrawPath(const SkPath& path,
    513                                         const SkStrokeRec& stroke,
    514                                         const GrDrawTarget* target,
    515                                         bool antiAlias) const {
    516     // this class can draw any path with any fill but doesn't do any anti-aliasing.
    517 
    518     return !antiAlias &&
    519         (stroke.isFillStyle() ||
    520          IsStrokeHairlineOrEquivalent(stroke, target->getDrawState().getViewMatrix(), NULL));
    521 }
    522 
    523 bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
    524                                        const SkStrokeRec& stroke,
    525                                        GrDrawTarget* target,
    526                                        bool antiAlias) {
    527     return this->internalDrawPath(path,
    528                                   stroke,
    529                                   target,
    530                                   false);
    531 }
    532 
    533 void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
    534                                           const SkStrokeRec& stroke,
    535                                           GrDrawTarget* target) {
    536     SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
    537     SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
    538     this->internalDrawPath(path, stroke, target, true);
    539 }
    540