gfx/skia/trunk/src/gpu/GrDefaultPathRenderer.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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  */
     8 #include "GrDefaultPathRenderer.h"
    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"
    19 GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
    20                                              bool stencilWrapOpsSupport)
    21     : fSeparateStencil(separateStencilSupport)
    22     , fStencilWrapOps(stencilWrapOpsSupport) {
    23 }
    26 ////////////////////////////////////////////////////////////////////////////////
    27 // Stencil rules for paths
    29 ////// Even/Odd
    31 GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
    32     kInvert_StencilOp,
    33     kKeep_StencilOp,
    34     kAlwaysIfInClip_StencilFunc,
    35     0xffff,
    36     0xffff,
    37     0xffff);
    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);
    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);
    57 ////// Winding
    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.
    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);
    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);
    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);
    95 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
    96     kDecWrap_StencilOp,
    97     kKeep_StencilOp,
    98     kAlwaysIfInClip_StencilFunc,
    99     0xffff,
   100     0xffff,
   101     0xffff);
   103 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
   104     kInvert_StencilOp,
   105     kIncClamp_StencilOp,
   106     kEqual_StencilFunc,
   107     0xffff,
   108     0xffff,
   109     0xffff);
   111 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
   112     kInvert_StencilOp,
   113     kDecClamp_StencilOp,
   114     kEqual_StencilFunc,
   115     0xffff,
   116     0x0000,
   117     0xffff);
   119 // Color passes are the same whether we use the two-sided stencil or two passes
   121 GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
   122     kZero_StencilOp,
   123     kZero_StencilOp,
   124     kNonZeroIfInClip_StencilFunc,
   125     0xffff,
   126     0x0000,
   127     0xffff);
   129 GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
   130     kZero_StencilOp,
   131     kZero_StencilOp,
   132     kEqualIfInClip_StencilFunc,
   133     0xffff,
   134     0x0000,
   135     0xffff);
   137 ////// Normal render to stencil
   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);
   149 ////////////////////////////////////////////////////////////////////////////////
   150 // Helpers for drawPath
   152 #define STENCIL_OFF     0   // Always disable stencil (even when needed)
   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 }
   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 }
   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 }
   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");
   201     SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
   202     int contourCnt;
   203     int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt,
   204                                                   srcSpaceTol);
   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     }
   214     bool indexed = contourCnt > 1;
   216     const bool isHairline = stroke.isHairlineStyle();
   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     }
   235     target->drawState()->setDefaultVertexAttribs();
   236     if (!arg->set(target, maxPts, maxIdxs)) {
   237         return false;
   238     }
   240     uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());
   241     uint16_t* idx = idxBase;
   242     uint16_t subpathIdxStart = 0;
   244     GrPoint* base = reinterpret_cast<GrPoint*>(arg->vertices());
   245     SkASSERT(NULL != base);
   246     GrPoint* vert = base;
   248     GrPoint pts[4];
   250     bool first = true;
   251     int subpath = 0;
   253     SkPath::Iter iter(path, false);
   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);
   321     *vertexCnt = static_cast<int>(vert - base);
   322     *indexCnt = static_cast<int>(idx - idxBase);
   324     }
   325     return true;
   326 }
   328 bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
   329                                              const SkStrokeRec& origStroke,
   330                                              GrDrawTarget* target,
   331                                              bool stencilOnly) {
   333     SkMatrix viewM = target->getDrawState().getViewMatrix();
   334     SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
   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);
   343         if (!stroke->isHairlineStyle()) {
   344             stroke.writable()->setHairlineStyle();
   345         }
   346     }
   348     SkScalar tol = SK_Scalar1;
   349     tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
   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     }
   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());
   373     int                         passCount = 0;
   374     const GrStencilSettings*    passes[3];
   375     GrDrawState::DrawFace       drawFace[3];
   376     bool                        reverse = false;
   377     bool                        lastPassIsBounds;
   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;
   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     }
   465     SkRect devBounds;
   466     GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds);
   468     for (int p = 0; p < passCount; ++p) {
   469         drawState->setDrawFace(drawFace[p]);
   470         if (NULL != passes[p]) {
   471             *drawState->stencil() = *passes[p];
   472         }
   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 }
   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.
   518     return !antiAlias &&
   519         (stroke.isFillStyle() ||
   520          IsStrokeHairlineOrEquivalent(stroke, target->getDrawState().getViewMatrix(), NULL));
   521 }
   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 }
   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 }

mercurial