mod common;
use common::{run_bench, BenchSuite};
use edgefirst_image::{Crop, Flip, ImageProcessor, ImageProcessorTrait, Rotation};
use edgefirst_tensor::{DType, PixelFormat, TensorMapTrait, TensorTrait};
const WARMUP: usize = 10;
const DEFAULT_ITERATIONS: usize = 200;
const IN_W: usize = 1280;
const IN_H: usize = 720;
const OUT_W: usize = 640;
const OUT_H: usize = 640;
fn nv_len(fmt: PixelFormat, w: usize, h: usize) -> usize {
match fmt {
PixelFormat::Nv12 => w * h * 3 / 2,
PixelFormat::Nv16 => w * h * 2,
PixelFormat::Nv24 => w * h * 3,
_ => w * h,
}
}
fn fill_nv(buf: &mut [u8], w: usize, h: usize) {
for r in 0..h {
for c in 0..w {
buf[r * w + c] = ((r + c) * 255 / (w + h)) as u8;
}
}
for b in buf.iter_mut().skip(w * h) {
*b = 128;
}
}
fn fmt_name(f: PixelFormat) -> &'static str {
match f {
PixelFormat::Nv12 => "nv12",
PixelFormat::Nv16 => "nv16",
PixelFormat::Nv24 => "nv24",
_ => "other",
}
}
fn main() {
if std::env::var("EDGEFIRST_FORCE_BACKEND").is_err() {
unsafe { std::env::set_var("EDGEFIRST_FORCE_BACKEND", "cpu") };
}
env_logger::init();
let mut suite = BenchSuite::from_args();
let iters: usize = std::env::var("EDGEFIRST_BENCH_ITERS")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(DEFAULT_ITERATIONS);
let only = std::env::var("EDGEFIRST_BENCH_ONLY").unwrap_or_default();
println!(
"\n== CPU preprocess benchmark ({IN_W}x{IN_H} -> {OUT_W}x{OUT_H}) backend={} ==",
std::env::var("EDGEFIRST_FORCE_BACKEND").unwrap_or_else(|_| "auto".into())
);
println!(" warmup={WARMUP} iterations={iters} filter={only:?}\n");
let mut proc = match ImageProcessor::new() {
Ok(p) => p,
Err(e) => {
println!(" [skipped: ImageProcessor init failed: {e}]");
suite.finish();
return;
}
};
let lb_crop = Crop::letterbox([114, 114, 114, 255]);
for fmt in [PixelFormat::Nv12, PixelFormat::Nv16, PixelFormat::Nv24] {
let src = match proc.create_image(IN_W, IN_H, fmt, DType::U8, None) {
Ok(s) => s,
Err(e) => {
println!(" {fmt:?}: [skipped: source alloc failed: {e}]");
continue;
}
};
{
let mut map = src.as_u8().unwrap().map().unwrap();
let n = nv_len(fmt, IN_W, IN_H);
fill_nv(&mut map.as_mut_slice()[..n], IN_W, IN_H);
}
let src_bytes = nv_len(fmt, IN_W, IN_H) as u64;
let cells: &[(&str, usize, usize, PixelFormat, DType, Crop)] = &[
(
"convert_720p_to_rgb",
IN_W,
IN_H,
PixelFormat::Rgb,
DType::U8,
Crop::no_crop(),
),
(
"convert_720p_to_planar_rgb",
IN_W,
IN_H,
PixelFormat::PlanarRgb,
DType::U8,
Crop::no_crop(),
),
(
"letterbox_720p_to_640_planar_rgb",
OUT_W,
OUT_H,
PixelFormat::PlanarRgb,
DType::U8,
lb_crop,
),
(
"letterbox_720p_to_640_planar_rgb_f32",
OUT_W,
OUT_H,
PixelFormat::PlanarRgb,
DType::F32,
lb_crop,
),
(
"letterbox_720p_to_640_planar_rgb_f16",
OUT_W,
OUT_H,
PixelFormat::PlanarRgb,
DType::F16,
lb_crop,
),
];
for &(suffix, ow, oh, ofmt, odt, crop) in cells {
let name = format!("{}/{}", fmt_name(fmt), suffix);
if !only.is_empty() && !name.contains(&only) {
continue;
}
let mut dst = match proc.create_image(ow, oh, ofmt, odt, None) {
Ok(d) => d,
Err(e) => {
println!(" {name:50} [dst alloc failed: {e}]");
continue;
}
};
if let Err(e) = proc.convert(&src, &mut dst, Rotation::None, Flip::None, crop) {
println!(" {name:50} [unsupported: {e}]");
continue;
}
let r = run_bench(&name, WARMUP, iters, || {
proc.convert(&src, &mut dst, Rotation::None, Flip::None, crop)
.unwrap();
});
r.print_summary_with_throughput(src_bytes);
suite.record(&r);
}
}
suite.finish();
}