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