Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
dl_complexity_gl.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
5#include "flutter/display_list/benchmarking/dl_complexity_gl.h"
6
7// The numbers and weightings used in this file stem from taking the
8// data from the DisplayListBenchmarks suite run on an Pixel 4 and
9// applying very rough analysis on them to identify the approximate
10// trends.
11//
12// See the comments in display_list_complexity_helper.h for details on the
13// process and rationale behind coming up with these numbers.
14
15namespace flutter {
16
17DisplayListGLComplexityCalculator*
18 DisplayListGLComplexityCalculator::instance_ = nullptr;
19
20DisplayListGLComplexityCalculator*
22 if (instance_ == nullptr) {
23 instance_ = new DisplayListGLComplexityCalculator();
24 }
25 return instance_;
26}
27
28unsigned int DisplayListGLComplexityCalculator::GLHelper::BatchedComplexity() {
29 // Calculate the impact of saveLayer.
30 unsigned int save_layer_complexity;
31 if (save_layer_count_ == 0) {
32 save_layer_complexity = 0;
33 } else {
34 // m = 1/5
35 // c = 10
36 save_layer_complexity = (save_layer_count_ + 50) * 40000;
37 }
38
39 unsigned int draw_text_blob_complexity;
40 if (draw_text_blob_count_ == 0) {
41 draw_text_blob_complexity = 0;
42 } else {
43 // m = 1/240
44 // c = 0.25
45 draw_text_blob_complexity = (draw_text_blob_count_ + 60) * 2500 / 3;
46 }
47
48 return save_layer_complexity + draw_text_blob_complexity;
49}
50
51void DisplayListGLComplexityCalculator::GLHelper::saveLayer(
52 const SkRect& bounds,
53 const SaveLayerOptions options,
54 const DlImageFilter* backdrop) {
55 if (IsComplex()) {
56 return;
57 }
58 if (backdrop) {
59 // Flutter does not offer this operation so this value can only ever be
60 // non-null for a frame-wide builder which is not currently evaluated for
61 // complexity.
62 AccumulateComplexity(Ceiling());
63 }
64 save_layer_count_++;
65}
66
67void DisplayListGLComplexityCalculator::GLHelper::drawLine(const SkPoint& p0,
68 const SkPoint& p1) {
69 if (IsComplex()) {
70 return;
71 }
72
73 // There is a relatively high fixed overhead cost for drawLine on OpenGL.
74 // Further, there is a strange bump where the cost of drawing a line of
75 // length ~500px is actually more costly than drawing a line of length
76 // ~1000px. The calculations here will be for a linear graph that
77 // approximate the overall trend.
78
79 float non_hairline_penalty = 1.0f;
80 unsigned int aa_penalty = 1;
81
82 // The non-hairline penalty is insignificant when AA is on.
83 if (!IsHairline() && !IsAntiAliased()) {
84 non_hairline_penalty = 1.15f;
85 }
86 if (IsAntiAliased()) {
87 aa_penalty = 2;
88 }
89
90 // Use an approximation for the distance to avoid floating point or
91 // sqrt() calls.
92 SkScalar distance = abs(p0.x() - p1.x()) + abs(p0.y() - p1.y());
93
94 // The baseline complexity is for a hairline stroke with no AA.
95 // m = 1/40
96 // c = 13
97 unsigned int complexity =
98 ((distance + 520) / 2) * non_hairline_penalty * aa_penalty;
99
100 AccumulateComplexity(complexity);
101}
102
103void DisplayListGLComplexityCalculator::GLHelper::drawRect(const SkRect& rect) {
104 if (IsComplex()) {
105 return;
106 }
107
108 unsigned int complexity;
109
110 // If stroked, cost scales linearly with the rectangle width/height.
111 // If filled, it scales with the area.
112 //
113 // Hairline stroke vs non hairline has no significant penalty.
114 //
115 // There is also a kStrokeAndFill_Style that Skia exposes, but we do not
116 // currently use it anywhere in Flutter.
117 if (DrawStyle() == DlDrawStyle::kFill) {
118 // No real difference for AA with filled styles
119 unsigned int area = rect.width() * rect.height();
120
121 // m = 1/3500
122 // c = 0
123 complexity = area * 2 / 175;
124 } else {
125 // Take the average of the width and height.
126 unsigned int length = (rect.width() + rect.height()) / 2;
127
128 if (IsAntiAliased()) {
129 // m = 1/30
130 // c = 0
131 complexity = length * 4 / 3;
132 } else {
133 // If AA is disabled, the data shows that at larger sizes the overall
134 // cost comes down, peaking at around 1000px. As we don't anticipate
135 // rasterising rects with AA disabled to be all that frequent, just treat
136 // it as a straight line that peaks at 1000px, beyond which it stays
137 // constant. The rationale here is that it makes more sense to
138 // overestimate than to start decreasing the cost as the length goes up.
139 //
140 // This should be a reasonable approximation as it doesn't decrease by
141 // much from 1000px to 2000px.
142 //
143 // m = 1/20
144 // c = 0
145 complexity = std::min(length, 1000u) * 2;
146 }
147 }
148
149 AccumulateComplexity(complexity);
150}
151
152void DisplayListGLComplexityCalculator::GLHelper::drawOval(
153 const SkRect& bounds) {
154 if (IsComplex()) {
155 return;
156 }
157 // DrawOval scales very roughly linearly with the bounding box width/height
158 // (not area) for stroked styles without AA.
159 //
160 // Filled styles and stroked styles with AA scale linearly with the bounding
161 // box area.
162 unsigned int area = bounds.width() * bounds.height();
163
164 unsigned int complexity;
165
166 // There is also a kStrokeAndFill_Style that Skia exposes, but we do not
167 // currently use it anywhere in Flutter.
168 if (DrawStyle() == DlDrawStyle::kFill) {
169 // With filled styles, there is no significant AA penalty.
170 // m = 1/6000
171 // c = 0
172 complexity = area / 30;
173 } else {
174 if (IsAntiAliased()) {
175 // m = 1/4000
176 // c = 0
177 complexity = area / 20;
178 } else {
179 // Take the average of the width and height.
180 unsigned int length = (bounds.width() + bounds.height()) / 2;
181
182 // m = 1/75
183 // c = 0
184 complexity = length * 8 / 3;
185 }
186 }
187
188 AccumulateComplexity(complexity);
189}
190
191void DisplayListGLComplexityCalculator::GLHelper::drawCircle(
192 const SkPoint& center,
193 SkScalar radius) {
194 if (IsComplex()) {
195 return;
196 }
197
198 unsigned int complexity;
199
200 // There is also a kStrokeAndFill_Style that Skia exposes, but we do not
201 // currently use it anywhere in Flutter.
202 if (DrawStyle() == DlDrawStyle::kFill) {
203 // We can ignore pi here
204 unsigned int area = radius * radius;
205 // m = 1/525
206 // c = 50
207 complexity = (area + 26250) * 8 / 105;
208
209 // Penalty of around 8% when AA is disabled.
210 if (!IsAntiAliased()) {
211 complexity *= 1.08f;
212 }
213 } else {
214 // Hairline vs non-hairline has no significant performance difference.
215 if (IsAntiAliased()) {
216 // m = 1/3
217 // c = 10
218 complexity = (radius + 30) * 40 / 3;
219 } else {
220 // m = 1/10
221 // c = 20
222 complexity = (radius + 200) * 4;
223 }
224 }
225
226 AccumulateComplexity(complexity);
227}
228
229void DisplayListGLComplexityCalculator::GLHelper::drawRRect(
230 const SkRRect& rrect) {
231 if (IsComplex()) {
232 return;
233 }
234
235 // Drawing RRects is split into three performance tiers:
236 //
237 // 1) All stroked styles without AA *except* simple/symmetric RRects.
238 // 2) All filled styles and symmetric stroked styles w/AA.
239 // 3) Remaining stroked styles with AA.
240 //
241 // 1) and 3) scale linearly with length, 2) scales with area.
242
243 unsigned int complexity;
244
245 // These values were worked out by creating a straight line graph (y=mx+c)
246 // approximately matching the measured data, normalising the data so that
247 // 0.0005ms resulted in a score of 100 then simplifying down the formula.
248 if (DrawStyle() == DlDrawStyle::kFill ||
249 ((rrect.getType() == SkRRect::Type::kSimple_Type) && IsAntiAliased())) {
250 unsigned int area = rrect.width() * rrect.height();
251 // m = 1/3200
252 // c = 0.5
253 complexity = (area + 1600) / 80;
254 } else {
255 // Take the average of the width and height.
256 unsigned int length = (rrect.width() + rrect.height()) / 2;
257
258 // There is some difference between hairline and non-hairline performance
259 // but the spread is relatively inconsistent and it's pretty much a wash.
260 if (IsAntiAliased()) {
261 // m = 1/25
262 // c = 1
263 complexity = (length + 25) * 8 / 5;
264 } else {
265 // m = 1/50
266 // c = 0.75
267 complexity = ((length * 2) + 75) * 2 / 5;
268 }
269 }
270
271 AccumulateComplexity(complexity);
272}
273
274void DisplayListGLComplexityCalculator::GLHelper::drawDRRect(
275 const SkRRect& outer,
276 const SkRRect& inner) {
277 if (IsComplex()) {
278 return;
279 }
280 // There are roughly four classes here:
281 // a) Filled style.
282 // b) Complex RRect type with AA enabled and filled style.
283 // c) Stroked style with AA enabled.
284 // d) Stroked style with AA disabled.
285 //
286 // a) and b) scale linearly with the area, c) and d) scale linearly with
287 // a single dimension (length). In all cases, the dimensions refer to
288 // the outer RRect.
289
290 unsigned int complexity;
291
292 // These values were worked out by creating a straight line graph (y=mx+c)
293 // approximately matching the measured data, normalising the data so that
294 // 0.0005ms resulted in a score of 100 then simplifying down the formula.
295 //
296 // There is also a kStrokeAndFill_Style that Skia exposes, but we do not
297 // currently use it anywhere in Flutter.
298 if (DrawStyle() == DlDrawStyle::kFill) {
299 unsigned int area = outer.width() * outer.height();
300 if (outer.getType() == SkRRect::Type::kComplex_Type) {
301 // m = 1/500
302 // c = 0.5
303 complexity = (area + 250) / 5;
304 } else {
305 // m = 1/1600
306 // c = 2
307 complexity = (area + 3200) / 16;
308 }
309 } else {
310 unsigned int length = (outer.width() + outer.height()) / 2;
311 if (IsAntiAliased()) {
312 // m = 1/15
313 // c = 1
314 complexity = (length + 15) * 20 / 3;
315 } else {
316 // m = 1/27
317 // c = 0.5
318 complexity = ((length * 2) + 27) * 50 / 27;
319 }
320 }
321
322 AccumulateComplexity(complexity);
323}
324
325void DisplayListGLComplexityCalculator::GLHelper::drawPath(const SkPath& path) {
326 if (IsComplex()) {
327 return;
328 }
329 // There is negligible effect on the performance for hairline vs. non-hairline
330 // stroke widths.
331 //
332 // The data for filled styles is currently suspicious, so for now we are going
333 // to assign scores based on stroked styles.
334
335 unsigned int line_verb_cost, quad_verb_cost, conic_verb_cost, cubic_verb_cost;
336 unsigned int complexity;
337
338 if (IsAntiAliased()) {
339 // There seems to be a fixed cost of around 1ms for calling drawPath with
340 // AA.
341 complexity = 200000;
342
343 line_verb_cost = 235;
344 quad_verb_cost = 365;
345 conic_verb_cost = 365;
346 cubic_verb_cost = 725;
347 } else {
348 // There seems to be a fixed cost of around 0.25ms for calling drawPath.
349 // without AA
350 complexity = 50000;
351
352 line_verb_cost = 135;
353 quad_verb_cost = 150;
354 conic_verb_cost = 200;
355 cubic_verb_cost = 235;
356 }
357
358 complexity += CalculatePathComplexity(path, line_verb_cost, quad_verb_cost,
359 conic_verb_cost, cubic_verb_cost);
360
361 AccumulateComplexity(complexity);
362}
363
364void DisplayListGLComplexityCalculator::GLHelper::drawArc(
365 const SkRect& oval_bounds,
366 SkScalar start_degrees,
367 SkScalar sweep_degrees,
368 bool use_center) {
369 if (IsComplex()) {
370 return;
371 }
372 // Hairline vs non-hairline makes no difference to the performance.
373 // Stroked styles without AA scale linearly with the log of the diameter.
374 // Stroked styles with AA scale linearly with the area.
375 // Filled styles scale lienarly with the area.
376 unsigned int area = oval_bounds.width() * oval_bounds.height();
377 unsigned int complexity;
378
379 // These values were worked out by creating a straight line graph (y=mx+c)
380 // approximately matching the measured data, normalising the data so that
381 // 0.0005ms resulted in a score of 100 then simplifying down the formula.
382 //
383 // There is also a kStrokeAndFill_Style that Skia exposes, but we do not
384 // currently use it anywhere in Flutter.
385 if (DrawStyle() == DlDrawStyle::kStroke) {
386 if (IsAntiAliased()) {
387 // m = 1/3800
388 // c = 12
389 complexity = (area + 45600) / 171;
390 } else {
391 unsigned int diameter = (oval_bounds.width() + oval_bounds.height()) / 2;
392 // m = 15
393 // c = -100
394 // This should never go negative though, so use std::max to ensure
395 // c is never larger than 15*log_diameter.
396 //
397 // Pre-multiply by 15 here so we get a little bit more precision.
398 unsigned int log_diameter = 15 * log(diameter);
399 complexity = (log_diameter - std::max(log_diameter, 100u)) * 200 / 9;
400 }
401 } else {
402 if (IsAntiAliased()) {
403 // m = 1/1000
404 // c = 10
405 complexity = (area + 10000) / 45;
406 } else {
407 // m = 1/6500
408 // c = 12
409 complexity = (area + 52000) * 2 / 585;
410 }
411 }
412
413 AccumulateComplexity(complexity);
414}
415
416void DisplayListGLComplexityCalculator::GLHelper::drawPoints(
418 uint32_t count,
419 const SkPoint points[]) {
420 if (IsComplex()) {
421 return;
422 }
423 unsigned int complexity;
424
425 if (IsAntiAliased()) {
427 if (IsHairline()) {
428 // This is a special case, it triggers an extremely fast path.
429 // m = 1/4500
430 // c = 0
431 complexity = count * 400 / 9;
432 } else {
433 // m = 1/500
434 // c = 0
435 complexity = count * 400;
436 }
437 } else if (mode == DlCanvas::PointMode::kLines) {
438 if (IsHairline()) {
439 // m = 1/750
440 // c = 0
441 complexity = count * 800 / 3;
442 } else {
443 // m = 1/500
444 // c = 0
445 complexity = count * 400;
446 }
447 } else {
448 if (IsHairline()) {
449 // m = 1/350
450 // c = 0
451 complexity = count * 4000 / 7;
452 } else {
453 // m = 1/250
454 // c = 0
455 complexity = count * 800;
456 }
457 }
458 } else {
460 // Hairline vs non hairline makes no difference for points without AA.
461 // m = 1/18000
462 // c = 0.25
463 complexity = (count + 4500) * 100 / 9;
464 } else if (mode == DlCanvas::PointMode::kLines) {
465 if (IsHairline()) {
466 // m = 1/8500
467 // c = 0.25
468 complexity = (count + 2125) * 400 / 17;
469 } else {
470 // m = 1/9000
471 // c = 0.25
472 complexity = (count + 2250) * 200 / 9;
473 }
474 } else {
475 // Polygon only really diverges for hairline vs non hairline at large
476 // point counts, and only by a few %.
477 // m = 1/7500
478 // c = 0.25
479 complexity = (count + 1875) * 80 / 3;
480 }
481 }
482
483 AccumulateComplexity(complexity);
484}
485
486void DisplayListGLComplexityCalculator::GLHelper::drawVertices(
487 const DlVertices* vertices,
489 // There is currently no way for us to get the VertexMode from the SkVertices
490 // object, but for future reference:
491 //
492 // TriangleStrip is roughly 25% more expensive than TriangleFan.
493 // TriangleFan is roughly 5% more expensive than Triangles.
494
495 // For the baseline, it's hard to identify the trend. It might be O(n^1/2)
496 // For now, treat it as linear as an approximation.
497 //
498 // m = 1/1600
499 // c = 1
500 unsigned int complexity = (vertices->vertex_count() + 1600) * 250 / 2;
501
502 AccumulateComplexity(complexity);
503}
504
505void DisplayListGLComplexityCalculator::GLHelper::drawImage(
506 const sk_sp<DlImage> image,
507 const SkPoint point,
508 DlImageSampling sampling,
509 bool render_with_attributes) {
510 if (IsComplex()) {
511 return;
512 }
513 // AA vs non-AA has a cost but it's dwarfed by the overall cost of the
514 // drawImage call.
515 //
516 // The main difference is if the image is backed by a texture already or not
517 // If we don't need to upload, then the cost scales linearly with the
518 // length of the image. If it needs uploading, the cost scales linearly
519 // with the square of the area (!!!).
520 SkISize dimensions = image->dimensions();
521 unsigned int length = (dimensions.width() + dimensions.height()) / 2;
522 unsigned int area = dimensions.width() * dimensions.height();
523
524 // m = 1/13
525 // c = 0
526 unsigned int complexity = length * 400 / 13;
527
528 if (!image->isTextureBacked()) {
529 // We can't square the area here as we'll overflow, so let's approximate
530 // by taking the calculated complexity score and applying a multiplier to
531 // it.
532 //
533 // (complexity * area / 60000) + 4000 gives a reasonable approximation with
534 // AA (complexity * area / 19000) gives a reasonable approximation without
535 // AA.
536 float multiplier;
537 if (IsAntiAliased()) {
538 multiplier = area / 60000.0f;
539 complexity = complexity * multiplier + 4000;
540 } else {
541 multiplier = area / 19000.0f;
542 complexity = complexity * multiplier;
543 }
544 }
545
546 AccumulateComplexity(complexity);
547}
548
549void DisplayListGLComplexityCalculator::GLHelper::ImageRect(
550 const SkISize& size,
551 bool texture_backed,
552 bool render_with_attributes,
553 bool enforce_src_edges) {
554 if (IsComplex()) {
555 return;
556 }
557 // Two main groups here - texture-backed and non-texture-backed images.
558 //
559 // Within each group, they all perform within a few % of each other *except*
560 // when we have a strict constraint and anti-aliasing enabled.
561
562 // These values were worked out by creating a straight line graph (y=mx+c)
563 // approximately matching the measured data, normalising the data so that
564 // 0.0005ms resulted in a score of 100 then simplifying down the formula.
565 unsigned int complexity;
566 if (!texture_backed || (texture_backed && render_with_attributes &&
567 enforce_src_edges && IsAntiAliased())) {
568 unsigned int area = size.width() * size.height();
569 // m = 1/4000
570 // c = 5
571 complexity = (area + 20000) / 10;
572 } else {
573 unsigned int length = (size.width() + size.height()) / 2;
574 // There's a little bit of spread here but the numbers are pretty large
575 // anyway.
576 //
577 // m = 1/22
578 // c = 0
579 complexity = length * 200 / 11;
580 }
581
582 AccumulateComplexity(complexity);
583}
584
585void DisplayListGLComplexityCalculator::GLHelper::drawImageNine(
586 const sk_sp<DlImage> image,
587 const SkIRect& center,
588 const SkRect& dst,
589 DlFilterMode filter,
590 bool render_with_attributes) {
591 if (IsComplex()) {
592 return;
593 }
594
595 SkISize dimensions = image->dimensions();
596 unsigned int area = dimensions.width() * dimensions.height();
597
598 // m = 1/3600
599 // c = 3
600 unsigned int complexity = (area + 10800) / 9;
601
602 // Uploading incurs about a 40% performance penalty.
603 if (!image->isTextureBacked()) {
604 complexity *= 1.4f;
605 }
606
607 AccumulateComplexity(complexity);
608}
609
610void DisplayListGLComplexityCalculator::GLHelper::drawDisplayList(
611 const sk_sp<DisplayList> display_list,
612 SkScalar opacity) {
613 if (IsComplex()) {
614 return;
615 }
616 GLHelper helper(Ceiling() - CurrentComplexityScore());
617 if (opacity < SK_Scalar1 && !display_list->can_apply_group_opacity()) {
618 auto bounds = display_list->bounds();
619 helper.saveLayer(bounds, SaveLayerOptions::kWithAttributes, nullptr);
620 }
621 display_list->Dispatch(helper);
622 AccumulateComplexity(helper.ComplexityScore());
623}
624
625void DisplayListGLComplexityCalculator::GLHelper::drawTextBlob(
626 const sk_sp<SkTextBlob> blob,
627 SkScalar x,
628 SkScalar y) {
629 if (IsComplex()) {
630 return;
631 }
632
633 // DrawTextBlob has a high fixed cost, but if we call it multiple times
634 // per frame, that fixed cost is greatly reduced per subsequent call. This
635 // is likely because there is batching being done in SkCanvas.
636
637 // Increment draw_text_blob_count_ and calculate the cost at the end.
638 draw_text_blob_count_++;
639}
640
641void DisplayListGLComplexityCalculator::GLHelper::drawTextFrame(
642 const std::shared_ptr<impeller::TextFrame>& text_frame,
643 SkScalar x,
644 SkScalar y) {}
645
646void DisplayListGLComplexityCalculator::GLHelper::drawShadow(
647 const SkPath& path,
648 const DlColor color,
649 const SkScalar elevation,
650 bool transparent_occluder,
651 SkScalar dpr) {
652 if (IsComplex()) {
653 return;
654 }
655
656 // Elevation has no significant effect on the timings. Whether the shadow
657 // is cast by a transparent occluder or not has a small impact of around 5%.
658 //
659 // The path verbs do have an effect but only if the verb type is cubic; line,
660 // quad and conic all perform similarly.
661 float occluder_penalty = 1.0f;
662 if (transparent_occluder) {
663 occluder_penalty = 1.20f;
664 }
665
666 // The benchmark uses a test path of around 10 path elements. This is likely
667 // to be similar to what we see in real world usage, but we should benchmark
668 // different path lengths to see how much impact there is from varying the
669 // path length.
670 //
671 // For now, we will assume that there is no fixed overhead and that the time
672 // spent rendering the shadow for a path is split evenly amongst all the verbs
673 // enumerated.
674 unsigned int line_verb_cost = 17000; // 0.085ms
675 unsigned int quad_verb_cost = 20000; // 0.1ms
676 unsigned int conic_verb_cost = 20000; // 0.1ms
677 unsigned int cubic_verb_cost = 120000; // 0.6ms
678
679 unsigned int complexity = CalculatePathComplexity(
680 path, line_verb_cost, quad_verb_cost, conic_verb_cost, cubic_verb_cost);
681
682 AccumulateComplexity(complexity * occluder_penalty);
683}
684
685} // namespace flutter
const char * options
int count
static const int points[]
SkColor4f color
static SkScalar center(float pos0, float pos1)
SkISize dimensions() const
Definition SkImage.h:297
virtual bool isTextureBacked() const =0
Type getType() const
Definition SkRRect.h:76
@ kSimple_Type
non-zero width and height with equal radii
Definition SkRRect.h:70
@ kComplex_Type
non-zero width and height with arbitrary radii
Definition SkRRect.h:72
SkScalar width() const
Definition SkRRect.h:95
SkScalar height() const
Definition SkRRect.h:102
static DisplayListGLComplexityCalculator * GetInstance()
@ kLines
draw each separate pair of points as a line segment
@ kPoints
draw each point separately
static const SaveLayerOptions kWithAttributes
sk_sp< SkImage > image
Definition examples.cpp:29
float SkScalar
Definition extension.cpp:12
size_t length
double y
double x
Optional< SkRect > bounds
Definition SkRecords.h:189
SkRRect rrect
Definition SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350
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
@ kStroke
strokes boundary of shapes
@ kFill
fills interior of shapes
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
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
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition SkVx.h:707
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
constexpr float y() const
constexpr float x() const
constexpr float height() const
Definition SkRect.h:769
constexpr float width() const
Definition SkRect.h:762