blob: 50fcbc3a1044df124f9477fad24ccfef7fa323fb [file]
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT
use crate::SEED;
use crate::fine::{BENCH_WIDTH, default_blend, fill_single};
use criterion::{Bencher, Criterion};
use rand::prelude::StdRng;
use rand::{Rng, SeedableRng};
use smallvec::{SmallVec, smallvec};
use vello_common::color::palette::css::{BLUE, GREEN, RED, YELLOW};
use vello_common::color::{AlphaColor, DynamicColor, Srgb};
use vello_common::encode::EncodeExt;
use vello_common::fearless_simd::Simd;
use vello_common::kurbo::{Affine, Point};
use vello_common::peniko;
use vello_common::peniko::{ColorStop, ColorStops, Gradient, GradientKind};
use vello_cpu::fine::{Fine, FineKernel};
use vello_cpu::peniko::LinearGradientPosition;
use vello_dev_macros::vello_bench;
pub fn gradient(c: &mut Criterion) {
linear::opaque(c);
radial::opaque(c);
radial::opaque_conical(c);
sweep::opaque(c);
extend::pad(c);
extend::repeat(c);
extend::reflect(c);
many_stops(c);
transparent(c);
}
#[vello_bench]
fn many_stops<S: Simd, N: FineKernel<S>>(b: &mut Bencher<'_>, fine: &mut Fine<S, N>) {
let kind = LinearGradientPosition {
start: Point::new(128.0, 128.0),
end: Point::new(134.0, 134.0),
}
.into();
gradient_base(b, fine, peniko::Extend::Repeat, kind, get_many_stops());
}
#[vello_bench]
fn transparent<S: Simd, N: FineKernel<S>>(b: &mut Bencher<'_>, fine: &mut Fine<S, N>) {
let kind = LinearGradientPosition {
start: Point::new(128.0, 128.0),
end: Point::new(134.0, 134.0),
}
.into();
gradient_base(
b,
fine,
peniko::Extend::Pad,
kind,
stops_blue_green_red_yellow_transparent(),
);
}
mod extend {
use crate::fine::gradient::{gradient_base, stops_blue_green_red_yellow_opaque};
use criterion::Bencher;
use vello_common::fearless_simd::Simd;
use vello_common::kurbo::Point;
use vello_common::peniko;
use vello_cpu::{
fine::{Fine, FineKernel},
peniko::LinearGradientPosition,
};
use vello_dev_macros::vello_bench;
fn extend<S: Simd, N: FineKernel<S>>(
b: &mut Bencher<'_>,
fine: &mut Fine<S, N>,
extend: peniko::Extend,
) {
let kind = LinearGradientPosition {
start: Point::new(128.0, 128.0),
end: Point::new(134.0, 134.0),
}
.into();
gradient_base(b, fine, extend, kind, stops_blue_green_red_yellow_opaque());
}
#[vello_bench]
pub(super) fn pad<S: Simd, N: FineKernel<S>>(b: &mut Bencher<'_>, fine: &mut Fine<S, N>) {
extend(b, fine, peniko::Extend::Pad);
}
#[vello_bench]
pub(super) fn reflect<S: Simd, N: FineKernel<S>>(b: &mut Bencher<'_>, fine: &mut Fine<S, N>) {
extend(b, fine, peniko::Extend::Reflect);
}
#[vello_bench]
pub(super) fn repeat<S: Simd, N: FineKernel<S>>(b: &mut Bencher<'_>, fine: &mut Fine<S, N>) {
extend(b, fine, peniko::Extend::Repeat);
}
}
mod linear {
use crate::fine::gradient::{gradient_base, stops_blue_green_red_yellow_opaque};
use criterion::Bencher;
use vello_common::fearless_simd::Simd;
use vello_common::kurbo::Point;
use vello_common::peniko;
use vello_cpu::{
fine::{Fine, FineKernel},
peniko::LinearGradientPosition,
};
use vello_dev_macros::vello_bench;
#[vello_bench]
pub(super) fn opaque<S: Simd, N: FineKernel<S>>(b: &mut Bencher<'_>, fine: &mut Fine<S, N>) {
let kind = LinearGradientPosition {
start: Point::new(128.0, 128.0),
end: Point::new(134.0, 134.0),
}
.into();
gradient_base(
b,
fine,
peniko::Extend::Pad,
kind,
stops_blue_green_red_yellow_opaque(),
);
}
}
mod radial {
use crate::fine::BENCH_WIDTH;
use crate::fine::gradient::{gradient_base, stops_blue_green_red_yellow_opaque};
use criterion::Bencher;
use vello_common::fearless_simd::Simd;
use vello_common::kurbo::Point;
use vello_common::peniko;
use vello_common::tile::Tile;
use vello_cpu::{
fine::{Fine, FineKernel},
peniko::RadialGradientPosition,
};
use vello_dev_macros::vello_bench;
#[vello_bench]
pub(super) fn opaque<S: Simd, N: FineKernel<S>>(b: &mut Bencher<'_>, fine: &mut Fine<S, N>) {
let kind = RadialGradientPosition {
start_center: Point::new(BENCH_WIDTH as f64 / 2.0, (Tile::HEIGHT / 2) as f64),
start_radius: 25.0,
end_center: Point::new(BENCH_WIDTH as f64 / 2.0, (Tile::HEIGHT / 2) as f64),
end_radius: 75.0,
}
.into();
gradient_base(
b,
fine,
peniko::Extend::Pad,
kind,
stops_blue_green_red_yellow_opaque(),
);
}
#[vello_bench]
pub(super) fn opaque_conical<S: Simd, N: FineKernel<S>>(
b: &mut Bencher<'_>,
fine: &mut Fine<S, N>,
) {
let kind = RadialGradientPosition {
start_center: Point::new(BENCH_WIDTH as f64 / 2.0, (Tile::HEIGHT / 2) as f64),
start_radius: 25.0,
end_center: Point::new(
BENCH_WIDTH as f64 / 2.0 + 5.0,
(Tile::HEIGHT / 2) as f64 + 5.0,
),
end_radius: 75.0,
}
.into();
gradient_base(
b,
fine,
peniko::Extend::Pad,
kind,
stops_blue_green_red_yellow_opaque(),
);
}
}
mod sweep {
use crate::fine::BENCH_WIDTH;
use crate::fine::gradient::{gradient_base, stops_blue_green_red_yellow_opaque};
use criterion::Bencher;
use vello_common::fearless_simd::Simd;
use vello_common::kurbo::Point;
use vello_common::peniko;
use vello_common::tile::Tile;
use vello_cpu::{
fine::{Fine, FineKernel},
peniko::SweepGradientPosition,
};
use vello_dev_macros::vello_bench;
#[vello_bench]
pub(super) fn opaque<S: Simd, N: FineKernel<S>>(b: &mut Bencher<'_>, fine: &mut Fine<S, N>) {
let kind = SweepGradientPosition {
center: Point::new(BENCH_WIDTH as f64 / 2.0, (Tile::HEIGHT / 2) as f64),
start_angle: 70.0_f32.to_radians(),
end_angle: 250.0_f32.to_radians(),
}
.into();
gradient_base(
b,
fine,
peniko::Extend::Pad,
kind,
stops_blue_green_red_yellow_opaque(),
);
}
}
fn gradient_base<S: Simd, N: FineKernel<S>>(
b: &mut Bencher<'_>,
fine: &mut Fine<S, N>,
extend: peniko::Extend,
kind: GradientKind,
stops: ColorStops,
) {
let mut paints = vec![];
let grad = Gradient {
kind,
stops,
extend,
..Default::default()
};
let paint = grad.encode_into(&mut paints, Affine::IDENTITY, None);
fill_single(&paint, &paints, BENCH_WIDTH, b, default_blend(), fine);
}
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_transparent() -> 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)),
},
])
}
fn get_many_stops() -> ColorStops {
let mut vec = SmallVec::new();
let mut rng = StdRng::from_seed(SEED);
let max = 120;
for i in 0..=120 {
let offset = i as f32 / max as f32;
let color = DynamicColor::from_alpha_color(AlphaColor::<Srgb>::new([
rng.random::<f32>(),
rng.random::<f32>(),
rng.random::<f32>(),
rng.random::<f32>(),
]));
vec.push(ColorStop { offset, color });
}
ColorStops(vec)
}