facett-map3d/tests/bloom_off_costs_nothing.rs
//! **Bloom OFF must cost three fewer passes AND change no pixel** (needs `--features wgpu`).
//!
//! GFX_V2 §V2.9b, "still open": *"bloom's bright-pass + 2 blurs run even when bloom is
//! OFF — `facett-map3d/src/gpu.rs:1901-1903`; only the composite intensity is zeroed."*
//! True as written. `write_uniforms` set `params.z = 0.0` and `record` then ran
//! bright → blur H → blur V anyway, three fullscreen passes (one full-res 4-tap read, two
//! half-res 9-tap) whose entire product was multiplied by zero one pass later.
//!
//! `record` now takes `bloom_on` and skips them. That is a **claim about pixels**, not
//! just about cost, and the claim is the risky half: the composite still SAMPLES
//! `bloom_a`, so skipping the passes leaves it holding whatever the last bloom-on frame
//! wrote. The argument that this is safe is that `bloom.wgsl` reaches that texture only
//! through `scene + bloom * U.params.z`, and `params.z` is an exact `0.0`; the bright
//! pass's output is `soft_threshold` of finite HDR radiance, so `bloom_a` is always
//! finite and finite × 0.0 is 0.0. There is no NaN path.
//!
//! An argument is not a measurement, so this file measures it, and the measurement is
//! built to be able to fail:
//!
//! * **The bloom texture is DELIBERATELY DIRTIED.** One renderer draws a bright bloom-ON
//! frame first, then the same renderer draws bloom-OFF. If stale glow could leak, this
//! is the run in which it leaks. A fresh renderer drawing only bloom-OFF is the
//! control, and the two must be **byte-identical**.
//! * **Non-vacuity, both ends.** The bloom-ON frame must differ from the bloom-OFF frame
//! (otherwise "identical" is a statement about a renderer that draws nothing), and the
//! pass counts must differ by exactly three.
//!
//! Run: `cargo test -p facett-map3d --features wgpu --test bloom_off_costs_nothing -- --nocapture`
#![cfg(feature = "wgpu")]
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use egui_kittest::wgpu::{create_render_state, default_wgpu_setup, WgpuTestRenderer};
use egui_kittest::Harness;
use facett_core::Facet as _;
use facett_map::Way;
use facett_map3d::{Map3D, SunSky, ViewPreset};
/// Tall bright blocks under a strong sun — a scene with genuine HDR highlights, so the
/// bright-pass has something above threshold to find. A scene the bloom chain finds
/// nothing in would make "bloom on == bloom off" trivially true.
fn blocks() -> Vec<Way> {
let (lon0, lat0) = (9.50_f64, 47.10_f64);
let theme = facett_core::Theme::default();
let tags = vec![
("building".to_string(), "yes".to_string()),
("height".to_string(), "120".to_string()),
];
let mut ways = Vec::new();
let mut id = 1i64;
for r in 0..3 {
for c in 0..3 {
let bx = lon0 + c as f64 * 0.0018;
let by = lat0 + r as f64 * 0.0018;
let b = 0.0012;
let ring = [(bx, by), (bx + b, by), (bx + b, by + b), (bx, by + b), (bx, by)];
ways.push(Way::from_lonlat(id, &ring, &tags, &theme).unwrap());
id += 1;
}
}
ways
}
fn scene(bloom: bool) -> Map3D {
let sun = SunSky {
dir: SunSky::from_angles(0.7, 0.6).dir,
sun_color: [1.0, 0.97, 0.90],
// Hot sun: pushes highlights well above 1.0 in the Rgba16Float offscreen, which
// is the only regime in which bloom is visible at all.
sun_intensity: 3.2,
sky_color: [0.55, 0.62, 0.80],
ambient: 0.5,
};
let mut m = Map3D::from_ways("bloomcost", &blocks(), 0.4)
.with_gpu(true)
.with_sun(sun)
.with_bloom(bloom);
m.spin = false;
m.set_clock(0.0);
m.view_preset(ViewPreset::Isometric);
m.cam.goal_distance = 2.6;
m.cam.settle();
m
}
/// Render one frame. When `dirty_first` is set, the SAME renderer draws several bloom-ON
/// frames before the bloom-OFF frame that is captured — so `bloom_a` is full of real glow
/// when the skip happens.
fn render(bloom: bool, dirty_first: bool) -> (image::RgbaImage, Option<u32>) {
let rs = create_render_state(
facett_map3d::gpu::proof_wgpu_setup().unwrap_or_else(default_wgpu_setup),
Default::default(),
);
{
// ATTRIBUTION: `create_render_state` hard-fails with no adapter, so reaching this
// line means a device answered — say which, because a proof that silently ran on
// llvmpipe is evidence about llvmpipe.
let info = rs.adapter.get_info();
eprintln!(
"[bloom_off] device: {} ({:?}, {:?}) bloom={bloom} dirty_first={dirty_first}",
info.name, info.backend, info.device_type
);
}
// ── THE TEMPORAL LANE IS OFF FOR THIS FILE, and that is isolation rather than
// convenience. The claim measured below is "a bloom-OFF frame is byte-identical
// whether or not `bloom_a` holds stale glow". With TAA on, a frame is a function of
// the accumulated history as well as of this frame's geometry, and the `dirty_first`
// arm deliberately renders five MORE frames than the control — so the two arms sit at
// different jitter phases with different histories and can never be byte-identical,
// for reasons that have nothing to do with the glow chain. MEASURED with TAA on:
// 84 235 of 230 400 px differ. Switching the temporal lane off is what makes the
// comparison a statement about bloom again — and it also keeps the pass counts here
// (10 on / 7 off) exactly the ones this file was written against, since `Off` records
// neither the velocity pass nor the resolve. The assertion that matters is on their
// DIFFERENCE of three either way.
facett_map3d::gpu::install_renderer_with_taa_for_test(&rs, facett_map3d::gpu::TaaMode::Off);
let probe = rs.clone();
// The live bloom flag the frame closure reads, so ONE renderer can draw both states.
let live = Arc::new(AtomicBool::new(if dirty_first { true } else { bloom }));
let flag = live.clone();
let mut view = scene(bloom);
let mut harness = Harness::builder()
.with_size(egui::vec2(480.0, 480.0))
.renderer(WgpuTestRenderer::from_render_state(rs))
.build_ui(move |ui| {
view.set_bloom(flag.load(Ordering::Relaxed));
facett_core::set_theme(ui.ctx(), facett_core::Theme::sci_fi());
view.ui(ui);
});
if dirty_first {
// Four bloom-ON frames: bloom_a now holds real, bright, blurred glow.
harness.run_steps(4);
let _ = harness.render().expect("wgpu render (dirtying pass)");
live.store(bloom, Ordering::Relaxed);
}
harness.run_steps(4);
let img = harness.render().expect("wgpu render");
(img, facett_map3d::gpu::post_passes_recorded(&probe))
}
#[test]
fn skipping_the_glow_chain_costs_three_passes_and_changes_no_pixel() {
let (on_img, on_n) = render(true, false);
let (off_img, off_n) = render(false, false);
let (dirty_img, dirty_n) = render(false, true);
let on_n = on_n.expect("the bloom-ON frame installed a renderer (Some(n) != None)");
let off_n = off_n.expect("the bloom-OFF frame installed a renderer");
let dirty_n = dirty_n.expect("the dirtied bloom-OFF frame installed a renderer");
eprintln!("EMIT-BLOOMCOST post_passes: on={on_n} off={off_n} off_after_on={dirty_n}");
for (name, img) in [("on", &on_img), ("off", &off_img), ("dirty", &dirty_img)] {
image::DynamicImage::ImageRgba8((*img).clone())
.save(format!("/tmp/map3d_bloomcost_{name}.png"))
.ok();
}
// ── THE COST. Exactly three passes, which is bright + blur H + blur V. ──
// "Exactly", not ">=": a skip that also dropped the composite would be the
// 2026-08-05 untonemapped-plan-view regression coming back through another door.
assert!(on_n >= 4, "the bloom-ON chain must record its four passes ({on_n})");
assert_eq!(
on_n - off_n,
3,
"bloom OFF must skip EXACTLY the three glow passes (on={on_n}, off={off_n}); the \
composite is the display transform and always runs"
);
assert_eq!(off_n, dirty_n, "the pass count does not depend on what ran before it");
// ── THE PIXELS. The claim that makes the skip a no-op rather than an optimisation. ──
// A fresh bloom-OFF frame and a bloom-OFF frame drawn by a renderer whose bloom
// texture is full of glow must be byte-identical.
let differing = off_img
.pixels()
.zip(dirty_img.pixels())
.filter(|(a, b)| a.0 != b.0)
.count();
let total = (off_img.width() * off_img.height()) as usize;
eprintln!(
"EMIT-BLOOMCOST stale-bloom leak: {differing} of {total} px ({:.4}%)",
100.0 * differing as f64 / total as f64
);
assert_eq!(
differing, 0,
"a bloom-OFF frame drawn after bloom-ON frames differs from a fresh one in \
{differing} of {total} px — stale `bloom_a` content is reaching the composite, so \
skipping the glow passes is NOT the no-op `record`'s doc claims"
);
// ── NON-VACUITY: bloom must actually DO something in this scene, or the whole file
// is a statement about a renderer that draws the same frame either way. ──
let bloom_delta = on_img
.pixels()
.zip(off_img.pixels())
.filter(|(a, b)| a.0 != b.0)
.count();
eprintln!(
"EMIT-BLOOMCOST bloom on-vs-off: {bloom_delta} of {total} px ({:.2}%)",
100.0 * bloom_delta as f64 / total as f64
);
assert!(
bloom_delta * 200 > total,
"bloom must change more than 0.5% of the frame in this scene ({bloom_delta} of \
{total}) — otherwise 'off is identical to off' proves nothing about the glow chain"
);
#[cfg(feature = "testmatrix")]
facett_core::testmatrix::emit(
"facett-map3d",
"bloom_off_skips_three_passes_pixel_identically",
differing == 0 && on_n - off_n == 3,
&format!("blob=/tmp/map3d_bloomcost_off.png on={on_n} off={off_n} leak_px={differing}"),
);
}