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