use criterion::{measurement::WallTime, BenchmarkGroup, BenchmarkId};
use rand::Fill;
use crate::bitmap::{BitmapAccess, BitmapAccessMut, BitmapRawData, BitmapRawDataMut};
use crate::colour::BlendMode;
use crate::formats::{self, PixelFormatSpec};
use crate::math::{PixelBox, PixelPoint};
use crate::op::generate::{Benchmark, ContextValueTag, DstSize, SrcSize};
use crate::{math, Bitmap};
use super::composite::CompositeOp;
use super::copy_from::CopyFromOp;
use super::fill::FillOp;
use super::fill_region::FillRegionOp;
use super::fill_region_masked::FillRegionMaskedOp;
use super::generate::{self, BinaryInputSpec, UnaryInputSpec, ValueGeneratorList};
use super::{BinaryOpSpec, GenericBinary, GenericUnary, UnaryOpSpec};
struct Signifier;
impl ContextValueTag for Signifier {
type Value = String;
}
type CriGroup<'a> = BenchmarkGroup<'a, WallTime>;
fn bench_unary_format<UIS: UnaryInputSpec, Format: PixelFormatSpec>(
group: &mut CriGroup,
ctx: &mut generate::Context,
n: usize,
) {
let gen = UIS::gen();
let op = UIS::build();
if op.is_generic::<Format>() {
return;
} else {
println!("Testing specific implementation {}", Format::NAME);
}
let mut rng = rand::rngs::ThreadRng::default();
let mut original_img = Bitmap::<Format>::new(n, n);
u8::fill_slice(original_img.data_mut(), &mut rng);
let mut out_img = original_img.clone();
ctx.insert::<DstSize>(original_img.size());
let signifier = ctx
.lookup::<Signifier>()
.map(ToOwned::to_owned)
.unwrap_or(String::new());
let params = gen.generate(ctx).expect("could not generate parameters");
group.bench_function(
BenchmarkId::new("generic", format!("{}_{signifier}_{n}", Format::NAME)),
|bencher| {
bencher.iter(|| {
<UIS as GenericUnary<UIS::Params<'static>>>::perform::<Format>(
&mut out_img,
¶ms,
);
});
},
);
group.bench_function(
BenchmarkId::new("specific", format!("{}_{signifier}_{n}", Format::NAME)),
|bencher| {
bencher.iter(|| {
op.select::<Format>()(&mut out_img, ¶ms);
});
},
);
}
fn bench_unary<UIS: UnaryInputSpec>(group: &mut CriGroup, ctx: &mut generate::Context, n: usize) {
bench_unary_format::<UIS, formats::A8>(group, ctx, n);
bench_unary_format::<UIS, formats::Abgr32>(group, ctx, n);
bench_unary_format::<UIS, formats::Rgba32>(group, ctx, n);
}
fn bench_binary_format<
BIS: BinaryInputSpec,
DstFormat: PixelFormatSpec,
SrcFormat: PixelFormatSpec,
>(
group: &mut CriGroup,
ctx: &mut generate::Context,
n: usize,
) {
let gen = BIS::gen();
let op = BIS::build();
if op.is_generic::<DstFormat, SrcFormat>() {
println!(
"Skipping generic implementation ({},{})",
DstFormat::NAME,
SrcFormat::NAME
);
return;
} else {
println!(
"Benchmarking specific implementation ({},{})",
DstFormat::NAME,
SrcFormat::NAME
);
}
let mut rng = rand::rngs::ThreadRng::default();
let mut original_dst_img = Bitmap::<DstFormat>::new(n, n);
u8::fill_slice(original_dst_img.data_mut(), &mut rng);
let mut src_img = Bitmap::<SrcFormat>::new(n, n);
u8::fill_slice(src_img.data_mut(), &mut rng);
let mut out_img = original_dst_img.clone();
ctx.insert::<DstSize>(src_img.size());
ctx.insert::<SrcSize>(src_img.size());
let signifier = ctx
.lookup::<Signifier>()
.map(ToOwned::to_owned)
.unwrap_or(String::new());
let params = gen.generate(ctx).expect("could not generate parameters");
group.bench_function(
BenchmarkId::new(
"generic",
format!("{}_{}_{signifier}_{n}", DstFormat::NAME, SrcFormat::NAME),
),
|bencher| {
bencher.iter(|| {
<BIS as GenericBinary<BIS::Params<'static>>>::perform::<DstFormat, SrcFormat>(
&mut out_img,
&src_img,
¶ms,
);
});
},
);
group.bench_function(
BenchmarkId::new(
"specific",
format!("{}_{}_{signifier}_{n}", DstFormat::NAME, SrcFormat::NAME),
),
|bencher| {
bencher.iter(|| {
op.select::<DstFormat, SrcFormat>()(&mut out_img, &src_img, ¶ms);
});
},
);
}
fn bench_binary<BIS: BinaryInputSpec>(
group: &mut criterion::BenchmarkGroup<'_, criterion::measurement::WallTime>,
ctx: &mut generate::Context,
n: usize,
) {
bench_binary_format::<BIS, formats::A8, formats::A8>(group, ctx, n);
bench_binary_format::<BIS, formats::A8, formats::Abgr32>(group, ctx, n);
bench_binary_format::<BIS, formats::A8, formats::Rgba32>(group, ctx, n);
bench_binary_format::<BIS, formats::Abgr32, formats::A8>(group, ctx, n);
bench_binary_format::<BIS, formats::Abgr32, formats::Abgr32>(group, ctx, n);
bench_binary_format::<BIS, formats::Abgr32, formats::Rgba32>(group, ctx, n);
bench_binary_format::<BIS, formats::Rgba32, formats::A8>(group, ctx, n);
bench_binary_format::<BIS, formats::Rgba32, formats::Abgr32>(group, ctx, n);
bench_binary_format::<BIS, formats::Rgba32, formats::Rgba32>(group, ctx, n);
}
pub fn op_benchmarks(cri: &mut criterion::Criterion) {
for n in [16, 64, 1024].into_iter() {
{
let mut composite = cri.benchmark_group("composite");
for blend in [
BlendMode::Simple,
BlendMode::SourceAlpha,
BlendMode::Multiply,
] {
let mut ctx = generate::Context::new(n);
ctx.insert::<BlendMode>(blend);
ctx.insert::<Benchmark>(true);
ctx.insert::<Signifier>(format!("{blend:?}"));
bench_binary::<CompositeOp>(&mut composite, &mut ctx, n);
}
}
{
let mut fill_region_masked = cri.benchmark_group("fill_region_masked");
{
for blend in [
BlendMode::Simple,
BlendMode::SourceAlpha,
BlendMode::Multiply,
] {
let mut ctx = generate::Context::new(n);
ctx.insert::<BlendMode>(blend);
ctx.insert::<Benchmark>(true);
ctx.insert::<Signifier>(format!("{blend:?}"));
bench_unary::<FillRegionMaskedOp>(&mut fill_region_masked, &mut ctx, n);
}
}
}
}
}