Flutter Engine
The Flutter Engine
PathTessellatorsSlide.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
11
12#if defined(SK_GANESH)
13
14#include "include/core/SkFont.h"
29
30namespace skgpu::ganesh {
31
32namespace {
33
34enum class Mode {
35 kWedgeMiddleOut,
36 kCurveMiddleOut
37};
38
39static const char* ModeName(Mode mode) {
40 switch (mode) {
41 case Mode::kWedgeMiddleOut:
42 return "MiddleOutShader (kWedges)";
43 case Mode::kCurveMiddleOut:
44 return "MiddleOutShader (kCurves)";
45 }
47}
48
49// Draws a path directly to the screen using a specific tessellator.
50class SamplePathTessellatorOp : public GrDrawOp {
51private:
53
54 SamplePathTessellatorOp(const SkRect& drawBounds, const SkPath& path, const SkMatrix& m,
55 GrPipeline::InputFlags pipelineFlags, Mode mode)
56 : GrDrawOp(ClassID())
57 , fPath(path)
58 , fMatrix(m)
59 , fPipelineFlags(pipelineFlags)
60 , fMode(mode) {
61 this->setBounds(drawBounds, HasAABloat::kNo, IsHairline::kNo);
62 }
63 const char* name() const override { return "SamplePathTessellatorOp"; }
64 void visitProxies(const GrVisitProxyFunc&) const override {}
65 FixedFunctionFlags fixedFunctionFlags() const override {
66 return FixedFunctionFlags::kUsesHWAA;
67 }
68 GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
69 GrClampType clampType) override {
71 return fProcessors.finalize(SK_PMColor4fWHITE, GrProcessorAnalysisCoverage::kNone, clip,
72 nullptr, caps, clampType, &color);
73 }
74 void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
75 const GrDstProxyView&, GrXferBarrierFlags, GrLoadOp colorLoadOp) override {}
76 void onPrepare(GrOpFlushState* flushState) override {
77 constexpr static SkPMColor4f kCyan = {0,1,1,1};
78 auto alloc = flushState->allocator();
79 const SkMatrix& shaderMatrix = SkMatrix::I();
80 const SkMatrix& pathMatrix = fMatrix;
81 const GrCaps& caps = flushState->caps();
82 const GrShaderCaps& shaderCaps = *caps.shaderCaps();
83
84 PathTessellator::PathDrawList pathList{pathMatrix, fPath, kCyan};
85 if (fMode == Mode::kCurveMiddleOut) {
86#if !defined(SK_ENABLE_OPTIMIZE_SIZE)
87 // This emulates what PathStencilCoverOp does when using curves, except we include the
88 // middle-out triangles directly in the written patches for convenience (normally they
89 // use a simple triangle pipeline). But PathCurveTessellator only knows how to read
90 // extra triangles from BreadcrumbTriangleList, so build on from the middle-out stack.
91 SkArenaAlloc storage{256};
93 for (tess::PathMiddleOutFanIter it(fPath); !it.done();) {
94 for (auto [p0, p1, p2] : it.nextStack()) {
95 triangles.append(&storage,
96 pathMatrix.mapPoint(p0),
97 pathMatrix.mapPoint(p1),
98 pathMatrix.mapPoint(p2),
99 /*winding=*/1);
100 }
101 }
102
103 auto* tess = PathCurveTessellator::Make(alloc, shaderCaps.fInfinitySupport);
104 tess->prepareWithTriangles(flushState, shaderMatrix, &triangles, pathList,
105 fPath.countVerbs());
106 fTessellator = tess;
107#else
108 auto* tess = PathCurveTessellator::Make(alloc, shaderCaps.fInfinitySupport);
109 tess->prepareWithTriangles(flushState, shaderMatrix, nullptr, pathList,
110 fPath.countVerbs());
111 fTessellator = tess;
112#endif
113 } else {
114 // This emulates what PathStencilCoverOp does when using wedges.
115 fTessellator = PathWedgeTessellator::Make(alloc, shaderCaps.fInfinitySupport);
116 fTessellator->prepare(flushState, shaderMatrix, pathList, fPath.countVerbs());
117 }
118
119 auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, std::move(fProcessors),
120 fPipelineFlags);
121 auto* tessShader = GrPathTessellationShader::Make(*caps.shaderCaps(),
122 alloc,
123 shaderMatrix,
124 kCyan,
125 fTessellator->patchAttribs());
126 fProgram = GrTessellationShader::MakeProgram({alloc, flushState->writeView(),
127 flushState->usesMSAASurface(),
128 &flushState->dstProxyView(),
129 flushState->renderPassBarriers(),
130 GrLoadOp::kClear, &flushState->caps()},
131 tessShader,
132 pipeline,
134 }
135
136 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
137 flushState->bindPipeline(*fProgram, chainBounds);
138 fTessellator->draw(flushState);
139 }
140
141 const SkPath fPath;
142 const SkMatrix fMatrix;
143 const GrPipeline::InputFlags fPipelineFlags;
144 const Mode fMode;
145 PathTessellator* fTessellator = nullptr;
146 GrProgramInfo* fProgram;
148
149 friend class GrOp; // For ctor.
150};
151
152} // namespace
153
154// This slide enables wireframe and visualizes the triangles generated by path tessellators.
155class PathTessellatorsSlide : public ClickHandlerSlide {
156public:
157 PathTessellatorsSlide() {
158#if 0
159 // For viewing middle-out triangulations of the inner fan.
160 fPath.moveTo(1, 0);
161 int numSides = 32 * 3;
162 for (int i = 1; i < numSides; ++i) {
163 float theta = 2*3.1415926535897932384626433832785 * i / numSides;
164 fPath.lineTo(std::cos(theta), std::sin(theta));
165 }
168#else
169 fPath.moveTo(100, 500);
170 fPath.cubicTo(300, 400, -100, 300, 100, 200);
171 fPath.quadTo(250, 0, 400, 200);
172 fPath.conicTo(600, 350, 400, 500, fConicWeight);
173 fPath.close();
174#endif
175 fName = "PathTessellators";
176 }
177
178 bool onChar(SkUnichar) override;
179
180 void draw(SkCanvas*) override;
181
182protected:
183 Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
184 bool onClick(Click*) override;
185
188 Mode fMode = Mode::kWedgeMiddleOut;
189
190 float fConicWeight = .5;
191
192 class Click;
193};
194
196 canvas->clear(SK_ColorBLACK);
197
198 auto ctx = canvas->recordingContext();
200
202 if (!sdc || !ctx) {
203 error = "GPU Only.";
204 } else if (!skgpu::ganesh::TessellationPathRenderer::IsSupported(*ctx->priv().caps())) {
205 error = "TessellationPathRenderer not supported.";
206 }
207 if (!error.isEmpty()) {
208 canvas->clear(SK_ColorRED);
210 SkPaint captionPaint;
211 captionPaint.setColor(SK_ColorWHITE);
212 canvas->drawString(error.c_str(), 10, 30, font, captionPaint);
213 return;
214 }
215
216 sdc->addDrawOp(GrOp::Make<SamplePathTessellatorOp>(ctx,
217 sdc->asRenderTargetProxy()->getBoundsRect(),
218 fPath, canvas->getTotalMatrix(),
219 fPipelineFlags, fMode));
220
221 // Draw the path points.
222 SkPaint pointsPaint;
223 pointsPaint.setColor(SK_ColorBLUE);
224 pointsPaint.setStrokeWidth(8);
225 SkPath devPath = fPath;
226 devPath.transform(canvas->getTotalMatrix());
227 {
228 SkAutoCanvasRestore acr(canvas, true);
229 canvas->setMatrix(SkMatrix::I());
230 SkString caption(ModeName(fMode));
231 caption.appendf(" (w=%g)", fConicWeight);
233 SkPaint captionPaint;
234 captionPaint.setColor(SK_ColorWHITE);
235 canvas->drawString(caption, 10, 30, font, captionPaint);
237 SkPathPriv::PointData(devPath), pointsPaint);
238 }
239}
240
241class PathTessellatorsSlide::Click : public ClickHandlerSlide::Click {
242public:
243 Click(int ptIdx) : fPtIdx(ptIdx) {}
244
245 void doClick(SkPath* path) {
246 SkPoint pt = path->getPoint(fPtIdx);
247 SkPathPriv::UpdatePathPoint(path, fPtIdx, pt + fCurr - fPrev);
248 }
249
250private:
251 int fPtIdx;
252};
253
254ClickHandlerSlide::Click* PathTessellatorsSlide::onFindClickHandler(SkScalar x, SkScalar y,
256 const SkPoint* pts = SkPathPriv::PointData(fPath);
257 float fuzz = 30;
258 for (int i = 0; i < fPath.countPoints(); ++i) {
259 if (fabs(x - pts[i].x()) < fuzz && fabsf(y - pts[i].y()) < fuzz) {
260 return new Click(i);
261 }
262 }
263 return nullptr;
264}
265
266bool PathTessellatorsSlide::onClick(ClickHandlerSlide::Click* click) {
267 Click* myClick = (Click*)click;
268 myClick->doClick(&fPath);
269 return true;
270}
271
272static SkPath update_weight(const SkPath& path, float w) {
273 SkPath path_;
274 for (auto [verb, pts, _] : SkPathPriv::Iterate(path)) {
275 switch (verb) {
277 path_.moveTo(pts[0]);
278 break;
280 path_.lineTo(pts[1]);
281 break;
283 path_.quadTo(pts[1], pts[2]);
284 break;
286 path_.cubicTo(pts[1], pts[2], pts[3]);
287 break;
289 path_.conicTo(pts[1], pts[2], (w != 1) ? w : .99f);
290 break;
292 break;
293 }
294 }
295 return path_;
296}
297
298bool PathTessellatorsSlide::onChar(SkUnichar unichar) {
299 switch (unichar) {
300 case 'w':
301 fPipelineFlags = (GrPipeline::InputFlags)(
302 (int)fPipelineFlags ^ (int)GrPipeline::InputFlags::kWireframe);
303 return true;
304 case 'D': {
305 fPath.dump();
306 return true;
307 }
308 case '+':
309 fConicWeight *= 2;
310 fPath = update_weight(fPath, fConicWeight);
311 return true;
312 case '=':
313 fConicWeight *= 5/4.f;
314 fPath = update_weight(fPath, fConicWeight);
315 return true;
316 case '_':
317 fConicWeight *= .5f;
318 fPath = update_weight(fPath, fConicWeight);
319 return true;
320 case '-':
321 fConicWeight *= 4/5.f;
322 fPath = update_weight(fPath, fConicWeight);
323 return true;
324 case '1':
325 case '2':
326 fMode = (Mode)(unichar - '1');
327 return true;
328 }
329 return false;
330}
331
332DEF_SLIDE( return new PathTessellatorsSlide; )
333
334} // namespace skgpu::ganesh
335
336#endif // defined(SK_GANESH)
SkPath fPath
SkMatrix fMatrix
Definition: FillRRectOp.cpp:74
const char * fName
#define DEFINE_OP_CLASS_ID
Definition: GrOp.h:64
GrClampType
Definition: GrTypesPriv.h:228
std::function< void(GrSurfaceProxy *, skgpu::Mipmapped)> GrVisitProxyFunc
Definition: GrTypesPriv.h:943
GrLoadOp
Definition: GrTypesPriv.h:155
GrXferBarrierFlags
#define SkUNREACHABLE
Definition: SkAssert.h:135
@ kSrcOver
r = s + (1-sa)*d
constexpr SkPMColor4f SK_PMColor4fWHITE
Definition: SkColorData.h:380
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
@ kClose
SkPath::RawIter returns 0 points.
@ kCubic
SkPath::RawIter returns 4 points.
@ kConic
SkPath::RawIter returns 3 points + 1 weight.
@ kQuad
SkPath::RawIter returns 3 points.
@ kMove
SkPath::RawIter returns 1 point.
@ kLine
SkPath::RawIter returns 2 points.
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
int32_t SkUnichar
Definition: SkTypes.h:175
#define DEF_SLIDE(code)
Definition: Slide.h:25
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
Definition: aaclip.cpp:27
Definition: GrCaps.h:57
const GrShaderCaps * shaderCaps() const
Definition: GrCaps.h:63
const GrDstProxyView & dstProxyView() const final
GrXferBarrierFlags renderPassBarriers() const final
SkArenaAlloc * allocator() override
const GrSurfaceProxyView & writeView() const final
const GrCaps & caps() const final
void bindPipeline(const GrProgramInfo &programInfo, const SkRect &drawBounds)
bool usesMSAASurface() const final
Definition: GrOp.h:70
static GrPathTessellationShader * Make(const GrShaderCaps &, SkArenaAlloc *, const SkMatrix &viewMatrix, const SkPMColor4f &, PatchAttribs)
static const GrPipeline * CreatePipeline(const GrCaps *, SkArenaAlloc *, skgpu::Swizzle writeViewSwizzle, GrAppliedClip &&, const GrDstProxyView &, GrProcessorSet &&, GrPipeline::InputFlags pipelineFlags)
static GrProgramInfo * MakeProgram(const ProgramArgs &args, const GrTessellationShader *shader, const GrPipeline *pipeline, const GrUserStencilSettings *stencil)
void append(SkArenaAlloc *alloc, SkPoint a, SkPoint b, SkPoint c, int winding)
void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint &paint)
Definition: SkCanvas.cpp:1710
virtual GrRecordingContext * recordingContext() const
Definition: SkCanvas.cpp:1637
void clear(SkColor color)
Definition: SkCanvas.h:1199
SkMatrix getTotalMatrix() const
Definition: SkCanvas.cpp:1629
void setMatrix(const SkM44 &matrix)
Definition: SkCanvas.cpp:1349
void drawString(const char str[], SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
Definition: SkCanvas.h:1803
@ kPoints_PointMode
draw each point separately
Definition: SkCanvas.h:1241
Definition: SkFont.h:35
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
SkPoint mapPoint(SkPoint pt) const
Definition: SkMatrix.h:1374
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
void setColor(SkColor color)
Definition: SkPaint.cpp:119
void setStrokeWidth(SkScalar width)
Definition: SkPaint.cpp:159
static void UpdatePathPoint(SkPath *path, int index, const SkPoint &pt)
Definition: SkPathPriv.h:400
static const SkPoint * PointData(const SkPath &path)
Definition: SkPathPriv.h:203
Definition: SkPath.h:59
int countPoints() const
Definition: SkPath.cpp:535
SkPath & moveTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:688
SkPath & lineTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:728
SkPath & quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Definition: SkPath.cpp:746
int countVerbs() const
Definition: SkPath.cpp:556
SkPath & cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
Definition: SkPath.cpp:799
SkPath & conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w)
Definition: SkPath.cpp:766
SkPath & close()
Definition: SkPath.cpp:823
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkPath.cpp:1711
void dump(SkWStream *stream, bool dumpAsHex) const
Definition: SkPath.cpp:2040
static PathCurveTessellator * Make(SkArenaAlloc *arena, bool infinitySupport, PatchAttribs attribs=PatchAttribs::kNone)
static PathWedgeTessellator * Make(SkArenaAlloc *arena, bool infinitySupport, PatchAttribs attribs=PatchAttribs::kNone)
DlColor color
float SkScalar
Definition: extension.cpp:12
const uint8_t uint32_t uint32_t GError ** error
double y
double x
constexpr SkColor4f kCyan
Definition: SkColor.h:444
sk_sp< SkTypeface > DefaultTypeface()
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
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
font
Font Metadata and Metrics.
static TessellatorLibtess tess
SurfaceDrawContext * TopDeviceSurfaceDrawContext(const SkCanvas *canvas)
Definition: GrCanvas.cpp:20
ModifierKey
Definition: ModifierKey.h:9
SkScalar w
static const GrUserStencilSettings & kUnused
bool fInfinitySupport
Definition: SkSLUtil.h:103
SkBlendMode fMode
Definition: xfermodes.cpp:52