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