Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
dl_benchmarks.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
14
15#include "third_party/skia/include/core/SkBitmap.h"
16#include "third_party/skia/include/core/SkImage.h"
17#include "third_party/skia/include/core/SkSurface.h"
18#include "third_party/skia/include/core/SkTextBlob.h"
19
20// This label can be defined to produce snapshots of what the benchmarks
21// are drawing for debugging purposes. (Disabled here for production use.)
22#undef WRITE_BENCHMARK_SNAPSHOTS
23
24namespace flutter {
25namespace testing {
26
27namespace {
28
29inline void SaveSnapshotIfNecessary(
30 const std::unique_ptr<DlSurfaceProvider>& provider,
31 const std::shared_ptr<DlSurfaceInstance>& surface,
32 benchmark::State& state,
33 const std::string& test_name) {
34#ifdef WRITE_BENCHMARK_SNAPSHOTS
35 auto filename = provider->GetBackendName() + "-" + test_name + "-" +
36 std::to_string(state.range(0)) + ".png";
37 surface->SnapshotToFile(filename);
38#endif // WRITE_BENCHMARK_SNAPSHOTS
39}
40
41class RectAnimator {
42 public:
43 RectAnimator(DlRect rect, DlPoint animation_delta, DlISize animation_limit)
44 : rect_(rect),
45 rect_origin_(rect.GetOrigin()),
46 animation_delta_(animation_delta),
47 animation_limit_(animation_limit) {}
48
49 RectAnimator(DlRect rect,
50 DlPoint animation_delta,
51 const std::shared_ptr<DlSurfaceInstance>& surface)
52 : RectAnimator(rect, animation_delta, surface->GetSize()) {}
53
54 void Animate() {
55 rect_ = rect_.Shift(animation_delta_);
56 if (rect_.GetRight() > animation_limit_.width) {
57 rect_ = rect_.Shift(rect_origin_.x - rect_.GetLeft(), 0);
58 }
59 if (rect_.GetBottom() > animation_limit_.height) {
60 rect_ = rect_.Shift(0, rect_origin_.y - rect_.GetTop());
61 }
62 }
63
64 const DlRect& GetRect() const { return rect_; }
65 const DlPoint GetPoint() const { return rect_.GetOrigin(); }
66 const DlPoint GetCenter() const { return rect_.GetCenter(); }
67
68 private:
69 DlRect rect_;
70 const DlPoint rect_origin_;
71
72 const DlPoint animation_delta_;
73 const DlSize animation_limit_;
74};
75
76class DlPathVerbCounter : public DlPathReceiver {
77 public:
78 void MoveTo(const DlPoint& p2, bool will_be_closed) override {
79 verb_count_++;
80 }
81 void LineTo(const DlPoint& p2) override { verb_count_++; }
82 void QuadTo(const DlPoint& cp, const DlPoint& p2) override { verb_count_++; }
83 bool ConicTo(const DlPoint& cp, const DlPoint& p2, DlScalar weight) override {
84 verb_count_++;
85 return false;
86 }
87 void CubicTo(const DlPoint& cp1,
88 const DlPoint& cp2,
89 const DlPoint& p2) override {
90 verb_count_++;
91 }
92 void Close() override { verb_count_++; }
93
94 uint32_t GetVerbCount() const { return verb_count_; }
95
96 private:
97 uint32_t verb_count_ = 0u;
98};
99
100DlPaint GetPaintForRun(unsigned attributes) {
101 DlPaint paint;
102
103 if (attributes & kStrokedStyle && attributes & kFilledStyle) {
104 // Not currently exposed by Flutter, but we can probably benchmark this in
105 // the future
107 } else if (attributes & kStrokedStyle) {
109 } else if (attributes & kFilledStyle) {
111 }
112
113 if (attributes & kHairlineStroke) {
114 paint.setStrokeWidth(0.0f);
115 } else if (attributes & kWideStroke10) {
116 paint.setStrokeWidth(10.0f);
117 } else {
118 paint.setStrokeWidth(1.0f);
119 }
120
121 if (attributes & kShadow5) {
122 static auto blur5filter =
124 paint.setMaskFilter(blur5filter);
125 } else if (attributes & kShadow10) {
126 static auto blur10filter =
128 paint.setMaskFilter(blur10filter);
129 }
130
131 paint.setAntiAlias(attributes & kAntiAliasing);
132 return paint;
133}
134
135void CheckAttributes(uint32_t attributes,
136 benchmark::State& state,
137 const DisplayListAttributeFlags flags) {
138 if (flags.always_stroked() && attributes & kFilledStyle) {
139 state.SkipWithError("Cannot fill an operation that is always stroked");
140 }
141 if (flags.applies_style()) {
142 if ((attributes & kFilledStyle) == 0 && (attributes & kStrokedStyle) == 0) {
143 state.SkipWithError("must specify stroked and/or filled style");
144 }
145 if ((attributes & kStrokedStyle) == 0) {
146 if ((attributes & kHairlineStroke) || (attributes & kWideStroke10)) {
147 state.SkipWithError("Cannot specify stroke style if op is not stroked");
148 }
149 }
150 }
151}
152
153// Constants chosen to produce benchmark results in the region of 1-50ms
154constexpr size_t kLinesToDraw = 10000;
155constexpr size_t kRectsToDraw = 5000;
156constexpr size_t kOvalsToDraw = 5000;
157constexpr size_t kCirclesToDraw = 5000;
158constexpr size_t kRRectsToDraw = 5000;
159constexpr size_t kRSEsToDraw = 5000;
160constexpr size_t kDRRectsToDraw = 2000;
161constexpr size_t kArcSweepSetsToDraw = 1000;
162constexpr size_t kImagesToDraw = 500;
163constexpr size_t kFixedCanvasSize = 1024;
164
165} // namespace
166
167// Perform just a surface sync on each iteration to determine how much
168// overhead the "Flush and Sync" operation costs.
169void BM_SyncOverhead(benchmark::State& state, BackendType backend_type) {
170 auto surface_provider = DlSurfaceProvider::Create(backend_type);
171
172 size_t length = state.range(0);
173
174 surface_provider->InitializeSurface(length, length);
175 auto surface = surface_provider->GetPrimarySurface();
177 surface->FlushSubmitCpuSync();
178
179 // We only want to time the surface Sync.
180 for ([[maybe_unused]] auto _ : state) {
181 surface->FlushSubmitCpuSync();
182 }
183}
184
185// Render an empty DisplayList to check the overhead of just calling the
186// DlSurfaceInstance::RenderDisplayList method even with no work to do.
187void BM_EmptyDisplayList(benchmark::State& state, BackendType backend_type) {
188 auto surface_provider = DlSurfaceProvider::Create(backend_type);
189
190 size_t length = state.range(0);
191
192 surface_provider->InitializeSurface(length, length);
193 auto surface = surface_provider->GetPrimarySurface();
195 surface->FlushSubmitCpuSync();
196
197 DisplayListBuilder builder;
198 auto display_list = builder.Build();
199
200 // We only want to time the surface Sync.
201 for ([[maybe_unused]] auto _ : state) {
202 surface->RenderDisplayList(display_list);
203 surface->FlushSubmitCpuSync();
204 }
205}
206
207// Render a DisplayList with a single tiny 1x1 rect to check the overhead of
208// processing a DisplayList with minimal non-empty contents.
209void BM_SingleOpDisplayList(benchmark::State& state, BackendType backend_type) {
210 auto surface_provider = DlSurfaceProvider::Create(backend_type);
211
212 size_t length = state.range(0);
213
214 surface_provider->InitializeSurface(length, length);
215 auto surface = surface_provider->GetPrimarySurface();
217 surface->FlushSubmitCpuSync();
218
219 DisplayListBuilder builder;
220 builder.DrawRect(DlRect::MakeLTRB(0, 0, 1, 1), DlPaint());
221 auto display_list = builder.Build();
222
223 // We only want to time the surface Sync.
224 for ([[maybe_unused]] auto _ : state) {
225 surface->RenderDisplayList(display_list);
226 surface->FlushSubmitCpuSync();
227 }
228}
229
230// Draw a series of diagonal lines across a square canvas of width/height of
231// the length requested. The lines will start from the top left corner to the
232// bottom right corner, and move from left to right (at the top) and from right
233// to left (at the bottom) until 10,000 lines are drawn.
234//
235// The resulting image will be an hourglass shape.
236void BM_DrawLine(benchmark::State& state,
237 BackendType backend_type,
238 unsigned attributes) {
239 auto surface_provider = DlSurfaceProvider::Create(backend_type);
240 DisplayListBuilder builder;
241 DlPaint paint = GetPaintForRun(attributes);
242
243 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawLineFlags);
244
245 size_t length = state.range(0);
246
247 surface_provider->InitializeSurface(length, length);
248 auto surface = surface_provider->GetPrimarySurface();
250 surface->FlushSubmitCpuSync();
251
252 state.counters["DrawCallCount"] = kLinesToDraw;
253 for (size_t i = 0; i < kLinesToDraw; i++) {
254 builder.DrawLine(DlPoint(i % length, 0),
255 DlPoint(length - i % length, length), paint);
256 }
257
258 auto display_list = builder.Build();
259 FML_CHECK(display_list->GetRecordCount() >= kLinesToDraw);
260
261 // We only want to time the actual rasterization.
262 size_t items_processed = 0;
263 for ([[maybe_unused]] auto _ : state) {
264 surface->RenderDisplayList(display_list);
265 items_processed += kLinesToDraw;
266 surface->FlushSubmitCpuSync();
267 }
268 state.SetItemsProcessed(items_processed);
269
270 SaveSnapshotIfNecessary(surface_provider, surface, state, "DrawLine");
271}
272
273// Draws a series of square rects of the requested width across
274// the canvas and repeats until `kRectsToDraw` rects have been drawn.
275//
276// Half the drawn rects will not have an integral offset.
277void BM_DrawRect(benchmark::State& state,
278 BackendType backend_type,
279 unsigned attributes) {
280 auto surface_provider = DlSurfaceProvider::Create(backend_type);
281 DisplayListBuilder builder;
282 DlPaint paint = GetPaintForRun(attributes);
283
284 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawRectFlags);
285
286 size_t length = state.range(0);
287 surface_provider->InitializeSurface(length * 2, length * 2);
288 auto surface = surface_provider->GetPrimarySurface();
290 surface->FlushSubmitCpuSync();
291
292 // As rects have DlScalar dimensions, we want to ensure that we also
293 // draw rects with non-integer position and size
294 const DlPoint delta(0.5f, 0.5f);
295 RectAnimator animator(DlRect::MakeWH(length, length), delta, surface);
296
297 state.counters["DrawCallCount"] = kRectsToDraw;
298 for (size_t i = 0; i < kRectsToDraw; i++) {
299 builder.DrawRect(animator.GetRect(), paint);
300 animator.Animate();
301 }
302
303 auto display_list = builder.Build();
304 FML_CHECK(display_list->GetRecordCount() >= kRectsToDraw);
305
306 // We only want to time the actual rasterization.
307 size_t items_processed = 0;
308 for ([[maybe_unused]] auto _ : state) {
309 surface->RenderDisplayList(display_list);
310 items_processed += kRectsToDraw;
311 surface->FlushSubmitCpuSync();
312 }
313 state.SetItemsProcessed(items_processed);
314
315 SaveSnapshotIfNecessary(surface_provider, surface, state, "DrawRect");
316}
317
318// Draws a series of ovals of the requested height with aspect ratio 3:2 across
319// the canvas and repeats until `kOvalsToDraw` ovals have been drawn.
320//
321// Half the drawn ovals will not have an integral offset.
322void BM_DrawOval(benchmark::State& state,
323 BackendType backend_type,
324 unsigned attributes) {
325 auto surface_provider = DlSurfaceProvider::Create(backend_type);
326 DisplayListBuilder builder;
327 DlPaint paint = GetPaintForRun(attributes);
328
329 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawOvalFlags);
330
331 size_t length = state.range(0);
332 surface_provider->InitializeSurface(length * 2, length * 2);
333 auto surface = surface_provider->GetPrimarySurface();
335 surface->FlushSubmitCpuSync();
336
337 const DlPoint delta(0.5f, 0.5f);
338 DlSize size(length * 1.5f, length);
339 RectAnimator animator(DlRect::MakeSize(size), delta, surface);
340
341 state.counters["DrawCallCount"] = kOvalsToDraw;
342 for (size_t i = 0; i < kOvalsToDraw; i++) {
343 builder.DrawOval(animator.GetRect(), paint);
344 animator.Animate();
345 }
346 auto display_list = builder.Build();
347 FML_CHECK(display_list->GetRecordCount() >= kOvalsToDraw);
348
349 // We only want to time the actual rasterization.
350 size_t items_processed = 0;
351 for ([[maybe_unused]] auto _ : state) {
352 surface->RenderDisplayList(display_list);
353 items_processed += kOvalsToDraw;
354 surface->FlushSubmitCpuSync();
355 }
356 state.SetItemsProcessed(items_processed);
357
358 SaveSnapshotIfNecessary(surface_provider, surface, state, "DrawOval");
359}
360
361// Draws a series of circles of the requested radius across
362// the canvas and repeats until `kCirclesToDraw` circles have been drawn.
363//
364// Half the drawn circles will not have an integral center point.
365void BM_DrawCircle(benchmark::State& state,
366 BackendType backend_type,
367 unsigned attributes) {
368 auto surface_provider = DlSurfaceProvider::Create(backend_type);
369 DisplayListBuilder builder;
370 DlPaint paint = GetPaintForRun(attributes);
371
372 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawCircleFlags);
373
374 size_t length = state.range(0);
375 surface_provider->InitializeSurface(length * 2, length * 2);
376 auto surface = surface_provider->GetPrimarySurface();
378 surface->FlushSubmitCpuSync();
379
380 DlScalar radius = length / 2.0f;
381 const DlPoint delta(0.5f, 0.5f);
382 RectAnimator animator(DlRect::MakeWH(length, length), delta, surface);
383
384 state.counters["DrawCallCount"] = kCirclesToDraw;
385 for (size_t i = 0; i < kCirclesToDraw; i++) {
386 builder.DrawCircle(animator.GetCenter(), radius, paint);
387 animator.Animate();
388 }
389 auto display_list = builder.Build();
390 FML_CHECK(display_list->GetRecordCount() >= kCirclesToDraw);
391
392 // We only want to time the actual rasterization.
393 size_t items_processed = 0;
394 for ([[maybe_unused]] auto _ : state) {
395 surface->RenderDisplayList(display_list);
396 items_processed += kCirclesToDraw;
397 surface->FlushSubmitCpuSync();
398 }
399 state.SetItemsProcessed(items_processed);
400
401 SaveSnapshotIfNecessary(surface_provider, surface, state, "DrawCircle");
402}
403
404// Draws a series of rounded rects of the requested width across
405// the canvas and repeats until `kRRectsToDraw` rects have been drawn.
406//
407// Half the drawn rounded rects will not have an integral offset.
408void BM_DrawRRect(benchmark::State& state,
409 BackendType backend_type,
410 unsigned attributes,
411 RRectType type) {
412 auto surface_provider = DlSurfaceProvider::Create(backend_type);
413 DisplayListBuilder builder;
414 DlPaint paint = GetPaintForRun(attributes);
415
416 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawRRectFlags);
417
418 size_t length = state.range(0);
419 surface_provider->InitializeSurface(length * 2, length * 2);
420 auto surface = surface_provider->GetPrimarySurface();
422 surface->FlushSubmitCpuSync();
423
424 DlRoundingRadii radii;
425 // Keep all radii under 8 so that they won't overflow the rrect
426 // bounds which are 16 units wide at the smallest.
427 switch (type) {
429 radii.top_left = DlSize(5.0f, 5.0f);
430 radii.top_right = DlSize(5.0f, 5.0f);
431 radii.bottom_right = DlSize(5.0f, 5.0f);
432 radii.bottom_left = DlSize(5.0f, 5.0f);
433 break;
435 radii.top_left = DlSize(5.0f, 2.0f);
436 radii.top_right = DlSize(3.0f, 2.0f);
437 radii.bottom_right = DlSize(3.0f, 4.0f);
438 radii.bottom_left = DlSize(5.0f, 4.0f);
439 break;
441 radii.top_left = DlSize(5.0f, 4.0f);
442 radii.top_right = DlSize(4.0f, 5.0f);
443 radii.bottom_right = DlSize(3.0f, 6.0f);
444 radii.bottom_left = DlSize(2.0f, 7.0f);
445 break;
446 default:
448 }
449
450 const DlPoint delta = DlPoint(0.5f, 0.5f);
451 const DlScalar multiplier = length / 16.0f;
452 RectAnimator animator(DlRect::MakeWH(length, length), delta, surface);
453
454 radii = radii * multiplier;
455
456 state.counters["DrawCallCount"] = kRRectsToDraw;
457 for (size_t i = 0; i < kRRectsToDraw; i++) {
458 DlRoundRect rrect = DlRoundRect::MakeRectRadii(animator.GetRect(), radii);
459 builder.DrawRoundRect(rrect, paint);
460 animator.Animate();
461 }
462 auto display_list = builder.Build();
463 FML_CHECK(display_list->GetRecordCount() >= kRRectsToDraw);
464
465 // We only want to time the actual rasterization.
466 size_t items_processed = 0;
467 for ([[maybe_unused]] auto _ : state) {
468 surface->RenderDisplayList(display_list);
469 items_processed += kRRectsToDraw;
470 surface->FlushSubmitCpuSync();
471 }
472 state.SetItemsProcessed(items_processed);
473
474 SaveSnapshotIfNecessary(surface_provider, surface, state, "DrawRRect");
475}
476
477void BM_DrawSimpleRRect(benchmark::State& state,
478 BackendType backend_type,
479 unsigned attributes) {
480 BM_DrawRRect(state, backend_type, attributes, RRectType::kSimple);
481}
482
483void BM_DrawNinePatchRRect(benchmark::State& state,
484 BackendType backend_type,
485 unsigned attributes) {
486 BM_DrawRRect(state, backend_type, attributes, RRectType::kNinePatch);
487}
488
489void BM_DrawComplexRRect(benchmark::State& state,
490 BackendType backend_type,
491 unsigned attributes) {
492 BM_DrawRRect(state, backend_type, attributes, RRectType::kComplex);
493}
494
495// Draws a series of rounded superellipses of the requested width across
496// the canvas and repeats until `kRSEsToDraw` rects have been drawn.
497//
498// Half the drawn rounded rects will not have an integral offset.
499void BM_DrawRSE(benchmark::State& state,
500 BackendType backend_type,
501 unsigned attributes,
502 RRectType type) {
503 auto surface_provider = DlSurfaceProvider::Create(backend_type);
504 DisplayListBuilder builder;
505 DlPaint paint = GetPaintForRun(attributes);
506
507 CheckAttributes(attributes, state,
509
510 size_t length = state.range(0);
511 surface_provider->InitializeSurface(length * 2, length * 2);
512 auto surface = surface_provider->GetPrimarySurface();
514 surface->FlushSubmitCpuSync();
515
516 DlRoundingRadii radii;
517 // Keep all radii under 8 so that they won't overflow the rrect
518 // bounds which are 16 units wide at the smallest.
519 switch (type) {
521 radii.top_left = DlSize(5.0f, 5.0f);
522 radii.top_right = DlSize(5.0f, 5.0f);
523 radii.bottom_right = DlSize(5.0f, 5.0f);
524 radii.bottom_left = DlSize(5.0f, 5.0f);
525 break;
527 radii.top_left = DlSize(5.0f, 2.0f);
528 radii.top_right = DlSize(3.0f, 2.0f);
529 radii.bottom_right = DlSize(3.0f, 4.0f);
530 radii.bottom_left = DlSize(5.0f, 4.0f);
531 break;
533 radii.top_left = DlSize(5.0f, 4.0f);
534 radii.top_right = DlSize(4.0f, 5.0f);
535 radii.bottom_right = DlSize(3.0f, 6.0f);
536 radii.bottom_left = DlSize(2.0f, 7.0f);
537 break;
538 default:
540 }
541
542 const DlPoint delta = DlPoint(0.5f, 0.5f);
543 const DlScalar multiplier = length / 16.0f;
544 RectAnimator animator(DlRect::MakeWH(length, length), delta, surface);
545
546 radii = radii * multiplier;
547
548 state.counters["DrawCallCount"] = kRSEsToDraw;
549 for (size_t i = 0; i < kRSEsToDraw; i++) {
551 DlRoundSuperellipse::MakeRectRadii(animator.GetRect(), radii);
552 builder.DrawRoundSuperellipse(rse, paint);
553 animator.Animate();
554 }
555 auto display_list = builder.Build();
556 FML_CHECK(display_list->GetRecordCount() >= kRSEsToDraw);
557
558 // We only want to time the actual rasterization.
559 size_t items_processed = 0;
560 for ([[maybe_unused]] auto _ : state) {
561 surface->RenderDisplayList(display_list);
562 items_processed += kRSEsToDraw;
563 surface->FlushSubmitCpuSync();
564 }
565 state.SetItemsProcessed(items_processed);
566
567 SaveSnapshotIfNecessary(surface_provider, surface, state, "DrawRSE");
568}
569
570void BM_DrawSimpleRSE(benchmark::State& state,
571 BackendType backend_type,
572 unsigned attributes) {
573 BM_DrawRSE(state, backend_type, attributes, RRectType::kSimple);
574}
575
576void BM_DrawNinePatchRSE(benchmark::State& state,
577 BackendType backend_type,
578 unsigned attributes) {
579 BM_DrawRSE(state, backend_type, attributes, RRectType::kNinePatch);
580}
581
582void BM_DrawComplexRSE(benchmark::State& state,
583 BackendType backend_type,
584 unsigned attributes) {
585 BM_DrawRSE(state, backend_type, attributes, RRectType::kComplex);
586}
587
588// Draws a series of "DR" rects of the requested width across
589// the canvas and repeats until `kRRectsToDraw` rects have been drawn.
590//
591// A "DR" rect is a shape consisting of the difference between two
592// rounded rects.
593//
594// Half the drawn DR rects will not have an integral offset.
595void BM_DrawDRRect(benchmark::State& state,
596 BackendType backend_type,
597 unsigned attributes,
598 RRectType type) {
599 auto surface_provider = DlSurfaceProvider::Create(backend_type);
600 DisplayListBuilder builder;
601 DlPaint paint = GetPaintForRun(attributes);
602
603 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawDRRectFlags);
604
605 size_t length = state.range(0);
606 surface_provider->InitializeSurface(length * 2, length * 2);
607 auto surface = surface_provider->GetPrimarySurface();
609 surface->FlushSubmitCpuSync();
610
611 DlRoundingRadii radii;
612 // Keep all radii under 6 so that they won't underflow on the inner rect
613 // which is 16 - 2 * 0.1 * 16 == 12.8 units wide and tall at the smallest.
614 switch (type) {
616 radii.top_left = DlSize(5.0f, 5.0f);
617 radii.top_right = DlSize(5.0f, 5.0f);
618 radii.bottom_right = DlSize(5.0f, 5.0f);
619 radii.bottom_left = DlSize(5.0f, 5.0f);
620 break;
622 radii.top_left = DlSize(5.0f, 6.0f);
623 radii.top_right = DlSize(3.0f, 6.0f);
624 radii.bottom_right = DlSize(3.0f, 4.0f);
625 radii.bottom_left = DlSize(5.0f, 4.0f);
626 break;
628 radii.top_left = DlSize(5.0f, 4.0f);
629 radii.top_right = DlSize(4.0f, 5.0f);
630 radii.bottom_right = DlSize(3.0f, 6.0f);
631 radii.bottom_left = DlSize(6.0f, 3.0f);
632 break;
633 default:
635 }
636
637 const DlPoint delta(0.5f, 0.5f);
638 const DlScalar inner_scale = -0.1f * length;
639 const DlScalar multiplier = length / 16.0f;
640 DlRoundingRadii scaled_radii = radii * multiplier;
641
642 RectAnimator animator(DlRect::MakeWH(length, length), delta, surface);
643
644 state.counters["DrawCallCount"] = kDRRectsToDraw;
645 for (size_t i = 0; i < kDRRectsToDraw; i++) {
646 const DlRect outer_rect = animator.GetRect();
647 const DlRect inner_rect = outer_rect.Expand(inner_scale);
648 DlRoundRect outer = DlRoundRect::MakeRectRadii(outer_rect, scaled_radii);
649 DlRoundRect inner = DlRoundRect::MakeRectRadii(inner_rect, scaled_radii);
650 builder.DrawDiffRoundRect(outer, inner, paint);
651 animator.Animate();
652 }
653 auto display_list = builder.Build();
654 FML_CHECK(display_list->GetRecordCount() >= kDRRectsToDraw);
655
656 // We only want to time the actual rasterization.
657 size_t items_processed = 0;
658 for ([[maybe_unused]] auto _ : state) {
659 surface->RenderDisplayList(display_list);
660 items_processed += kDRRectsToDraw;
661 surface->FlushSubmitCpuSync();
662 }
663 state.SetItemsProcessed(items_processed);
664
665 SaveSnapshotIfNecessary(surface_provider, surface, state, "DrawDRRect");
666}
667
668void BM_DrawArc(benchmark::State& state,
669 BackendType backend_type,
670 unsigned attributes) {
671 auto surface_provider = DlSurfaceProvider::Create(backend_type);
672 DisplayListBuilder builder;
673 DlPaint paint = GetPaintForRun(attributes);
674
675 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawArcNoCenterFlags);
676
677 size_t length = state.range(0);
678 surface_provider->InitializeSurface(length * 2, length * 2);
679 auto surface = surface_provider->GetPrimarySurface();
681 surface->FlushSubmitCpuSync();
682
683 DlScalar starting_angle = 0.0f;
684 DlPoint delta(0.5f, 0.5f);
685
686 // Just some random sweeps that will mostly circumnavigate the circle
687 std::vector<DlScalar> segment_sweeps = {5.5f, -10.0f, 42.0f, 71.7f, 90.0f,
688 37.5f, 17.9f, 32.0f, 379.4f};
689
691 RectAnimator animator(DlRect::MakeSize(size), delta, surface);
692
693 size_t total_call_count = kArcSweepSetsToDraw * segment_sweeps.size();
694 state.counters["DrawCallCount"] = total_call_count;
695 for (size_t i = 0; i < kArcSweepSetsToDraw; i++) {
696 for (DlScalar sweep : segment_sweeps) {
697 builder.DrawArc(animator.GetRect(), starting_angle, sweep, false, paint);
698 starting_angle += sweep + 5.0f;
699 }
700 animator.Animate();
701 }
702
703 auto display_list = builder.Build();
704 FML_CHECK(display_list->GetRecordCount() >= total_call_count);
705
706 // We only want to time the actual rasterization.
707 size_t items_processed = 0;
708 for ([[maybe_unused]] auto _ : state) {
709 surface->RenderDisplayList(display_list);
710 items_processed += total_call_count;
711 surface->FlushSubmitCpuSync();
712 }
713 state.SetItemsProcessed(items_processed);
714
715 SaveSnapshotIfNecessary(surface_provider, surface, state, "DrawArc");
716}
717
718// Returns a list of DlPoints that represent `n` points equally spaced out
719// along the circumference of a circle with radius `r` and centered on `center`.
720std::vector<DlPoint> GetPolygonPoints(size_t n, DlPoint center, DlScalar r) {
721 std::vector<DlPoint> points;
722 DlScalar x, y;
723 float angle;
724 float full_circle = 2.0f * M_PI;
725 for (size_t i = 0; i < n; i++) {
726 angle = (full_circle / static_cast<float>(n)) * static_cast<float>(i);
727 x = center.x + r * std::cosf(angle);
728 y = center.y + r * std::sinf(angle);
729 points.emplace_back(x, y);
730 }
731 return points;
732}
733
734// Creates a path that represents a regular polygon with `sides` sides,
735// centered on `center` with a radius of `radius`. The control points are
736// equally spaced out along the circumference of the circle described by
737// `radius` and `center`.
738//
739// The path segment connecting each control point is a line segment.
740void GetLinesPath(DlPathBuilder& path_builder,
741 size_t sides,
742 DlPoint center,
743 float radius) {
744 std::vector<DlPoint> points = GetPolygonPoints(sides, center, radius);
745 path_builder.MoveTo(points[0]);
746 for (size_t i = 1; i < sides; i++) {
747 path_builder.LineTo(points[i]);
748 }
749 path_builder.LineTo(points[0]);
750 path_builder.Close();
751}
752
753// Creates a path that represents a regular polygon with `sides` sides,
754// centered on `center` with a radius of `radius`. The control points are
755// equally spaced out along the circumference of the circle described by
756// `radius` and `center`.
757//
758// The path segment connecting each control point is a quad bezier, with the
759// bezier control point being on a circle with 80% of `radius` and with the
760// control point angle half way between the start and end point angles for the
761// polygon segment.
762void GetQuadsPath(DlPathBuilder& path_builder,
763 size_t sides,
764 DlPoint center,
765 float radius) {
766 std::vector<DlPoint> points = GetPolygonPoints(sides, center, radius);
767 std::vector<DlPoint> control_points =
768 GetPolygonPoints(sides * 2, center, radius * 0.8f);
769
770 path_builder.MoveTo(points[0]);
771 for (size_t i = 1; i < sides; i++) {
772 path_builder.QuadraticCurveTo(control_points[2 * i - 1], points[i]);
773 }
774 path_builder.QuadraticCurveTo(control_points[2 * sides - 1], points[0]);
775 path_builder.Close();
776}
777
778// Creates a path that represents a regular polygon with `sides` sides,
779// centered on `center` with a radius of `radius`. The control points are
780// equally spaced out along the circumference of the circle described by
781// `radius` and `center`.
782//
783// The path segment connecting each control point is a conic, with the
784// control point being on a circle with 80% of `radius` and with the
785// control point angle half way between the start and end point angles for the
786// polygon segment, and the conic weight set to 3.7f.
787void GetConicsPath(DlPathBuilder& path_builder,
788 size_t sides,
789 DlPoint center,
790 float radius) {
791 std::vector<DlPoint> points = GetPolygonPoints(sides, center, radius);
792 std::vector<DlPoint> control_points =
793 GetPolygonPoints(sides * 2, center, radius * 0.8f);
794
795 path_builder.MoveTo(points[0]);
796 for (size_t i = 1; i < sides; i++) {
797 path_builder.ConicCurveTo(control_points[2 * i - 1], points[i], 3.7f);
798 }
799 path_builder.ConicCurveTo(control_points[2 * sides - 1], points[0], 3.7f);
800 path_builder.Close();
801}
802
803// Creates a path that represents a regular polygon with `sides` sides,
804// centered on `center` with a radius of `radius`. The control points are
805// equally spaced out along the circumference of the circle described by
806// `radius` and `center`.
807//
808// The path segment connecting each control point is a cubic, with the first
809// control point being on a circle with 80% of `radius` and with the second
810// control point being on a circle with 120% of `radius`. The first
811// control point is 1/3, and the second control point is 2/3, of the angle
812// between the start and end point angles for the polygon segment.
813void GetCubicsPath(DlPathBuilder& path_builder,
814 size_t sides,
815 DlPoint center,
816 float radius) {
817 std::vector<DlPoint> points = GetPolygonPoints(sides, center, radius);
818 std::vector<DlPoint> inner_control_points =
819 GetPolygonPoints(sides * 3, center, radius * 0.8f);
820 std::vector<DlPoint> outer_control_points =
821 GetPolygonPoints(sides * 3, center, radius * 1.2f);
822
823 path_builder.MoveTo(points[0]);
824 for (size_t i = 1; i < sides; i++) {
825 path_builder.CubicCurveTo(inner_control_points[3 * i - 2],
826 outer_control_points[3 * i - 1], points[i]);
827 }
828 path_builder.CubicCurveTo(inner_control_points[3 * sides - 2],
829 outer_control_points[3 * sides - 1], points[0]);
830 path_builder.Close();
831}
832
833// Returns a path generated by one of the above path generators
834// which is multiplied `number` times centered on each of the `number` control
835// points along the circumference of a circle centered on `center` with radius
836// `radius`.
837//
838// Each of the polygons will have `sides` sides, and the resulting path will be
839// bounded by a circle with radius of 150% of `radius` (or another 20% on top of
840// that for cubics)
841void MultiplyPath(DlPathBuilder& path_builder,
843 DlPoint center,
844 size_t sides,
845 size_t number,
846 float radius) {
847 std::vector<DlPoint> center_points =
848 GetPolygonPoints(number, center, radius / 2.0f);
849
850 for (DlPoint p : center_points) {
851 switch (type) {
852 case PathVerb::kLine:
853 GetLinesPath(path_builder, sides, p, radius);
854 break;
855 case PathVerb::kQuad:
856 GetQuadsPath(path_builder, sides, p, radius);
857 break;
858 case PathVerb::kConic:
859 GetConicsPath(path_builder, sides, p, radius);
860 break;
861 case PathVerb::kCubic:
862 GetCubicsPath(path_builder, sides, p, radius);
863 break;
864 default:
865 break;
866 }
867 }
868}
869
871 switch (type) {
872 case PathVerb::kLine:
873 return "Lines";
874 case PathVerb::kQuad:
875 return "Quads";
876 case PathVerb::kConic:
877 return "Conics";
878 case PathVerb::kCubic:
879 return "Cubics";
880 default:
881 return "Unknown";
882 }
883}
884
885// Draws a series of overlapping 20-sided polygons where the path segment
886// between each point is one of the verb types defined in PathVerb.
887//
888// The number of polygons drawn will be varied to get an overall path
889// with approximately 20*N verbs, so we can get an idea of the fixed
890// cost of using drawPath as well as an idea of how the cost varies according
891// to the verb count.
892void BM_DrawPath(benchmark::State& state,
893 BackendType backend_type,
894 unsigned attributes,
895 PathVerb type) {
896 auto surface_provider = DlSurfaceProvider::Create(backend_type);
897 DisplayListBuilder builder;
898 DlPaint paint = GetPaintForRun(attributes);
899
900 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawPathFlags);
901
902 size_t length = kFixedCanvasSize;
903 surface_provider->InitializeSurface(length, length);
904 auto surface = surface_provider->GetPrimarySurface();
906 surface->FlushSubmitCpuSync();
907
908 DlPathBuilder path_builder;
909
910 std::string label = VerbToString(type);
911 DlPoint center = DlPoint(length / 2.0f, length / 2.0f);
912 float radius = length * 0.25f;
913 state.SetComplexityN(state.range(0));
914
915 MultiplyPath(path_builder, type, center, 20, state.range(0), radius);
916 DlPath path = path_builder.TakePath();
917
918 DlPathVerbCounter counter;
919 path.Dispatch(counter);
920 state.counters["VerbCount"] = counter.GetVerbCount();
921 state.counters["DrawCallCount"] = 1;
922
923 builder.DrawPath(path, paint);
924 auto display_list = builder.Build();
925
926 // Prime any path conversions
927 surface->RenderDisplayList(display_list);
928 surface->FlushSubmitCpuSync();
929
930 // We only want to time the actual rasterization.
931 size_t items_processed = 0;
932 for ([[maybe_unused]] auto _ : state) {
933 surface->RenderDisplayList(display_list);
934 items_processed += counter.GetVerbCount();
935 surface->FlushSubmitCpuSync();
936 }
937 state.SetItemsProcessed(items_processed);
938
939 SaveSnapshotIfNecessary(surface_provider, surface, state,
940 "DrawPath-" + label);
941}
942
943// Returns a set of vertices that describe a circle that has a
944// radius of `radius` and outer vertex count of approximately
945// `vertex_count`. The final number of vertices will differ as we
946// need to ensure the correct usage of vertices to ensure we do not
947// request degenerate triangles be drawn. This final count is output
948// through `final_vertex_count`.
949//
950// The resulting vertices will describe a disc consisting of a series
951// of triangles with two vertices on the circumference of the disc,
952// and the final vertex being the center point of the disc.
953//
954// Each vertex colour will alternate through Red, Green, Blue and Cyan.
955std::shared_ptr<DlVertices> GetTestVertices(DlPoint center,
956 float radius,
957 size_t vertex_count,
958 DlVertexMode mode,
959 size_t& final_vertex_count) {
960 size_t outer_vertex_count = vertex_count / 2;
961 std::vector<DlPoint> outer_points =
962 GetPolygonPoints(outer_vertex_count, center, radius);
963
964 std::vector<DlPoint> vertices;
965 std::vector<DlColor> colors;
966
967 switch (mode) {
969 // Calling the points on the outer circle O_0, O_1, O_2, ..., and
970 // the center point C, this should create a triangle fan with vertices
971 // C, O_0, O_1, O_2, O_3, ...
972 vertices.push_back(center);
973 colors.push_back(DlColor(SK_ColorCYAN));
974 for (size_t i = 0; i <= outer_points.size(); i++) {
975 vertices.push_back(outer_points[i % outer_points.size()]);
976 if (i % 3 == 0) {
977 colors.push_back(DlColor(SK_ColorRED));
978 } else if (i % 3 == 1) {
979 colors.push_back(DlColor(SK_ColorGREEN));
980 } else {
981 colors.push_back(DlColor(SK_ColorBLUE));
982 }
983 }
984 break;
986 // Calling the points on the outer circle O_0, O_1, O_2, ..., and
987 // the center point C, this should create a series of triangles with
988 // vertices O_0, O_1, C, O_1, O_2, C, O_2, O_3, C, ...
989 for (size_t i = 0; i < outer_vertex_count; i++) {
990 vertices.push_back(outer_points[i % outer_points.size()]);
991 colors.push_back(DlColor(SK_ColorRED));
992 vertices.push_back(outer_points[(i + 1) % outer_points.size()]);
993 colors.push_back(DlColor(SK_ColorGREEN));
994 vertices.push_back(center);
995 colors.push_back(DlColor(SK_ColorBLUE));
996 }
997 break;
999 // Calling the points on the outer circle O_0, O_1, O_2, ..., and
1000 // the center point C, this should create a strip with vertices
1001 // O_0, O_1, C, O_2, O_3, C, O_4, O_5, C, ...
1002 for (size_t i = 0; i <= outer_vertex_count; i++) {
1003 vertices.push_back(outer_points[i % outer_points.size()]);
1004 colors.push_back(i % 2 ? DlColor(SK_ColorRED) : DlColor(SK_ColorGREEN));
1005 if (i % 2 == 1) {
1006 vertices.push_back(center);
1007 colors.push_back(DlColor(SK_ColorBLUE));
1008 }
1009 }
1010 break;
1011 default:
1012 break;
1013 }
1014
1015 final_vertex_count = vertices.size();
1016 return DlVertices::Make(mode, vertices.size(), vertices.data(), nullptr,
1017 colors.data());
1018}
1019
1021 switch (mode) {
1023 return "TriangleStrip";
1025 return "TriangleFan";
1027 return "Triangles";
1028 }
1029 return "Unknown";
1030}
1031
1032// Draws a series of discs generated by `GetTestVertices()` with
1033// 50 vertices in each disc. The number of discs drawn will vary according
1034// to the benchmark input, and the benchmark will automatically calculate
1035// the Big-O complexity of `DrawVertices` with N being the number of vertices
1036// being drawn.
1037//
1038// The discs drawn will be centered on points along a circle with radius of 25%
1039// of the canvas width/height, with each point being equally spaced out.
1040void BM_DrawVertices(benchmark::State& state,
1041 BackendType backend_type,
1042 unsigned attributes,
1043 DlVertexMode mode) {
1044 auto surface_provider = DlSurfaceProvider::Create(backend_type);
1045 DisplayListBuilder builder;
1046 DlPaint paint = GetPaintForRun(attributes);
1047
1048 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawVerticesFlags);
1049
1050 size_t length = kFixedCanvasSize;
1051 surface_provider->InitializeSurface(length, length);
1052 auto surface = surface_provider->GetPrimarySurface();
1054 surface->FlushSubmitCpuSync();
1055
1056 DlPoint center = DlPoint(length / 2.0f, length / 2.0f);
1057
1058 float radius = length / 4.0f;
1059
1060 size_t vertex_count, total_vertex_count = 0;
1061 size_t disc_count = state.range(0);
1062
1063 std::vector<DlPoint> center_points =
1064 GetPolygonPoints(disc_count, center, radius / 4.0f);
1065
1066 state.counters["DrawCallCount"] = center_points.size();
1067 for (DlPoint p : center_points) {
1068 std::shared_ptr<DlVertices> vertices =
1069 GetTestVertices(p, radius, 50, mode, vertex_count);
1070 total_vertex_count += vertex_count;
1071 builder.DrawVertices(vertices, DlBlendMode::kSrc, paint);
1072 }
1073
1074 state.counters["VertexCount"] = total_vertex_count;
1075 state.SetComplexityN(total_vertex_count);
1076
1077 auto display_list = builder.Build();
1078 FML_CHECK(display_list->GetRecordCount() >= center_points.size());
1079
1080 // We only want to time the actual rasterization.
1081 size_t items_processed = 0;
1082 for ([[maybe_unused]] auto _ : state) {
1083 surface->RenderDisplayList(display_list);
1084 items_processed += total_vertex_count;
1085 surface->FlushSubmitCpuSync();
1086 }
1087 state.SetItemsProcessed(items_processed);
1088
1089 SaveSnapshotIfNecessary(surface_provider, surface, state,
1090 "DrawVertices-" + std::to_string(disc_count) + "-" +
1092}
1093
1094// Generate `count` test points.
1095//
1096// The points are distributed using some fixed constant offsets that were
1097// chosen to appear somewhat random.
1098//
1099// The points generated will wrap in x and y for the bounds of `canvas_size`.
1100std::vector<DlPoint> GetTestPoints(size_t count, DlISize canvas_size) {
1101 std::vector<DlPoint> points;
1102
1103 // Some arbitrary offsets to use when building the list of points
1104 std::vector<DlScalar> delta_x = {10.0f, 6.3f, 15.0f, 3.5f, 22.6f, 4.7f};
1105 std::vector<DlScalar> delta_y = {9.3f, -5.4f, 8.5f, -12.0f, 19.2f, -19.6f};
1106
1107 DlPoint current;
1108 for (size_t i = 0; i < count; i++) {
1109 points.push_back(current);
1110 current +=
1111 DlPoint(delta_x[i % delta_x.size()], delta_y[i % delta_y.size()]);
1112 if (current.x > canvas_size.width) {
1113 current += DlPoint(-canvas_size.width, 25.0f);
1114 }
1115 if (current.y > canvas_size.height) {
1116 current += DlPoint(0.0f, -canvas_size.height);
1117 }
1118 }
1119
1120 return points;
1121}
1122
1124 switch (mode) {
1126 return "Lines";
1128 return "Polygon";
1130 default:
1131 return "Points";
1132 }
1133}
1134
1135// Draws a series of points generated by `GetTestPoints()` above to
1136// a fixed-size canvas. The benchmark will vary the number of points drawn,
1137// and they can be drawn in one of three modes - Lines, Polygon or Points mode.
1138//
1139// This benchmark will automatically calculate the Big-O complexity of
1140// `DrawPoints` with N being the number of points being drawn.
1141void BM_DrawPoints(benchmark::State& state,
1142 BackendType backend_type,
1143 unsigned attributes,
1144 DlPointMode mode) {
1145 auto surface_provider = DlSurfaceProvider::Create(backend_type);
1146 DisplayListBuilder builder;
1147 DlPaint paint = GetPaintForRun(attributes);
1148
1149 switch (mode) {
1151 CheckAttributes(attributes, state,
1153 break;
1155 CheckAttributes(attributes, state,
1157 break;
1159 CheckAttributes(attributes, state,
1161 break;
1162 }
1163
1164 size_t length = kFixedCanvasSize;
1165 surface_provider->InitializeSurface(length, length);
1166 auto surface = surface_provider->GetPrimarySurface();
1168 surface->FlushSubmitCpuSync();
1169
1170 size_t point_count = state.range(0);
1171 state.SetComplexityN(point_count);
1172 state.counters["PointCount"] = point_count;
1173 state.counters["DrawCallCount"] = 1;
1174
1175 std::vector<DlPoint> points = GetTestPoints(point_count, surface->GetSize());
1176 builder.DrawPoints(mode, points.size(), points.data(), paint);
1177
1178 auto display_list = builder.Build();
1179
1180 size_t items_processed = 0;
1181 for ([[maybe_unused]] auto _ : state) {
1182 surface->RenderDisplayList(display_list);
1183 items_processed += point_count;
1184 surface->FlushSubmitCpuSync();
1185 }
1186 state.SetItemsProcessed(items_processed);
1187
1188 SaveSnapshotIfNecessary(surface_provider, surface, state,
1189 "DrawPoints-" + PointModeToString(mode) + "-" +
1190 std::to_string(point_count));
1191}
1192
1193sk_sp<SkImage> ImageFromBitmapWithNewID(const SkBitmap& bitmap) {
1194 // If we create an SkPixmap with a ref to the SkBitmap's pixel data,
1195 // then create an SkImage from that, we always get a new generation ID,
1196 // so we will avoid hitting the cache.
1197 SkPixmap pixmap;
1198 bitmap.peekPixels(&pixmap);
1199 return SkImages::RasterFromPixmap(pixmap, nullptr, nullptr);
1200}
1201
1202// Draws `kImagesToDraw` bitmaps to a canvas, either with texture-backed
1203// bitmaps or bitmaps that need to be uploaded to the GPU first.
1204void BM_DrawImage(benchmark::State& state,
1205 BackendType backend_type,
1206 unsigned attributes,
1207 DlImageSampling options,
1208 bool upload_bitmap) {
1209 auto surface_provider = DlSurfaceProvider::Create(backend_type);
1210 DisplayListBuilder builder;
1211 DlPaint paint = GetPaintForRun(attributes);
1212
1213 CheckAttributes(attributes, state,
1215
1216 size_t bitmap_size = state.range(0);
1217 surface_provider->InitializeSurface(bitmap_size * 2, bitmap_size * 2);
1218 auto surface = surface_provider->GetPrimarySurface();
1220 surface->FlushSubmitCpuSync();
1221
1222 sk_sp<DlImage> image;
1223 SkBitmap bitmap;
1224
1225 if (upload_bitmap) {
1226 SkImageInfo info = SkImageInfo::Make(bitmap_size, bitmap_size,
1227 SkColorType::kRGBA_8888_SkColorType,
1228 SkAlphaType::kPremul_SkAlphaType);
1229 bitmap.allocPixels(info, 0);
1230 bitmap.eraseColor(SK_ColorBLUE);
1231 } else {
1232 image = MakeTestImage(bitmap_size, bitmap_size, DlColor::kRed());
1233 }
1234
1235 const DlPoint delta(0.5f, 0.5f);
1236 const DlSize size(bitmap_size, bitmap_size);
1237 RectAnimator animator(DlRect::MakeSize(size), delta, surface);
1238
1239 state.counters["DrawCallCount"] = kImagesToDraw;
1240 for (size_t i = 0; i < kImagesToDraw; i++) {
1241 if (upload_bitmap) {
1242 auto sk_image = ImageFromBitmapWithNewID(bitmap);
1243 image = DlImageSkia::Make(sk_image);
1244 }
1245 builder.DrawImage(image, animator.GetPoint(), options, &paint);
1246 animator.Animate();
1247 }
1248
1249 auto display_list = builder.Build();
1250 FML_CHECK(display_list->GetRecordCount() >= kImagesToDraw);
1251
1252 size_t items_processed = 0;
1253 for ([[maybe_unused]] auto _ : state) {
1254 surface->RenderDisplayList(display_list);
1255 items_processed += kImagesToDraw;
1256 surface->FlushSubmitCpuSync();
1257 }
1258 state.SetItemsProcessed(items_processed);
1259
1260 std::string image_type = (upload_bitmap ? "Upload-" : "Texture-");
1261 SaveSnapshotIfNecessary(
1262 surface_provider, surface, state,
1263 "DrawImage-" + image_type + std::to_string(bitmap_size));
1264}
1265
1267 switch (constraint) {
1269 return "Strict";
1271 return "Fast";
1272 default:
1273 return "Unknown";
1274 }
1275}
1276
1277// Draws `kImagesToDraw` bitmaps to a canvas, either with texture-backed
1278// bitmaps or bitmaps that need to be uploaded to the GPU first.
1279//
1280// The bitmaps are shrunk down to 75% of their size when rendered to the canvas.
1281void BM_DrawImageRect(benchmark::State& state,
1282 BackendType backend_type,
1283 unsigned attributes,
1284 DlImageSampling options,
1285 DlSrcRectConstraint constraint,
1286 bool upload_bitmap) {
1287 auto surface_provider = DlSurfaceProvider::Create(backend_type);
1288 DisplayListBuilder builder;
1289 DlPaint paint = GetPaintForRun(attributes);
1290
1291 CheckAttributes(attributes, state,
1293
1294 size_t bitmap_size = state.range(0);
1295 surface_provider->InitializeSurface(bitmap_size * 2, bitmap_size * 2);
1296 auto surface = surface_provider->GetPrimarySurface();
1298 surface->FlushSubmitCpuSync();
1299
1300 sk_sp<DlImage> image;
1301 SkBitmap bitmap;
1302
1303 if (upload_bitmap) {
1304 SkImageInfo info = SkImageInfo::Make(bitmap_size, bitmap_size,
1305 SkColorType::kRGBA_8888_SkColorType,
1306 SkAlphaType::kPremul_SkAlphaType);
1307 bitmap.allocPixels(info, 0);
1308 bitmap.eraseColor(SK_ColorBLUE);
1309 } else {
1310 image = MakeTestImage(bitmap_size, bitmap_size, DlColor::kRed());
1311 }
1312
1313 const DlPoint delta(0.5f, 0.5f);
1314 DlRect src = DlRect::MakeXYWH(bitmap_size / 4.0f, bitmap_size / 4.0f,
1315 bitmap_size / 2.0f, bitmap_size / 2.0f);
1316 DlSize size(bitmap_size * 0.75f, bitmap_size * 0.75f);
1317 RectAnimator animator(DlRect::MakeSize(size), delta, surface);
1318
1319 state.counters["DrawCallCount"] = kImagesToDraw;
1320 for (size_t i = 0; i < kImagesToDraw; i++) {
1321 if (upload_bitmap) {
1322 auto sk_image = ImageFromBitmapWithNewID(bitmap);
1323 image = DlImageSkia::Make(sk_image);
1324 }
1325 builder.DrawImageRect(image, src, animator.GetRect(), options, &paint,
1326 constraint);
1327 animator.Animate();
1328 }
1329
1330 auto display_list = builder.Build();
1331 FML_CHECK(display_list->GetRecordCount() >= kImagesToDraw);
1332
1333 size_t items_processed = 0;
1334 for ([[maybe_unused]] auto _ : state) {
1335 surface->RenderDisplayList(display_list);
1336 items_processed += kImagesToDraw;
1337 surface->FlushSubmitCpuSync();
1338 }
1339 state.SetItemsProcessed(items_processed);
1340
1341 std::string image_type = (upload_bitmap ? "Upload-" : "Texture-");
1342 SaveSnapshotIfNecessary(surface_provider, surface, state,
1343 "DrawImageRect-" + image_type +
1344 ConstraintToString(constraint) + "-" +
1345 std::to_string(bitmap_size));
1346}
1347
1348std::string FilterModeToString(const DlFilterMode mode) {
1349 switch (mode) {
1351 return "Nearest";
1353 return "Linear";
1354 default:
1355 return "Unknown";
1356 }
1357}
1358
1359// Draws `kImagesToDraw` bitmaps to a canvas, either with texture-backed
1360// bitmaps or bitmaps that need to be uploaded to the GPU first.
1361//
1362// The image is split into 9 sub-rects and stretched proportionally for final
1363// rendering.
1364void BM_DrawImageNine(benchmark::State& state,
1365 BackendType backend_type,
1366 unsigned attributes,
1367 const DlFilterMode filter,
1368 bool upload_bitmap) {
1369 auto surface_provider = DlSurfaceProvider::Create(backend_type);
1370 DisplayListBuilder builder;
1371 DlPaint paint = GetPaintForRun(attributes);
1372
1373 CheckAttributes(attributes, state,
1375
1376 size_t bitmap_size = state.range(0);
1377 surface_provider->InitializeSurface(bitmap_size * 2, bitmap_size * 2);
1378 auto surface = surface_provider->GetPrimarySurface();
1380 surface->FlushSubmitCpuSync();
1381
1382 DlIRect center = DlIRect::MakeXYWH(bitmap_size / 4, bitmap_size / 4,
1383 bitmap_size / 2, bitmap_size / 2);
1384
1385 sk_sp<DlImage> image;
1386 SkBitmap bitmap;
1387
1388 if (upload_bitmap) {
1389 SkImageInfo info = SkImageInfo::Make(bitmap_size, bitmap_size,
1390 SkColorType::kRGBA_8888_SkColorType,
1391 SkAlphaType::kPremul_SkAlphaType);
1392 bitmap.allocPixels(info, 0);
1393 bitmap.eraseColor(SK_ColorBLUE);
1394 } else {
1395 image = MakeTestImage(bitmap_size, bitmap_size, DlColor::kRed());
1396 }
1397
1398 const DlPoint delta(0.5f, 0.5f);
1399 DlSize size(bitmap_size * 0.75f, bitmap_size * 0.75f);
1400 RectAnimator animator(DlRect::MakeSize(size), delta, surface);
1401
1402 state.counters["DrawCallCount"] = kImagesToDraw;
1403 for (size_t i = 0; i < kImagesToDraw; i++) {
1404 if (upload_bitmap) {
1405 auto sk_image = ImageFromBitmapWithNewID(bitmap);
1406 image = DlImageSkia::Make(sk_image);
1407 }
1408 builder.DrawImageNine(image, center, animator.GetRect(), filter, &paint);
1409 animator.Animate();
1410 }
1411
1412 auto display_list = builder.Build();
1413 FML_CHECK(display_list->GetRecordCount() >= kImagesToDraw);
1414
1415 size_t items_processed = 0;
1416 for ([[maybe_unused]] auto _ : state) {
1417 surface->RenderDisplayList(display_list);
1418 items_processed += kImagesToDraw;
1419 surface->FlushSubmitCpuSync();
1420 }
1421 state.SetItemsProcessed(items_processed);
1422
1423 std::string image_type = (upload_bitmap ? "Upload-" : "Texture-");
1424 SaveSnapshotIfNecessary(surface_provider, surface, state,
1425 "DrawImageNine-" + image_type +
1426 FilterModeToString(filter) + "-" +
1427 std::to_string(bitmap_size));
1428}
1429
1430// Draws a series of glyph runs with 32 glyphs in each run. The number of runs
1431// may vary according to the benchmark parameters. The text will start in the
1432// upper left corner of the canvas and advance from left to right and wrap at
1433// the canvas boundaries in both x and y.
1434//
1435// This benchmark will automatically calculate the Big-O complexity of
1436// `DrawTextBlob` with N being the number of glyphs being drawn.
1437void BM_DrawTextBlob(benchmark::State& state,
1438 BackendType backend_type,
1439 unsigned attributes) {
1440 auto surface_provider = DlSurfaceProvider::Create(backend_type);
1441 DisplayListBuilder builder;
1442 DlPaint paint = GetPaintForRun(attributes);
1443
1444 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawTextFlags);
1445
1446 size_t draw_calls = state.range(0);
1447 surface_provider->InitializeSurface(kFixedCanvasSize, kFixedCanvasSize);
1448 auto surface = surface_provider->GetPrimarySurface();
1450 surface->FlushSubmitCpuSync();
1451
1452 state.SetComplexityN(draw_calls);
1453 state.counters["DrawCallCount_Varies"] = draw_calls;
1454 state.counters["GlyphCount"] = draw_calls;
1455 char character[2] = {'A', '\0'};
1456
1457 for (size_t i = 0; i < draw_calls; i++) {
1458 character[0] = 'A' + (i % 26);
1459 auto blob = SkTextBlob::MakeFromString(character, CreateTestFontOfSize(20));
1460 builder.DrawText(DlTextSkia::Make(blob), 50.0f, 50.0f, paint);
1461 }
1462
1463 auto display_list = builder.Build();
1464 FML_CHECK(display_list->GetRecordCount() >= draw_calls);
1465
1466 size_t items_processed = 0;
1467 for ([[maybe_unused]] auto _ : state) {
1468 surface->RenderDisplayList(display_list);
1469 items_processed += draw_calls;
1470 surface->FlushSubmitCpuSync();
1471 }
1472 state.SetItemsProcessed(items_processed);
1473
1474 SaveSnapshotIfNecessary(surface_provider, surface, state,
1475 "DrawTextBlob-" + std::to_string(draw_calls));
1476}
1477
1478// Draw the shadow for a 10-sided regular polygon where the polygon's
1479// sides are denoted by one of a Line, Quad, Conic or Cubic path segment.
1480//
1481// The elevation of the light source will vary according to the benchmark
1482// paremeters.
1483//
1484// The benchmark can be run with either a transparent occluder or an opaque
1485// occluder.
1486void BM_DrawShadow(benchmark::State& state,
1487 BackendType backend_type,
1488 unsigned attributes,
1489 bool transparent_occluder,
1490 PathVerb type) {
1491 auto surface_provider = DlSurfaceProvider::Create(backend_type);
1492 DisplayListBuilder builder;
1493 DlPaint paint = GetPaintForRun(attributes);
1494
1495 CheckAttributes(attributes, state, DisplayListOpFlags::kDrawShadowFlags);
1496
1497 size_t length = kFixedCanvasSize;
1498 surface_provider->InitializeSurface(length, length);
1499 auto surface = surface_provider->GetPrimarySurface();
1501 surface->FlushSubmitCpuSync();
1502
1503 DlPathBuilder path_builder;
1504
1505 DlPoint center = DlPoint(length / 2.0f, length / 2.0f);
1506 float radius = length * 0.25f;
1507
1508 switch (type) {
1509 case PathVerb::kLine:
1510 GetLinesPath(path_builder, 10, center, radius);
1511 break;
1512 case PathVerb::kQuad:
1513 GetQuadsPath(path_builder, 10, center, radius);
1514 break;
1515 case PathVerb::kConic:
1516 GetConicsPath(path_builder, 10, center, radius);
1517 break;
1518 case PathVerb::kCubic:
1519 GetCubicsPath(path_builder, 10, center, radius);
1520 break;
1521 default:
1522 break;
1523 }
1524
1525 float elevation = state.range(0);
1526 state.counters["DrawCallCount"] = 1;
1527
1528 DlPath path = path_builder.TakePath();
1529
1530 // We can hardcode dpr to 1.0f as we're varying elevation, and dpr is only
1531 // ever used in conjunction with elevation.
1532 builder.DrawShadow(path, DlColor(SK_ColorBLUE), elevation,
1533 transparent_occluder, 1.0f);
1534 auto display_list = builder.Build();
1535
1536 // Prime the path conversion.
1537 surface->RenderDisplayList(display_list);
1538 surface->FlushSubmitCpuSync();
1539
1540 // We only want to time the actual rasterization.
1541 size_t items_processed = 0;
1542 for ([[maybe_unused]] auto _ : state) {
1543 surface->RenderDisplayList(display_list);
1544 items_processed += 1;
1545 surface->FlushSubmitCpuSync();
1546 }
1547 state.SetItemsProcessed(items_processed);
1548
1549 SaveSnapshotIfNecessary(
1550 surface_provider, surface, state,
1551 "DrawShadow-" + VerbToString(type) + "-" +
1552 (transparent_occluder ? "Transparent-" : "Opaque-") +
1553 std::to_string(elevation));
1554}
1555
1556// Calls saveLayer N times from the root canvas layer, and optionally calls
1557// saveLayer a further M times nested inside that top saveLayer call.
1558//
1559// The total number of saveLayer calls will be N * (M+1).
1560//
1561// In each saveLayer call, simply draw the colour red with no clip rect.
1562void BM_SaveLayer(benchmark::State& state,
1563 BackendType backend_type,
1564 unsigned attributes,
1565 size_t save_depth) {
1566 auto surface_provider = DlSurfaceProvider::Create(backend_type);
1567 DisplayListBuilder builder;
1568 DlPaint paint = GetPaintForRun(attributes);
1569
1570 CheckAttributes(attributes, state, DisplayListOpFlags::kSaveLayerFlags);
1571
1572 size_t length = kFixedCanvasSize;
1573 surface_provider->InitializeSurface(length, length);
1574 auto surface = surface_provider->GetPrimarySurface();
1576 surface->FlushSubmitCpuSync();
1577
1578 size_t save_layer_calls = state.range(0);
1579
1580 // Ensure we draw two overlapping rects to avoid any peephole optimisations
1581 DlRect rect1 = DlRect::MakeLTRB(0, 0, 0.75f * length, 0.75f * length);
1582 DlRect rect2 =
1583 DlRect::MakeLTRB(0.25f * length, 0.25f * length, length, length);
1584
1585 size_t total_save_calls = save_layer_calls * save_depth;
1586 state.counters["DrawCallCount_Varies"] = total_save_calls;
1587 for (size_t i = 0; i < save_layer_calls; i++) {
1588 for (size_t j = 0; j < save_depth; j++) {
1589 builder.SaveLayer(std::nullopt, nullptr);
1590 builder.DrawRect(rect1, paint);
1591 builder.DrawRect(rect2, paint);
1592 }
1593 for (size_t j = 0; j < save_depth; j++) {
1594 builder.Restore();
1595 }
1596 }
1597 auto display_list = builder.Build();
1598 FML_CHECK(display_list->GetRecordCount() >= total_save_calls);
1599
1600 // We only want to time the actual rasterization.
1601 size_t items_processed = 0;
1602 for ([[maybe_unused]] auto _ : state) {
1603 surface->RenderDisplayList(display_list);
1604 items_processed += total_save_calls;
1605 surface->FlushSubmitCpuSync();
1606 }
1607 state.SetItemsProcessed(items_processed);
1608
1609 SaveSnapshotIfNecessary(surface_provider, surface, state,
1610 "SaveLayer-" + std::to_string(save_depth) + "x" +
1611 std::to_string(save_layer_calls));
1612}
1613
1614#ifdef DISPLAY_LIST_BENCHMARK_ALL_OPS
1615
1616#ifdef ENABLE_SOFTWARE_BENCHMARKS
1617RUN_DISPLAYLIST_BENCHMARKS(SkiaSoftware)
1618#endif
1619
1620#ifdef ENABLE_OPENGL_BENCHMARKS
1622#endif
1623
1624#ifdef ENABLE_METAL_BENCHMARKS
1626RUN_DISPLAYLIST_BENCHMARKS(ImpellerMetal)
1627RUN_DISPLAYLIST_BENCHMARKS(ImpellerMetalSDF)
1628#endif
1629
1630#else // DISPLAY_LIST_BENCHMARK_ALL_OPS
1631
1632// clang-format off
1633
1634constexpr int kAAFilledPrimitive =
1644
1645#define BENCHMARK_OVERHEAD(FUNC, BACKEND) \
1646 BENCHMARK_CAPTURE(BM_##FUNC, BACKEND, BackendType::k##BACKEND) \
1647 ->RangeMultiplier(4) \
1648 ->Range(16, 1024) \
1649 ->UseRealTime() \
1650 ->Unit(benchmark::kNanosecond);
1651
1652#define DRAW_BENCHMARK_PRIMITIVES_LIMITS(BACKEND, TYPE, ATTRIBUTES, \
1653 MIN, MAX, MULT) \
1654 BENCHMARK_CAPTURE(BM_Draw##TYPE, ATTRIBUTES/BACKEND, \
1655 BackendType::k##BACKEND, \
1656 k##ATTRIBUTES##Primitive) \
1657 ->RangeMultiplier(MULT) \
1658 ->Range(MIN, MAX) \
1659 ->UseRealTime() \
1660 ->Unit(benchmark::kMillisecond);
1661
1662#define DRAW_BENCHMARK_PRIMITIVE(BACKEND, TYPE, ATTRIBUTES) \
1663 DRAW_BENCHMARK_PRIMITIVES_LIMITS(BACKEND, TYPE, ATTRIBUTES, 16, 1024, 4)
1664
1665#define DRAW_BENCHMARK_SHADOW_PRIMITIVE(BACKEND, TYPE, ATTRIBUTES) \
1666 DRAW_BENCHMARK_PRIMITIVES_LIMITS(BACKEND, TYPE, ATTRIBUTES, 64, 256, 4)
1667
1668#define DRAW_BENCHMARK_PRIMITIVES_LINE(BACKEND) \
1669 DRAW_BENCHMARK_PRIMITIVE(BACKEND, Line, AAHairline) \
1670 DRAW_BENCHMARK_PRIMITIVE(BACKEND, Line, AAStroke10) \
1671
1672#define DRAW_BENCHMARK_PRIMITIVES_TYPE(BACKEND, TYPE) \
1673 DRAW_BENCHMARK_PRIMITIVE(BACKEND, TYPE, AAFilled) \
1674 DRAW_BENCHMARK_PRIMITIVE(BACKEND, TYPE, AAHairline) \
1675 DRAW_BENCHMARK_PRIMITIVE(BACKEND, TYPE, AAStroke10) \
1676 DRAW_BENCHMARK_SHADOW_PRIMITIVE(BACKEND, TYPE, FilledShadow5) \
1677 DRAW_BENCHMARK_SHADOW_PRIMITIVE(BACKEND, TYPE, FilledShadow10) \
1678
1679#define DRAW_BENCHMARK_PRIMITIVE_SUITE(BACKEND) \
1680 BENCHMARK_OVERHEAD(SyncOverhead, BACKEND) \
1681 BENCHMARK_OVERHEAD(EmptyDisplayList, BACKEND) \
1682 BENCHMARK_OVERHEAD(SingleOpDisplayList, BACKEND) \
1683 DRAW_BENCHMARK_PRIMITIVES_LINE(BACKEND) \
1684 DRAW_BENCHMARK_PRIMITIVES_TYPE(BACKEND, Rect) \
1685 DRAW_BENCHMARK_PRIMITIVES_TYPE(BACKEND, Oval) \
1686 DRAW_BENCHMARK_PRIMITIVES_TYPE(BACKEND, Circle) \
1687 DRAW_BENCHMARK_PRIMITIVES_TYPE(BACKEND, SimpleRRect) \
1688 DRAW_BENCHMARK_PRIMITIVES_TYPE(BACKEND, ComplexRRect) \
1689 DRAW_BENCHMARK_PRIMITIVES_TYPE(BACKEND, SimpleRSE) \
1690 DRAW_BENCHMARK_PRIMITIVES_TYPE(BACKEND, ComplexRSE)
1691
1692// clang-format on
1693
1694#ifdef ENABLE_SOFTWARE_BENCHMARKS
1696#endif
1697
1698#ifdef ENABLE_OPENGL_BENCHMARKS
1700#endif
1701
1702#ifdef ENABLE_METAL_BENCHMARKS
1704DRAW_BENCHMARK_PRIMITIVE_SUITE(ImpellerMetal)
1705DRAW_BENCHMARK_PRIMITIVE_SUITE(ImpellerMetalSDF)
1706#endif
1707
1708#endif // DISPLAY_LIST_BENCHMARK_ALL_OPS
1709
1710} // namespace testing
1711} // namespace flutter
void DrawOval(const DlRect &bounds, const DlPaint &paint) override
void DrawImageRect(const sk_sp< DlImage > &image, const DlRect &src, const DlRect &dst, DlImageSampling sampling, const DlPaint *paint=nullptr, DlSrcRectConstraint constraint=DlSrcRectConstraint::kFast) override
void DrawVertices(const std::shared_ptr< DlVertices > &vertices, DlBlendMode mode, const DlPaint &paint) override
void DrawImageNine(const sk_sp< DlImage > &image, const DlIRect &center, const DlRect &dst, DlFilterMode filter, const DlPaint *paint=nullptr) override
void DrawRoundRect(const DlRoundRect &rrect, const DlPaint &paint) override
void DrawArc(const DlRect &bounds, DlScalar start, DlScalar sweep, bool useCenter, const DlPaint &paint) override
void DrawShadow(const DlPath &path, const DlColor color, const DlScalar elevation, bool transparent_occluder, DlScalar dpr) override
Draws the shadow of the given |path| rendered in the provided |color| (which is only consulted for it...
void DrawImage(const sk_sp< DlImage > &image, const DlPoint &point, DlImageSampling sampling, const DlPaint *paint=nullptr) override
void DrawCircle(const DlPoint &center, DlScalar radius, const DlPaint &paint) override
void SaveLayer(const std::optional< DlRect > &bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr, std::optional< int64_t > backdrop_id=std::nullopt) override
void DrawLine(const DlPoint &p0, const DlPoint &p1, const DlPaint &paint) override
void DrawText(const std::shared_ptr< DlText > &text, DlScalar x, DlScalar y, const DlPaint &paint) override
void DrawRoundSuperellipse(const DlRoundSuperellipse &rse, const DlPaint &paint) override
sk_sp< DisplayList > Build()
void DrawPath(const DlPath &path, const DlPaint &paint) override
void DrawPoints(DlPointMode mode, uint32_t count, const DlPoint pts[], const DlPaint &paint) override
void DrawDiffRoundRect(const DlRoundRect &outer, const DlRoundRect &inner, const DlPaint &paint) override
void DrawRect(const DlRect &rect, const DlPaint &paint) override
static constexpr DisplayListAttributeFlags kDrawVerticesFlags
static constexpr DisplayListAttributeFlags kDrawArcNoCenterFlags
static constexpr DisplayListAttributeFlags kDrawImageRectWithPaintFlags
static constexpr DisplayListAttributeFlags kSaveLayerFlags
static constexpr DisplayListAttributeFlags kDrawOvalFlags
static constexpr DisplayListAttributeFlags kDrawPointsAsLinesFlags
static constexpr DisplayListAttributeFlags kDrawPointsAsPolygonFlags
static constexpr DisplayListAttributeFlags kDrawCircleFlags
static constexpr DisplayListAttributeFlags kDrawPathFlags
static constexpr DisplayListAttributeFlags kDrawLineFlags
static constexpr DisplayListAttributeFlags kDrawPointsAsPointsFlags
static constexpr DisplayListAttributeFlags kDrawImageWithPaintFlags
static constexpr DisplayListAttributeFlags kDrawImageNineWithPaintFlags
static constexpr DisplayListAttributeFlags kDrawTextFlags
static constexpr DisplayListAttributeFlags kDrawShadowFlags
static constexpr DisplayListAttributeFlags kDrawRSuperellipseFlags
static constexpr DisplayListAttributeFlags kDrawRRectFlags
static constexpr DisplayListAttributeFlags kDrawDRRectFlags
static constexpr DisplayListAttributeFlags kDrawRectFlags
static std::shared_ptr< DlMaskFilter > Make(DlBlurStyle style, SkScalar sigma, bool respect_ctm=true)
static sk_sp< DlImage > Make(const SkImage *image)
DlPaint & setStrokeWidth(float width)
Definition dl_paint.h:115
DlPaint & setDrawStyle(DlDrawStyle style)
Definition dl_paint.h:93
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & ConicCurveTo(DlPoint cp, DlPoint p2, DlScalar weight)
Draw a conic curve (a rational quadratic bezier curve) from the current point to the indicated point ...
DlPathBuilder & QuadraticCurveTo(DlPoint cp, DlPoint p2)
Draw a quadratic bezier curve from the current point to the indicated point p2, using the indicated p...
DlPathBuilder & Close()
The path is closed back to the location of the most recent MoveTo call. Contours that are filled are ...
DlPathBuilder & CubicCurveTo(DlPoint cp1, DlPoint cp2, DlPoint p2)
Draw a cubic bezier curve from the current point to the indicated point p2, using the indicated point...
void Dispatch(DlPathReceiver &receiver) const override
Definition dl_path.cc:120
static std::shared_ptr< DlTextSkia > Make(const sk_sp< SkTextBlob > &blob)
static std::shared_ptr< DlVertices > Make(DlVertexMode mode, int vertex_count, const DlPoint vertices[], const DlPoint texture_coordinates[], const DlColor colors[], int index_count=0, const uint16_t indices[]=nullptr, const DlRect *bounds=nullptr)
Constructs a DlVector with compact inline storage for all of its required and optional lists of data.
static std::unique_ptr< DlSurfaceProvider > Create(BackendType backend_type)
#define DRAW_BENCHMARK_PRIMITIVE_SUITE(BACKEND)
#define RUN_DISPLAYLIST_BENCHMARKS(BACKEND)
int32_t x
FlutterVulkanImage * image
VkSurfaceKHR surface
Definition main.cc:65
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_UNREACHABLE()
Definition logging.h:128
std::shared_ptr< SkBitmap > bitmap
size_t length
double y
std::string VertexModeToString(DlVertexMode mode)
void BM_DrawNinePatchRSE(benchmark::State &state, BackendType backend_type, unsigned attributes)
void BM_DrawVertices(benchmark::State &state, BackendType backend_type, unsigned attributes, DlVertexMode mode)
void BM_DrawNinePatchRRect(benchmark::State &state, BackendType backend_type, unsigned attributes)
constexpr int kFilledShadow10Primitive
std::shared_ptr< DlVertices > GetTestVertices(DlPoint center, float radius, size_t vertex_count, DlVertexMode mode, size_t &final_vertex_count)
void BM_DrawPath(benchmark::State &state, BackendType backend_type, unsigned attributes, PathVerb type)
SkFont CreateTestFontOfSize(DlScalar scalar)
constexpr int kAAFilledPrimitive
void BM_DrawPoints(benchmark::State &state, BackendType backend_type, unsigned attributes, DlPointMode mode)
void BM_DrawOval(benchmark::State &state, BackendType backend_type, unsigned attributes)
void BM_DrawComplexRRect(benchmark::State &state, BackendType backend_type, unsigned attributes)
void GetLinesPath(DlPathBuilder &path_builder, size_t sides, DlPoint center, float radius)
void BM_DrawShadow(benchmark::State &state, BackendType backend_type, unsigned attributes, bool transparent_occluder, PathVerb type)
void BM_SyncOverhead(benchmark::State &state, BackendType backend_type)
std::string ConstraintToString(DlSrcRectConstraint constraint)
std::string PointModeToString(DlPointMode mode)
void BM_DrawImage(benchmark::State &state, BackendType backend_type, unsigned attributes, DlImageSampling options, bool upload_bitmap)
void BM_DrawLine(benchmark::State &state, BackendType backend_type, unsigned attributes)
void BM_DrawCircle(benchmark::State &state, BackendType backend_type, unsigned attributes)
void BM_DrawRRect(benchmark::State &state, BackendType backend_type, unsigned attributes, RRectType type)
void GetConicsPath(DlPathBuilder &path_builder, size_t sides, DlPoint center, float radius)
void GetQuadsPath(DlPathBuilder &path_builder, size_t sides, DlPoint center, float radius)
void BM_DrawRSE(benchmark::State &state, BackendType backend_type, unsigned attributes, RRectType type)
void BM_DrawRect(benchmark::State &state, BackendType backend_type, unsigned attributes)
sk_sp< DlImage > MakeTestImage(int w, int h, int checker_size)
std::string FilterModeToString(const DlFilterMode mode)
sk_sp< SkImage > ImageFromBitmapWithNewID(const SkBitmap &bitmap)
std::vector< DlPoint > GetPolygonPoints(size_t n, DlPoint center, DlScalar r)
std::string VerbToString(PathVerb type)
void BM_DrawDRRect(benchmark::State &state, BackendType backend_type, unsigned attributes, RRectType type)
void BM_DrawTextBlob(benchmark::State &state, BackendType backend_type, unsigned attributes)
std::vector< DlPoint > GetTestPoints(size_t count, DlISize canvas_size)
constexpr int kAAStroke10Primitive
void BM_DrawArc(benchmark::State &state, BackendType backend_type, unsigned attributes)
void MultiplyPath(DlPathBuilder &path_builder, PathVerb type, DlPoint center, size_t sides, size_t number, float radius)
constexpr int kFilledShadow5Primitive
void BM_DrawImageNine(benchmark::State &state, BackendType backend_type, unsigned attributes, const DlFilterMode filter, bool upload_bitmap)
void BM_SaveLayer(benchmark::State &state, BackendType backend_type, unsigned attributes, size_t save_depth)
void BM_DrawSimpleRRect(benchmark::State &state, BackendType backend_type, unsigned attributes)
void GetCubicsPath(DlPathBuilder &path_builder, size_t sides, DlPoint center, float radius)
void BM_DrawImageRect(benchmark::State &state, BackendType backend_type, unsigned attributes, DlImageSampling options, DlSrcRectConstraint constraint, bool upload_bitmap)
void BM_DrawSimpleRSE(benchmark::State &state, BackendType backend_type, unsigned attributes)
constexpr int kAAHairlinePrimitive
void BM_DrawComplexRSE(benchmark::State &state, BackendType backend_type, unsigned attributes)
void BM_EmptyDisplayList(benchmark::State &state, BackendType backend_type)
void BM_SingleOpDisplayList(benchmark::State &state, BackendType backend_type)
impeller::Scalar DlScalar
impeller::PathReceiver DlPathReceiver
Definition dl_path.h:17
impeller::Rect DlRect
impeller::ISize32 DlISize
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all 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
DlPointMode
Definition dl_types.h:15
@ kLines
draw each separate pair of points as a line segment
@ kPolygon
draw each pair of overlapping points as a line segment
@ kPoints
draw each point separately
impeller::Size DlSize
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 switch_defs.h:52
DlVertexMode
Defines the way in which the vertices of a DlVertices object are separated into triangles into which ...
Definition dl_vertices.h:18
@ kTriangles
The vertices are taken 3 at a time to form a triangle.
@ kStrokeAndFill
both strokes and fills shapes
@ kStroke
strokes boundary of shapes
@ kFill
fills interior of shapes
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all 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
@ kNormal
fuzzy inside and outside
impeller::Point DlPoint
DlSrcRectConstraint
Definition dl_types.h:21
void MoveTo(PathBuilder *builder, Scalar x, Scalar y)
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
void CubicTo(PathBuilder *builder, Scalar x1, Scalar y1, Scalar x2, Scalar y2, Scalar x3, Scalar y3)
void Close(PathBuilder *builder)
flutter::DlPaint DlPaint
impeller::ShaderType type
static constexpr DlColor kTransparent()
Definition dl_color.h:68
static constexpr DlColor kRed()
Definition dl_color.h:71
static RoundRect MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
Definition round_rect.cc:9
static RoundSuperellipse MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
static constexpr TRect MakeWH(Type width, Type height)
Definition rect.h:140
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition rect.h:652
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
Type height
Definition size.h:29
Type width
Definition size.h:28
std::vector< Point > points