![]() This PR adds a fast blurring algorithm for `RSuperellipse`s with uniform corner radius, similar to `AttemptDrawBlurredRRect`. Fixes https://github.com/flutter/flutter/issues/163893. Fixes https://github.com/flutter/flutter/issues/167366. This approximate algorithm is implemented by adding additional retraction to RRect's algorithm. Since they share most the logic, much effort is made to ensure reasonable code share. I've also built a playground test `RoundSuperellipseShadowComparison` to compare the effect between the fast algorithm and the bruteforce algorithm, and added a macrobenchmark "rsuperellipse_blur". ### Result The following video shows the reproduction app from https://github.com/flutter/flutter/issues/167366, which shows much better framerate on RSE after the PR, almost the same as RRect. (I've verified that it was much worse without the PR.) https://github.com/user-attachments/assets/5433af91-c0a1-4b15-9161-cf2280543e27 The following video shows the `RoundSuperellipseShadowComparison` playground, which compares the fast algorithm (left) against the bruteforce algorithm (right). * Pay attention to the cases with small but non zero sigma. They should be of almost the same shape as those with zero sigma, which skips the blurring altogether. With this algorithm, the difference between the two cases are about 1~2 pixel at most. https://github.com/user-attachments/assets/e26d2d8f-d29e-4db8-9c20-67103d77891c The following images compare macrobenchmarks "rrect_blur" against the new "rsuperellipse_blur". (Notice that the avg frame time fluctuates a lot but at least it shows that they're on par.) <img width="389" alt="image" src="https://github.com/user-attachments/assets/67cf4b10-f13f-4e55-bdfd-35d358617f38" /> <img width="365" alt="image" src="https://github.com/user-attachments/assets/6869fa9c-5752-4a11-babe-b6a2d590ebc9" /> ### Open questions * Should I improve the code share of shader files? Currently they're not shared mostly because I'm not sure about its gain and cost. ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md |
||
---|---|---|
.. | ||
android | ||
assets | ||
ios | ||
lib | ||
macos | ||
test | ||
test_driver | ||
test_memory | ||
web | ||
.gitignore | ||
pubspec.yaml | ||
README.md |
Macrobenchmarks
Performance benchmarks use either flutter drive or the web benchmark harness.
Mobile benchmarks
Cull opacity benchmark
To run the cull opacity benchmark on a device:
flutter drive --profile -t test_driver/run_app.dart --driver test_driver/cull_opacity_perf_test.dart
Results should be in the file build/cull_opacity_perf.timeline_summary.json
.
More detailed logs should be in build/cull_opacity_perf.timeline.json
.
Cubic bezier benchmark
To run the cubic-bezier benchmark on a device:
flutter drive --profile -t test_driver/run_app.dart --driver test_driver/cubic_bezier_perf_test.dart
Results should be in the file build/cubic_bezier_perf.timeline_summary.json
.
More detailed logs should be in build/cubic_bezier_perf.timeline.json
.
Backdrop filter benchmark
To run the backdrop filter benchmark on a device: To run a mobile benchmark on a device:
flutter drive --profile -t test_driver/run_app.dart --driver test_driver/[test_name]_test.dart
Results should be in the file build/[test_name].timeline_summary.json
.
More detailed logs should be in build/[test_name].timeline.json
.
The key [test_name]
can be:
animated_placeholder_perf
backdrop_filter_perf
color_filter_and_fade_perf
cubic_bezier_perf
cull_opacity_perf
fading_child_animation_perf
imagefiltered_transform_animation_perf
multi_widget_construction_perf
picture_cache_perf
post_backdrop_filter_perf
simple_animation_perf
textfield_perf
fullscreen_textfield_perf
E2E benchmarks
(On-going work)
E2E-based tests are driven independent of the host machine. The following tests are E2E:
cull_opacity_perf.dart
multi_widget_construction_perf
These tests should be run by:
flutter drive --profile -t test/[test_name]_e2e.dart --driver test_driver/e2e_test.dart
Web benchmarks
Web benchmarks are compiled from the same entry point in lib/web_benchmarks.dart
.
How to write a web benchmark
Create a new file for your benchmark under lib/src/web
. See bench_draw_rect.dart
as an example.
Choose one of the two benchmark types:
- A "raw benchmark" records performance metrics from direct interactions with
dart:ui
with no framework. This kind of benchmark is good for benchmarking low-level engine primitives, such as layer, picture, and semantics performance. - A "widget benchmark" records performance metrics using a widget. This kind of benchmark is good for measuring the performance of widgets, often together with engine work that widget-under-test incurs.
- A "widget build benchmark" records the cost of building a widget from nothing. This is different from the "widget benchmark" because typically the latter only performs incremental UI updates, such as an animation. In contrast, this benchmark pumps an empty frame to clear all previously built widgets and rebuilds them from scratch.
For a raw benchmark extend RawRecorder
(tip: you can start by copying
bench_draw_rect.dart
).
For a widget benchmark extend WidgetRecorder
(tip: you can start by copying
bench_simple_lazy_text_scroll.dart
).
For a widget build benchmark extend WidgetBuildRecorder
(tip: you can start by copying
bench_build_material_checkbox.dart
).
Pick a unique benchmark name and class name and add it to the benchmarks
list
in lib/web_benchmarks.dart
.
How to run a web benchmark
Web benchmarks can be run using flutter run
in debug, profile, and release
modes, using either the CanvasKit or the Skwasm rendering backend. Note, however,
that running in debug mode will result in worse numbers. Profile mode is useful
for profiling in Chrome DevTools because the numbers are close to release mode
and the profile contains unobfuscated names.
Example:
cd dev/benchmarks/macrobenchmarks
# Runs in profile mode
flutter run --profile -d web-server lib/web_benchmarks.dart
You can also run all benchmarks exactly as the devicelab runs them:
cd dev/devicelab
# Runs using the CanvasKit renderer
../../bin/cache/dart-sdk/bin/dart bin/run.dart -t bin/tasks/web_benchmarks_canvaskit.dart
Frame policy test
File test/frame_policy.dart
and its driving script test_driver/frame_policy_test.dart
are used for testing fullyLive
and benchmarkLive
policies in terms of its effect on WidgetTester.handlePointerEventRecord
.