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