Home | History | Annotate | Download | only in batches
      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 "GrCaps.h"
     12 #include "GrContext.h"
     13 #include "GrDrawPathBatch.h"
     14 #include "GrGpu.h"
     15 #include "GrPath.h"
     16 #include "GrRenderTarget.h"
     17 #include "GrResourceProvider.h"
     18 #include "GrStrokeInfo.h"
     19 #include "batches/GrRectBatchFactory.h"
     20 
     21 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
     22                                                       const GrCaps& caps) {
     23     if (caps.shaderCaps()->pathRenderingSupport()) {
     24         return new GrStencilAndCoverPathRenderer(resourceProvider);
     25     } else {
     26         return nullptr;
     27     }
     28 }
     29 
     30 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider)
     31     : fResourceProvider(resourceProvider) {
     32 }
     33 
     34 bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     35     if (args.fStroke->isHairlineStyle()) {
     36         return false;
     37     }
     38     if (!args.fIsStencilDisabled) {
     39         return false;
     40     }
     41     if (args.fAntiAlias) {
     42         return args.fIsStencilBufferMSAA;
     43     } else {
     44         return true; // doesn't do per-path AA, relies on the target having MSAA
     45     }
     46 }
     47 
     48 static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& skPath,
     49                            const GrStrokeInfo& stroke) {
     50     GrUniqueKey key;
     51     bool isVolatile;
     52     GrPath::ComputeKey(skPath, stroke, &key, &isVolatile);
     53     SkAutoTUnref<GrPath> path(
     54         static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
     55     if (!path) {
     56         path.reset(resourceProvider->createPath(skPath, stroke));
     57         if (!isVolatile) {
     58             resourceProvider->assignUniqueKeyToResource(key, path);
     59         }
     60     } else {
     61         SkASSERT(path->isEqualTo(skPath, stroke));
     62     }
     63     return path.detach();
     64 }
     65 
     66 void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
     67     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
     68                               "GrStencilAndCoverPathRenderer::onStencilPath");
     69     SkASSERT(!args.fPath->isInverseFillType());
     70     SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, *args.fStroke));
     71     args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, p->getFillType());
     72 }
     73 
     74 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
     75     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
     76                               "GrStencilAndCoverPathRenderer::onDrawPath");
     77     SkASSERT(!args.fStroke->isHairlineStyle());
     78     const SkPath& path = *args.fPath;
     79     GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
     80     const SkMatrix& viewMatrix = *args.fViewMatrix;
     81 
     82     SkASSERT(pipelineBuilder->getStencil().isDisabled());
     83 
     84     if (args.fAntiAlias) {
     85         SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled());
     86         pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag);
     87     }
     88 
     89     SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStroke));
     90 
     91     if (path.isInverseFillType()) {
     92         GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
     93             kKeep_StencilOp,
     94             kZero_StencilOp,
     95             // We know our rect will hit pixels outside the clip and the user bits will be 0
     96             // outside the clip. So we can't just fill where the user bits are 0. We also need to
     97             // check that the clip bit is set.
     98             kEqualIfInClip_StencilFunc,
     99             0xffff,
    100             0x0000,
    101             0xffff);
    102 
    103         pipelineBuilder->setStencil(kInvertedStencilPass);
    104 
    105         // fake inverse with a stencil and cover
    106         args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->getFillType());
    107 
    108         SkMatrix invert = SkMatrix::I();
    109         SkRect bounds =
    110             SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()),
    111                              SkIntToScalar(pipelineBuilder->getRenderTarget()->height()));
    112         SkMatrix vmi;
    113         // mapRect through persp matrix may not be correct
    114         if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
    115             vmi.mapRect(&bounds);
    116             // theoretically could set bloat = 0, instead leave it because of matrix inversion
    117             // precision.
    118             SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
    119             bounds.outset(bloat, bloat);
    120         } else {
    121             if (!viewMatrix.invert(&invert)) {
    122                 return false;
    123             }
    124         }
    125         const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
    126         if (pipelineBuilder->getRenderTarget()->hasMixedSamples()) {
    127             pipelineBuilder->disableState(GrPipelineBuilder::kHWAntialias_Flag);
    128         }
    129 
    130         SkAutoTUnref<GrDrawBatch> batch(
    131                 GrRectBatchFactory::CreateNonAAFill(args.fColor, viewM, bounds, nullptr,
    132                                                     &invert));
    133         args.fTarget->drawBatch(*pipelineBuilder, batch);
    134     } else {
    135         GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
    136             kZero_StencilOp,
    137             kKeep_StencilOp,
    138             kNotEqual_StencilFunc,
    139             0xffff,
    140             0x0000,
    141             0xffff);
    142 
    143         pipelineBuilder->setStencil(kStencilPass);
    144         SkAutoTUnref<GrDrawPathBatchBase> batch(
    145                 GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p));
    146         args.fTarget->drawPathBatch(*pipelineBuilder, batch);
    147     }
    148 
    149     pipelineBuilder->stencil()->setDisabled();
    150     return true;
    151 }
    152