-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Open
Labels
P3Issues that are less important to the Flutter projectIssues that are less important to the Flutter projectengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.22Found to occur in 3.22Found to occur in 3.22found in release: 3.24Found to occur in 3.24Found to occur in 3.24has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onteam-engineOwned by Engine teamOwned by Engine teamtriaged-engineTriaged by Engine teamTriaged by Engine team
Description
Beyond about 10,000 points, the raster overhead of a drawPoints call becomes too slow to be usable in interactive UIs or animations.
It seems to be worse on Skia on Linux than on Impeller and Android, though it is a problem in both cases.
Benchmark code
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() {
runApp(const Test());
}
class Test extends StatefulWidget {
const Test({super.key});
@override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
final List<Offset> points = [];
final math.Random random = math.Random(0);
@override
void initState() {
super.initState();
print('count,vsyncOverhead,buildDuration,rasterDuration,totalSpan');
addPoints(1024);
SchedulerBinding.instance.addTimingsCallback(_timings);
}
@override
void reassemble() {
super.reassemble();
}
@override
void dispose() {
SchedulerBinding.instance.removeTimingsCallback(_timings);
super.dispose();
}
void _timings(List<FrameTiming> timings) {
for (FrameTiming timing in timings) {
print('${points.length},${timing.vsyncOverhead.inMilliseconds},${timing.buildDuration.inMilliseconds},${timing.rasterDuration.inMilliseconds},${timing.totalSpan.inMilliseconds}');
}
setState(() {
int more = (points.length / 16).ceil();
addPoints(more);
});
}
void addPoints(int more) {
for (int index = 0; index < more; index += 1) {
points.add(Offset(random.nextDouble() * 1000, random.nextDouble() * 1000));
}
if (points.length >= 1<<21) {
points.clear();
addPoints(1024);
}
}
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: Painter(
points: points.toList(),
),
);
}
}
class Painter extends CustomPainter {
Painter({
required this.points,
});
final List<Offset> points;
@override
void paint(Canvas canvas, Size size) {
canvas.drawPaint(Paint()..color = const Color(0xFF000000));
canvas.drawPoints(PointMode.points, points, Paint()..strokeWidth = 2.0..color = const Color(0xFFFFFFFF));
}
@override
bool shouldRepaint(Painter oldDelegate) => points != oldDelegate.points;
}Measuring the raster time for drawPoints at various numbers of points gives the following results:


Source: raw data
Drawing many points is useful when rendering extensive data sets, such as stars in a galaxy:
...but unfortunately the current performance makes this kind of UI impractical.
Metadata
Metadata
Assignees
Labels
P3Issues that are less important to the Flutter projectIssues that are less important to the Flutter projectengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.22Found to occur in 3.22Found to occur in 3.22found in release: 3.24Found to occur in 3.24Found to occur in 3.24has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onteam-engineOwned by Engine teamOwned by Engine teamtriaged-engineTriaged by Engine teamTriaged by Engine team
