open-standards/wai/wai-rs/tests/exact_upscale_gpu.rs

90 lines
3.8 KiB
Rust

//! The super-resolution derivations of extensions/exact-upscale.md §3 with their graph on a GPU
//! (`int_ops::gpu`, `wai_ops_gpu`): under every prior of the committed corpus
//! (`live-conformance/upscale/priors/`), `wai-upscale:sr2` and `wai-upscale:sr4` of the corpus's
//! generated pictures, and `sr2` of a larger one, give the same bytes on every adapter this
//! process finds as on the CPU. Every graph the device runs is also run on the interpreter and
//! compared (`gpu::with_gpu_compared`).
//!
//! **A skip is not a pass.** With no adapter the test prints `exact-upscale gpu: SKIPPED` and
//! fails when `WAI_OPS_GPU_REQUIRE` is set. Each adapter's result is one line,
//! `exact-upscale gpu: key=…`, appended to `WAI_OPS_GPU_REPORT` when it is set.
#![cfg(all(feature = "ops_gpu", feature = "exact_upscale"))]
use std::io::Write;
use std::path::PathBuf;
use std::sync::Arc;
use wai::exact_upscale::corpus::picture;
use wai::int_ops::gpu::{self, wai_ops_gpu};
use wai::int_sr;
fn report(line: &str) {
println!("{line}");
if let Ok(p) = std::env::var("WAI_OPS_GPU_REPORT") {
let mut f = std::fs::OpenOptions::new().create(true).append(true).open(&p).unwrap();
writeln!(f, "{line}").unwrap();
}
}
/// One derivation: its name, the prior's bytes, the picture and its size.
type Case = (&'static str, Vec<u8>, Vec<u8>, usize, usize);
fn cases() -> Vec<Case> {
let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../live-conformance/upscale/priors");
let mut out = Vec::new();
for name in ["generic.wsr", "title.wsr", "seeded.wsr"] {
let prior = std::fs::read(dir.join(name)).unwrap_or_else(|e| panic!("{name}: {e}"));
out.push((int_sr::SR2, prior.clone(), picture("scene one", 8, 6), 8, 6));
out.push((int_sr::SR4, prior.clone(), picture("scene two", 4, 3), 4, 3));
out.push((int_sr::SR2, prior, picture("a larger picture", 64, 48), 64, 48));
}
out
}
fn run(cases: &[Case]) -> Vec<Vec<u8>> {
cases
.iter()
.map(|(d, prior, px, w, h)| {
let g = int_sr::load(prior).expect("a corpus prior loads");
int_sr::derive(d, &g, px, *w, *h).expect("within the limits")
})
.collect()
}
#[test]
fn the_derivations_give_the_same_bytes_with_their_graph_on_every_adapter() {
let d = wai_ops_gpu::blocking::discover();
for (a, why) in &d.refused {
report(&format!("exact-upscale gpu: adapter refused: key={} {} reason={why:?}", a.key(), a.describe()));
}
if d.found.is_empty() {
report("exact-upscale gpu: SKIPPED: no adapter");
assert!(std::env::var_os("WAI_OPS_GPU_REQUIRE").is_none(), "WAI_OPS_GPU_REQUIRE is set and no adapter was found");
return;
}
let cases = cases();
let want = run(&cases);
// sr4 runs the graph twice.
let runs = cases.iter().map(|c| if c.0 == int_sr::SR4 { 2 } else { 1 }).sum::<u64>();
for g in d.found.into_iter().map(Arc::new) {
let (got, stats) = gpu::with_gpu_compared(&g, || run(&cases));
let same = got == want;
report(&format!(
"exact-upscale gpu: key={} {} cases={} graph_runs={} acc32={} acc64={} cpu={} compared={} differ={} errors={} {}",
g.adapter().key(),
g.adapter().describe(),
cases.len(),
runs,
stats.acc32,
stats.acc64,
stats.on_cpu(),
stats.compared,
stats.differed,
stats.errors.len(),
if same { "equal" } else { "DIFFERENT" }
));
assert!(same, "the derivations' bytes differ on the device");
assert_eq!((stats.on_gpu(), stats.on_cpu(), stats.differed), (runs, 0, 0), "every graph runs on the device and equals the interpreter: {stats:?}");
assert!(stats.errors.is_empty(), "{:?}", stats.errors);
}
}