Flutter Engine
The Flutter Engine
DashBench.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2011 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#include "bench/Benchmark.h"
11#include "include/core/SkPath.h"
17#include "src/base/SkRandom.h"
18
19/*
20 * Cases to consider:
21 *
22 * 1. antialiasing on/off (esp. width <= 1)
23 * 2. strokewidth == 0, 1, 2
24 * 3. hline, vline, diagonal, rect, oval
25 * 4. dots [1,1] ([N,N] where N=strokeWidth?) or arbitrary (e.g. [2,1] or [1,2,3,2])
26 */
27static void path_hline(SkPath* path) {
28 path->moveTo(SkIntToScalar(10), SkIntToScalar(10));
29 path->lineTo(SkIntToScalar(600), SkIntToScalar(10));
30}
31
32class DashBench : public Benchmark {
33protected:
36 int fWidth;
38 bool fDoClip;
39
40public:
41 DashBench(const SkScalar intervals[], int count, int width,
42 bool doClip = false) {
43 fIntervals.append(count, intervals);
44 for (int i = 0; i < count; ++i) {
45 fIntervals[i] *= width;
46 }
47 fWidth = width;
48 fName.printf("dash_%d_%s", width, doClip ? "clipped" : "noclip");
49 fDoClip = doClip;
50
52 fPts[1].set(SkIntToScalar(600), SkIntToScalar(10));
53 }
54
55 virtual void makePath(SkPath* path) {
57 }
58
59protected:
60 const char* onGetName() override {
61 return fName.c_str();
62 }
63
64 void onDraw(int loops, SkCanvas* canvas) override {
66 this->setupPaint(&paint);
68 paint.setStrokeWidth(SkIntToScalar(fWidth));
69 paint.setAntiAlias(false);
70
72 this->makePath(&path);
73
75
76 if (fDoClip) {
77 SkRect r = path.getBounds();
78 r.inset(-SkIntToScalar(20), -SkIntToScalar(20));
79 // now move it so we don't intersect
80 r.offset(0, r.height() * 3 / 2);
81 canvas->clipRect(r);
82 }
83
84 this->handlePath(canvas, path, paint, loops);
85 }
86
87 virtual void handlePath(SkCanvas* canvas, const SkPath& path,
88 const SkPaint& paint, int N) {
89 for (int i = 0; i < N; ++i) {
90// canvas->drawPoints(SkCanvas::kLines_PointMode, 2, fPts, paint);
91 canvas->drawPath(path, paint);
92 }
93 }
94
95private:
96 using INHERITED = Benchmark;
97};
98
99class RectDashBench : public DashBench {
100public:
101 RectDashBench(const SkScalar intervals[], int count, int width)
102 : INHERITED(intervals, count, width) {
103 fName.append("_rect");
104 }
105
106protected:
107 void handlePath(SkCanvas* canvas, const SkPath& path, const SkPaint& paint, int N) override {
108 SkPoint pts[2];
109 if (!path.isLine(pts) || pts[0].fY != pts[1].fY) {
110 this->INHERITED::handlePath(canvas, path, paint, N);
111 } else {
112 SkRect rect;
113 rect.fLeft = pts[0].fX;
114 rect.fTop = pts[0].fY - paint.getStrokeWidth() / 2;
115 rect.fRight = rect.fLeft + SkIntToScalar(fWidth);
116 rect.fBottom = rect.fTop + paint.getStrokeWidth();
117
118 SkPaint p(paint);
119 p.setStyle(SkPaint::kFill_Style);
120 p.setPathEffect(nullptr);
121
122 int count = SkScalarRoundToInt((pts[1].fX - pts[0].fX) / (2*fWidth));
124
125 for (int i = 0; i < N*10; ++i) {
126 SkRect r = rect;
127 for (int j = 0; j < count; ++j) {
128 canvas->drawRect(r, p);
129 r.offset(dx, 0);
130 }
131 }
132 }
133 }
134
135private:
136 using INHERITED = DashBench;
137};
138
139static void make_unit_star(SkPath* path, int n) {
140 SkScalar rad = -SK_ScalarPI / 2;
141 const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
142
143 path->moveTo(0, -SK_Scalar1);
144 for (int i = 1; i < n; i++) {
145 rad += drad;
146 path->lineTo(SkScalarCos(rad), SkScalarSin(rad));
147 }
148 path->close();
149}
150
151static void make_poly(SkPath* path) {
153 const SkMatrix matrix = SkMatrix::Scale(100, 100);
154 path->transform(matrix);
155}
156
157static void make_quad(SkPath* path) {
158 SkScalar x0 = SkIntToScalar(10);
159 SkScalar y0 = SkIntToScalar(10);
160 path->moveTo(x0, y0);
161 path->quadTo(x0, y0 + 400 * SK_Scalar1,
162 x0 + 600 * SK_Scalar1, y0 + 400 * SK_Scalar1);
163}
164
165static void make_cubic(SkPath* path) {
166 SkScalar x0 = SkIntToScalar(10);
167 SkScalar y0 = SkIntToScalar(10);
168 path->moveTo(x0, y0);
169 path->cubicTo(x0, y0 + 400 * SK_Scalar1,
170 x0 + 600 * SK_Scalar1, y0 + 400 * SK_Scalar1,
171 x0 + 600 * SK_Scalar1, y0);
172}
173
174class MakeDashBench : public Benchmark {
175 SkString fName;
176 SkPath fPath;
178
179public:
180 MakeDashBench(void (*proc)(SkPath*), const char name[]) {
181 fName.printf("makedash_%s", name);
182 proc(&fPath);
183
184 SkScalar vals[] = { SkIntToScalar(4), SkIntToScalar(4) };
185 fPE = SkDashPathEffect::Make(vals, 2, 0);
186 }
187
188protected:
189 const char* onGetName() override {
190 return fName.c_str();
191 }
192
193 void onDraw(int loops, SkCanvas*) override {
194 SkPath dst;
195 for (int i = 0; i < loops; ++i) {
197
198 fPE->filterPath(&dst, fPath, &rec, nullptr);
199 dst.rewind();
200 }
201 }
202
203private:
204 using INHERITED = Benchmark;
205};
206
207/*
208 * We try to special case square dashes (intervals are equal to strokewidth).
209 */
210class DashLineBench : public Benchmark {
212 SkScalar fStrokeWidth;
213 bool fIsRound;
215
216public:
217 DashLineBench(SkScalar width, bool isRound) {
218 fName.printf("dashline_%g_%s", width, isRound ? "circle" : "square");
219 fStrokeWidth = width;
220 fIsRound = isRound;
221
222 SkScalar vals[] = { SK_Scalar1, SK_Scalar1 };
223 fPE = SkDashPathEffect::Make(vals, 2, 0);
224 }
225
226protected:
227 const char* onGetName() override {
228 return fName.c_str();
229 }
230
231 void onDraw(int loops, SkCanvas* canvas) override {
233 this->setupPaint(&paint);
234 paint.setStrokeWidth(fStrokeWidth);
235 paint.setStrokeCap(fIsRound ? SkPaint::kRound_Cap : SkPaint::kSquare_Cap);
236 paint.setPathEffect(fPE);
237 for (int i = 0; i < loops; ++i) {
238 canvas->drawLine(10 * SK_Scalar1, 10 * SK_Scalar1,
239 640 * SK_Scalar1, 10 * SK_Scalar1, paint);
240 }
241 }
242
243private:
244 using INHERITED = Benchmark;
245};
246
249 int fStrokeWidth;
250 bool fDoAA;
251
252 sk_sp<SkPathEffect> fPathEffect;
253
254public:
255 DrawPointsDashingBench(int dashLength, int strokeWidth, bool doAA)
256 {
257 fName.printf("drawpointsdash_%d_%d%s", dashLength, strokeWidth, doAA ? "_aa" : "_bw");
258 fStrokeWidth = strokeWidth;
259 fDoAA = doAA;
260
261 SkScalar vals[] = { SkIntToScalar(dashLength), SkIntToScalar(dashLength) };
262 fPathEffect = SkDashPathEffect::Make(vals, 2, SK_Scalar1);
263 }
264
265protected:
266 const char* onGetName() override {
267 return fName.c_str();
268 }
269
270 void onDraw(int loops, SkCanvas* canvas) override {
271 SkPaint p;
272 this->setupPaint(&p);
273 p.setColor(SK_ColorBLACK);
274 p.setStyle(SkPaint::kStroke_Style);
275 p.setStrokeWidth(SkIntToScalar(fStrokeWidth));
276 p.setPathEffect(fPathEffect);
277 p.setAntiAlias(fDoAA);
278
279 SkPoint pts[2] = {
280 { SkIntToScalar(10), 0 },
281 { SkIntToScalar(640), 0 }
282 };
283
284 for (int i = 0; i < loops; ++i) {
285 pts[0].fY = pts[1].fY = SkIntToScalar(i % 480);
286 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
287 }
288 }
289
290private:
291 using INHERITED = Benchmark;
292};
293
294// Want to test how we handle dashing when 99% of the dash is clipped out
295class GiantDashBench : public Benchmark {
297 SkScalar fStrokeWidth;
298 SkPoint fPts[2];
299 sk_sp<SkPathEffect> fPathEffect;
300
301public:
302 enum LineType {
307 };
308
309 static const char* LineTypeName(LineType lt) {
310 static const char* gNames[] = { "hori", "vert", "diag" };
311 static_assert(kLineTypeCount == std::size(gNames), "names_wrong_size");
312 return gNames[lt];
313 }
314
316 fName.printf("giantdashline_%s_%g", LineTypeName(lt), width);
317 fStrokeWidth = width;
318
319 // deliberately pick intervals that won't be caught by asPoints(), so
320 // we can test the filterPath code-path.
321 const SkScalar intervals[] = { 20, 10, 10, 10 };
322 fPathEffect = SkDashPathEffect::Make(intervals, std::size(intervals), 0);
323
324 SkScalar cx = 640 / 2; // center X
325 SkScalar cy = 480 / 2; // center Y
327
328 switch (lt) {
329 case kHori_LineType:
330 matrix.setIdentity();
331 break;
332 case kVert_LineType:
333 matrix.setRotate(90, cx, cy);
334 break;
335 case kDiag_LineType:
336 matrix.setRotate(45, cx, cy);
337 break;
338 case kLineTypeCount:
339 // Not a real enum value.
340 break;
341 }
342
343 const SkScalar overshoot = 100*1000;
344 const SkPoint pts[2] = {
345 { -overshoot, cy }, { 640 + overshoot, cy }
346 };
347 matrix.mapPoints(fPts, pts, 2);
348 }
349
350protected:
351 const char* onGetName() override {
352 return fName.c_str();
353 }
354
355 void onDraw(int loops, SkCanvas* canvas) override {
356 SkPaint p;
357 this->setupPaint(&p);
358 p.setStyle(SkPaint::kStroke_Style);
359 p.setStrokeWidth(fStrokeWidth);
360 p.setPathEffect(fPathEffect);
361
362 for (int i = 0; i < loops; i++) {
364 }
365 }
366
367private:
368 using INHERITED = Benchmark;
369};
370
371// Want to test how we draw a dashed grid (like what is used in spreadsheets) of many
372// small dashed lines switching back and forth between horizontal and vertical
373class DashGridBench : public Benchmark {
375 int fStrokeWidth;
376 bool fDoAA;
377
378 sk_sp<SkPathEffect> fPathEffect;
379
380public:
381 DashGridBench(int dashLength, int strokeWidth, bool doAA) {
382 fName.printf("dashgrid_%d_%d%s", dashLength, strokeWidth, doAA ? "_aa" : "_bw");
383 fStrokeWidth = strokeWidth;
384 fDoAA = doAA;
385
386 SkScalar vals[] = { SkIntToScalar(dashLength), SkIntToScalar(dashLength) };
387 fPathEffect = SkDashPathEffect::Make(vals, 2, SK_Scalar1);
388 }
389
390protected:
391 const char* onGetName() override {
392 return fName.c_str();
393 }
394
395 void onDraw(int loops, SkCanvas* canvas) override {
396 SkPaint p;
397 this->setupPaint(&p);
398 p.setColor(SK_ColorBLACK);
399 p.setStyle(SkPaint::kStroke_Style);
400 p.setStrokeWidth(SkIntToScalar(fStrokeWidth));
401 p.setPathEffect(fPathEffect);
402 p.setAntiAlias(fDoAA);
403
404 SkPoint pts[4] = {
405 { SkIntToScalar(0), 20.5f },
406 { SkIntToScalar(20), 20.5f },
407 { 20.5f, SkIntToScalar(0) },
408 { 20.5f, SkIntToScalar(20) }
409 };
410
411 for (int i = 0; i < loops; ++i) {
412 for (int j = 0; j < 10; ++j) {
413 for (int k = 0; k < 10; ++k) {
414 // Horizontal line
415 SkPoint horPts[2];
416 horPts[0].fX = pts[0].fX + k * 22.f;
417 horPts[0].fY = pts[0].fY + j * 22.f;
418 horPts[1].fX = pts[1].fX + k * 22.f;
419 horPts[1].fY = pts[1].fY + j * 22.f;
420 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, horPts, p);
421
422 // Vertical line
423 SkPoint vertPts[2];
424 vertPts[0].fX = pts[2].fX + k * 22.f;
425 vertPts[0].fY = pts[2].fY + j * 22.f;
426 vertPts[1].fX = pts[3].fX + k * 22.f;
427 vertPts[1].fY = pts[3].fY + j * 22.f;
428 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, vertPts, p);
429 }
430 }
431 }
432 }
433
434private:
435 using INHERITED = Benchmark;
436};
437
438///////////////////////////////////////////////////////////////////////////////
439
440static const SkScalar gDots[] = { SK_Scalar1, SK_Scalar1 };
441
442#define PARAM(array) array, std::size(array)
443
444DEF_BENCH( return new DashBench(PARAM(gDots), 0); )
445DEF_BENCH( return new DashBench(PARAM(gDots), 1); )
446DEF_BENCH( return new DashBench(PARAM(gDots), 1, true); )
447DEF_BENCH( return new DashBench(PARAM(gDots), 4); )
448DEF_BENCH( return new MakeDashBench(make_poly, "poly"); )
449DEF_BENCH( return new MakeDashBench(make_quad, "quad"); )
450DEF_BENCH( return new MakeDashBench(make_cubic, "cubic"); )
451DEF_BENCH( return new DashLineBench(0, false); )
452DEF_BENCH( return new DashLineBench(SK_Scalar1, false); )
453DEF_BENCH( return new DashLineBench(2 * SK_Scalar1, false); )
454DEF_BENCH( return new DashLineBench(0, true); )
455DEF_BENCH( return new DashLineBench(SK_Scalar1, true); )
456DEF_BENCH( return new DashLineBench(2 * SK_Scalar1, true); )
457
458DEF_BENCH( return new DrawPointsDashingBench(1, 1, false); )
459DEF_BENCH( return new DrawPointsDashingBench(1, 1, true); )
460DEF_BENCH( return new DrawPointsDashingBench(3, 1, false); )
461DEF_BENCH( return new DrawPointsDashingBench(3, 1, true); )
462DEF_BENCH( return new DrawPointsDashingBench(5, 5, false); )
463DEF_BENCH( return new DrawPointsDashingBench(5, 5, true); )
464
465/* Disable the GiantDashBench for Android devices until we can better control
466 * the memory usage. (https://code.google.com/p/skia/issues/detail?id=1430)
467 */
468#ifndef SK_BUILD_FOR_ANDROID
472
473// pass 2 to explicitly avoid any 1-is-the-same-as-hairline special casing
474
475// hori_2 is just too slow to enable at the moment
479
480DEF_BENCH( return new DashGridBench(1, 1, true); )
481DEF_BENCH( return new DashGridBench(1, 1, false); )
482DEF_BENCH( return new DashGridBench(3, 1, true); )
483DEF_BENCH( return new DashGridBench(3, 1, false); )
484#endif
SkPoint fPts[2]
SkPath fPath
static const int strokeWidth
Definition: BlurTest.cpp:60
static const SkScalar gDots[]
Definition: DashBench.cpp:440
static void path_hline(SkPath *path)
Definition: DashBench.cpp:27
static void make_cubic(SkPath *path)
Definition: DashBench.cpp:165
static void make_quad(SkPath *path)
Definition: DashBench.cpp:157
DEF_BENCH(return new DashBench(PARAM(gDots), 0);) DEF_BENCH(return new DashBench(PARAM(gDots)
static void make_unit_star(SkPath *path, int n)
Definition: DashBench.cpp:139
static void make_poly(SkPath *path)
Definition: DashBench.cpp:151
#define PARAM(array)
Definition: DashBench.cpp:442
const char * fName
int count
Definition: FontMgrTest.cpp:50
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
#define SkScalarSin(radians)
Definition: SkScalar.h:45
#define SK_Scalar1
Definition: SkScalar.h:18
#define SkScalarRoundToInt(x)
Definition: SkScalar.h:37
#define SkIntToScalar(x)
Definition: SkScalar.h:57
#define SkScalarCos(radians)
Definition: SkScalar.h:46
#define SK_ScalarPI
Definition: SkScalar.h:21
#define N
Definition: beziers.cpp:19
virtual void setupPaint(SkPaint *paint)
Definition: Benchmark.cpp:55
SkPoint fPts[2]
Definition: DashBench.cpp:37
DashBench(const SkScalar intervals[], int count, int width, bool doClip=false)
Definition: DashBench.cpp:41
bool fDoClip
Definition: DashBench.cpp:38
const char * onGetName() override
Definition: DashBench.cpp:60
virtual void makePath(SkPath *path)
Definition: DashBench.cpp:55
int fWidth
Definition: DashBench.cpp:36
SkString fName
Definition: DashBench.cpp:34
SkTDArray< SkScalar > fIntervals
Definition: DashBench.cpp:35
virtual void handlePath(SkCanvas *canvas, const SkPath &path, const SkPaint &paint, int N)
Definition: DashBench.cpp:87
void onDraw(int loops, SkCanvas *canvas) override
Definition: DashBench.cpp:64
void onDraw(int loops, SkCanvas *canvas) override
Definition: DashBench.cpp:395
DashGridBench(int dashLength, int strokeWidth, bool doAA)
Definition: DashBench.cpp:381
const char * onGetName() override
Definition: DashBench.cpp:391
const char * onGetName() override
Definition: DashBench.cpp:227
void onDraw(int loops, SkCanvas *canvas) override
Definition: DashBench.cpp:231
DashLineBench(SkScalar width, bool isRound)
Definition: DashBench.cpp:217
void onDraw(int loops, SkCanvas *canvas) override
Definition: DashBench.cpp:270
const char * onGetName() override
Definition: DashBench.cpp:266
DrawPointsDashingBench(int dashLength, int strokeWidth, bool doAA)
Definition: DashBench.cpp:255
static const char * LineTypeName(LineType lt)
Definition: DashBench.cpp:309
void onDraw(int loops, SkCanvas *canvas) override
Definition: DashBench.cpp:355
const char * onGetName() override
Definition: DashBench.cpp:351
GiantDashBench(LineType lt, SkScalar width)
Definition: DashBench.cpp:315
const char * onGetName() override
Definition: DashBench.cpp:189
void onDraw(int loops, SkCanvas *) override
Definition: DashBench.cpp:193
MakeDashBench(void(*proc)(SkPath *), const char name[])
Definition: DashBench.cpp:180
void handlePath(SkCanvas *canvas, const SkPath &path, const SkPaint &paint, int N) override
Definition: DashBench.cpp:107
RectDashBench(const SkScalar intervals[], int count, int width)
Definition: DashBench.cpp:101
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1361
void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint &paint)
Definition: SkCanvas.cpp:1710
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
Definition: SkCanvas.cpp:2700
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
@ kLines_PointMode
draw each pair of points as a line segment
Definition: SkCanvas.h:1242
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
@ kRound_Cap
adds circle
Definition: SkPaint.h:335
@ kSquare_Cap
adds square
Definition: SkPaint.h:336
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
bool filterPath(SkPath *dst, const SkPath &src, SkStrokeRec *, const SkRect *cullR) const
Definition: SkPath.h:59
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:534
void append(const char text[])
Definition: SkString.h:203
const char * c_str() const
Definition: SkString.h:133
@ kHairline_InitStyle
Definition: SkStrokeRec.h:25
int size() const
Definition: SkTDArray.h:138
T * begin()
Definition: SkTDArray.h:150
T * append()
Definition: SkTDArray.h:191
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
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 keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
int32_t width
float fX
x-axis value
Definition: SkPoint_impl.h:164
void set(float x, float y)
Definition: SkPoint_impl.h:200
float fY
y-axis value
Definition: SkPoint_impl.h:165
void inset(float dx, float dy)
Definition: SkRect.h:1060
void offset(float dx, float dy)
Definition: SkRect.h:1016
constexpr float height() const
Definition: SkRect.h:769