Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

6
vendor/png/benches/README.md vendored Normal file
View File

@@ -0,0 +1,6 @@
# Getting started with benchmarking
To run the benchmarks you need a nightly rust toolchain.
Then you launch it with
rustup run nightly cargo bench --features=benchmarks

41
vendor/png/benches/adam7.rs vendored Normal file
View File

@@ -0,0 +1,41 @@
//! Usage example:
//!
//! ```
//! $ alias bench="rustup run nightly cargo bench"
//! $ bench --bench=expand_adam7 --features=benchmarks -- --save-baseline my_baseline
//! ... tweak something, say the expansion of 8-bit ...
//! $ bench --bench=expand_adam7 --features=benchmarks -- bpp=8 --baseline my_baseline
//! ```
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use png::benchable_apis::adam7;
fn expand_all(c: &mut Criterion) {
let expand_bpp = [1, 2, 4, 8, 16, 24, 32];
let expand_size = [1 << 4, 1 << 8, 1 << 12];
for &bpp in expand_bpp.iter() {
for &sz in expand_size.iter() {
bench_group_expand_full(c, sz, bpp);
}
}
}
criterion_group!(benches, expand_all);
criterion_main!(benches);
fn bench_group_expand_full(c: &mut Criterion, sz: u32, bpp: u8) {
let mut group = c.benchmark_group("expand-adam7");
group.throughput(Throughput::Bytes(
u64::from(sz) * (u64::from(sz) * u64::from(bpp)).div_ceil(8),
));
let row_bytes = (sz as usize * usize::from(bpp)).div_ceil(8);
let buffer = vec![0u8; (sz as usize) * row_bytes];
let buffer = core::cell::RefCell::new(buffer);
let rowdata = core::hint::black_box(vec![0u8; row_bytes]);
group.bench_with_input(format!("size={sz:?}/bpp={bpp}"), &buffer, |b, img| {
b.iter(|| adam7(&mut *img.borrow_mut(), &rowdata, sz, sz, bpp));
});
}

106
vendor/png/benches/decoder.rs vendored Normal file
View File

@@ -0,0 +1,106 @@
use std::{fs, io::Cursor};
use criterion::{
criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, Throughput,
};
use png::{Decoder, Reader, Transformations};
#[path = "../src/test_utils.rs"]
mod test_utils;
fn load_all(c: &mut Criterion) {
let mut g = c.benchmark_group("decode");
for entry in fs::read_dir("tests/benches/").unwrap().flatten() {
match entry.path().extension() {
Some(st) if st == "png" => {}
_ => continue,
}
let data = fs::read(entry.path()).unwrap();
bench_file(&mut g, data, entry.file_name().into_string().unwrap());
}
g.finish();
// Small IDATS
let mut g = c.benchmark_group("generated-noncompressed-4k-idat");
bench_noncompressed_png(&mut g, 8, 4096); // 256 B
bench_noncompressed_png(&mut g, 128, 4096); // 64 KB
bench_noncompressed_png(&mut g, 2048, 4096); // 16 MB
bench_noncompressed_png(&mut g, 12288, 4096); // 576 MB
g.finish();
// Normal IDATS
let mut g = c.benchmark_group("generated-noncompressed-64k-idat");
bench_noncompressed_png(&mut g, 128, 65536); // 64 KB
bench_noncompressed_png(&mut g, 2048, 65536); // 16 MB
bench_noncompressed_png(&mut g, 12288, 65536); // 576 MB
g.finish();
// Large IDATS
let mut g = c.benchmark_group("generated-noncompressed-2g-idat");
bench_noncompressed_png(&mut g, 2048, 0x7fffffff); // 16 MB
bench_noncompressed_png(&mut g, 12288, 0x7fffffff); // 576 MB
g.finish();
// Incremental decoding via `read_row`
let mut g = c.benchmark_group("row-by-row");
let mut data = Vec::new();
test_utils::write_noncompressed_png(&mut data, 128, 4096);
bench_read_row(&mut g, data, "128x128-4k-idat");
g.finish();
}
criterion_group! {benches, load_all}
criterion_main!(benches);
fn bench_noncompressed_png(g: &mut BenchmarkGroup<WallTime>, size: u32, idat_bytes: usize) {
let mut data = Vec::new();
test_utils::write_noncompressed_png(&mut data, size, idat_bytes);
bench_file(g, data, format!("{size}x{size}.png"));
}
/// This benchmarks decoding via a call to `Reader::next_frame`.
fn bench_file(g: &mut BenchmarkGroup<WallTime>, data: Vec<u8>, name: String) {
if data.len() > 1_000_000 {
g.sample_size(10);
}
let mut reader = create_reader(data.as_slice());
let mut image = vec![0; reader.output_buffer_size().unwrap()];
let info = reader.next_frame(&mut image).unwrap();
g.throughput(Throughput::Bytes(info.buffer_size() as u64));
g.bench_with_input(name, &data, |b, data| {
b.iter(|| {
let mut reader = create_reader(data.as_slice());
reader.next_frame(&mut image).unwrap();
})
});
}
/// This benchmarks decoding via a sequence of `Reader::read_row` calls.
fn bench_read_row(g: &mut BenchmarkGroup<WallTime>, data: Vec<u8>, name: &str) {
let reader = create_reader(data.as_slice());
let mut image = vec![0; reader.output_buffer_size().unwrap()];
let bytes_per_row = reader.output_line_size(reader.info().width).unwrap();
g.throughput(Throughput::Bytes(image.len() as u64));
g.bench_with_input(name, &data, |b, data| {
b.iter(|| {
let mut reader = create_reader(data.as_slice());
for output_row in image.chunks_exact_mut(bytes_per_row) {
reader.read_row(output_row).unwrap().unwrap();
}
})
});
}
fn create_reader(data: &[u8]) -> Reader<Cursor<&[u8]>> {
let mut decoder = Decoder::new(Cursor::new(data));
// Cover default transformations used by the `image` crate when constructing
// `image::codecs::png::PngDecoder`.
decoder.set_transformations(Transformations::EXPAND);
decoder.read_info().unwrap()
}

