fn main() {
println!("== GPU Preview Pipeline Validation ==");
println!();
println!("[1/4] Initializing wgpu device...");
let context = match mcraw_tui::preview::pipeline::device::PreviewGpuContext::new() {
Ok(ctx) => {
println!(" ✓ Device created");
println!(" ✓ Queue acquired");
ctx
}
Err(e) => {
println!(" ✗ FAILED: {}", e);
std::process::exit(1);
}
};
println!();
println!("[2/4] Creating compute pipeline + compiling WGSL shader...");
let ctx_arc = std::sync::Arc::new(context);
let mut pipeline = match mcraw_tui::preview::pipeline::GpuPreviewPipeline::new().init(ctx_arc.clone()) {
Ok(p) => {
println!(" ✓ SHADER COMPILED — all 15 OETFs loaded");
println!(" ✓ Pipeline cache pre-warmed with default combo");
p
}
Err(e) => {
println!(" ✗ FAILED: {}", e);
std::process::exit(1);
}
};
println!();
println!("[3/4] Processing synthetic 256x128 Bayer frame...");
const W: u32 = 256;
const H: u32 = 128;
let mut bayer: Vec<u16> = Vec::with_capacity((W * H) as usize);
for y in 0..H {
for x in 0..W {
let phase = (y & 1) * 2 + (x & 1); let val = match phase {
0 | 3 => { let r = ((x as f32 / W as f32) * 0.8 + 0.1) * 65535.0;
r as u16
}
1 | 2 => { let g = 0.5 * 65535.0 + ((y as f32 / H as f32) * 0.3 - 0.15) * 65535.0;
g as u16
}
_ => unreachable!(),
};
bayer.push(val);
}
}
println!(" ✓ Synthetic Bayer frame: {}x{}", W, H);
use mcraw_tui::preview::pipeline::params::PreviewParams;
let params = PreviewParams {
width: W,
height: H,
bayer_width: W,
bayer_height: H,
black_level: 64.0,
white_level: 4095.0,
exposure: 1.0,
wb_r: 1.0, wb_g: 1.0, wb_b: 1.0,
contrast: 1.0,
saturation: 1.0,
shadows: 0.0,
highlights: 0.0,
_align0: 0.0, _align1: 0.0,
ccm_row0: [1.0, 0.0, 0.0, 0.0],
ccm_row1: [0.0, 1.0, 0.0, 0.0],
ccm_row2: [0.0, 0.0, 1.0, 0.0],
color_space: 0,
transfer: 1, adjust_enabled: 0,
bayer_phase: 0,
compute_histogram: 0,
_pad0: 0, _pad1: 0, _pad2: 0, _pad3: 0, _pad4: 0, _pad5: 0, _pad6: 0,
};
let start = std::time::Instant::now();
match pipeline.process_and_readback(&bayer, ¶ms) {
Ok((rgba, out_w, out_h)) => {
let elapsed = start.elapsed();
println!(" ✓ GPU process + readback: {}x{} → {} bytes in {:?} ({:.0} fps)",
out_w, out_h, rgba.len(), elapsed, 1.0 / elapsed.as_secs_f64());
let expected_pixels = (out_w * out_h) as usize;
if rgba.len() == expected_pixels * 4 {
println!(" ✓ Output buffer size correct: {} RGBA pixels", expected_pixels);
} else {
println!(" ✗ Size mismatch: got {} bytes, expected {}", rgba.len(), expected_pixels * 4);
std::process::exit(1);
}
let non_zero = rgba.iter().filter(|&&b| b != 0).count();
if non_zero > 0 {
println!(" ✓ Output has {} non-zero bytes (image content verified)", non_zero);
} else {
println!(" ✗ All output bytes are zero — pipeline produced black frame");
std::process::exit(1);
}
}
Err(e) => {
println!(" ✗ FAILED: {}", e);
std::process::exit(1);
}
}
println!();
println!("[4/4] Testing all 15 transfer function combinations...");
use mcraw_tui::preview::pipeline::params::transfer_to_u32;
use mcraw_tui::color::TransferFunction;
let mut passed = 0u32;
let mut failed = 0u32;
for tf in TransferFunction::all() {
let mut params = params.clone();
params.transfer = transfer_to_u32(tf);
let start = std::time::Instant::now();
match pipeline.process_and_readback(&bayer, ¶ms) {
Ok((_, _, _)) => {
let elapsed = start.elapsed();
if elapsed.as_millis() < 5000 {
println!(" ✓ {:<20} {:>6?}", tf.name(), elapsed);
passed += 1;
} else {
println!(" ✗ {:<20} timed out", tf.name());
failed += 1;
}
}
Err(e) => {
println!(" ✗ {:<20} {}", tf.name(), e);
failed += 1;
}
}
}
println!();
println!("== RESULTS ==");
println!(" ✓ GPU device init: PASS");
println!(" ✓ WGSL compilation: PASS");
println!(" ✓ Synthetic frame: PASS");
println!(" ✓ OETF variants: {}/15 passed, {}/15 failed", passed, failed);
if failed == 0 {
println!();
println!(" 🎉 All checks passed — pipeline is fully functional on this GPU!");
0
} else {
println!();
println!(" ⚠ {} OETF variants failed — see above for details", failed);
1
};
}