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 "GrStencilPathOp.h"
     18 #include "GrStyle.h"
     19 #include "ops/GrRectOpFactory.h"
     20 
     21 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
     22                                                       const GrCaps& caps) {
     23     if (caps.shaderCaps()->pathRenderingSupport() && !caps.avoidStencilBuffers()) {
     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     // GrPath doesn't support hairline paths. An arbitrary path effect could produce a hairline
     36     // path.
     37     if (args.fShape->style().strokeRec().isHairlineStyle() ||
     38         args.fShape->style().hasNonDashPathEffect()) {
     39         return false;
     40     }
     41     if (args.fHasUserStencilSettings) {
     42         return false;
     43     }
     44     // doesn't do per-path AA, relies on the target having MSAA.
     45     return (GrAAType::kCoverage != args.fAAType);
     46 }
     47 
     48 static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const GrShape& shape) {
     49     GrUniqueKey key;
     50     bool isVolatile;
     51     GrPath::ComputeKey(shape, &key, &isVolatile);
     52     sk_sp<GrPath> path;
     53     if (!isVolatile) {
     54         path.reset(
     55             static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
     56     }
     57     if (!path) {
     58         SkPath skPath;
     59         shape.asPath(&skPath);
     60         path = resourceProvider->createPath(skPath, shape.style());
     61         if (!isVolatile) {
     62             resourceProvider->assignUniqueKeyToResource(key, path.get());
     63         }
     64     } else {
     65 #ifdef SK_DEBUG
     66         SkPath skPath;
     67         shape.asPath(&skPath);
     68         SkASSERT(path->isEqualTo(skPath, shape.style()));
     69 #endif
     70     }
     71     return path.release();
     72 }
     73 
     74 void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
     75     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
     76                               "GrStencilAndCoverPathRenderer::onStencilPath");
     77     sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape));
     78     args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType,
     79                                                   *args.fViewMatrix, p.get());
     80 }
     81 
     82 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
     83     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
     84                               "GrStencilAndCoverPathRenderer::onDrawPath");
     85     SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle());
     86 
     87     const SkMatrix& viewMatrix = *args.fViewMatrix;
     88 
     89 
     90     sk_sp<GrPath> path(get_gr_path(fResourceProvider, *args.fShape));
     91 
     92     if (args.fShape->inverseFilled()) {
     93         SkMatrix invert = SkMatrix::I();
     94         SkRect bounds =
     95             SkRect::MakeLTRB(0, 0,
     96                              SkIntToScalar(args.fRenderTargetContext->width()),
     97                              SkIntToScalar(args.fRenderTargetContext->height()));
     98         SkMatrix vmi;
     99         // mapRect through persp matrix may not be correct
    100         if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
    101             vmi.mapRect(&bounds);
    102             // theoretically could set bloat = 0, instead leave it because of matrix inversion
    103             // precision.
    104             SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
    105             bounds.outset(bloat, bloat);
    106         } else {
    107             if (!viewMatrix.invert(&invert)) {
    108                 return false;
    109             }
    110         }
    111         const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
    112 
    113         // fake inverse with a stencil and cover
    114         args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType, viewMatrix,
    115                                                       path.get());
    116 
    117         {
    118             static constexpr GrUserStencilSettings kInvertedCoverPass(
    119                 GrUserStencilSettings::StaticInit<
    120                     0x0000,
    121                     // We know our rect will hit pixels outside the clip and the user bits will
    122                     // be 0 outside the clip. So we can't just fill where the user bits are 0. We
    123                     // also need to check that the clip bit is set.
    124                     GrUserStencilTest::kEqualIfInClip,
    125                     0xffff,
    126                     GrUserStencilOp::kKeep,
    127                     GrUserStencilOp::kZero,
    128                     0xffff>()
    129             );
    130             // We have to suppress enabling MSAA for mixed samples or we will get seams due to
    131             // coverage modulation along the edge where two triangles making up the rect meet.
    132             GrAAType coverAAType = args.fAAType;
    133             if (GrAAType::kMixedSamples == coverAAType) {
    134                 coverAAType = GrAAType::kNone;
    135             }
    136             args.fRenderTargetContext->addDrawOp(*args.fClip,
    137                                                  GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
    138                                                          std::move(args.fPaint), viewM, invert,
    139                                                          bounds, coverAAType, &kInvertedCoverPass));
    140         }
    141     } else {
    142         std::unique_ptr<GrDrawOp> op =
    143                 GrDrawPathOp::Make(viewMatrix, std::move(args.fPaint), args.fAAType, path.get());
    144         args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
    145     }
    146 
    147     return true;
    148 }
    149