155
vendor/png/benches/expand_paletted.rs vendored Normal file
View File

@@ -0,0 +1,155 @@
//! Usage example:
//!
//! ```
//! $ alias bench="rustup run nightly cargo bench"
//! $ bench --bench=expand_paletted --features=benchmarks -- --save-baseline my_baseline
//! ... tweak something ...
//! $ bench --bench=expand_paletted --features=benchmarks -- --baseline my_baseline
//! ```
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use png::benchable_apis::{create_info_from_plte_trns_bitdepth, create_transform_fn, TransformFn};
use png::{Info, Transformations};
use rand::Rng;
use std::fmt::{self, Display};
#[derive(Clone, Copy)]
enum TrnsPresence {
Present,
Absent,
}
impl Display for TrnsPresence {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TrnsPresence::Present => write!(f, "trns=yes"),
TrnsPresence::Absent => write!(f, "trns=no"),
}
}
}
fn expand_paletted_all(c: &mut Criterion) {
let trns_options = [TrnsPresence::Absent, TrnsPresence::Present];
let bit_depths = [4, 8];
let input_size = {
let typical_l1_cache_size = 32 * 1024;
let mut factor = 1; // input
factor += 4; // RGBA output
factor += 1; // other data
typical_l1_cache_size / factor
};
for trns in trns_options.iter().copied() {
for bit_depth in bit_depths.iter().copied() {
bench_expand_palette(c, trns, bit_depth, input_size);
}
}
bench_create_fn(c, 256, 256); // Full PLTE and trNS
bench_create_fn(c, 224, 32); // Partial PLTE and trNS
bench_create_fn(c, 16, 1); // Guess: typical for small images?
}
criterion_group!(benches, expand_paletted_all);
criterion_main!(benches);
fn get_random_bytes<R: Rng>(rng: &mut R, n: usize) -> Vec<u8> {
use rand::Fill;
let mut result = vec![0u8; n];
result.as_mut_slice().try_fill(rng).unwrap();
result
}
struct Input {
palette: Vec<u8>,
trns: Option<Vec<u8>>,
src: Vec<u8>,
src_bit_depth: u8,
}
impl Input {
fn new(trns: TrnsPresence, src_bit_depth: u8, input_size_in_bytes: usize) -> Self {
let mut rng = rand::thread_rng();
// We provide RGB entries for 192 out of 256 possible indices and Alpha/Transparency
// entries for 32 out of 256 possible indices. Rationale for these numbers:
// * Oftentimes only a handful of colors at the edges of an icon need transparency
// * In general, code needs to handle out-of-bounds indices, so it seems desirable
// to explicitly test this.
let palette = get_random_bytes(&mut rng, 192.min(input_size_in_bytes) * 3);
let trns = match trns {
TrnsPresence::Absent => None,
TrnsPresence::Present => Some(get_random_bytes(&mut rng, 32.min(input_size_in_bytes))),
};
let src = get_random_bytes(&mut rng, input_size_in_bytes);
Self {
palette,
trns,
src,
src_bit_depth,
}
}
fn output_size_in_bytes(&self) -> usize {
let output_bytes_per_input_sample = match self.trns {
None => 3,
Some(_) => 4,
};
let samples_count_per_byte = (8 / self.src_bit_depth) as usize;
let samples_count = self.src.len() * samples_count_per_byte;
samples_count * output_bytes_per_input_sample
}
fn to_info(&self) -> Info {
create_info_from_plte_trns_bitdepth(&self.palette, self.trns.as_deref(), self.src_bit_depth)
}
}
#[inline(always)]
fn create_expand_palette_fn(info: &Info) -> TransformFn {
create_transform_fn(info, Transformations::EXPAND).unwrap()
}
fn bench_create_fn(c: &mut Criterion, plte_size: usize, trns_size: usize) {
let mut group = c.benchmark_group("expand_paletted(ctor)");
group.sample_size(1000);
let mut rng = rand::thread_rng();
let plte = get_random_bytes(&mut rng, 3 * plte_size as usize);
let trns = get_random_bytes(&mut rng, trns_size as usize);
let info = create_info_from_plte_trns_bitdepth(&plte, Some(&trns), 8);
group.bench_with_input(
format!("plte={plte_size}/trns={trns_size:?}"),
&info,
|b, info| {
b.iter(|| create_expand_palette_fn(info));
},
);
}
fn bench_expand_palette(
c: &mut Criterion,
trns: TrnsPresence,
src_bit_depth: u8,
input_size_in_bytes: usize,
) {
let mut group = c.benchmark_group("expand_paletted(exec)");
let input = Input::new(trns, src_bit_depth, input_size_in_bytes);
let transform_fn = create_expand_palette_fn(&input.to_info());
group.throughput(Throughput::Bytes(input.output_size_in_bytes() as u64));
group.sample_size(500);
group.bench_with_input(
format!("{trns}/src_bits={src_bit_depth}/src_size={input_size_in_bytes}"),
&input,
|b, input| {
let mut output = vec![0; input.output_size_in_bytes()];
let info = input.to_info();
b.iter(|| {
transform_fn(input.src.as_slice(), output.as_mut_slice(), &info);
});
},
);
}

