Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-pipeline/tests/flow_gpu.rs

//! Real Falsett callbacks, resident-buffer updates and the pipeline golden.
//! The initial reference was captured on Apple M2 Pro / Metal; see snapshots/README.md.
//! Compare with `FACETT_TEST_GPU=integrated cargo test -p facett-pipeline --features wgpu --test flow_gpu`.
//! UPDATE_SNAPSHOTS=1 replaces the reference only for an intended, reviewed change.
//! A missing reference fails; other hardware comparisons are separate evidence.
#![cfg(feature = "wgpu")]

use egui_kittest::{Harness, wgpu::WgpuTestRenderer};
use facett_core::{Facet, render::lane};
use facett_flow::gpu;
use facett_pipeline::{PipelineNode, PipelineView, Status};

fn enabled() -> bool {
    let enabled = matches!(
        std::env::var("FACETT_TEST_GPU").as_deref(),
        Ok("integrated" | "discrete" | "software")
    );
    if !enabled {
        eprintln!("SKIPPED: no GPU proof; set FACETT_TEST_GPU=integrated|discrete|software");
    }
    enabled
}

fn view(status: Status) -> PipelineView {
    PipelineView::from_nodes(
        "ETL",
        vec![
            PipelineNode::new("source", Status::Done).with_rows(120_000),
            PipelineNode::new("transform", status).with_throughput_rows_s(300.0),
            PipelineNode::new("warehouse", Status::Idle).with_throughput_rows_s(0.0),
        ],
        vec![(1, 0), (2, 1)],
    )
    .with_clock(0.375)
}

fn harness() -> (Harness<'static, PipelineView>, egui_wgpu::RenderState) {
    let setup = facett_core::render::gpu::adapter_wgpu::facett_wgpu_options().wgpu_setup;
    let rs = egui_kittest::wgpu::create_render_state(setup, Default::default());
    assert!(gpu::install_renderer(&rs), "Falsett renderer must install");
    let h = Harness::builder()
        .with_size(egui::vec2(900.0, 600.0))
        .with_pixels_per_point(1.0)
        .renderer(WgpuTestRenderer::from_render_state(rs.clone()))
        .build_ui_state(
            |ui, v: &mut PipelineView| {
                facett_core::set_theme(ui.ctx(), facett_core::Theme::sci_fi());
                v.ui(ui);
            },
            view(Status::Running),
        );
    (h, rs)
}

fn frame(h: &mut Harness<'_, PipelineView>) -> image::RgbaImage {
    let before = lane::frames_of(gpu::lane_name());
    h.step();
    let image = h.render().expect("real GPU framebuffer");
    assert!(
        lane::frames_of(gpu::lane_name()) > before,
        "CPU paint cannot satisfy this proof"
    );
    image
}

fn bytes() -> u64 {
    lane::clock_stats_of(gpu::lane_name()).upload_bytes_total
}
fn diff(a: &image::RgbaImage, b: &image::RgbaImage) -> usize {
    assert_eq!(a.dimensions(), b.dimensions());
    a.pixels().zip(b.pixels()).filter(|(a, b)| a != b).count()
}

#[test]
fn callbacks_cache_geometry_and_upload_only_changed_attributes() {
    if !enabled() {
        return;
    }
    let _turn = facett_core::render::gputurn::hold();
    let (mut h, rs) = harness();
    frame(&mut h);
    frame(&mut h);
    let initial = frame(&mut h);
    let generation = h.state().flow_scene().generation();
    let targets = gpu::residency(&rs);
    assert_eq!(targets.0, 1);
    let resident_bytes = bytes();
    assert_eq!(diff(&initial, &frame(&mut h)), 0);
    assert_eq!(
        bytes(),
        resident_bytes,
        "idle frame must reuse resident buffers"
    );

    h.state_mut().set_clock(0.91);
    assert!(
        diff(&initial, &frame(&mut h)) > 10,
        "injected clock must move packets"
    );
    assert_eq!(
        bytes(),
        resident_bytes,
        "clock writes uniforms, not geometry"
    );

    // Real hosts reconstruct the read-only PipelineView from live models. The
    // content-addressed geometry generation must survive a status-only model.
    let nav = *h.state().nav();
    let mut failed = view(Status::Failed);
    failed.set_camera(nav, true);
    *h.state_mut() = failed;
    let failure = frame(&mut h);
    assert_eq!(h.state().flow_scene().generation(), generation);
    assert!(
        diff(&initial, &failure) > 100,
        "failure must visibly reach the frame"
    );
    assert_eq!(
        bytes() - resident_bytes,
        3 * 16 + 2 * 8,
        "status change uploads only three node and two edge attributes"
    );
    assert_eq!(
        gpu::residency(&rs),
        targets,
        "status must reuse offscreen target"
    );

    let before_pan = bytes();
    h.state_mut().pan_pixels(29.0, 13.0);
    assert!(diff(&failure, &frame(&mut h)) > 100);
    assert_eq!(bytes(), before_pan, "camera must not upload geometry");
    assert_eq!(h.state().flow_scene().generation(), generation);

    gpu::evict_idle(&rs, u64::MAX);
    assert_eq!(gpu::residency(&rs).0, 0);
}

#[test]
fn canonical_pipeline_golden() {
    if !enabled() {
        return;
    }
    let _turn = facett_core::render::gputurn::hold();
    let (mut h, _) = harness();
    frame(&mut h);
    frame(&mut h);
    let actual = frame(&mut h);
    let path =
        std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/snapshots/flow_gpu.png");
    // Plan's per-channel tolerance; a missing reference remains a hard failure.
    facett_core::golden::assert_golden_within(&actual, &path, "pipeline_flow_gpu", 2);
}