| // 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); | |
| sweep::opaque(c); | |
| if crate::EXTENDED { | |
| radial::opaque_conical(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) | |
| .expect("identity paint transform is invertible"); | |
| 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) | |
| } |