51
vendor/png/benches/unfilter.rs vendored Normal file
View File

@@ -0,0 +1,51 @@
//! Usage example:
//!
//! ```
//! $ alias bench="rustup run nightly cargo bench"
//! $ bench --bench=unfilter --features=benchmarks -- --save-baseline my_baseline
//! ... tweak something, say the Sub filter ...
//! $ bench --bench=unfilter --features=benchmarks -- filter=Sub --baseline my_baseline
//! ```
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use png::benchable_apis::unfilter;
use png::Filter;
use rand::Rng;
fn unfilter_all(c: &mut Criterion) {
let bpps = [1, 2, 3, 4, 6, 8];
let filters = [Filter::Sub, Filter::Up, Filter::Avg, Filter::Paeth];
for &filter in filters.iter() {
for &bpp in bpps.iter() {
bench_unfilter(c, filter, bpp);
}
}
}
criterion_group!(benches, unfilter_all);
criterion_main!(benches);
fn bench_unfilter(c: &mut Criterion, filter: Filter, bpp: u8) {
let mut group = c.benchmark_group("unfilter");
fn get_random_bytes<R: Rng>(rng: &mut R, n: usize) -> Vec<u8> {
use rand::Fill;
let mut result = vec![0u8; n];
result.as_mut_slice().try_fill(rng).unwrap();
result
}
let mut rng = rand::thread_rng();
let row_size = 4096 * (bpp as usize);
let two_rows = get_random_bytes(&mut rng, row_size * 2);
group.throughput(Throughput::Bytes(row_size as u64));
group.bench_with_input(
format!("filter={filter:?}/bpp={bpp}"),
&two_rows,
|b, two_rows| {
let (prev_row, curr_row) = two_rows.split_at(row_size);
let mut curr_row = curr_row.to_vec();
b.iter(|| unfilter(filter, bpp, prev_row, curr_row.as_mut_slice()));
},
);
}