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

nordisk/facett

facett-graph3d/tests/cpu_paint_budget.rs

//! **The CPU-painter fallback must stay bounded when the cloud gets big.**
//!
//! The instanced GPU cloud draws the whole cloud as instances, which is what let the
//! demo's graph3d go from 140 nodes to 100000. But `draw_cloud` is deliberately
//! fail-SAFE: with no `RenderState`, no installed renderer, or on wasm it returns
//! false and the CPU painter draws instead — tessellating a disc plus a glow orb per
//! node and a line per edge, on ONE core. That is the measured 33.75 ms/frame wall at
//! 30000 nodes; at 100000 it would be seconds per frame, i.e. raising the data would
//! have traded a hollow pane for a frozen one.
//!
//! So the fallback carries a budget, exactly like the OSM-2D point layer:
//! [`CPU_PAINT_MAX_NODES`] / [`CPU_PAINT_MAX_EDGES`]. Above it the CPU pass paints a
//! strided SAMPLE; below it the stride is 1 and the paint is byte-identical to
//! before, which is what keeps every existing snapshot golden valid.

use facett_core::harness;
use facett_graph3d::{dataset, Graph3D, Layout3D, CPU_PAINT_MAX_EDGES, CPU_PAINT_MAX_NODES};

fn built(n: usize) -> Graph3D {
    let d = dataset::generate(&dataset::GraphSpec::sized(n));
    Graph3D::new(d.nodes, d.edges, Layout3D::Force)
}

/// A SMALL cloud paints in full — stride 1, so every golden is unchanged.
#[test]
fn a_small_cloud_is_painted_in_full() {
    let mut g = built(1_000);
    assert!(g.nodes.len() < CPU_PAINT_MAX_NODES);
    let r = harness::headless_render(&mut g);
    assert_eq!(r.state["cpu_paint_stride"][0], 1, "no node decimation under budget");
    assert_eq!(r.state["cpu_paint_stride"][1], 1, "no edge decimation under budget");
    assert!(r.drew(), "and it really drew");
}

/// **RED-when-broken.** A LARGE cloud on the CPU lane must bound its own per-frame
/// tessellation: the painted node count is capped by the budget however big the
/// dataset is. Without the stride this is `nodes.len()` and the frame is seconds long.
#[test]
fn a_large_cloud_bounds_its_cpu_tessellation() {
    let mut g = built(100_000);
    let n = g.nodes.len();
    let e = g.edges.len();
    assert!(n > CPU_PAINT_MAX_NODES * 4, "the input really is large ({n})");

    let r = harness::headless_render(&mut g);
    let ns = r.state["cpu_paint_stride"][0].as_u64().unwrap() as usize;
    let es = r.state["cpu_paint_stride"][1].as_u64().unwrap() as usize;
    assert!(ns > 1, "a 100k cloud strides its CPU node pass, got {ns}");

    let painted_nodes = n.div_ceil(ns);
    let painted_edges = e.div_ceil(es);
    assert!(
        painted_nodes <= CPU_PAINT_MAX_NODES,
        "CPU node pass is bounded: {painted_nodes} <= {CPU_PAINT_MAX_NODES}"
    );
    assert!(
        painted_edges <= CPU_PAINT_MAX_EDGES,
        "CPU edge pass is bounded: {painted_edges} <= {CPU_PAINT_MAX_EDGES}"
    );
    // Bounded is not blank: a real sample still draws.
    assert!(painted_nodes > CPU_PAINT_MAX_NODES / 2, "…and it is a full-value sample");
    assert!(r.drew(), "the pane is not empty");
}

/// The budget bounds the frame's ACTUAL tessellation, not just a reported number —
/// vertex count at 100k must stay in the same league as at 12k, not 8x it.
#[test]
fn the_budget_bounds_the_real_vertex_count() {
    let small = harness::headless_render(&mut built(CPU_PAINT_MAX_NODES)).vertices;
    let huge = harness::headless_render(&mut built(100_000)).vertices;
    assert!(
        huge <= small * 3,
        "a 100k cloud tessellates no more than ~3x a budget-sized one ({huge} vs {small})"
    );
}

/// **The two budgets are not the same number, and a host must not confuse them.**
///
/// [`CPU_PAINT_MAX_NODES`] is what the CPU *fallback* tessellates per frame;
/// [`VIEWER_MAX_NODES`] is what the VIEWER is exercised at. korp read the first as its
/// 3D `node_ceiling` and so declined every graph over 12 000 nodes — a graph this pane
/// draws, which is exactly what the test above proves. The guard is that the viewer
/// number is strictly the larger of the two AND that the pane really draws there, so
/// the constant can never quietly collapse back onto the fallback's budget.
#[test]
fn the_viewer_ceiling_is_not_the_cpu_fallback_budget() {
    const _: () = assert!(
        facett_graph3d::VIEWER_MAX_NODES > CPU_PAINT_MAX_NODES,
        "the viewer ceiling (VIEWER_MAX_NODES) must exceed the CPU fallback budget \
         (CPU_PAINT_MAX_NODES) — a host that cannot tell them apart declines graphs the pane draws"
    );
    // And it is a size the pane actually reaches: render AT the ceiling and require a
    // bounded, non-blank frame. A constant nobody rendered at is a promise, not a fact.
    let mut g = built(facett_graph3d::VIEWER_MAX_NODES);
    let r = harness::headless_render(&mut g);
    assert!(r.drew(), "the pane draws at VIEWER_MAX_NODES");
    let ns = r.state["cpu_paint_stride"][0].as_u64().unwrap() as usize;
    assert!(
        g.nodes.len().div_ceil(ns) <= CPU_PAINT_MAX_NODES,
        "…and the CPU lane stays inside its own budget while doing it"
    );
}