Skip to main content

raster_bench/
raster_bench.rs

1//! The raster cost picture. Times the two CPU raster
2//! paths per glyph across the tier sizes, latin vs CJK, so tier thresholds
3//! and generator work are chosen from numbers instead of vibes.
4//!
5//! Run: `cargo run --release -p valo-text --example raster_bench`
6
7use std::time::Instant;
8
9use valo_text::{FaceSet, FontId, Rasterizer};
10
11const SIZES: [f32; 6] = [16.0, 32.0, 72.0, 162.0, 256.0, 324.0];
12const LATIN: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn";
13const CJK: &str =
14    "春夏秋冬风花雪月山水天地日出而作息万物生长设计海报标题正文字体渲染引擎性能测试基准数据";
15
16fn main() {
17    let dir = concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/fonts");
18    // A CJK face is 20k+ glyphs and too big to vendor: point VALO_CJK_FONT
19    // at one to get the CJK column, otherwise the bench runs latin only.
20    let cjk_file = std::env::var("VALO_CJK_FONT").unwrap_or_default();
21    let mut fonts = FaceSet::default();
22    let latin = fonts
23        .register(
24            "Latin",
25            std::fs::read(format!("{dir}/fira_sans.ttf")).unwrap(),
26        )
27        .unwrap();
28    let cjk = std::fs::read(cjk_file)
29        .ok()
30        .and_then(|bytes| fonts.register("CJK", bytes));
31
32    let mut sets = vec![("latin", latin, glyphs(&fonts, latin, LATIN))];
33    if let Some(id) = cjk {
34        sets.push(("cjk", id, glyphs(&fonts, id, CJK)));
35    }
36
37    println!(
38        "{:>6} {:>6}  {:>12} {:>12}  (µs/glyph, n={})",
39        "set",
40        "px",
41        "alpha",
42        "sdf",
43        LATIN.len()
44    );
45    let mut raster = Rasterizer::new();
46    for (label, font, ids) in &sets {
47        for px in SIZES {
48            let alpha = time_per_glyph(ids, |g| {
49                raster.alpha(fonts.get(*font), g, px, 0.0);
50            });
51            let mut raster2 = Rasterizer::new();
52            let sdf = time_per_glyph(ids, |g| {
53                raster2.sdf(fonts.get(*font), g, px);
54            });
55            println!("{label:>6} {px:>6.0}  {alpha:>10.1}µs {sdf:>10.1}µs");
56        }
57    }
58}
59
60fn glyphs(fonts: &FaceSet, id: FontId, text: &str) -> Vec<u32> {
61    let font = fonts.get(id);
62    text.chars().filter_map(|ch| font.glyph_for(ch)).collect()
63}
64
65fn time_per_glyph(ids: &[u32], mut raster: impl FnMut(u32)) -> f64 {
66    let t0 = Instant::now();
67    for &g in ids {
68        raster(g);
69    }
70    t0.elapsed().as_secs_f64() * 1e6 / ids.len() as f64
71}