Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2012 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "GrStencilAndCoverPathRenderer.h"
     11 #include "GrContext.h"
     12 #include "GrGpu.h"
     13 #include "GrPath.h"
     14 #include "SkStrokeRec.h"
     15 
     16 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) {
     17     GrAssert(NULL != context);
     18     GrAssert(NULL != context->getGpu());
     19     if (context->getGpu()->getCaps().pathStencilingSupport()) {
     20         return SkNEW_ARGS(GrStencilAndCoverPathRenderer, (context->getGpu()));
     21     } else {
     22         return NULL;
     23     }
     24 }
     25 
     26 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrGpu* gpu) {
     27     GrAssert(gpu->getCaps().pathStencilingSupport());
     28     fGpu = gpu;
     29     gpu->ref();
     30 }
     31 
     32 GrStencilAndCoverPathRenderer::~GrStencilAndCoverPathRenderer() {
     33     fGpu->unref();
     34 }
     35 
     36 bool GrStencilAndCoverPathRenderer::canDrawPath(const SkPath& path,
     37                                                 const SkStrokeRec& stroke,
     38                                                 const GrDrawTarget* target,
     39                                                 bool antiAlias) const {
     40     return stroke.isFillStyle() &&
     41            !antiAlias && // doesn't do per-path AA, relies on the target having MSAA
     42            target->getDrawState().getStencil().isDisabled();
     43 }
     44 
     45 GrPathRenderer::StencilSupport GrStencilAndCoverPathRenderer::onGetStencilSupport(
     46                                                         const SkPath&,
     47                                                         const SkStrokeRec& ,
     48                                                         const GrDrawTarget*) const {
     49     return GrPathRenderer::kStencilOnly_StencilSupport;
     50 }
     51 
     52 void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path,
     53                                                   const SkStrokeRec& stroke,
     54                                                   GrDrawTarget* target) {
     55     GrAssert(!path.isInverseFillType());
     56     SkAutoTUnref<GrPath> p(fGpu->createPath(path));
     57     target->stencilPath(p, stroke, path.getFillType());
     58 }
     59 
     60 bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path,
     61                                                const SkStrokeRec& stroke,
     62                                                GrDrawTarget* target,
     63                                                bool antiAlias) {
     64     GrAssert(!antiAlias);
     65     GrAssert(!stroke.isHairlineStyle());
     66 
     67     GrDrawState* drawState = target->drawState();
     68     GrAssert(drawState->getStencil().isDisabled());
     69 
     70     SkAutoTUnref<GrPath> p(fGpu->createPath(path));
     71 
     72     SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(path.getFillType());
     73     target->stencilPath(p, stroke, nonInvertedFill);
     74 
     75     // TODO: Use built in cover operation rather than a rect draw. This will require making our
     76     // fragment shaders be able to eat varyings generated by a matrix.
     77 
     78     // fill the path, zero out the stencil
     79     GrRect bounds = p->getBounds();
     80     SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf;
     81     GrDrawState::AutoDeviceCoordDraw adcd;
     82 
     83     if (nonInvertedFill == path.getFillType()) {
     84         GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
     85             kZero_StencilOp,
     86             kZero_StencilOp,
     87             kNotEqual_StencilFunc,
     88             0xffff,
     89             0x0000,
     90             0xffff);
     91         *drawState->stencil() = kStencilPass;
     92     } else {
     93         GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
     94             kZero_StencilOp,
     95             kZero_StencilOp,
     96             // We know our rect will hit pixels outside the clip and the user bits will be 0
     97             // outside the clip. So we can't just fill where the user bits are 0. We also need to
     98             // check that the clip bit is set.
     99             kEqualIfInClip_StencilFunc,
    100             0xffff,
    101             0x0000,
    102             0xffff);
    103         SkMatrix vmi;
    104         bounds.setLTRB(0, 0,
    105                        SkIntToScalar(drawState->getRenderTarget()->width()),
    106                        SkIntToScalar(drawState->getRenderTarget()->height()));
    107         // mapRect through persp matrix may not be correct
    108         if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
    109             vmi.mapRect(&bounds);
    110             // theoretically could set bloat = 0, instead leave it because of matrix inversion
    111             // precision.
    112         } else {
    113             adcd.set(drawState);
    114             bloat = 0;
    115         }
    116         *drawState->stencil() = kInvertedStencilPass;
    117     }
    118     bounds.outset(bloat, bloat);
    119     target->drawSimpleRect(bounds, NULL);
    120     target->drawState()->stencil()->setDisabled();
    121     return true;
    122 }
    123