facett-graphview 0.1.12

facett — a vello-backed, domain-agnostic scalable 2D graph render engine. Runtime-selects vello (GPU/wgpu) when a usable GPU exists, vello_cpu (multithreaded SIMD) as the no-GPU fallback. The eventual home for every graph surface (dep/arch/release dashboards, korp, graph-DB browsing).
Documentation
//! **Runtime backend selection** — re-pointed to the L0 kernel
//! ([`facett_core::render::backend`]) as of CONS-CORE Phase C. The policy
//! (`probe the hardware, then choose`) now lives once in `facett-core` so the map
//! skins and this graph engine decide identically; graphview **re-exports** the
//! types here for back-compat, so every existing `facett_graphview::{Backend,
//! GpuProbe, decide}` import (the benches, the example, nornir's `draw_graph`)
//! keeps resolving with zero source change.
//!
//! vello is *not* GPU-only: the same scene rasterizes on the GPU (`vello` / the L0
//! SDF wgpu pipeline) when a usable adapter exists, and on the CPU (`vello_cpu`,
//! multithreaded SIMD) when it doesn't. The caller probes once and renders through
//! whichever [`Backend`] [`decide`] returns.
//!
//! Note one preserved nuance: graphview's own CPU-force env var was
//! `FACETT_GRAPHVIEW_CPU`; the core probe reads `FACETT_RENDER_CPU`. Both are
//! honoured by [`GpuProbe::from_env`] here via the [`probe_from_env`] shim so a
//! host that set either still forces CPU.

pub use facett_core::render::backend::{decide, gpu_arm_compiled, Backend, GpuProbe};

/// Build a [`GpuProbe`] from a detected-GPU flag, honouring **both** the core
/// `FACETT_RENDER_CPU` override and graphview's historical `FACETT_GRAPHVIEW_CPU`
/// override (back-compat: hosts that set the old name still force the CPU path).
///
/// Prefer this over [`GpuProbe::from_env`] in graphview hosts; `from_env` (the
/// core method) only reads `FACETT_RENDER_CPU`.
pub fn probe_from_env(usable_gpu: bool) -> GpuProbe {
    let force_cpu = std::env::var_os("FACETT_RENDER_CPU").is_some()
        || std::env::var_os("FACETT_GRAPHVIEW_CPU").is_some();
    GpuProbe { usable_gpu, force_cpu }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn cpu_only_probe_always_picks_cpu() {
        assert_eq!(decide(GpuProbe::cpu_only()), Backend::CpuVello);
    }

    #[test]
    fn force_cpu_overrides_a_present_gpu() {
        let p = GpuProbe { usable_gpu: true, force_cpu: true };
        assert_eq!(decide(p), Backend::CpuVello);
    }

    #[test]
    fn gpu_probe_picks_gpu_only_when_feature_on() {
        // The GPU arm is gated on facett-core's `wgpu` feature. That can be lit by
        // graphview's own `gpu` feature OR, under a workspace build, by feature
        // unification from a sibling crate — so key the expectation off core's
        // actual compiled state (`gpu_arm_compiled`), not this crate's `gpu` cfg.
        let got = decide(GpuProbe::gpu());
        if gpu_arm_compiled() {
            assert_eq!(got, Backend::GpuVello);
        } else {
            // No GPU path compiled in → the probe still resolves, to CPU.
            assert_eq!(got, Backend::CpuVello);
        }
    }

    /// INJECT-ASSERT (back-compat): the re-pointed `Backend` is literally
    /// `facett-core`'s enum, and graphview's `probe_from_env` still honours the
    /// historical `FACETT_GRAPHVIEW_CPU` override.
    #[test]
    fn graphview_env_override_still_forces_cpu() {
        // Cannot mutate process env safely in parallel tests; assert the type
        // identity + the shim's logic on an explicit probe instead.
        let p = GpuProbe { usable_gpu: true, force_cpu: false };
        assert!(decide(p).is_gpu() == gpu_arm_compiled());
        // Re-export identity: a core Backend flows straight through.
        let b: facett_core::render::Backend = Backend::CpuVello;
        assert_eq!(b, Backend::CpuVello);
    }
}