Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
TessellationPathRenderer.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2019 Google LLC.
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
9
10#include "src/core/SkPathPriv.h"
24
25namespace {
26
27using namespace skgpu::tess;
28
29GrOp::Owner make_non_convex_fill_op(GrRecordingContext* rContext,
30 SkArenaAlloc* arena,
31 skgpu::ganesh::FillPathFlags fillPathFlags,
32 GrAAType aaType,
33 const SkRect& drawBounds,
34 const SkIRect& clipBounds,
35 const SkMatrix& viewMatrix,
36 const SkPath& path,
37 GrPaint&& paint) {
38 SkASSERT(!path.isConvex() || path.isInverseFillType());
39#if !defined(SK_ENABLE_OPTIMIZE_SIZE)
40 int numVerbs = path.countVerbs();
41 if (numVerbs > 0 && !path.isInverseFillType()) {
42 // Check if the path is large and/or simple enough that we can triangulate the inner fan
43 // on the CPU. This is our fastest approach. It allows us to stencil only the curves,
44 // and then fill the inner fan directly to the final render target, thus drawing the
45 // majority of pixels in a single render pass.
46 SkRect clippedDrawBounds = SkRect::Make(clipBounds);
47 if (clippedDrawBounds.intersect(drawBounds)) {
48 float gpuFragmentWork = clippedDrawBounds.height() * clippedDrawBounds.width();
49 float cpuTessellationWork = numVerbs * SkNextLog2(numVerbs); // N log N.
50 constexpr static float kCpuWeight = 512;
51 constexpr static float kMinNumPixelsToTriangulate = 256 * 256;
52 if (cpuTessellationWork * kCpuWeight + kMinNumPixelsToTriangulate < gpuFragmentWork) {
53 return GrOp::Make<skgpu::ganesh::PathInnerTriangulateOp>(rContext,
54 viewMatrix,
55 path,
56 std::move(paint),
57 aaType,
58 fillPathFlags,
59 drawBounds);
60 }
61 } // we should be clipped out when the GrClip is analyzed, so just return the default op
62 }
63#endif
64
65 return GrOp::Make<skgpu::ganesh::PathStencilCoverOp>(
66 rContext, arena, viewMatrix, path, std::move(paint), aaType, fillPathFlags, drawBounds);
67}
68
69} // anonymous namespace
70
71namespace skgpu::ganesh {
72
78
80 const GrStyledShape& shape) const {
81 if (!shape.style().isSimpleFill() || shape.inverseFilled()) {
82 // Don't bother with stroke stencilling or inverse fills yet. The Skia API doesn't support
83 // clipping by a stroke, and the stencilling code already knows how to invert a fill.
85 }
87}
88
90 const CanDrawPathArgs& args) const {
91 const GrStyledShape& shape = *args.fShape;
92 if (args.fAAType == GrAAType::kCoverage ||
93 shape.style().hasPathEffect() ||
94 args.fViewMatrix->hasPerspective() ||
96 !args.fProxy->canUseStencil(*args.fCaps)) {
97 return CanDrawPath::kNo;
98 }
99 if (!shape.style().isSimpleFill()) {
100 if (shape.inverseFilled()) {
101 return CanDrawPath::kNo;
102 }
103 if (shape.style().strokeRec().getWidth() * args.fViewMatrix->getMaxScale() > 10000) {
104 // crbug.com/1266446 -- Don't draw massively wide strokes with the tessellator. Since we
105 // outset the viewport by stroke width for pre-chopping, astronomically wide strokes can
106 // result in an astronomical viewport size, and therefore an exponential explosion chops
107 // and memory usage. It is also simply inefficient to tessellate these strokes due to
108 // the number of radial edges required. We're better off just converting them to a path
109 // after a certain point.
110 return CanDrawPath::kNo;
111 }
112 }
113 if (args.fHasUserStencilSettings) {
114 // Non-convex paths and strokes use the stencil buffer internally, so they can't support
115 // draws with stencil settings.
116 if (!shape.style().isSimpleFill() || !shape.knownToBeConvex() || shape.inverseFilled()) {
117 return CanDrawPath::kNo;
118 }
119 }
120 return CanDrawPath::kYes;
121}
122
124 auto sdc = args.fSurfaceDrawContext;
125
126 SkPath path;
127 args.fShape->asPath(&path);
128
129 const SkRect pathDevBounds = args.fViewMatrix->mapRect(args.fShape->bounds());
131 pathDevBounds.width(),
132 pathDevBounds.height());
134 // The path is extremely large. Pre-chop its curves to keep the number of tessellation
135 // segments tractable. This will also flatten curves that fall completely outside the
136 // viewport.
137 SkRect viewport = SkRect::Make(*args.fClipConservativeBounds);
138 if (!args.fShape->style().isSimpleFill()) {
139 // Outset the viewport to pad for the stroke width.
140 const SkStrokeRec& stroke = args.fShape->style().strokeRec();
141 float inflationRadius;
142 if (stroke.isHairlineStyle()) {
143 // SkStrokeRec::getInflationRadius() doesn't handle hairlines robustly. Instead
144 // find the inflation of an equivalent stroke in device space with a width of 1.
145 inflationRadius = SkStrokeRec::GetInflationRadius(stroke.getJoin(),
146 stroke.getMiter(),
147 stroke.getCap(), 1);
148 } else {
149 inflationRadius = stroke.getInflationRadius() * args.fViewMatrix->getMaxScale();
150 }
151 viewport.outset(inflationRadius, inflationRadius);
152 }
153 path = PreChopPathCurves(tess::kPrecision, path, *args.fViewMatrix, viewport);
154 }
155
156 // Handle strokes first.
157 if (!args.fShape->style().isSimpleFill()) {
158 SkASSERT(!path.isInverseFillType()); // See onGetStencilSupport().
159 SkASSERT(args.fUserStencilSettings->isUnused());
160 const SkStrokeRec& stroke = args.fShape->style().strokeRec();
162 auto op = GrOp::Make<StrokeTessellateOp>(args.fContext, args.fAAType, *args.fViewMatrix,
163 path, stroke, std::move(args.fPaint));
164 sdc->addDrawOp(args.fClip, std::move(op));
165 return true;
166 }
167
168 // Handle empty paths.
169 if (pathDevBounds.isEmpty()) {
170 if (path.isInverseFillType()) {
171 args.fSurfaceDrawContext->drawPaint(args.fClip, std::move(args.fPaint),
172 *args.fViewMatrix);
173 }
174 return true;
175 }
176
177 // Handle convex paths. Make sure to check 'path' for convexity since it may have been
178 // pre-chopped, not 'fShape'.
179 if (path.isConvex() && !path.isInverseFillType()) {
180 auto op = GrOp::Make<PathTessellateOp>(args.fContext,
181 args.fSurfaceDrawContext->arenaAlloc(),
182 args.fAAType,
183 args.fUserStencilSettings,
184 *args.fViewMatrix,
185 path,
186 std::move(args.fPaint),
187 pathDevBounds);
188 sdc->addDrawOp(args.fClip, std::move(op));
189 return true;
190 }
191
192 SkASSERT(args.fUserStencilSettings->isUnused()); // See onGetStencilSupport().
193 const SkRect& drawBounds = path.isInverseFillType()
194 ? args.fSurfaceDrawContext->asSurfaceProxy()->backingStoreBoundsRect()
195 : pathDevBounds;
196 auto op = make_non_convex_fill_op(args.fContext,
197 args.fSurfaceDrawContext->arenaAlloc(),
199 args.fAAType,
200 drawBounds,
201 *args.fClipConservativeBounds,
202 *args.fViewMatrix,
203 path,
204 std::move(args.fPaint));
205 sdc->addDrawOp(args.fClip, std::move(op));
206 return true;
207}
208
210 SkASSERT(args.fShape->style().isSimpleFill()); // See onGetStencilSupport().
211 SkASSERT(!args.fShape->inverseFilled()); // See onGetStencilSupport().
212
213 auto sdc = args.fSurfaceDrawContext;
214 GrAAType aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
215
216 SkRect pathDevBounds;
217 args.fViewMatrix->mapRect(&pathDevBounds, args.fShape->bounds());
218
219 SkPath path;
220 args.fShape->asPath(&path);
221
223 pathDevBounds.width(),
224 pathDevBounds.height());
226 SkRect viewport = SkRect::Make(*args.fClipConservativeBounds);
227 path = PreChopPathCurves(tess::kPrecision, path, *args.fViewMatrix, viewport);
228 }
229
230 // Make sure to check 'path' for convexity since it may have been pre-chopped, not 'fShape'.
231 if (path.isConvex()) {
232 constexpr static GrUserStencilSettings kMarkStencil(
234 0x0001,
236 0xffff,
239 0xffff>());
240
241 GrPaint stencilPaint;
243 auto op = GrOp::Make<PathTessellateOp>(args.fContext,
244 args.fSurfaceDrawContext->arenaAlloc(),
245 aaType,
247 *args.fViewMatrix,
248 path,
249 std::move(stencilPaint),
250 pathDevBounds);
251 sdc->addDrawOp(args.fClip, std::move(op));
252 return;
253 }
254
255 auto op = make_non_convex_fill_op(args.fContext,
256 args.fSurfaceDrawContext->arenaAlloc(),
258 aaType,
259 pathDevBounds,
260 *args.fClipConservativeBounds,
261 *args.fViewMatrix,
262 path,
263 GrPaint());
264 sdc->addDrawOp(args.fClip, std::move(op));
265}
266
267} // namespace skgpu::ganesh
GrAAType
#define SkASSERT(cond)
Definition SkAssert.h:116
static int SkNextLog2(uint32_t value)
Definition SkMathPriv.h:238
bool avoidStencilBuffers() const
Definition GrCaps.h:139
bool drawInstancedSupport() const
Definition GrCaps.h:80
bool disableTessellationPathRenderer() const
Definition GrCaps.h:441
static const GrDisableColorXPFactory * Get()
std::unique_ptr< GrOp > Owner
Definition GrOp.h:72
void setXPFactory(const GrXPFactory *xpFactory)
Definition GrPaint.h:53
bool hasPathEffect() const
Definition GrStyle.h:122
bool isSimpleFill() const
Definition GrStyle.h:114
const SkStrokeRec & strokeRec() const
Definition GrStyle.h:140
bool knownToBeConvex() const
bool inverseFilled() const
const GrStyle & style() const
Style getStyle() const
@ kStrokeAndFill_Style
Definition SkStrokeRec.h:36
static SkScalar GetInflationRadius(const SkPaint &, SkPaint::Style)
SkScalar getInflationRadius() const
bool isHairlineStyle() const
Definition SkStrokeRec.h:47
SkScalar getWidth() const
Definition SkStrokeRec.h:42
SkPaint::Join getJoin() const
Definition SkStrokeRec.h:45
SkPaint::Cap getCap() const
Definition SkStrokeRec.h:44
SkScalar getMiter() const
Definition SkStrokeRec.h:43
CanDrawPath onCanDrawPath(const CanDrawPathArgs &) const override
bool onDrawPath(const DrawPathArgs &) override
void onStencilPath(const StencilPathArgs &) override
StencilSupport onGetStencilSupport(const GrStyledShape &) const override
const Paint & paint
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
static constexpr GrUserStencilSettings kMarkStencil(GrUserStencilSettings::StaticInit< 0x0001, GrUserStencilTest::kLessIfInClip, 0x0000, GrUserStencilOp::kZero, GrUserStencilOp::kReplace, 0xffff >())
static constexpr float kMaxSegmentsPerCurve_p4
SkPath PreChopPathCurves(float tessellationPrecision, const SkPath &path, const SkMatrix &matrix, const SkRect &viewport)
static constexpr float kPrecision
AI float worst_case_cubic_p4(float precision, float devWidth, float devHeight)
static constexpr Init< Ref, Test, TestMask, PassOp, FailOp, WriteMask > StaticInit()
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
bool intersect(const SkRect &r)
Definition SkRect.cpp:114
void outset(float dx, float dy)
Definition SkRect.h:1077
constexpr float height() const
Definition SkRect.h:769
constexpr float width() const
Definition SkRect.h:762
bool isEmpty() const
Definition SkRect.h:693