1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 06:40:06 -04:00

Optimize tessellation of filled circles (#1616)

When painting a scatter plot we sometimes want to paint hundreds of thousands of points (filled circles) on screen every frame.

In this PR the font texture atlas is pre-populated with some filled circled of various radii. These are then used when painting (small) filled circled, which means A LOT less triangles and vertices are generated for them.

In a new benchmark we can see a 10x speedup in circle tessellation, but the the real benefit comes in the painting of these circles: since we generate a lot less vertices, the backend painter has less to do.

In a real-life scenario with a lot of things being painted (including around 100k points) I saw tessellation go from 35ms -> 7ms and painting go from 45ms -> 1ms. This means the total frame time went from 80ms to 8ms, or a 10x speedup.
This commit is contained in:
Emil Ernerfeldt
2022-05-10 19:31:19 +02:00
committed by GitHub
parent 28efc0e1c8
commit 7b18fab7a4
12 changed files with 232 additions and 23 deletions

View File

@@ -1,6 +1,6 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use epaint::{pos2, Color32, Shape, Stroke};
use epaint::*;
fn single_dashed_lines(c: &mut Criterion) {
c.bench_function("single_dashed_lines", move |b| {
@@ -39,5 +39,43 @@ fn many_dashed_lines(c: &mut Criterion) {
});
}
criterion_group!(benches, single_dashed_lines, many_dashed_lines);
fn tessellate_circles(c: &mut Criterion) {
c.bench_function("tessellate_circles_100k", move |b| {
let radii: [f32; 10] = [1.0, 2.0, 3.6, 4.0, 5.7, 8.0, 10.0, 13.0, 15.0, 17.0];
let mut clipped_shapes = vec![];
for r in radii {
for _ in 0..10_000 {
let clip_rect = Rect::from_min_size(Pos2::ZERO, Vec2::splat(1024.0));
let shape = Shape::circle_filled(Pos2::new(10.0, 10.0), r, Color32::WHITE);
clipped_shapes.push(ClippedShape(clip_rect, shape));
}
}
assert_eq!(clipped_shapes.len(), 100_000);
let pixels_per_point = 2.0;
let options = TessellationOptions::default();
let atlas = TextureAtlas::new([4096, 256]);
let font_tex_size = atlas.size();
let prepared_discs = atlas.prepared_discs();
b.iter(|| {
let clipped_primitive = tessellate_shapes(
pixels_per_point,
options,
font_tex_size,
prepared_discs.clone(),
clipped_shapes.clone(),
);
black_box(clipped_primitive);
});
});
}
criterion_group!(
benches,
single_dashed_lines,
many_dashed_lines,
tessellate_circles
);
criterion_main!(benches);