Line data Source code
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 :
23 0 : GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
24 : const GrCaps& caps) {
25 0 : if (caps.shaderCaps()->pathRenderingSupport()) {
26 0 : return new GrStencilAndCoverPathRenderer(resourceProvider);
27 : } else {
28 0 : return nullptr;
29 : }
30 : }
31 :
32 0 : GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider)
33 0 : : fResourceProvider(resourceProvider) {
34 0 : }
35 :
36 0 : 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 0 : if (args.fShape->style().strokeRec().isHairlineStyle() ||
40 0 : args.fShape->style().hasNonDashPathEffect()) {
41 0 : return false;
42 : }
43 0 : if (args.fHasUserStencilSettings) {
44 0 : return false;
45 : }
46 : // doesn't do per-path AA, relies on the target having MSAA.
47 0 : return (GrAAType::kCoverage != args.fAAType);
48 : }
49 :
50 0 : static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const GrShape& shape) {
51 0 : GrUniqueKey key;
52 : bool isVolatile;
53 0 : GrPath::ComputeKey(shape, &key, &isVolatile);
54 0 : sk_sp<GrPath> path;
55 0 : if (!isVolatile) {
56 : path.reset(
57 0 : static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
58 : }
59 0 : if (!path) {
60 0 : SkPath skPath;
61 0 : shape.asPath(&skPath);
62 0 : path.reset(resourceProvider->createPath(skPath, shape.style()));
63 0 : if (!isVolatile) {
64 0 : resourceProvider->assignUniqueKeyToResource(key, path.get());
65 : }
66 : } else {
67 : #ifdef SK_DEBUG
68 0 : SkPath skPath;
69 0 : shape.asPath(&skPath);
70 0 : SkASSERT(path->isEqualTo(skPath, shape.style()));
71 : #endif
72 : }
73 0 : return path.release();
74 : }
75 :
76 0 : void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
77 0 : GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
78 : "GrStencilAndCoverPathRenderer::onStencilPath");
79 0 : sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape));
80 0 : args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType,
81 0 : *args.fViewMatrix, p.get());
82 0 : }
83 :
84 0 : bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
85 0 : GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
86 : "GrStencilAndCoverPathRenderer::onDrawPath");
87 0 : SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle());
88 :
89 0 : const SkMatrix& viewMatrix = *args.fViewMatrix;
90 :
91 :
92 0 : sk_sp<GrPath> path(get_gr_path(fResourceProvider, *args.fShape));
93 :
94 0 : if (args.fShape->inverseFilled()) {
95 0 : SkMatrix invert = SkMatrix::I();
96 : SkRect bounds =
97 : SkRect::MakeLTRB(0, 0,
98 0 : SkIntToScalar(args.fRenderTargetContext->width()),
99 0 : SkIntToScalar(args.fRenderTargetContext->height()));
100 : SkMatrix vmi;
101 : // mapRect through persp matrix may not be correct
102 0 : if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
103 0 : vmi.mapRect(&bounds);
104 : // theoretically could set bloat = 0, instead leave it because of matrix inversion
105 : // precision.
106 0 : SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
107 0 : bounds.outset(bloat, bloat);
108 : } else {
109 0 : if (!viewMatrix.invert(&invert)) {
110 0 : return false;
111 : }
112 : }
113 0 : const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
114 :
115 : std::unique_ptr<GrLegacyMeshDrawOp> coverOp(GrRectOpFactory::MakeNonAAFill(
116 0 : args.fPaint.getColor(), viewM, bounds, nullptr, &invert));
117 :
118 : // fake inverse with a stencil and cover
119 0 : args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType, viewMatrix,
120 0 : 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 0 : GrAAType coverAAType = args.fAAType;
138 0 : if (GrAAType::kMixedSamples == coverAAType) {
139 0 : coverAAType = GrAAType::kNone;
140 : }
141 0 : GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), coverAAType);
142 0 : pipelineBuilder.setUserStencil(&kInvertedCoverPass);
143 :
144 0 : args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip,
145 0 : std::move(coverOp));
146 : }
147 : } else {
148 : std::unique_ptr<GrDrawOp> op =
149 0 : GrDrawPathOp::Make(viewMatrix, std::move(args.fPaint), args.fAAType, path.get());
150 0 : args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
151 : }
152 :
153 0 : return true;
154 : }
|