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