tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5364Rust 86Markdown 12TOML 91841 Sutichaykuna

⎇ fd8f81fc639e71cecef3a6bb618bca6606bdf644 benches/benches/mixed.rs Rust · 170 siq'ikuna · 6.2 KB Ñawpa willay Pi imata llamkarqan ch'uya

Mixed benchmark fixups (#900) fd8f81fc6 · Nico Burns ·

1use cosmic_text::{Attrs, Buffer, FontSystem, Metrics, Shaping};
2use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
3use rand::prelude::*;
4use rand_chacha::ChaCha8Rng;
5use std::iter;
6use taffy::prelude::*;
7use taffy::style::Style;
8
9pub const LOREM_IPSUM : &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
10
11struct CosmicTextContext {
12    buffer: cosmic_text::Buffer,
13}
14
15impl CosmicTextContext {
16    fn new(metrics: Metrics, text: &str, attrs: Attrs, font_system: &mut FontSystem) -> Self {
17        let mut buffer = Buffer::new_empty(metrics);
18        buffer.set_size(font_system, None, None);
19        buffer.set_text(font_system, text, attrs, Shaping::Advanced);
20        buffer.shape_until_scroll(font_system, false);
21        Self { buffer }
22    }
23
24    fn measure(
25        &mut self,
26        known_dimensions: taffy::Size<Option<f32>>,
27        available_space: taffy::Size<taffy::AvailableSpace>,
28        font_system: &mut FontSystem,
29    ) -> taffy::Size<f32> {
30        let width_constraint = known_dimensions.width.or(match available_space.width {
31            AvailableSpace::MinContent => Some(0.0),
32            AvailableSpace::MaxContent => None,
33            AvailableSpace::Definite(width) => Some(width),
34        });
35        self.buffer.set_size(font_system, width_constraint, None);
36
37        let (width, total_lines) = self
38            .buffer
39            .layout_runs()
40            .fold((0.0, 0usize), |(width, total_lines), run| (run.line_w.max(width), total_lines + 1));
41        let height = total_lines as f32 * self.buffer.metrics().line_height;
42
43        taffy::Size { width, height }
44    }
45}
46
47fn measure_function(
48    known_dimensions: taffy::Size<Option<f32>>,
49    available_space: taffy::Size<taffy::AvailableSpace>,
50    node_context: Option<&mut CosmicTextContext>,
51    font_system: &mut FontSystem,
52) -> Size<f32> {
53    if let Size { width: Some(width), height: Some(height) } = known_dimensions {
54        return Size { width, height };
55    }
56
57    match node_context {
58        None => Size::ZERO,
59        Some(text_context) => text_context.measure(known_dimensions, available_space, font_system),
60    }
61}
62
63fn random_grid_track<R: Rng>(rng: &mut R) -> GridTemplateComponent<String> {
64    let switch: f32 = rng.random_range(0.0..=1.0);
65    if switch < 0.1 {
66        auto()
67    } else if switch < 0.2 {
68        min_content()
69    } else if switch < 0.3 {
70        max_content()
71    } else if switch < 0.5 {
72        fr(1.0)
73    } else if switch < 0.6 {
74        minmax(length(0.0), fr(1.0))
75    } else if switch < 0.8 {
76        length(40.0)
77    } else {
78        percent(0.3)
79    }
80}
81
82fn random_nxn_grid_style<R: Rng>(rng: &mut R, track_count: usize) -> Style {
83    Style {
84        display: Display::Grid,
85        grid_template_columns: iter::from_fn(|| Some(random_grid_track(rng))).take(track_count).collect(),
86        grid_template_rows: iter::from_fn(|| Some(random_grid_track(rng))).take(track_count).collect(),
87        ..Default::default()
88    }
89}
90
91fn random_flex_style<R: Rng>(rng: &mut R) -> Style {
92    Style {
93        display: Display::Flex,
94        flex_direction: if rng.random_bool(0.5) { FlexDirection::Row } else { FlexDirection::Column },
95        flex_wrap: if rng.random_bool(0.5) { FlexWrap::Wrap } else { FlexWrap::NoWrap },
96        ..Default::default()
97    }
98}
99
100fn build_mixed_tree(
101    taffy: &mut TaffyTree<CosmicTextContext>,
102    font_system: &mut FontSystem,
103    depth: usize,
104    width: usize,
105    rng: &mut ChaCha8Rng,
106    is_grid: bool,
107) -> NodeId {
108    if depth == 0 {
109        let metrics = Metrics { font_size: 14.0, line_height: 16.0 };
110        let context = CosmicTextContext::new(metrics, LOREM_IPSUM, Attrs::new(), font_system);
111        return taffy.new_leaf_with_context(Style::default(), context).unwrap();
112    }
113
114    let children: Vec<NodeId> =
115        (0..width).map(|_| build_mixed_tree(taffy, font_system, depth - 1, width, rng, !is_grid)).collect();
116
117    let style = if is_grid {
118        random_nxn_grid_style(rng, (width as f32).sqrt().ceil() as usize)
119    } else {
120        random_flex_style(rng)
121    };
122
123    taffy.new_with_children(style, &children).unwrap()
124}
125
126fn mixed_benchmark(c: &mut Criterion) {
127    let font_system = std::cell::RefCell::new(FontSystem::new());
128    let mut group = c.benchmark_group("mixed_flex_grid");
129
130    let depths = [2, 4];
131    let widths = [4, 8];
132
133    for &depth in &depths {
134        for &width in &widths {
135            let benchmark_id = BenchmarkId::new("mixed", format!("depth_{}_width_{}", depth, width));
136            group.bench_with_input(benchmark_id, &(depth, width), |b, &(depth, width)| {
137                b.iter_batched(
138                    || {
139                        let mut taffy = TaffyTree::new();
140                        let mut rng = ChaCha8Rng::seed_from_u64(12345);
141                        let root =
142                            build_mixed_tree(&mut taffy, &mut font_system.borrow_mut(), depth, width, &mut rng, true);
143                        (taffy, root)
144                    },
145                    |(mut taffy, root)| {
146                        taffy
147                            .compute_layout_with_measure(
148                                root,
149                                Size::MAX_CONTENT,
150                                |known_dimensions, available_space, _node_id, node_context, _style| {
151                                    measure_function(
152                                        known_dimensions,
153                                        available_space,
154                                        node_context,
155                                        &mut font_system.borrow_mut(),
156                                    )
157                                },
158                            )
159                            .unwrap();
160                    },
161                    criterion::BatchSize::SmallInput,
162                )
163            });
164        }
165    }
166    group.finish();
167}
168
169criterion_group!(benches, mixed_benchmark);
170criterion_main!(benches);