90 lines
3.8 KiB
Rust
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);
|
|
}
|
|
}
|