Another project
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 3.3 kB View raw
1#![allow( 2 dead_code, 3 reason = "dead_code checks each test binary alone and misses helpers used only by sibling binaries" 4)] 5 6use std::path::PathBuf; 7 8use bone_render::{ 9 AdapterPolicy, OffscreenContext, PixelDiff, PixelDiffThreshold, RenderError, SnapshotFrame, 10 ViewportExtent, ViewportPx, decode_png, encode_png, 11}; 12 13const ADAPTER_RETRIES: u32 = 3; 14const ADAPTER_RETRY_BACKOFF_MS: u64 = 100; 15const GOLDEN_DIFF_TOLERANCE: f64 = 16.0 / 255.0; 16 17#[must_use] 18pub fn extent_square(side: u32) -> ViewportExtent { 19 ViewportExtent::square(ViewportPx::new(side)) 20} 21 22#[must_use] 23pub fn make_context(extent: ViewportExtent) -> OffscreenContext { 24 let mut last_err: Option<RenderError> = None; 25 for attempt in 0..ADAPTER_RETRIES { 26 match pollster::block_on(OffscreenContext::new(extent, AdapterPolicy::Platform)) { 27 Ok(ctx) => return ctx, 28 Err(e @ (RenderError::NoAdapter(_) | RenderError::Device(_))) => { 29 last_err = Some(e); 30 let backoff_ms = ADAPTER_RETRY_BACKOFF_MS * u64::from(attempt + 1); 31 std::thread::sleep(std::time::Duration::from_millis(backoff_ms)); 32 } 33 Err(e) => panic!("offscreen context init failed: {e}"), 34 } 35 } 36 match last_err { 37 Some(RenderError::NoAdapter(e)) => panic!( 38 "no wgpu adapter available after {ADAPTER_RETRIES} attempts, configure lavapipe or an iGPU: {e}" 39 ), 40 Some(RenderError::Device(e)) => { 41 panic!("wgpu device request failed after {ADAPTER_RETRIES} attempts: {e}") 42 } 43 Some(other) => { 44 panic!("offscreen context init failed after {ADAPTER_RETRIES} attempts: {other}") 45 } 46 None => unreachable!("retry loop always populates last_err on failure"), 47 } 48} 49 50pub fn check_golden(frame: &SnapshotFrame, golden_rel: &str, update_env: &str) { 51 let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(golden_rel); 52 if std::env::var(update_env).is_ok() { 53 let Ok(bytes) = encode_png(frame) else { 54 panic!("encode_png failed"); 55 }; 56 if let Some(parent) = path.parent() { 57 assert!( 58 std::fs::create_dir_all(parent).is_ok(), 59 "failed to create goldens dir" 60 ); 61 } 62 assert!( 63 std::fs::write(&path, &bytes).is_ok(), 64 "failed to write golden {}", 65 path.display() 66 ); 67 return; 68 } 69 let Ok(bytes) = std::fs::read(&path) else { 70 panic!( 71 "golden missing at {}: rerun with {update_env}=1 to generate", 72 path.display() 73 ); 74 }; 75 let Ok((golden_extent, golden_rgba)) = decode_png(&bytes) else { 76 panic!("failed to decode golden PNG"); 77 }; 78 assert_eq!(golden_extent, frame.extent(), "golden extent drift"); 79 let threshold = PixelDiffThreshold::new(GOLDEN_DIFF_TOLERANCE); 80 let Ok(report) = PixelDiff::compare(frame, &golden_rgba, threshold) else { 81 panic!("PixelDiff rejected inputs"); 82 }; 83 assert!( 84 report.is_clean(), 85 "{golden_rel} drifted from golden: {} mismatches, worst {:?}, backend {}", 86 report.over_threshold(), 87 report.worst(), 88 frame.backend(), 89 ); 90}