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
Create(GrResourceProvider * resourceProvider,const GrCaps & caps)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
GrStencilAndCoverPathRenderer(GrResourceProvider * resourceProvider)32 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider)
33 : fResourceProvider(resourceProvider) {
34 }
35
36 GrPathRenderer::CanDrawPath
onCanDrawPath(const CanDrawPathArgs & args) const37 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
get_gr_path(GrResourceProvider * resourceProvider,const GrShape & shape)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
onStencilPath(const StencilPathArgs & args)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
onDrawPath(const DrawPathArgs & args)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