facett-core/src/render/lane.rs
//! **GPU LANE ATTRIBUTION** — is the app actually rendering through a GPU lane, or
//! is it silently on the CPU painter?
//!
//! [`crate::render::adapter`] answers *which device* was opened. That is only half
//! the question, and answering only that half is how a box with an RTX 4090 spent a
//! whole day painting 60 000 shapes per frame on one core: `renderer_installed()`
//! was `true`, the adapter banner said `discrete/Vulkan`, and **nothing on the GPU
//! lane was ever called**, because the pane's only consumer of it lives in another
//! crate. An About box that reads "wgpu" off the adapter alone would repeat that lie
//! in the UI.
//!
//! So this module records the *other* half, as data:
//!
//! * [`note_installed`] — a lane's renderer went into an egui-wgpu
//! `RenderState`'s callback resources. Called ONCE, by construction, from the
//! shared `crate::render::gpu::install_renderer` — so every lane that routes
//! through the one install writer registers itself with no per-lane wiring.
//! It also raises the lane's [`is_installed`] flag — the cheap read a paint path
//! makes every frame (one `AtomicBool` per renderer name, no allocation).
//! * [`note_reports_frames`] — this lane promises to count encoded frames. Opt-in
//! per lane, because the frame bump has to sit at the one point in that lane's
//! `prepare` where real GPU work was genuinely encoded, and only the lane knows
//! where that is.
//! * [`note_frame`] — one frame of real GPU work encoded.
//!
//! ## Why "unknown" is a first-class answer
//!
//! [`lane_use`] folds the registry into [`GpuLaneUse`]. The interesting case is
//! [`GpuLaneUse::Unknown`]: a lane is installed, no frames have been counted, and at
//! least one installed lane never promised to count any. That is exactly the state
//! where "installed but unused" would be a *guess* — the lane may well be painting
//! every frame and simply not reporting. Guessing there is the failure mode this
//! module exists to prevent, so it reports `unknown` instead and says how many lanes
//! it could not account for.
//!
//! This is lane ATTRIBUTION, not a correctness oracle (the same caveat
//! `facett_flowsim`'s `flow_frames_drawn` carries): a lane that encoded a frame of
//! nothing still bumps the counter. It answers *who painted*, which no pixel diff
//! can, and it is only ever meaningful paired with a pixel assertion.
use std::collections::BTreeMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Mutex, OnceLock, PoisonError, RwLock};
use super::adapter::{
gpu_unavailable_json, is_management_display, selected_adapter, AdapterSelection,
};
/// One GPU lane's registration.
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct LaneRecord {
/// The lane's renderer type path, e.g. `facett_map::gpu::GpuMapRenderer`
/// (`std::any::type_name`, so it cannot drift from the type it names).
pub name: String,
/// A host installed this lane's renderer in this process.
pub installed: bool,
/// This lane promises to count encoded frames ([`note_frame`]), so a zero here
/// MEANS "did not paint" rather than "did not say".
pub reports_frames: bool,
/// Frames of real GPU work this lane encoded.
pub frames: u64,
/// **WHY this lane sat idle**, in its owner's own words, when it last declined to
/// paint ([`note_idle_reason`]). `None` = it never said.
///
/// This exists because "installed but UNUSED" is not, on its own, a diagnosis: a
/// lane that correctly stood aside (a camera it cannot express, nothing of its kind
/// to draw) and a lane that is BROKEN produce the identical row, and an operator
/// looking at the product cannot tell them apart. It cost real time on 2026-08-02:
/// korp reported `installed but UNUSED` on an RTX 4090 and neither the About box nor
/// several tool calls could say whether that was a correct choice or the bug.
pub idle_reason: Option<String>,
/// **The lane's GPU clocks** — upload wall-time/bytes + in-GPU pass time. See
/// [`LaneClockStats`]. `#[serde(default)]` so a json written before these existed
/// still deserialises.
#[serde(default)]
pub clocks: LaneClockStats,
}
/// **Per-lane GPU timing observables** — the tail of a host's mousewheel→GPU TRACE
/// line. The CPU legs are clocked host-side (korp); these are the two legs only the
/// lane itself can see:
///
/// * **upload wall-time** — the `write_buffer`/`create_buffer_init` work a lane's
/// `prepare` does when geometry changes. Wall clock, because that is the time the
/// frame actually paid on the CPU handing bytes to the driver.
/// * **in-GPU pass time** — measured with `wgpu` TIMESTAMP_QUERY where the device has
/// the feature. `last_gpu_pass_us` is `None` until a real sample resolves, and
/// STAYS `None` on a device without the feature — an adapter that cannot measure
/// reports "cannot measure", never `0` (a faked zero is indistinguishable from a
/// free pass, which is the identity-value trap LAW 2 names).
///
/// One struct, one writer set (`note_upload` / `note_gpu_pass` /
/// `note_gpu_timestamps`), read through [`clock_stats_of`] — so korp's TRACE line, an
/// About row and a device test all read the same numbers (LAW #5).
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize,
)]
pub struct LaneClockStats {
/// Wall-clock microseconds the LAST upload event spent handing bytes to the
/// device (buffer creation + `write_buffer`). `0` before the first upload.
pub last_upload_us: u64,
/// Bytes the last upload event actually moved — the payload streams written to
/// the device, exactly (a device test asserts equality with the payload it fed).
///
/// **ONE EVENT, not one frame.** The 2D tile lane calls [`note_upload`] once per
/// hand-over GROUP, and a real viewport is hundreds of groups, so this field is
/// whichever group uploaded last. Reading it as "what the lane took this frame" is
/// how korp's `FIRST-PAINT` line came to report `upload 25 us (1280 bytes)` for a
/// Stockholm viewport of 1 264 ways — and how the lane came to be blamed for
/// owning nothing when it in fact owned every way on screen. For the per-frame
/// question use [`Self::upload_bytes_total`] across two reads, or
/// `MapFacet::gpu_lane_share`, which counts WAYS on each side.
pub last_upload_bytes: u64,
/// Upload events since process start. The 2D lane re-uploads on geometry change
/// only; the 3D lane on a new `GpuGeometry::generation` stamp — so this counts
/// re-bakes, not frames.
pub uploads_total: u64,
/// **Every byte this lane has handed the device since process start** — the
/// cumulative twin of [`Self::last_upload_bytes`], and the only one of the two
/// that can answer "what did this frame (or this pan) cost", by difference across
/// two reads. `#[serde(default)]` so a `state_json` written before this field
/// existed still deserialises.
#[serde(default)]
pub upload_bytes_total: u64,
/// In-GPU microseconds of the lane's most recent resolved pass window
/// (2D: the cull compute pass; 3D: shadow→post aggregate). `None` = no sample
/// yet OR timestamps unavailable — see [`Self::gpu_timestamps`] to tell which.
/// Resolved a few frames late by design (non-blocking readback ring).
pub last_gpu_pass_us: Option<u64>,
/// Are the pass timestamps REAL? `Some(true)` = the device has TIMESTAMP_QUERY
/// (+ INSIDE_ENCODERS) and the lane is writing them; `Some(false)` = the device
/// lacks the feature, so `last_gpu_pass_us` can never fill; `None` = the lane has
/// not probed yet (no frame prepared).
pub gpu_timestamps: Option<bool>,
}
impl LaneRecord {
/// The last `::` segment — what a UI row shows (`GpuMapRenderer`).
#[must_use]
pub fn short_name(&self) -> &str {
self.name.rsplit("::").next().unwrap_or(self.name.as_str())
}
}
/// **Is a GPU lane actually in use?** The honest fold of the lane registry.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GpuLaneUse {
/// No lane's renderer was installed in this process — every pane that has a CPU
/// painter is on it. (A wgpu *device* may still be open: egui itself paints
/// through wgpu. This is about facett's own compute/instanced lanes.)
NotInstalled,
/// A lane encoded `frames` frames of real GPU work.
InUse {
/// Frames counted across every reporting lane.
frames: u64,
},
/// Every installed lane reports frames, and all of them are at zero: installed
/// and genuinely never painted. **This is korp's map facet.**
InstalledUnused,
/// A lane is installed but cannot be accounted for — it never promised to count
/// frames, so neither "in use" nor "unused" is knowable. Says so instead of
/// picking one.
Unknown {
/// How many installed lanes are unaccounted for.
silent_lanes: usize,
},
}
impl GpuLaneUse {
/// Stable token for `state_json`.
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
GpuLaneUse::NotInstalled => "not_installed",
GpuLaneUse::InUse { .. } => "in_use",
GpuLaneUse::InstalledUnused => "installed_unused",
GpuLaneUse::Unknown { .. } => "unknown",
}
}
/// Frames counted (0 for every non-[`InUse`](Self::InUse) state).
#[must_use]
pub fn frames(self) -> u64 {
match self {
GpuLaneUse::InUse { frames } => frames,
_ => 0,
}
}
}
// ── the registry ────────────────────────────────────────────────────────────
static LANES: OnceLock<Mutex<BTreeMap<&'static str, LaneRecord>>> = OnceLock::new();
fn lanes_slot() -> &'static Mutex<BTreeMap<&'static str, LaneRecord>> {
LANES.get_or_init(|| Mutex::new(BTreeMap::new()))
}
fn with_lane(name: &'static str, f: impl FnOnce(&mut LaneRecord)) {
if let Ok(mut g) = lanes_slot().lock() {
let rec = g.entry(name).or_insert_with(|| LaneRecord {
name: name.to_owned(),
installed: false,
reports_frames: false,
frames: 0,
idle_reason: None,
clocks: LaneClockStats::default(),
});
f(rec);
}
}
/// Record that a lane's renderer was installed into a `RenderState`.
///
/// Called from the ONE shared install writer (`crate::render::gpu::install_renderer`)
/// with `std::any::type_name::<R>()`, so a new lane that uses the shared install is
/// registered without touching this module. Raises the lane's [`is_installed`] flag.
pub fn note_installed(name: &'static str) {
with_lane(name, |r| r.installed = true);
installed_flag(name).store(true, Ordering::Release);
}
// ── the cheap "is this lane installed?" read, for a paint path ──────────────
/// **One `AtomicBool` per lane name**, raised by [`note_installed`] (so by every
/// `crate::render::gpu::install_renderer` / `install_renderer_checked`) and lowered
/// only when the device REFUSED an install (`install_renderer_checked` undoes it).
/// Append-only: a flag, once created, lives for the process — there is one per
/// renderer TYPE, a few dozen at most.
///
/// It is separate from the [`LaneRecord`] registry on purpose. A pane decides "GPU lane
/// or CPU painter" every frame, and before this the only public way to ask was
/// [`lanes`], which clones every record (and its `String` name) to answer one bool.
/// `graphcloud::cloud::cloud_renderer_installed` carried its own private `AtomicBool`
/// for the same reason; it reads this registry now (one writer, LAW #5).
static INSTALLED_FLAGS: RwLock<Vec<(&'static str, &'static AtomicBool)>> =
RwLock::new(Vec::new());
fn find_installed_flag(
flags: &[(&'static str, &'static AtomicBool)],
name: &str,
) -> Option<&'static AtomicBool> {
flags.iter().find(|(n, _)| *n == name).map(|&(_, f)| f)
}
/// **Lane `name`'s installed flag, as a `&'static AtomicBool`** — created (lowered) on
/// the first ask, the same flag on every later one.
///
/// For a per-frame reader that wants no lock at all: cache it once and `load` it.
///
/// ```ignore
/// static FLAG: OnceLock<&'static AtomicBool> = OnceLock::new();
/// let up = FLAG.get_or_init(|| lane::installed_flag(lane_name())).load(Ordering::Acquire);
/// ```
///
/// That is how `graphcloud::cloud::cloud_renderer_installed` reads it. Everyone else
/// can call [`is_installed`].
pub fn installed_flag(name: &'static str) -> &'static AtomicBool {
if let Some(f) =
find_installed_flag(&INSTALLED_FLAGS.read().unwrap_or_else(PoisonError::into_inner), name)
{
return f;
}
let mut flags = INSTALLED_FLAGS.write().unwrap_or_else(PoisonError::into_inner);
// Another thread may have created it between the two locks.
if let Some(f) = find_installed_flag(&flags, name) {
return f;
}
let f: &'static AtomicBool = Box::leak(Box::new(AtomicBool::new(false)));
flags.push((name, f));
f
}
/// **Is lane `name`'s renderer installed?** — `true` once [`note_installed`] ran for it
/// (every `install_renderer` / `install_renderer_checked` does), `false` for a name
/// never installed and after the device refused the install (`install_renderer_checked`).
///
/// The per-frame twin of reading `installed` off [`lanes`]: a shared read lock and a
/// scan of a few dozen `&'static str`s, **no allocation** (pinned by
/// `tests/lane_is_installed_allocates_nothing.rs`). `name` is the renderer's
/// `std::any::type_name`, exactly as the lane registers it.
///
/// [`reset_for_test`] does NOT lower these flags: it clears the attribution records,
/// while a renderer installed in a `RenderState` is still there after it.
#[must_use]
pub fn is_installed(name: &str) -> bool {
find_installed_flag(&INSTALLED_FLAGS.read().unwrap_or_else(PoisonError::into_inner), name)
.is_some_and(|f| f.load(Ordering::Acquire))
}
/// **The device REFUSED this lane's install** (`install_renderer_checked`: a validation
/// error inside its error scope). The install was undone, so the lane is no longer
/// installed — flag lowered, record cleared — and the reason goes out through
/// [`note_gpu_error`], the same channel a refused buffer uses.
#[cfg(feature = "wgpu")]
pub(crate) fn note_install_refused(name: &'static str, why: &str) {
installed_flag(name).store(false, Ordering::Release);
with_lane(name, |r| r.installed = false);
note_gpu_error(name, why);
}
/// Declare that this lane counts encoded frames via [`note_frame`].
///
/// Without this the lane is *silent*, and [`lane_use`] degrades to
/// [`GpuLaneUse::Unknown`] rather than claiming the lane went unused. Call it next to
/// the lane's install.
pub fn note_reports_frames(name: &'static str) {
with_lane(name, |r| r.reports_frames = true);
}
/// Count one frame of real GPU work encoded by this lane.
///
/// Put this at the point in the lane's `prepare` where the work has actually been
/// recorded against a real device — *after* every fail-safe early-return, or the
/// counter starts claiming frames the GPU never saw. Implies both
/// [`note_installed`] and [`note_reports_frames`]: a lane cannot encode a frame
/// without being installed, and it is plainly reporting.
pub fn note_frame(name: &'static str) {
with_lane(name, |r| {
r.installed = true;
r.reports_frames = true;
r.frames += 1;
});
}
/// **The lane has not been ASKED to draw yet** — nobody has painted the pane that owns
/// it since the process started. Not a declined lane and not a broken one.
///
/// Named here, next to the reader that classifies it, rather than as a string literal in
/// the crate that emits it: [`GpuStatus::lane_line`] has to recognise this exact token to
/// avoid printing a sentence that contradicts the very next row (LAW #5 — one writer for
/// a value two crates agree on).
pub const PANE_NOT_PAINTED_YET: &str = "pane_not_painted_yet";
/// **The lane was CHOSEN this frame and has not encoded yet.** The facet picked the GPU,
/// handed egui the callback, and no frame has come out the other side — a covered,
/// clipped or just-mounted pane produces no GPU work, which is correct.
pub const AWAITING_FIRST_ENCODE: &str = "awaiting_first_encode";
/// The reasons that mean **"nothing has asked this lane to draw"**, as opposed to
/// "the lane was offered the work and declined it".
///
/// The distinction is the whole point: a lane that declined (`rotated_camera`,
/// `no_line_ways`) really did leave the work to the CPU painter, and saying so is
/// accurate. A lane in one of the states below did not — **there is no CPU painter doing
/// its work either, because the pane it belongs to has not been drawn at all**. Printing
/// the same sentence for both is what made korp's About box read as a fault on a healthy
/// RTX 4090; see [`GpuStatus::lane_line`].
pub const NOT_YET_DRAWN_REASONS: [&str; 2] = [PANE_NOT_PAINTED_YET, AWAITING_FIRST_ENCODE];
/// **The plain words for "this process has no GPU lane to hand the pane".** Owner ruling
/// 2026-09-28: a GPU always exists (an iGPU counts, SwiftShader/llvmpipe do not), so a
/// pane that selected a GPU lane and found no renderer installed says so in these words
/// instead of quietly reading `cpu` as if that were a choice.
pub const NO_GPU: &str = "no GPU";
/// **The one `state_json` block a pane on the shared GPU cloud lane publishes**
/// (`graphcloud::cloud::draw_cloud`, 2026-09-29: `facett-graph` `GraphView`,
/// `facett-geomap` `GeoMap`). One writer, so the probe (`facet-wrapped/examples/
/// gallery_probe.rs`, which walks `lane_flag` / `gpu_cloud`) and the panes cannot spell
/// it two ways.
///
/// * `selected` — the host asked for the GPU lane (`with_gpu(true)`);
/// * `installed` — a cloud renderer exists in this process (a host installed it on its
/// `RenderState`); `false` is reported as `gpu: "no GPU"`;
/// * `drew` — what the LAST frame did: `Some(true)` GPU, `Some(false)` CPU painter,
/// `None` not painted yet ([`LaneFlag::Pending`], never `cpu`).
#[must_use]
pub fn cloud_lane_json(selected: bool, installed: bool, drew: Option<bool>) -> serde_json::Value {
serde_json::json!({
"selected": selected,
"lane_flag": LaneFlag::from_observed(drew).token(),
"gpu_cloud": drew == Some(true),
"gpu": if installed { "installed" } else { NO_GPU },
})
}
/// **Say why this lane is not painting**, so "installed but UNUSED" stops being
/// ambiguous. `Some(reason)` when the lane's owner chose another route this frame,
/// `None` when it is painting.
///
/// The reason is the OWNER's, because only the owner knows: `facett_map`'s `MapFacet`
/// reports `rotated_camera` / `no_renderer` / `no_line_ways` / `not_compiled`. A lane
/// that declined for a good reason and a lane that is broken must not render the same
/// row — that ambiguity is what this whole module exists to remove, and leaving it at
/// the lane level would have re-created it one level up.
pub fn note_idle_reason(name: &'static str, reason: Option<&str>) {
with_lane(name, |r| {
// Only overwrite with a real reason, or clear it deliberately; a caller that
// does not know must not erase a reason another writer supplied.
r.idle_reason = reason.map(str::to_owned);
});
}
/// The reason ONE lane last gave for standing aside (`None` = it never said).
#[must_use]
pub fn idle_reason_of(name: &str) -> Option<String> {
lanes_slot().lock().ok().and_then(|g| g.get(name).and_then(|r| r.idle_reason.clone()))
}
/// **One upload event landed**: the lane spent `micros` of wall time moving `bytes`
/// of payload onto the device. Called by the lane's OWN `upload` body (facett-map's
/// `GpuMapRenderer::upload`, facett-map3d's `Map3dRenderer::upload`) — the one
/// writer both the live `prepare` path and every `upload_for_test` hook route
/// through, so a test and the product count the same event (LAW #5).
pub fn note_upload(name: &'static str, micros: u64, bytes: u64) {
with_lane(name, |r| {
r.clocks.last_upload_us = micros;
r.clocks.last_upload_bytes = bytes;
r.clocks.upload_bytes_total = r.clocks.upload_bytes_total.saturating_add(bytes);
r.clocks.uploads_total += 1;
});
}
/// **One in-GPU pass window resolved to `micros`** (device timestamps, converted
/// through `Queue::get_timestamp_period`). Implies timestamps are real — only the
/// pass-clock readback calls this, and it cannot run without the feature.
pub fn note_gpu_pass(name: &'static str, micros: u64) {
with_lane(name, |r| {
r.clocks.last_gpu_pass_us = Some(micros);
r.clocks.gpu_timestamps = Some(true);
});
}
/// **Say whether this lane's device can measure pass time at all.** `false` = the
/// device was requested without (or the adapter lacks) TIMESTAMP_QUERY, so
/// `last_gpu_pass_us` will honestly stay `None` — never `0`. Recorded once per
/// probe (the lane's pass-clock slot), not per frame.
pub fn note_gpu_timestamps(name: &'static str, real: bool) {
with_lane(name, |r| r.clocks.gpu_timestamps = Some(real));
}
/// **ONE lane's GPU clocks** — what a host (korp) polls to finish its per-viewport
/// mousewheel→GPU TRACE line. Zero-valued default for a lane that never registered,
/// so the caller can always destructure.
#[must_use]
pub fn clock_stats_of(name: &str) -> LaneClockStats {
lanes_slot().lock().ok().and_then(|g| g.get(name).map(|r| r.clocks)).unwrap_or_default()
}
/// Every registered lane, name-ordered.
#[must_use]
pub fn lanes() -> Vec<LaneRecord> {
lanes_slot().lock().map(|g| g.values().cloned().collect()).unwrap_or_default()
}
/// **Frames ONE lane has encoded** — `0` for a lane that never registered.
///
/// The cheap read: [`lanes`] clones every record's `String` name, which is fine for an
/// About box and wasteful for something a per-frame paint path consults. And a paint
/// path genuinely needs it: `facett_map::layer::MapFacet` latches its upload-once VRAM
/// bake on "has a frame actually been encoded since I handed the geometry over", because
/// egui may DISCARD the frame a payload rode on (a sizing pass is one) — and a host that
/// latched on the *handover* would never re-send it, leaving the lane at zero frames
/// forever. That is the [`GpuLaneUse::InstalledUnused`] disease reappearing one level
/// down, so the ack is read from the same counter the About box reports.
#[must_use]
pub fn frames_of(name: &str) -> u64 {
lanes_slot().lock().map(|g| g.get(name).map_or(0, |r| r.frames)).unwrap_or(0)
}
/// **THE fold**: is a GPU lane in use, installed-but-unused, absent — or unknowable?
#[must_use]
pub fn lane_use() -> GpuLaneUse {
fold_lane_use(&lanes())
}
/// The pure fold [`lane_use`] applies, so the policy is testable without touching
/// the process-global registry.
#[must_use]
pub fn fold_lane_use(lanes: &[LaneRecord]) -> GpuLaneUse {
let live: Vec<&LaneRecord> = lanes.iter().filter(|l| l.installed || l.frames > 0).collect();
if live.is_empty() {
return GpuLaneUse::NotInstalled;
}
let frames: u64 = live.iter().map(|l| l.frames).sum();
if frames > 0 {
return GpuLaneUse::InUse { frames };
}
let silent = live.iter().filter(|l| !l.reports_frames).count();
if silent == 0 {
GpuLaneUse::InstalledUnused
} else {
GpuLaneUse::Unknown { silent_lanes: silent }
}
}
/// **WHICH LANE DREW — the on-screen flag, in THREE states.**
///
/// The owner, 2026-08-23: *"PLEASE add a flag saying GPU or CPU when rendering osm 2d and
/// 3d, so i know whats being used"*. This is the one writer of that answer's text, so a
/// pane, a log line and a `state_json` block cannot disagree about it (LAW 5).
///
/// # Why THREE and not two
///
/// Because [`Pending`](Self::Pending) is a real and common state, and rendering it as
/// `CPU` is the exact lie this whole module exists to stop. `Map3D::used_gpu_observed()`
/// is `None` until a frame has been through the backend, and the 2D lane can have its
/// callback placed with nothing yet out of the device
/// ([`AWAITING_FIRST_ENCODE`]). Both are "nobody has measured", not "the CPU painter
/// drew it".
///
/// This is the same trap that was caught on this codebase twice on one day: a `gpu=false`
/// read before the first paint (korp's `log_map3d_lane`, 2026-08-06 — read as the genuine
/// defect by three people) and `paint_order_pixels` passing on the CPU painter while the
/// device lane was wrong. A two-state flag would put a confident `CPU` on the screen for
/// every pane that simply has not painted yet.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LaneFlag {
/// A frame really went through the GPU lane.
Gpu,
/// A frame really went through the CPU painter. A first-class outcome, not a failure.
Cpu,
/// **No measurement exists yet.** Never render this as `CPU`.
Pending,
}
impl LaneFlag {
/// From an OBSERVATION of the lane: `Some(true)` GPU, `Some(false)` CPU, `None`
/// nothing has painted yet.
///
/// Takes `Option<bool>` and not `bool` on purpose — the `bool`-shaped readers
/// (`Map3D::used_gpu`) collapse "not measured" into `false`, which is how a pane on an
/// RTX 4090 came to report the CPU painter.
#[must_use]
pub fn from_observed(observed: Option<bool>) -> Self {
match observed {
Some(true) => Self::Gpu,
Some(false) => Self::Cpu,
None => Self::Pending,
}
}
/// **The short label a pane shows.** `GPU` · `CPU` · `—` (an em dash: visibly not a
/// verdict, and the same width-ish glyph in a monospace chip).
#[must_use]
pub fn label(self) -> &'static str {
match self {
Self::Gpu => "GPU",
Self::Cpu => "CPU",
Self::Pending => "—",
}
}
/// The stable token for `state_json` and log lines — the machine-readable twin of
/// [`Self::label`], from the same match so the two cannot drift.
#[must_use]
pub fn token(self) -> &'static str {
match self {
Self::Gpu => "gpu",
Self::Cpu => "cpu",
Self::Pending => "pending",
}
}
/// `(foreground, opaque plate)` for the chip.
///
/// The plate is **fully opaque** for the reason `crate::devid::chip_colors` records
/// and measured: this is an overlay on a pane that has already drawn there, so a
/// translucent plate superimposes two strings in the same pixels instead of putting
/// the flag on the pane.
///
/// GPU reads cool/confident, CPU reads warm (it is the answer a user may want to act
/// on), and `Pending` is deliberately DIM — it must not look like a verdict.
#[must_use]
pub fn colors(self) -> (egui::Color32, egui::Color32) {
match self {
Self::Gpu => (egui::Color32::from_rgb(140, 230, 170), egui::Color32::from_rgb(10, 22, 14)),
Self::Cpu => (egui::Color32::from_rgb(255, 200, 120), egui::Color32::from_rgb(26, 18, 8)),
Self::Pending => (egui::Color32::from_gray(130), egui::Color32::from_rgb(20, 20, 22)),
}
}
}
/// The a11y atom prefix every lane flag is emitted under — what a headless test and the
/// robot driver match on.
///
/// The flag is painted as a real a11y node and not as bare glyphs for the reason
/// `crate::devid::badge` states in so many words: *"Painted-only text is invisible to
/// every check we have — which is how a badge ships green and never appears."*
pub const LANE_FLAG_ATOM: &str = "lane:";
/// **The full atom label for a flag** — `lane: GPU`. One writer, so the test matches what
/// the pane emits by construction rather than by two people spelling it the same way.
#[must_use]
pub fn lane_flag_atom(flag: LaneFlag) -> String {
format!("{LANE_FLAG_ATOM} {}", flag.label())
}
/// **Paint the lane flag in the top-LEFT of `rect`**, as a real a11y atom.
///
/// Top-left, not top-right, because `crate::devid::badge` already owns the top-right band
/// and the two must not land in the same pixels — the dev-id chip's own doc records what
/// overlapping overlay text costs to read.
///
/// `Sense::hover()` only, never `click`: measured 2026-08-21, a clicking overlay chip in a
/// pane's own control band ate every click on the Git pane's `Log` toggle. A debug overlay
/// must never steal input from the pane it labels.
///
/// **Not gated on a debug build.** `devid::badge` is a no-op in release because a dev-id is
/// for developers; this one answers a question the owner asks of the shipped binary, so it
/// paints in every profile.
pub fn paint_lane_flag(ui: &mut egui::Ui, rect: egui::Rect, flag: LaneFlag) {
let text = flag.label();
let (fg, bg) = flag.colors();
let font = egui::FontId::monospace(10.0);
let galley = ui.painter().layout_no_wrap(text.to_string(), font.clone(), fg);
let size = galley.size();
let chip = egui::Rect::from_min_size(egui::pos2(rect.left() + 4.0, rect.top() + 4.0), size)
.expand2(egui::vec2(4.0, 2.0));
let label = lane_flag_atom(flag);
let resp = crate::a11y::node(
ui,
ui.id(),
("lane_flag", text),
egui::Sense::hover(),
chip,
crate::a11y::Semantics::button(label),
);
let p = ui.painter();
p.rect_filled(chip, 3.0, bg);
p.text(chip.center(), egui::Align2::CENTER_CENTER, text, font, fg);
resp.on_hover_text(match flag {
LaneFlag::Gpu => "This pane's last frame was drawn by its GPU lane.",
LaneFlag::Cpu => "This pane's last frame was drawn by the CPU painter.",
LaneFlag::Pending => {
"No frame has reached this pane's renderer yet — this is NOT 'the CPU drew it'."
}
});
}
/// **The three states must be three, and `None` must never read as CPU.**
///
/// RED: make `from_observed` map `None => Self::Cpu` (the collapse every `bool`-shaped
/// reader in this codebase has made at least once) and the third assertion fires; make
/// `label`/`token` share one match arm across two variants and the distinctness
/// assertions fire.
#[cfg(test)]
mod lane_flag {
use super::*;
#[test]
fn the_three_states_are_three_and_pending_is_not_cpu() {
assert_eq!(LaneFlag::from_observed(Some(true)), LaneFlag::Gpu);
assert_eq!(LaneFlag::from_observed(Some(false)), LaneFlag::Cpu);
assert_eq!(LaneFlag::from_observed(None), LaneFlag::Pending);
// The labels a human reads are DISTINCT, and the pending one is not a verdict.
let labels = [LaneFlag::Gpu.label(), LaneFlag::Cpu.label(), LaneFlag::Pending.label()];
assert_eq!(
labels.iter().collect::<std::collections::HashSet<_>>().len(),
3,
"three states must produce three labels, got {labels:?}"
);
assert_ne!(
LaneFlag::Pending.label(),
LaneFlag::Cpu.label(),
"a pane that has not painted must NOT read as the CPU painter — that is the \
exact lie this type exists to prevent"
);
// …and the machine tokens too, so a state_json consumer can tell them apart.
let tokens = [LaneFlag::Gpu.token(), LaneFlag::Cpu.token(), LaneFlag::Pending.token()];
assert_eq!(tokens.iter().collect::<std::collections::HashSet<_>>().len(), 3);
assert_eq!(tokens, ["gpu", "cpu", "pending"]);
}
/// The atom label is what a headless test matches on, so it is pinned here rather
/// than spelled a second time in every consumer's test.
#[test]
fn the_atom_label_carries_the_flag() {
assert_eq!(lane_flag_atom(LaneFlag::Gpu), "lane: GPU");
assert_eq!(lane_flag_atom(LaneFlag::Cpu), "lane: CPU");
assert_eq!(lane_flag_atom(LaneFlag::Pending), "lane: —");
}
/// The plate must be OPAQUE — the chip sits over a pane that has already drawn there.
/// RED: drop the alpha in any `colors()` arm.
#[test]
fn every_plate_is_opaque_so_the_flag_does_not_superimpose_two_strings() {
for f in [LaneFlag::Gpu, LaneFlag::Cpu, LaneFlag::Pending] {
let (fg, bg) = f.colors();
assert_eq!(bg.a(), 255, "{f:?}: the plate must be fully opaque, got alpha {}", bg.a());
assert_eq!(fg.a(), 255, "{f:?}: the text must be fully opaque, got alpha {}", fg.a());
}
}
}
/// **The `unknown` row must name the SILENT lane, not the roster.**
///
/// Reported live 2026-08-08 on a 4090: `GPU lane: unknown — 1 installed lane(s)
/// (CloudRenderer, Map3dRenderer, GpuMapRenderer) do not report frames`. One silent lane,
/// three renderers accused, and no way to tell from the row which to fix.
///
/// RED direction: put `names(false)` back in the `Unknown` arm and the row names lanes that
/// are counting.
#[cfg(test)]
mod silent_lane_naming {
use super::*;
fn rec(name: &'static str, reports: bool) -> LaneRecord {
LaneRecord {
name: name.to_string(),
installed: true,
reports_frames: reports,
frames: 0,
idle_reason: None,
clocks: LaneClockStats::default(),
}
}
#[test]
fn the_unknown_row_names_only_the_lanes_that_do_not_count() {
let lanes = vec![
rec("a::CloudRenderer", true),
rec("b::Map3dRenderer", false),
rec("c::GpuMapRenderer", true),
];
let g = GpuStatus {
notes: Vec::new(),
adapter: None,
unavailable: None,
lane: fold_lane_use(&lanes),
lanes,
};
assert_eq!(g.lane, GpuLaneUse::Unknown { silent_lanes: 1 }, "precondition");
assert_eq!(g.silent_lane_names(), "Map3dRenderer", "only the silent one is named");
let line = g.lane_line();
assert!(line.contains("Map3dRenderer"), "the row names the lane to fix: {line}");
for innocent in ["CloudRenderer", "GpuMapRenderer"] {
assert!(
!line.contains(innocent),
"a lane that IS counting must not be accused: {line}",
);
}
assert!(line.contains("1 installed lane(s)"), "count and names must agree: {line}");
}
#[test]
fn a_registry_with_nothing_silent_never_reaches_the_unknown_row() {
let lanes = vec![rec("a::CloudRenderer", true), rec("c::GpuMapRenderer", true)];
assert_eq!(
fold_lane_use(&lanes),
GpuLaneUse::InstalledUnused,
"every lane counting ⇒ a zero is a real zero, not an unknown",
);
}
}
// ── a GPU resource the device REFUSED, said in the state instead of a panic ──
/// The last GPU resource a lane could not create (lane M, 2026-10-02: on SwiftShader the
/// resident cloud's 1.6 MB `createBuffer` with `mappedAtCreation` threw and the page
/// panicked). The lane draws nothing for that model and says why here.
static GPU_ERROR: Mutex<String> = Mutex::new(String::new());
/// Record that `lane` could not create a GPU resource, and why. Also the lane's
/// [`note_idle_reason`], so an About card says it next to the lane's row.
pub fn note_gpu_error(lane: &'static str, why: &str) {
eprintln!("facett GPU: {lane}: {why}");
if let Ok(mut g) = GPU_ERROR.lock() {
g.clear();
g.push_str(why);
}
note_idle_reason(lane, Some(why));
}
/// The last GPU resource refusal ([`note_gpu_error`]), `None` when there was none.
/// Published as `gpu_error` in the demo's and facet-wrapped's state.
#[must_use]
pub fn gpu_error() -> Option<String> {
GPU_ERROR.lock().ok().map(|g| g.clone()).filter(|s| !s.is_empty())
}
/// Clear the registry. **Tests only** — the registry is a process-global and a test
/// that asserts a fold needs a known starting point.
#[doc(hidden)]
pub fn reset_for_test() {
if let Ok(mut g) = lanes_slot().lock() {
g.clear();
}
}
// ── the whole GPU story, as one value ───────────────────────────────────────
// ── Live STATUS NOTES: one-line facts other crates want on the About card ────
//
// The GPU rows are the ONE writer of "what is this app rendering on"
// (`GpuStatus::rows`), and facett-core cannot depend on the crates that own
// adjacent facts (facett-map's baked-vertex store lives ABOVE this crate). So a
// crate registers a CALLBACK returning its one live line, and `probe()` reads
// them all — the row set stays one writer, the fact stays with its owner, and a
// host (korp, holger, dwarves-ui) adds nothing. A callback returning `None`
// contributes no row (honest absence: "no store installed" is silence, not a
// zeroed reading).
/// One registered status-note callback: its live line, or `None` for no row.
type StatusNote = fn() -> Option<String>;
static STATUS_NOTES: OnceLock<Mutex<Vec<StatusNote>>> = OnceLock::new();
fn status_note_slot() -> &'static Mutex<Vec<StatusNote>> {
STATUS_NOTES.get_or_init(|| Mutex::new(Vec::new()))
}
/// Register a live status-note callback (idempotent per function pointer, so an
/// install path that runs twice does not double its row).
pub fn register_status_note(f: fn() -> Option<String>) {
if let Ok(mut g) = status_note_slot().lock() && !g.iter().any(|&h| std::ptr::fn_addr_eq(h, f)) {
g.push(f);
}
}
/// Every registered note's CURRENT line, in registration order.
fn status_notes() -> Vec<String> {
status_note_slot().lock().map(|g| g.iter().filter_map(|f| f()).collect()).unwrap_or_default()
}
/// **What a UI shows about the GPU**: which adapter, which backend, which device
/// class, how many adapters were enumerated, and whether a GPU lane is really being
/// used.
///
/// One value so the About card, a status bar and a robot assertion all read the same
/// facts through the same formatting (LAW #5), instead of each re-deriving "is this
/// software?" from `AdapterInfo` and getting it subtly differently.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GpuStatus {
/// The adapter selection the host recorded at startup; `None` when no GPU
/// backend was brought up in this process (a CPU-painter build, or headless).
pub adapter: Option<AdapterSelection>,
/// A recorded bring-up FAILURE (`facet-gpu-<n>` + remedy), if there was one.
pub unavailable: Option<serde_json::Value>,
/// The lane fold.
pub lane: GpuLaneUse,
/// Every registered lane (what the fold was computed from).
pub lanes: Vec<LaneRecord>,
/// Live one-line facts other crates registered ([`register_status_note`]) —
/// e.g. facett-map's baked-vertex cache hit line. Painted after the GPU rows,
/// in `state_json` as `"notes"`.
pub notes: Vec<String>,
}
impl GpuStatus {
/// Read the live process globals: the recorded adapter selection, any recorded
/// bring-up failure, and the lane registry.
#[must_use]
pub fn probe() -> Self {
let lanes = lanes();
let un = gpu_unavailable_json();
Self {
adapter: selected_adapter(),
unavailable: if un.is_null() { None } else { Some(un) },
lane: fold_lane_use(&lanes),
lanes,
notes: status_notes(),
}
}
/// A status with nothing recorded — what a headless CPU build honestly reports.
#[must_use]
pub fn none() -> Self {
Self {
adapter: None,
unavailable: None,
lane: GpuLaneUse::NotInstalled,
lanes: Vec::new(),
notes: Vec::new(),
}
}
/// Build a status from an explicit selection + lane list (tests, and a host that
/// wants to show a decision it has in hand rather than the global).
#[must_use]
pub fn of(adapter: Option<AdapterSelection>, lanes: Vec<LaneRecord>) -> Self {
Self { adapter, unavailable: None, lane: fold_lane_use(&lanes), lanes, notes: Vec::new() }
}
/// **Is the app rendering on a CPU software rasteriser?** Taken from the
/// selection's `software` flag, which is computed by name AND device class — so
/// llvmpipe reporting itself as `DiscreteGpu` is still software here. Never read
/// `kind` alone for this question.
#[must_use]
pub fn is_software(&self) -> bool {
self.adapter.as_ref().is_some_and(|s| s.software)
}
/// How many adapters the host enumerated (0 when no backend came up).
#[must_use]
pub fn adapter_count(&self) -> usize {
self.adapter.as_ref().map_or(0, |s| s.considered.len())
}
/// The device class as a UI shows it: **`SOFTWARE (CPU rasteriser)`** for
/// llvmpipe/lavapipe/SwiftShader whatever they claim to be, `management console
/// (BMC)` for an ASPEED/Matrox framebuffer, else the adapter's own class.
#[must_use]
pub fn device_class(&self) -> String {
match &self.adapter {
None => "none".to_owned(),
Some(s) if s.software => "SOFTWARE (CPU rasteriser)".to_owned(),
Some(s) if is_management_display(&s.chosen) => "management console (BMC)".to_owned(),
Some(s) => s.chosen.kind.as_str().to_owned(),
}
}
/// Row 1 — the adapter name.
#[must_use]
pub fn adapter_line(&self) -> String {
match &self.adapter {
Some(s) => format!("GPU: {}", s.chosen.name),
None => "GPU: none — no adapter was brought up in this process".to_owned(),
}
}
/// Row 2 — backend · device class · how many adapters were enumerated.
#[must_use]
pub fn detail_line(&self) -> String {
match &self.adapter {
Some(s) => format!(
"{} · {} · {} adapter(s) enumerated{}",
if s.chosen.backend.is_empty() { "?" } else { s.chosen.backend.as_str() },
self.device_class(),
s.considered.len(),
if s.forced { " · FORCED" } else { "" },
),
None => "no backend · no adapter enumerated".to_owned(),
}
}
/// Row 3 — the honest lane answer.
#[must_use]
pub fn lane_line(&self) -> String {
let names = |only_used: bool| -> String {
let v: Vec<&str> = self
.lanes
.iter()
.filter(|l| if only_used { l.frames > 0 } else { l.installed })
.map(LaneRecord::short_name)
.collect();
if v.is_empty() { "—".to_owned() } else { v.join(", ") }
};
match self.lane {
GpuLaneUse::InUse { frames } => {
format!("GPU lane: IN USE — {frames} frame(s) encoded by {}", names(true))
}
// **"the CPU painter is doing the work" is a CLAIM, and it is false whenever
// nothing has drawn the pane.** MEASURED 2026-08-03 on the shipped korp-ui, in
// the posture a human lands in (korp opens on 🧊 Tables, and the map lane
// belongs to the 🗺 Map pane):
//
// GPU lane: installed but UNUSED — CloudRenderer, GpuMapRenderer drew 0
// frames (the CPU painter is doing the work)
// idle because — GpuMapRenderer: pane_not_painted_yet
//
// Two adjacent rows contradicting each other: no CPU painter was doing that
// lane's work, because no map was being drawn by anything. That headline is
// the exact sentence the owner has been reading all day and reasonably taking
// for a broken GPU on a 4090.
//
// So the claim is made only when it is TRUE — when at least one idle lane
// actually DECLINED the work (`rotated_camera`, `no_line_ways`, …). When every
// idle lane is merely un-drawn ([`NOT_YET_DRAWN_REASONS`]) the row says that
// instead, and the `idle because` row below still names which lane and why.
GpuLaneUse::InstalledUnused if self.every_idle_lane_is_undrawn() => format!(
"GPU lane: installed, NOT YET DRAWN — {} has not been asked to paint (no CPU painter is doing its work either)",
names(false)
),
GpuLaneUse::InstalledUnused => format!(
"GPU lane: installed but UNUSED — {} drew 0 frames (the CPU painter is doing the work)",
names(false)
),
GpuLaneUse::NotInstalled => {
"GPU lane: not installed — the CPU painter owns every pane".to_owned()
}
// **Name the SILENT lanes, not every installed one.** This printed
// `names(false)` — the whole installed roster — beside a count of the silent
// subset, so a registry with one silent lane read
//
// GPU lane: unknown — 1 installed lane(s)
// (CloudRenderer, Map3dRenderer, GpuMapRenderer) do not report frames
//
// Three renderers named for one lane's omission, and the two counting faithfully
// accused alongside it. The owner read exactly that on a 4090, 2026-08-08. A row
// whose count and whose names disagree cannot be acted on: it does not say which
// lane to go and wire.
GpuLaneUse::Unknown { silent_lanes } => format!(
"GPU lane: unknown — {silent_lanes} installed lane(s) ({}) do not report \
frames; the rest are counting",
self.silent_lane_names()
),
}
}
/// **The lanes that never promised to count** — the ones
/// [`GpuLaneUse::Unknown`](GpuLaneUse::Unknown) counts, by name, so the row says which
/// renderer to go and wire rather than naming the whole roster.
#[must_use]
pub fn silent_lane_names(&self) -> String {
let v: Vec<&str> = self
.lanes
.iter()
.filter(|l| (l.installed || l.frames > 0) && !l.reports_frames)
.map(LaneRecord::short_name)
.collect();
if v.is_empty() { "—".to_owned() } else { v.join(", ") }
}
/// **Has EVERY idle lane merely not been drawn yet** (as opposed to having declined
/// the work)? Drives the [`lane_line`](Self::lane_line) split above.
///
/// `false` when a single idle lane declined for a reason of its own, or stayed silent
/// — silence is not evidence of un-drawn-ness, and over-claiming here would swap one
/// wrong sentence for another. `false` on no idle lanes at all, so a live lane never
/// reaches this arm.
#[must_use]
pub fn every_idle_lane_is_undrawn(&self) -> bool {
let mut idle = self.lanes.iter().filter(|l| l.installed && l.frames == 0).peekable();
idle.peek().is_some()
&& idle.all(|l| {
l.idle_reason.as_deref().is_some_and(|r| NOT_YET_DRAWN_REASONS.contains(&r))
})
}
/// Row 4 — a recorded bring-up failure's code + remedy, when there was one.
#[must_use]
pub fn unavailable_line(&self) -> Option<String> {
let u = self.unavailable.as_ref()?;
Some(format!(
"{} — {}",
u["code"].as_str().unwrap_or("facet-gpu-?"),
u["remedy"].as_str().unwrap_or("(no remedy recorded)")
))
}
/// Every row, in paint order — the ONE writer a UI and a robot both read, so the
/// assertion cannot drift from the pixels.
#[must_use]
pub fn rows(&self) -> Vec<String> {
let mut v = vec![self.adapter_line(), self.detail_line(), self.lane_line()];
v.extend(self.idle_reason_line());
v.extend(self.unavailable_line());
v.extend(self.notes.iter().cloned());
v
}
/// Row 3b — **WHY each idle lane is idle**, in its owner's words.
///
/// Its OWN row rather than a tail on [`lane_line`](Self::lane_line): that line is
/// already long enough to reach the edge of korp's About card, and a reason appended
/// to it was MEASURED clipped off-screen on 2026-08-02 — a diagnosis nobody can read
/// is no better than the ambiguity it was added to remove.
///
/// `None` when every lane is painting, or when no idle lane has been taught to
/// explain itself: silence is a truthful "nobody said", never a guess.
#[must_use]
pub fn idle_reason_line(&self) -> Option<String> {
let v: Vec<String> = self
.lanes
.iter()
.filter(|l| l.frames == 0)
.filter_map(|l| l.idle_reason.as_ref().map(|r| format!("{}: {r}", l.short_name())))
.collect();
if v.is_empty() { None } else { Some(format!("idle because — {}", v.join("; "))) }
}
/// The `state_json` fragment.
#[must_use]
pub fn to_json(&self) -> serde_json::Value {
serde_json::json!({
"adapter": match &self.adapter {
Some(s) => s.to_json(),
None => serde_json::Value::Null,
},
"adapter_count": self.adapter_count(),
"backend": self.adapter.as_ref().map(|s| s.chosen.backend.clone()),
"device_class": self.device_class(),
"software": self.is_software(),
"lane": self.lane.as_str(),
"lane_frames": self.lane.frames(),
"lanes": self.lanes,
"unavailable": self.unavailable.clone().unwrap_or(serde_json::Value::Null),
"notes": self.notes,
"rows": self.rows(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::render::adapter::{AdapterFacts, AdapterKind, VENDOR_MESA, VENDOR_NVIDIA};
#[test]
fn a_refused_gpu_resource_is_said_in_the_state() {
note_gpu_error("lane-m-test", "graph3d_cloud_pts: 1600000 B is over this device's max_buffer_size");
assert!(gpu_error().is_some_and(|e| e.contains("max_buffer_size")));
assert!(idle_reason_of("lane-m-test").is_some_and(|e| e.contains("1600000")), "the lane's own row says it too");
}
fn nvidia() -> AdapterFacts {
AdapterFacts::new("NVIDIA GeForce RTX 4090", AdapterKind::DiscreteGpu, "Vulkan")
.with_vendor(VENDOR_NVIDIA)
}
fn llvmpipe() -> AdapterFacts {
AdapterFacts::new("llvmpipe (LLVM 21.1.8, 256 bits)", AdapterKind::Cpu, "Vulkan")
.with_vendor(VENDOR_MESA)
}
fn lane(name: &str, installed: bool, reports: bool, frames: u64) -> LaneRecord {
LaneRecord {
name: name.to_owned(),
installed,
reports_frames: reports,
frames,
idle_reason: None,
clocks: LaneClockStats::default(),
}
}
/// **RED-when-broken: the headline must not claim a CPU painter is doing work that
/// nobody is doing.**
///
/// MEASURED on the shipped korp-ui 2026-08-03, in the posture a human actually lands
/// in (korp opens on 🧊 Tables; the map lane belongs to the 🗺 Map pane), on a real
/// Xvfb window with the RTX 4090 selected:
///
/// ```text
/// GPU lane: installed but UNUSED — CloudRenderer, GpuMapRenderer drew 0 frames
/// (the CPU painter is doing the work)
/// idle because — GpuMapRenderer: pane_not_painted_yet
/// ```
///
/// Two adjacent rows that contradict each other. No CPU painter was drawing that
/// lane's work — nothing was drawing a map at all. That parenthesis is the sentence
/// The owner read all day and reasonably took for a broken GPU. `idle_reason` alone did
/// not fix it, because the headline is the line the eye lands on first.
///
/// The negative leg matters as much: a lane that genuinely DECLINED
/// (`rotated_camera`) really did leave the work to the CPU painter, and must keep
/// saying so — otherwise this "fix" just installs a different wrong sentence.
#[test]
fn an_undrawn_lane_is_not_reported_as_the_cpu_painter_doing_the_work() {
let undrawn = |name: &str, reason: &str| LaneRecord {
idle_reason: Some(reason.to_owned()),
..lane(name, true, true, 0)
};
let status = |lanes: Vec<LaneRecord>| GpuStatus {
notes: Vec::new(),
adapter: None,
unavailable: None,
lane: fold_lane_use(&lanes),
lanes,
};
// korp's exact measured shape: both installed lanes idle, both merely un-drawn.
let korp = status(vec![
undrawn("facett_core::render::gpu::graphcloud::cloud::CloudRenderer", PANE_NOT_PAINTED_YET),
undrawn("facett_map::gpu::GpuMapRenderer", PANE_NOT_PAINTED_YET),
]);
assert!(korp.every_idle_lane_is_undrawn());
let line = korp.lane_line();
assert!(
!line.contains("the CPU painter is doing the work"),
"nothing was drawing this lane's pane, so nothing was doing its work: {line}",
);
assert!(line.contains("NOT YET DRAWN"), "the row must say what is actually true: {line}");
// The reason row still names WHICH lane and WHY — the headline replaces nothing.
assert!(
korp.rows().iter().any(|r| r.contains("GpuMapRenderer: pane_not_painted_yet")),
"{:?}",
korp.rows(),
);
// A lane chosen this frame that has not encoded yet is the same class of answer.
let chosen = status(vec![undrawn("facett_map::gpu::GpuMapRenderer", AWAITING_FIRST_ENCODE)]);
assert!(!chosen.lane_line().contains("the CPU painter is doing the work"));
// ── THE NEGATIVE LEG. A lane that DECLINED the work left it to the CPU painter,
// and that sentence is true and must survive.
let declined = status(vec![undrawn("facett_map::gpu::GpuMapRenderer", "rotated_camera")]);
assert!(!declined.every_idle_lane_is_undrawn());
assert!(
declined.lane_line().contains("the CPU painter is doing the work"),
"a declined lane really did hand the work over: {}",
declined.lane_line(),
);
// ── AND A SILENT LANE IS NOT EVIDENCE. One lane that never said why is enough to
// withhold the claim in either direction — this is the arm that made me teach
// CloudRenderer to speak rather than weaken the predicate.
let mixed = status(vec![
lane("facett_core::render::gpu::graphcloud::cloud::CloudRenderer", true, true, 0),
undrawn("facett_map::gpu::GpuMapRenderer", PANE_NOT_PAINTED_YET),
]);
assert!(
!mixed.every_idle_lane_is_undrawn(),
"a lane that never explained itself cannot be counted as un-drawn",
);
}
/// **RED-when-broken: an idle lane's REASON reaches the row a human reads.**
///
/// `installed but UNUSED — … drew 0 frames (the CPU painter is doing the work)` is
/// every word true of a lane that correctly stood aside AND of a lane that is broken.
/// On 2026-08-02 korp printed exactly that on an RTX 4090 while nothing was wrong —
/// the map pane simply had not been painted yet (modal infra chooser, landing tab is
/// Tables) — and neither the owner nor a coordinating agent could tell which it was by
/// looking at the product. A diagnostic that cannot separate "correct" from "broken"
/// is the same disease this module was written to cure, one level up.
#[test]
fn an_idle_lane_names_its_reason_in_the_row_a_human_reads() {
let mut rec = lane("facett_map::gpu::GpuMapRenderer", true, true, 0);
let bare = GpuStatus {
notes: Vec::new(),
adapter: None,
unavailable: None,
lane: fold_lane_use(std::slice::from_ref(&rec)),
lanes: vec![rec.clone()],
};
let bare_rows = bare.rows();
assert!(bare_rows.iter().any(|r| r.contains("installed but UNUSED")), "{bare_rows:?}");
assert!(
!bare_rows.iter().any(|r| r.contains("idle because")),
"a lane that never explained itself must not have words put in its mouth: {bare_rows:?}"
);
assert_eq!(bare.idle_reason_line(), None);
// Now the lane says why. The SAME fold, the SAME state — only the reason added.
rec.idle_reason = Some("pane_not_painted_yet".to_owned());
let told = GpuStatus {
notes: Vec::new(),
adapter: None,
unavailable: None,
lane: fold_lane_use(std::slice::from_ref(&rec)),
lanes: vec![rec.clone()],
};
let told_rows = told.rows();
assert_ne!(bare_rows, told_rows, "the reason must CHANGE what a human reads, or it is not reaching them");
assert!(
told_rows.iter().any(|r| r == "idle because — GpuMapRenderer: pane_not_painted_yet"),
"the reason must be its OWN row, naming lane and reason: {told_rows:?}"
);
// …and it must NOT be pasted onto the already-edge-reaching lane line, where it
// was measured clipped off korp's About card.
assert!(
!told.lane_line().contains("pane_not_painted_yet"),
"the reason belongs on its own row: {}",
told.lane_line()
);
// A PAINTING lane must not be slandered with a stale reason, and a mixed process
// (korp: map lane painting, graph-3D lane idle with no graph open) must report
// both halves — `InUse` overall, and WHY the other one sat out.
let painting = lane("facett_map::gpu::GpuMapRenderer", true, true, 7);
let mut idle_other = lane("facett_graph3d::gpu::CloudRenderer", true, true, 0);
idle_other.idle_reason = Some("no_graph_open".to_owned());
let mixed = GpuStatus {
notes: Vec::new(),
adapter: None,
unavailable: None,
lane: fold_lane_use(&[painting.clone(), idle_other.clone()]),
lanes: vec![painting, idle_other],
};
let mixed_rows = mixed.rows();
assert!(mixed_rows.iter().any(|r| r.contains("IN USE — 7 frame(s)")), "{mixed_rows:?}");
assert!(
!mixed_rows.iter().any(|r| r.contains("GpuMapRenderer: ")),
"the lane that PAINTED must not be listed as idle: {mixed_rows:?}"
);
assert!(
mixed_rows.iter().any(|r| r == "idle because — CloudRenderer: no_graph_open"),
"the idle lane's reason must survive alongside a painting one: {mixed_rows:?}"
);
}
/// **RED-when-broken: the four lane states are distinct and none is guessed.**
///
/// The one that matters is the last: a silent installed lane must fold to
/// `Unknown`, NOT to `InstalledUnused`. Claiming "unused" there is a guess about
/// a lane that never reported, and it is the exact overstatement an About box
/// must not make.
#[test]
fn the_lane_fold_never_guesses() {
assert_eq!(fold_lane_use(&[]), GpuLaneUse::NotInstalled);
// Registered-but-not-installed is still "not installed".
assert_eq!(fold_lane_use(&[lane("A", false, true, 0)]), GpuLaneUse::NotInstalled);
// Reporting lane at zero → genuinely unused (korp's map facet).
assert_eq!(fold_lane_use(&[lane("A", true, true, 0)]), GpuLaneUse::InstalledUnused);
// Any frame at all → in use, summed across lanes.
assert_eq!(
fold_lane_use(&[lane("A", true, true, 7), lane("B", true, true, 5)]),
GpuLaneUse::InUse { frames: 12 }
);
// A SILENT installed lane is unknowable — never "unused".
assert_eq!(
fold_lane_use(&[lane("A", true, false, 0)]),
GpuLaneUse::Unknown { silent_lanes: 1 },
"a lane that never promised to count frames must fold to unknown, not to unused"
);
// Mixed: one reporting-at-zero + one silent is still unknown.
assert_eq!(
fold_lane_use(&[lane("A", true, true, 0), lane("B", true, false, 0)]),
GpuLaneUse::Unknown { silent_lanes: 1 }
);
// …but a real frame from the reporting lane settles it.
assert_eq!(
fold_lane_use(&[lane("A", true, true, 3), lane("B", true, false, 0)]),
GpuLaneUse::InUse { frames: 3 }
);
}
/// **RED-when-broken — THE headline: a software adapter can never read as
/// discrete.** llvmpipe that *reports itself* `DeviceType::DiscreteGpu` (a
/// lying ICD, and the shape `is_software_rasteriser` exists to catch) must still
/// show `SOFTWARE` in the row and `software: true` in the json. If this goes red,
/// the About box tells a 4090 story on a CPU rasteriser — the failure the rows
/// exist to expose.
#[test]
fn a_lying_software_adapter_still_reads_software() {
let liar = AdapterFacts::new("llvmpipe (LLVM 21.1.8)", AdapterKind::DiscreteGpu, "Vulkan")
.with_vendor(VENDOR_MESA);
let st = GpuStatus::of(AdapterSelection::decide(&[liar], None), vec![]);
assert!(st.is_software(), "llvmpipe is software however it classes itself");
assert_eq!(st.device_class(), "SOFTWARE (CPU rasteriser)");
assert!(
st.detail_line().contains("SOFTWARE"),
"the row must say SOFTWARE: {}",
st.detail_line()
);
assert!(
!st.detail_line().contains("discrete"),
"the row must NOT call a software rasteriser discrete: {}",
st.detail_line()
);
assert_eq!(st.to_json()["software"], serde_json::json!(true));
assert_eq!(st.to_json()["device_class"], serde_json::json!("SOFTWARE (CPU rasteriser)"));
}
/// The real oden enumeration: the rows name the card, the backend, the class and
/// the adapter count, and the json carries the same facts.
#[test]
fn rows_carry_adapter_backend_class_and_count() {
let st = GpuStatus::of(
AdapterSelection::decide(&[llvmpipe(), nvidia()], None),
vec![lane("facett_map::gpu::GpuMapRenderer", true, true, 42)],
);
let rows = st.rows();
assert!(rows[0].contains("NVIDIA GeForce RTX 4090"), "{:?}", rows);
assert!(rows[1].contains("Vulkan"), "{:?}", rows);
assert!(rows[1].contains("discrete"), "{:?}", rows);
assert!(rows[1].contains("2 adapter(s)"), "the count of enumerated adapters: {:?}", rows);
assert!(rows[2].contains("IN USE") && rows[2].contains("42"), "{:?}", rows);
assert!(rows[2].contains("GpuMapRenderer"), "the lane is named: {:?}", rows);
assert!(!st.is_software());
let j = st.to_json();
assert_eq!(j["backend"], serde_json::json!("Vulkan"));
assert_eq!(j["device_class"], serde_json::json!("discrete"));
assert_eq!(j["adapter_count"], serde_json::json!(2));
assert_eq!(j["lane"], serde_json::json!("in_use"));
assert_eq!(j["lane_frames"], serde_json::json!(42));
assert_eq!(j["rows"].as_array().expect("rows").len(), 3);
}
/// No GPU at all: the rows must SAY so rather than going blank, and the json
/// keys must still exist so a robot can tell "no GPU" from "key missing".
#[test]
fn a_gpu_less_process_says_so() {
let st = GpuStatus::none();
assert!(st.adapter_line().contains("none"), "{}", st.adapter_line());
assert!(st.lane_line().contains("not installed"), "{}", st.lane_line());
let j = st.to_json();
assert!(j["adapter"].is_null());
assert_eq!(j["lane"], serde_json::json!("not_installed"));
assert_eq!(j["software"], serde_json::json!(false));
assert_eq!(j["adapter_count"], serde_json::json!(0));
}
/// **The clock seam, pure**: uploads accumulate a count and replace the last
/// event; pass time is `None` until a sample lands and never becomes `0` by
/// omission; an "unavailable" verdict does not invent a number.
///
/// RED direction that matters (LAW 2): make `note_gpu_timestamps(_, false)` set
/// `last_gpu_pass_us = Some(0)` and the `None` assertions here fail — the exact
/// fake this seam forbids. Uses its own lane key so parallel tests in this binary
/// cannot race it.
/// The two tests below both touch the ONE process-global registry (and one of
/// them clears it), so they serialise on this rather than racing.
static REGISTRY_LOCK: Mutex<()> = Mutex::new(());
#[test]
fn the_clock_seam_counts_uploads_and_never_fakes_a_pass_time() {
let _g = REGISTRY_LOCK.lock().unwrap();
let name = "test::ClockLane";
let z = clock_stats_of(name);
assert_eq!((z.uploads_total, z.last_upload_bytes, z.last_upload_us), (0, 0, 0));
assert_eq!(z.last_gpu_pass_us, None, "no lane, no number");
assert_eq!(z.gpu_timestamps, None, "unprobed is 'did not say', not 'unavailable'");
note_upload(name, 120, 4096);
note_upload(name, 80, 2048);
let s = clock_stats_of(name);
assert_eq!(s.uploads_total, 2, "uploads accumulate");
assert_eq!((s.last_upload_us, s.last_upload_bytes), (80, 2048), "last event replaces");
assert_eq!(s.last_gpu_pass_us, None, "uploads say nothing about pass time");
// The unavailable verdict: a flag, NEVER a number.
note_gpu_timestamps(name, false);
let s = clock_stats_of(name);
assert_eq!(s.gpu_timestamps, Some(false));
assert_eq!(s.last_gpu_pass_us, None, "an adapter without the feature reports None, not 0");
// A real sample flips the flag and fills the number together.
note_gpu_pass(name, 37);
let s = clock_stats_of(name);
assert_eq!(s.last_gpu_pass_us, Some(37));
assert_eq!(s.gpu_timestamps, Some(true), "a resolved sample IS the proof of realness");
}
/// The registry accumulates through the public notes, and `note_frame` implies
/// both installed and reporting (a lane cannot encode a frame otherwise).
#[test]
fn the_registry_records_what_the_lanes_report() {
let _g = REGISTRY_LOCK.lock().unwrap();
reset_for_test();
note_installed("test::LaneA");
assert_eq!(lane_use(), GpuLaneUse::Unknown { silent_lanes: 1 });
note_reports_frames("test::LaneA");
assert_eq!(lane_use(), GpuLaneUse::InstalledUnused);
note_frame("test::LaneB");
assert_eq!(lane_use(), GpuLaneUse::InUse { frames: 1 });
let recs = lanes();
let b = recs.iter().find(|l| l.name == "test::LaneB").expect("LaneB registered");
assert!(b.installed && b.reports_frames && b.frames == 1);
assert_eq!(b.short_name(), "LaneB");
reset_for_test();
assert_eq!(lane_use(), GpuLaneUse::NotInstalled);
}
/// `is_installed` answers exactly what `note_installed` said, per NAME: an unknown
/// name, and a name merely ASKED about through `installed_flag`, read `false`; the
/// installed one reads `true`, through the same flag object every time.
///
/// RED: drop the `installed_flag(name).store(true, …)` line from `note_installed`.
#[test]
fn is_installed_follows_note_installed_per_name() {
// note_installed adds a RECORD too, which the fold tests count.
let _g = REGISTRY_LOCK.lock().unwrap();
// Names no other test touches — the flags are process-global and never lowered.
let a = "test::is_installed::A";
let b = "test::is_installed::B";
assert!(!is_installed(a), "a name nobody installed must read false");
let flag_b = installed_flag(b);
assert!(!is_installed(b), "asking for the flag must not raise it");
note_installed(a);
assert!(is_installed(a), "note_installed must raise the flag");
assert!(!is_installed(b), "…of THAT lane only");
assert!(std::ptr::eq(flag_b, installed_flag(b)), "one flag per name, every time");
assert!(installed_flag(a).load(Ordering::Acquire), "the cached flag is the same flag");
// A name compared by CONTENT, not by pointer: a caller may hold another copy.
let a_copy = String::from(a);
assert!(is_installed(&a_copy));
}
/// `reset_for_test` clears the attribution records and leaves the installed flags
/// alone — the renderer a test installed is still in its `RenderState`.
#[test]
fn a_registry_reset_does_not_uninstall_a_renderer() {
let _g = REGISTRY_LOCK.lock().unwrap();
let c = "test::is_installed::C";
note_installed(c);
reset_for_test();
assert!(lanes().iter().all(|l| l.name != c), "the record is gone");
assert!(is_installed(c), "the flag is not");
}
}