Home | History | Annotate | Download | only in ops
      1 /*
      2  * Copyright 2012 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 "GrStencilAndCoverPathRenderer.h"
      9 #include "GrCaps.h"
     10 #include "GrContext.h"
     11 #include "GrDrawPathOp.h"
     12 #include "GrFixedClip.h"
     13 #include "GrGpu.h"
     14 #include "GrPath.h"
     15 #include "GrRenderTargetContextPriv.h"
     16 #include "GrResourceProvider.h"
     17 #include "GrShape.h"
     18 #include "GrStencilClip.h"
     19 #include "GrStencilPathOp.h"
     20 #include "GrStyle.h"
     21 #include "ops/GrFillRectOp.h"
     22 
     23 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
     24                                                       const GrCaps& caps) {
     25     if (caps.shaderCaps()->pathRenderingSupport() && !caps.avoidStencilBuffers()) {
     26         return new GrStencilAndCoverPathRenderer(resourceProvider);
     27     } else {
     28         return nullptr;
     29     }
     30 }
     31 
     32 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider)
     33     : fResourceProvider(resourceProvider) {
     34 }
     35 
     36 GrPathRenderer::CanDrawPath
     37 GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     38     SkASSERT(!args.fTargetIsWrappedVkSecondaryCB);
     39     // GrPath doesn't support hairline paths. An arbitrary path effect could produce a hairline
     40     // path.
     41     if (args.fShape->style().strokeRec().isHairlineStyle() ||
     42         args.fShape->style().hasNonDashPathEffect()) {
     43         return CanDrawPath::kNo;
     44     }
     45     if (args.fHasUserStencilSettings) {
     46         return CanDrawPath::kNo;
     47     }
     48     // doesn't do per-path AA, relies on the target having MSAA.
     49     if (GrAAType::kCoverage == args.fAAType) {
     50         return CanDrawPath::kNo;
     51     }
     52     return CanDrawPath::kYes;
     53 }
     54 
     55 static sk_sp<GrPath> get_gr_path(GrResourceProvider* resourceProvider, const GrShape& shape) {
     56     GrUniqueKey key;
     57     bool isVolatile;
     58     GrPath::ComputeKey(shape, &key, &isVolatile);
     59     sk_sp<GrPath> path;
     60     if (!isVolatile) {
     61         path = resourceProvider->findByUniqueKey<GrPath>(key);
     62     }
     63     if (!path) {
     64         SkPath skPath;
     65         shape.asPath(&skPath);
     66         path = resourceProvider->createPath(skPath, shape.style());
     67         if (!isVolatile) {
     68             resourceProvider->assignUniqueKeyToResource(key, path.get());
     69         }
     70     } else {
     71 #ifdef SK_DEBUG
     72         SkPath skPath;
     73         shape.asPath(&skPath);
     74         SkASSERT(path->isEqualTo(skPath, shape.style()));
     75 #endif
     76     }
     77     return path;
     78 }
     79 
     80 void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
     81     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
     82                               "GrStencilAndCoverPathRenderer::onStencilPath");
     83     sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape));
     84     args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType,
     85                                                   *args.fViewMatrix, p.get());
     86 }
     87 
     88 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
     89     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
     90                               "GrStencilAndCoverPathRenderer::onDrawPath");
     91     SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle());
     92 
     93     const SkMatrix& viewMatrix = *args.fViewMatrix;
     94 
     95 
     96     sk_sp<GrPath> path(get_gr_path(fResourceProvider, *args.fShape));
     97 
     98     if (args.fShape->inverseFilled()) {
     99         SkMatrix vmi;
    100         if (!viewMatrix.invert(&vmi)) {
    101             return true;
    102         }
    103 
    104         SkRect devBounds = SkRect::MakeIWH(args.fRenderTargetContext->width(),
    105                                            args.fRenderTargetContext->height()); // Inverse fill.
    106 
    107         // fake inverse with a stencil and cover
    108         GrAppliedClip appliedClip;
    109         if (!args.fClip->apply(args.fContext, args.fRenderTargetContext,
    110                                GrAATypeIsHW(args.fAAType), true, &appliedClip, &devBounds)) {
    111             return true;
    112         }
    113         GrStencilClip stencilClip(appliedClip.stencilStackID());
    114         if (appliedClip.scissorState().enabled()) {
    115             stencilClip.fixedClip().setScissor(appliedClip.scissorState().rect());
    116         }
    117         if (appliedClip.windowRectsState().enabled()) {
    118             stencilClip.fixedClip().setWindowRectangles(appliedClip.windowRectsState().windows(),
    119                                                         appliedClip.windowRectsState().mode());
    120         }
    121         // Just ignore the analytic FPs (if any) during the stencil pass. They will still clip the
    122         // final draw and it is meaningless to multiply by coverage when drawing to stencil.
    123         args.fRenderTargetContext->priv().stencilPath(stencilClip, args.fAAType, viewMatrix,
    124                                                       path.get());
    125 
    126         {
    127             static constexpr GrUserStencilSettings kInvertedCoverPass(
    128                 GrUserStencilSettings::StaticInit<
    129                     0x0000,
    130                     // We know our rect will hit pixels outside the clip and the user bits will
    131                     // be 0 outside the clip. So we can't just fill where the user bits are 0. We
    132                     // also need to check that the clip bit is set.
    133                     GrUserStencilTest::kEqualIfInClip,
    134                     0xffff,
    135                     GrUserStencilOp::kKeep,
    136                     GrUserStencilOp::kZero,
    137                     0xffff>()
    138             );
    139 
    140             SkRect coverBounds;
    141             // mapRect through persp matrix may not be correct
    142             if (!viewMatrix.hasPerspective()) {
    143                 vmi.mapRect(&coverBounds, devBounds);
    144                 // theoretically could set bloat = 0, instead leave it because of matrix inversion
    145                 // precision.
    146                 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
    147                 coverBounds.outset(bloat, bloat);
    148             } else {
    149                 coverBounds = devBounds;
    150             }
    151             const SkMatrix& coverMatrix = !viewMatrix.hasPerspective() ? viewMatrix : SkMatrix::I();
    152             const SkMatrix& localMatrix = !viewMatrix.hasPerspective() ? SkMatrix::I() : vmi;
    153 
    154             // We have to suppress enabling MSAA for mixed samples or we will get seams due to
    155             // coverage modulation along the edge where two triangles making up the rect meet.
    156             GrAAType coverAAType = args.fAAType;
    157             if (GrAAType::kMixedSamples == coverAAType) {
    158                 coverAAType = GrAAType::kNone;
    159             }
    160             // This is a non-coverage aa rect operation
    161             SkASSERT(coverAAType == GrAAType::kNone || coverAAType == GrAAType::kMSAA);
    162             std::unique_ptr<GrDrawOp> op = GrFillRectOp::MakeWithLocalMatrix(
    163                                                          args.fContext, std::move(args.fPaint),
    164                                                          coverAAType, coverMatrix, localMatrix,
    165                                                          coverBounds, &kInvertedCoverPass);
    166 
    167             args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
    168         }
    169     } else {
    170         std::unique_ptr<GrDrawOp> op =
    171                 GrDrawPathOp::Make(args.fContext, viewMatrix, std::move(args.fPaint),
    172                                    args.fAAType, path.get());
    173         args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
    174     }
    175 
    176     return true;
    177 }
    178