mod scenes;
use criterion::{Criterion, criterion_group, criterion_main};
use std::hint::black_box;
use kurbo::{Affine, Point, Shape};
use peniko::color::{ColorSpaceTag, DynamicColor, HueDirection};
use peniko::{
Brush, Color, ColorStop, ColorStops, Fill, Gradient, GradientKind, LinearGradientPosition,
};
use vello_common::encode::EncodedPaint;
use vello_common::fearless_simd::Level;
use vello_common::strip_generator::{GenerationMode, StripGenerator, StripStorage};
use frust_engine::gpu::{GpuStrip, StripDraw};
use frust_engine::{SceneCompiler, encode_brush};
use scenes::{VIEWPORT, glyph_run_placeholder, icon_set, rect_page};
const RECT_COUNT: usize = 200;
const ICON_COUNT: usize = 50;
const GLYPH_COUNT: usize = 400;
fn compile_group(c: &mut Criterion) {
let mut group = c.benchmark_group("compile");
let page = rect_page(RECT_COUNT);
group.bench_function("rect_page_200", |b| {
let mut compiler = SceneCompiler::new(VIEWPORT.0, VIEWPORT.1);
b.iter(|| {
let frame = compiler
.compile(black_box(&page), Affine::IDENTITY, VIEWPORT)
.expect("fixture scene compiles");
black_box(frame.draws().len());
});
});
let icons = icon_set(ICON_COUNT);
group.bench_function("icon_set_50", |b| {
let mut compiler = SceneCompiler::new(VIEWPORT.0, VIEWPORT.1);
b.iter(|| {
let frame = compiler
.compile(black_box(&icons), Affine::IDENTITY, VIEWPORT)
.expect("fixture scene compiles");
black_box(frame.draws().len());
});
});
let glyphs = glyph_run_placeholder(GLYPH_COUNT);
group.bench_function("glyph_run_400_reserved", |b| {
let mut compiler = SceneCompiler::new(VIEWPORT.0, VIEWPORT.1);
b.iter(|| {
let frame = compiler
.compile(black_box(&glyphs), Affine::IDENTITY, VIEWPORT)
.expect("fixture scene compiles");
black_box(frame.draws().len());
});
});
group.finish();
}
fn strip_generation_group(c: &mut Criterion) {
let mut group = c.benchmark_group("strip_generation");
let (width, height) = VIEWPORT;
let paths: Vec<_> = (0..RECT_COUNT)
.map(|i| {
let col = (i % 20) as f64;
let row = (i / 20) as f64;
let center = Point::new(20.0 + col * 48.0, 20.0 + row * 32.0);
kurbo::Circle::new(center, 10.0).to_path(0.1)
})
.collect();
group.bench_function("filled_circles_200", |b| {
let level = Level::try_detect().unwrap_or(Level::baseline());
let mut generator = StripGenerator::new(width, height, level);
b.iter(|| {
generator.reset(width, height);
let mut storage = StripStorage::new(GenerationMode::Append);
for path in &paths {
generator.generate_filled_path(
black_box(path.iter()),
Fill::NonZero,
Affine::IDENTITY,
None,
&mut storage,
None,
);
}
black_box(storage.strips.len());
});
});
group.finish();
}
fn alpha_packing_group(c: &mut Criterion) {
let mut group = c.benchmark_group("alpha_packing");
let page = rect_page(RECT_COUNT);
let mut compiler = SceneCompiler::new(VIEWPORT.0, VIEWPORT.1);
let frame = compiler
.compile(&page, Affine::IDENTITY, VIEWPORT)
.expect("fixture scene compiles");
let strips = frame.strip_buf();
group.bench_function("rect_page_200", |b| {
b.iter(|| {
let draw = StripDraw {
payload: 0,
paint: 0,
depth_index: 0,
};
let mut instances = Vec::with_capacity(strips.len());
for pair in black_box(strips).windows(2) {
let span = GpuStrip::from_strip_pair(&pair[0], &pair[1], draw);
if span.width > 0 {
instances.push(span);
}
if let Some(gap) = GpuStrip::gap_fill(&pair[0], &pair[1], draw) {
instances.push(gap);
}
}
black_box(instances.len());
});
});
group.finish();
}
fn paint_encoding_group(c: &mut Criterion) {
let mut group = c.benchmark_group("paint_encoding");
let solid = Brush::Solid(Color::from_rgba8(30, 120, 220, 255));
let gradient = Brush::Gradient(Gradient {
kind: linear_kind(),
stops: stops(),
interpolation_cs: ColorSpaceTag::Srgb,
hue_direction: HueDirection::Shorter,
..Default::default()
});
let brushes = [solid, gradient];
group.bench_function("solid_and_gradient_x100", |b| {
b.iter(|| {
let mut encoded_paints: Vec<EncodedPaint> = Vec::new();
for _ in 0..100 {
for brush in black_box(&brushes) {
let encoding = encode_brush(brush, Affine::IDENTITY, &mut encoded_paints);
black_box(encoding);
}
}
black_box(encoded_paints.len());
});
});
group.finish();
}
fn linear_kind() -> GradientKind {
LinearGradientPosition {
start: Point::new(0.0, 0.0),
end: Point::new(100.0, 0.0),
}
.into()
}
fn stops() -> ColorStops {
ColorStops(
vec![
ColorStop {
offset: 0.0,
color: DynamicColor::from_alpha_color(Color::from_rgb8(255, 0, 0)),
},
ColorStop {
offset: 0.5,
color: DynamicColor::from_alpha_color(Color::from_rgb8(0, 255, 0)),
},
ColorStop {
offset: 1.0,
color: DynamicColor::from_alpha_color(Color::from_rgb8(0, 0, 255)),
},
]
.into(),
)
}
criterion_group!(
benches,
compile_group,
strip_generation_group,
alpha_packing_group,
paint_encoding_group,
);
criterion_main!(benches);