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