blob: d3a125d45edad677ee4be6d4e8a9364ae2dac350 [file]
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT
use crate::SEED;
use criterion::Criterion;
use rand::prelude::StdRng;
use rand::{Rng, SeedableRng};
use smallvec::smallvec;
use vello_common::coarse::WideTile;
use vello_common::color::DynamicColor;
use vello_common::color::palette::css::{BLUE, GREEN, RED, ROYAL_BLUE, YELLOW};
use vello_common::encode::{EncodeExt, EncodedPaint};
use vello_common::kurbo::{Affine, Point};
use vello_common::paint::{Paint, PremulColor};
use vello_common::peniko;
use vello_common::peniko::{
BlendMode, ColorStop, ColorStops, Compose, Gradient, GradientKind, Mix,
};
use vello_common::tile::Tile;
use vello_cpu::fine::{Fine, SCRATCH_BUF_SIZE};
pub fn fill(c: &mut Criterion) {
let mut g = c.benchmark_group("fine/fill");
macro_rules! fill_single {
($name:ident, $paint:expr, $paints:expr, $width:expr) => {
g.bench_function(stringify!($name), |b| {
let mut fine = Fine::new(WideTile::WIDTH, Tile::HEIGHT);
let paint = $paint;
let paints: &[EncodedPaint] = $paints;
b.iter(|| {
fine.fill(
0,
$width,
paint,
BlendMode::new(Mix::Normal, Compose::SrcOver),
paints,
);
std::hint::black_box(&fine);
})
});
};
}
fill_single!(
solid_opaque,
&Paint::Solid(PremulColor::new(ROYAL_BLUE)),
&[],
WideTile::WIDTH as usize
);
fill_single!(
solid_opaque_short,
&Paint::Solid(PremulColor::new(ROYAL_BLUE)),
&[],
16
);
fill_single!(
solid_transparent,
&Paint::Solid(PremulColor::new(ROYAL_BLUE.with_alpha(0.2))),
&[],
WideTile::WIDTH as usize
);
macro_rules! fill_single_linear {
($name:ident, $extend:ident, $stops:expr) => {
let mut paints = vec![];
let grad = Gradient {
kind: GradientKind::Linear {
start: Point::new(0.0, 0.0),
end: Point::new(WideTile::WIDTH as f64, Tile::HEIGHT as f64),
},
stops: $stops,
extend: peniko::Extend::$extend,
..Default::default()
};
let paint = grad.encode_into(&mut paints, Affine::IDENTITY);
fill_single!($name, &paint, &paints, WideTile::WIDTH as usize);
};
}
fill_single_linear!(
linear_gradient_pad,
Pad,
stops_blue_green_red_yellow_opaque()
);
fill_single_linear!(
linear_gradient_repeat,
Repeat,
stops_blue_green_red_yellow_opaque()
);
fill_single_linear!(
linear_gradient_reflect,
Repeat,
stops_blue_green_red_yellow_opaque()
);
fill_single_linear!(
linear_gradient_transparent,
Pad,
stops_blue_green_red_yellow()
);
macro_rules! fill_single_sweep {
($name:ident, $extend:ident, $stops:expr) => {
let mut paints = vec![];
let grad = Gradient {
kind: GradientKind::Sweep {
center: Point::new(WideTile::WIDTH as f64 / 2.0, (Tile::HEIGHT / 2) as f64),
start_angle: 150.0,
end_angle: 210.0,
},
stops: $stops,
extend: peniko::Extend::$extend,
..Default::default()
};
let paint = grad.encode_into(&mut paints, Affine::IDENTITY);
fill_single!($name, &paint, &paints, WideTile::WIDTH as usize);
};
}
fill_single_sweep!(
sweep_gradient_pad,
Pad,
stops_blue_green_red_yellow_opaque()
);
fill_single_sweep!(
sweep_gradient_repeat,
Repeat,
stops_blue_green_red_yellow_opaque()
);
fill_single_sweep!(
sweep_gradient_reflect,
Reflect,
stops_blue_green_red_yellow_opaque()
);
fill_single_sweep!(
sweep_gradient_transparent,
Pad,
stops_blue_green_red_yellow()
);
macro_rules! fill_single_radial {
($name:ident, $extend:ident, $stops:expr) => {
let mut paints = vec![];
let grad = Gradient {
kind: GradientKind::Radial {
start_center: Point::new(
WideTile::WIDTH as f64 / 2.0,
(Tile::HEIGHT / 2) as f64,
),
start_radius: 25.0,
end_center: Point::new(WideTile::WIDTH as f64 / 2.0, (Tile::HEIGHT / 2) as f64),
end_radius: 75.0,
},
stops: $stops,
extend: peniko::Extend::$extend,
..Default::default()
};
let paint = grad.encode_into(&mut paints, Affine::IDENTITY);
fill_single!($name, &paint, &paints, WideTile::WIDTH as usize);
};
}
fill_single_radial!(
radial_gradient_pad,
Pad,
stops_blue_green_red_yellow_opaque()
);
fill_single_radial!(
radial_gradient_repeat,
Repeat,
stops_blue_green_red_yellow_opaque()
);
fill_single_radial!(
radial_gradient_reflect,
Reflect,
stops_blue_green_red_yellow_opaque()
);
fill_single_radial!(
radial_gradient_transparent,
Pad,
stops_blue_green_red_yellow()
);
}
pub fn strip(c: &mut Criterion) {
let mut g = c.benchmark_group("fine/strip");
let mut rng = StdRng::from_seed(SEED);
let mut alphas = vec![];
for _ in 0..WideTile::WIDTH * Tile::HEIGHT {
alphas.push(rng.random());
}
macro_rules! strip_single {
($name:ident, $paint:expr, $paints:expr, $width:expr) => {
g.bench_function(stringify!($name), |b| {
let mut fine = Fine::new(WideTile::WIDTH, Tile::HEIGHT);
let paint = $paint;
let paints: &[EncodedPaint] = $paints;
b.iter(|| {
fine.strip(
0,
$width,
&alphas,
paint,
BlendMode::new(Mix::Normal, Compose::SrcOver),
paints,
);
std::hint::black_box(&fine);
})
});
};
}
strip_single!(
basic,
&Paint::Solid(PremulColor::new(ROYAL_BLUE)),
&[],
WideTile::WIDTH as usize
);
strip_single!(
basic_short,
&Paint::Solid(PremulColor::new(ROYAL_BLUE)),
&[],
8
);
// There is not really a need to measure performance of complex paint types
// for stripping because the code path for generating the gradient data is exactly the same
// as for filling.
}
fn stops_blue_green_red_yellow_opaque() -> ColorStops {
ColorStops(smallvec![
ColorStop {
offset: 0.0,
color: DynamicColor::from_alpha_color(BLUE),
},
ColorStop {
offset: 0.33,
color: DynamicColor::from_alpha_color(GREEN),
},
ColorStop {
offset: 0.66,
color: DynamicColor::from_alpha_color(RED),
},
ColorStop {
offset: 1.0,
color: DynamicColor::from_alpha_color(YELLOW),
},
])
}
fn stops_blue_green_red_yellow() -> ColorStops {
ColorStops(smallvec![
ColorStop {
offset: 0.0,
color: DynamicColor::from_alpha_color(BLUE),
},
ColorStop {
offset: 0.33,
color: DynamicColor::from_alpha_color(GREEN.with_alpha(0.5)),
},
ColorStop {
offset: 0.66,
color: DynamicColor::from_alpha_color(RED),
},
ColorStop {
offset: 1.0,
color: DynamicColor::from_alpha_color(YELLOW.with_alpha(0.7)),
},
])
}
pub fn pack(c: &mut Criterion) {
c.bench_function("fine/pack", |b| {
let mut buf = vec![0_u8; SCRATCH_BUF_SIZE];
let mut scratch = [0_u8; SCRATCH_BUF_SIZE];
for (n, e) in scratch.iter_mut().enumerate() {
*e = u8::try_from(n % 256).unwrap();
}
let mut fine = Fine::new(WideTile::WIDTH, Tile::HEIGHT);
b.iter(|| {
fine.pack(&mut buf);
std::hint::black_box(&buf);
});
});
}