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

nordisk/facett

facett-map/src/gpu/line.wgsl

// Triangle-list line shader with SCREEN-SPACE width, miter/bevel joins, SDF anti-
// aliasing, and an optional dark casing pass — the "pretty roads" upgrade over the
// raw 1px `LineList` hairlines in draw.wgsl.
//
// Vertices are origin-local Mercator centreline points (the SAME high-zoom-safe bake
// as draw.wgsl): each polyline vertex is emitted twice (side = ±1) so a segment
// becomes a quad. The width offset is applied in SCREEN space (px), so a road keeps
// a constant on-screen width at any zoom (width-scaled, not world-scaled). The join
// bisector + miter factor (1/cos(θ/2), clamped for a bevel) are baked per vertex on
// the CPU so a corner is a clean miter, not two overlapping quads.

struct Uniforms {
    zoom_x:          f32,
    zoom_y:          f32,
    screen_center_x: f32,
    screen_center_y: f32,
    ref_x:           f32,
    ref_y:           f32,
    viewport_w:      f32,
    viewport_h:      f32,
    feather_px:      f32, // AA edge softness (px)
    width_add:       f32, // CEILING on the casing's extra half-width (px)
    use_casing:      f32, // 1.0 → paint `casing_col`; 0.0 → the per-vertex colour
    // deck.gl's `widthScale` + `widthMinPixels`/`widthMaxPixels`, applied HERE (per
    // frame) instead of being baked into the vertex buffer — so a road's on-screen
    // width tracks zoom without re-uploading geometry, and matches the CPU painter's
    // `facett_map::style::line_width_px` exactly (ONE formula, both lanes).
    width_scale:     f32,
    width_min_px:    f32,
    width_max_px:    f32,
    // ── THE CASING IS A FRACTION OF ITS ROAD, NOT A CONSTANT ─────────────────
    // `casing_ratio` is the extra half-width as a fraction of the road's OWN
    // half-width; `casing_min_px` is the floor so a hairline still gets an edge.
    // See `LINE_CASING_RATIO` in `gpu/mod.rs` for the measurement that forced it.
    casing_ratio:    f32,
    casing_min_px:   f32,
    casing_col:      vec4<f32>,
    // The 2D ground frame (bearing rotation + cos(tilt) foreshorten) — the term this
    // lane did not have, which is why a rotated camera fell back to the CPU painter
    // entirely. Applied through the shared prelude's `project_ground_px` /
    // `ground_apply`, so the two lanes and the CPU painter share ONE rotation.
    rot:             vec4<f32>,
    foreshorten:     f32,
    _pad2:           f32,
    _pad3:           f32,
    _pad4:           f32,
}

// **Two uniform slots, selected by `instance_index`** (GG audit row 21). A road chunk
// is drawn with `instance_count = 2`: instance 0 reads slot 0 (the casing block,
// `use_casing = 1`, wide, dark) and instance 1 reads slot 1 (the fill block). The two
// used to be two draws with two bind groups; the device rasterises a draw's instances
// in instance order, so the casing still lands under the fill exactly as before, for
// one command instead of two. A fill-outline chunk is drawn with one instance and both
// slots hold the outline block. Rust twin: `line.rs`'s `UNIFORM_PAIR_BYTES`.
@group(0) @binding(0) var<uniform> u2: array<Uniforms, 2>;

// Mercator → px scale for a LENGTH, as the inner-miter clamp reads it. Exactly `zoom`
// for the uniform camera every live caller builds; under a non-uniform fit it divides
// the allowance by the anisotropy ratio, which bounds the error in approximating the
// screen-space `sin(τ/2)` by the Mercator one — so the ceiling can only clamp HARDER
// than needed, never looser. Rust twin: `merc_to_px_scale`.
fn merc_to_px_len(zoom_x: f32, zoom_y: f32) -> f32 {
    let lo = min(zoom_x, zoom_y);
    let hi = max(max(zoom_x, zoom_y), 1e-20);
    return lo * lo / hi;
}

struct VsOut {
    @builtin(position) pos:     vec4<f32>,
    @location(0)       col:     vec4<f32>,
    @location(1)       side:    f32, // signed across-width position in [-1, 1]
    @location(2)       half_px: f32, // this vertex's half-width (px), incl. width_add
    // **The along-axis half of a ROUND END's offset** — lane GG #25. `0` on every quad
    // vertex, so `length(vec2(side, cap_t))` degenerates to `abs(side)` and the road's
    // body is unchanged; `0 → 1` across a cap/joint half-disc, where the pair together
    // is the fragment's radial position in the disc. See `round_end_miter` in line.rs.
    @location(3)       cap_t:   f32,
    // **The fragment's ARC LENGTH along its way, in px** — HO-T3. `0` on every undashed
    // vertex. Interpolates linearly across a segment quad, which IS the arc length there.
    @location(4)       arc_px:  f32,
    // **The dash period in px, or 0 for "no dash"** — HO-T3. Non-zero only on a dashed
    // way in the FILL pass; the casing pass and every road carry 0 and take the exact
    // path they took before this term existed.
    @location(5)       dash_period_px: f32,
}

// Rust twin: `paint_order::CASING_DEPTH_BIAS`.
const CASING_DEPTH_BIAS: f32 = 1.0e-6;

// ── THE DASH LAW (HO-T3). Rust twins: `style::DASH_PERIOD_RATIO` / `style::DASH_DUTY`,
// asserted equal by `tests/rail_dash_pixels.rs` from this text. A dashed core is lit for
// `DASH_DUTY` of every `DASH_PERIOD_RATIO · w_px` of ARC LENGTH along the way — the
// way's length, not the screen's x, so a diagonal rail carries as many dashes as a
// horizontal one of the same length and nothing crawls under a pan.
const DASH_PERIOD_RATIO: f32 = 4.0;
const DASH_DUTY: f32 = 0.5;

// **Coverage of the lit part of the dash cycle at arc position `arc_px`**, through the
// same `coverage_inside` ramp the road's edge uses, so a dash END is anti-aliased with the
// same feather as its SIDE. `d` is the signed px distance to the nearest lit/gap edge —
// positive inside the lit half, negative in the gap — so a fragment straddling the edge
// gets exactly the half-coverage a fragment straddling the road's edge gets.
fn dash_coverage(arc_px: f32, period_px: f32, feather_px: f32) -> f32 {
    let lit = period_px * DASH_DUTY;
    let ph = fract(arc_px / period_px) * period_px; // 0 ≤ ph < period
    let d = select(-min(ph - lit, period_px - ph), min(ph, lit - ph), ph <= lit);
    return coverage_inside(d, feather_px);
}

// The coverage below which a fragment is DISCARDED rather than drawn — lane GG #2.
// `0.5/255`: half a step of an 8-bit alpha channel, so a fragment under it rounds to
// nothing in the target and its only remaining effect would be the depth it writes.
// Rust twin: `MIN_COVERAGE_ALPHA` in this module's Rust file.
const MIN_COVERAGE_ALPHA: f32 = 0.00196078431;

// The sample count of the map's offscreen colour+depth pair — the ONE multisampled
// target in facett, and the reason this shader can hand its coverage to the rasteriser
// at all. Rust twin: `MAP_MSAA_SAMPLES` in `gpu/mod.rs`, which carries the ruling.
const MSAA_SAMPLES: u32 = 4u;

// **Geometric coverage → a sample mask** — lane GG #2, the real cure.
//
// `n = ceil(cov · 4)` of the four samples, as the low `n` bits.
//
// * **CEILING, not rounding, and the colour is corrected for it below.** A mask alone can
//   only express coverage in quarters, and pushing a road's whole AA ramp through four
//   levels is a real regression: MEASURED on oden / RTX 4090, 2026-09-05, with a plain
//   `round` mask and the alpha left alone, the motorway's faintest edge pixel
//   (x = 256, `[28, 28, 34]`) vanished into paper entirely and the residential's own
//   mid-row colour moved `[46, 51, 62]` → `[42, 47, 57]`. `coverage_alpha` removes that
//   error exactly rather than trading it, which is why the ceiling is the right rounding:
//   `n` is only ever the number of samples the DEPTH is claimed on, and claiming at most
//   one sample too many is the conservative direction.
// * **The LOW bits, not an arbitrary n.** A road's casing and its fill are concentric,
//   drawn back to back at one depth bias apart, and the fill's coverage at a pixel is
//   never greater than the casing's. Taking the low bits nests them: the fill's samples
//   are always a SUBSET of the casing's, so the two never dither against each other. A
//   pattern that varied per pass would sparkle along every road edge.
//
// A NOTE ON WHAT IS NOT HERE. A per-way ROTATION of the run was written and then removed,
// because the argument for it is good and the measurement for it is empty. The argument:
// if every way starts at bit 0, two overlapping ways claim maximally overlapping samples,
// so a lower-ranked way underneath only ever gets what the upper one's coverage ran out
// of, and what shows through is systematically its OUTERMOST ink. A per-way rotation is a
// bijection on the four bits, so it decorrelates that while leaving a single way's
// casing⊇fill nesting intact.
//
// MEASURED on oden / RTX 4090, 2026-09-05, with the rotation hashed from `paint_depth` and
// again with it forced to zero: the crossing frame was **bit-identical**, every pixel,
// both ways. It buys nothing that can be shown on any fixture in this repo, so it is not
// carried. If a future frame shows an edge sparkling between two ways, this paragraph is
// the first thing to try.
fn coverage_mask(cov: f32) -> u32 {
    let n = u32(ceil(clamp(cov, 0.0, 1.0) * f32(MSAA_SAMPLES)));
    return (1u << n) - 1u;
}

// **The alpha those `n` samples must blend at for the resolve to reproduce `cov` EXACTLY.**
//
// The mask puts the fragment on `n/4` of the pixel; blending there at `α` and averaging
// gives `(n/4)·α` of the ink. Setting `α = cov·4/n` makes that identically `cov`, for
// every coverage, with no quantisation error in the COLOUR at all — the four levels are
// spent on the depth claim, which is the only thing that needed them.
//
// `n = ceil(cov·4) ≥ cov·4`, so the result is always in `(0, 1]` and never has to be
// clamped. `cov = 0` cannot reach here: `fs_main` discards below `MIN_COVERAGE_ALPHA`.
fn coverage_alpha(cov: f32) -> f32 {
    let c = clamp(cov, 0.0, 1.0) * f32(MSAA_SAMPLES);
    return c / max(ceil(c), 1.0);
}

// **The two things `fs_main` used to fold into one alpha.**
//
// `col` carries the way's MATERIAL alpha and blends as it always did; `mask` carries the
// SUB-PIXEL coverage and gates colour and depth per sample. They were one number
// (`col.a · coverage_inside(...)`) and that is precisely why a half-covered fragment had
// to choose between compositing and owning the pixel's depth.
struct FsOut {
    @location(0) col:  vec4<f32>,
    @builtin(sample_mask) mask: u32,
}

@vertex
fn vs_main(
    @location(0) pos:      vec2<f32>, // centreline, origin-local Mercator
    @location(1) bisector: vec2<f32>, // mercator-space join bisector (unit)
    // **`side` carries TWO things** (lane MP-a): its sign is the across-width side
    // (+1 / -1) and its magnitude is `1 + depth`, the way's paint depth in 0..=1
    // derived from its `PaintKey` rank. `LineVertex` is exactly 48 B and that size is
    // load-bearing (vertex layout, chunk partition, bake format), while
    // this field was one bit of information in a whole f32. Rust twin:
    // `paint_order::pack_side_depth`.
    @location(2) side_packed: f32,
    @location(3) half_px:  f32,       // half width (px)
    @location(4) miter:    f32,       // miter length factor (1/cos(θ/2)), clamped
    @location(5) col:      vec4<f32>,
    @location(6) inner_lim: f32,      // inner-miter ceiling, MERCATOR units
    @builtin(instance_index) inst: u32,
) -> VsOut {
    // Which pass this instance is: 0 casing, 1 fill (see `u2`). Clamped so a stray
    // third instance could only ever redraw the fill, never read past the array.
    let u = u2[min(inst, 1u)];
    // Unpack the two halves `side_packed` carries. The RAW side drives the across-width
    // offset exactly as before; the depth goes to Z so ordering survives being split
    // across submissions — which is the whole point, since `PaintKey` cannot.
    let side = select(1.0, -1.0, side_packed < 0.0);
    let paint_depth = clamp(abs(side_packed) - 1.0, 0.0, 1.0);
    // ── ROUND ENDS (lane GG #25) ─────────────────────────────────────────────
    // `vertex_join` never emits a miter below 1.0 and MITER_LIMIT caps it at 4.0, so
    // the sign is a free bit in a word that is already in the vertex — and `LineVertex`
    // is 48 B, which is load-bearing, so a free bit is the only kind available. A
    // NEGATIVE miter marks a cap/joint half-disc vertex and carries `-(1 + cap_t)`.
    // Rust twin: `round_end_miter` / `decode_round_end`.
    let is_round = miter < 0.0;
    let cap_t = select(0.0, -miter - 1.0, is_round);
    let miter_eff = select(miter, 1.0, is_round);
    // ── THE DASH FLAG AND THE ARC LENGTH (HO-T3) ─────────────────────────────
    // `half_px` is a half-WIDTH, strictly positive, so its sign was a free bit: negative
    // marks a dashed way. On such a vertex `col.a` is not an alpha but the ARC LENGTH from
    // the way's first point (origin-local Mercator) — a dashed way is opaque by
    // definition, and the alpha is restored to 1.0 below. Same trick, same reason, as the
    // two decodes above: `LineVertex` is 48 B and that is load-bearing. Rust twins:
    // `pack_dash_half_px` / `decode_dash` / `pack_dash_col`.
    let is_dashed = half_px < 0.0;
    let half_abs = abs(half_px);
    let arc_merc = select(0.0, col.a, is_dashed);
    // Centreline → screen px through the shared prelude's ONE projection writer
    // (subtract-before-scale, then the ground frame, then the pane centre) — the same
    // call `draw.wgsl`'s `vs_main` makes.
    let sc = project_ground_px(
        pos,
        vec2<f32>(u.ref_x, u.ref_y),
        vec2<f32>(u.zoom_x, u.zoom_y),
        u.rot,
        u.foreshorten,
        vec2<f32>(u.screen_center_x, u.screen_center_y),
    );
    let sx = sc.x;
    let sy = sc.y;
    // Bisector direction in SCREEN space (per-axis zoom), then ROTATED by the ground
    // frame — the width offset has to turn with the map or a rotated road is drawn
    // with its casing on the wrong side.
    //
    // Deliberately `ground_apply` with foreshorten = 1, NOT the full frame: this
    // vector is normalised immediately below and then scaled by a width in PIXELS, so
    // a road keeps a constant on-screen thickness under tilt. That is exactly what the
    // CPU painter does — `egui::Shape::line` strokes a constant-width path along the
    // already-foreshortened centreline — so the two lanes still resolve ONE width.
    let sb0 = vec2<f32>(bisector.x * u.zoom_x, bisector.y * u.zoom_y);
    let sb = ground_apply(sb0, u.rot, 1.0);
    var sbn = vec2<f32>(0.0, 0.0);
    if (length(sb) > 1e-12) {
        sbn = normalize(sb);
    }
    // deck.gl `PathLayer`: resolve the stroke width for THIS frame's view, then clamp
    // it into the pixel band, then halve. `half_px` carries the way's raw themed
    // half-width (zoom-independent), so the clamp — not the bake — decides the pixels.
    let w_px = resolve_line_width_px(half_abs * 2.0, u.width_scale, u.width_min_px, u.width_max_px);
    // ── THE CASING SCALES WITH ITS ROAD ──────────────────────────────────────
    // A FLAT `+ width_add` made the casing a constant 2 px of extra half-width on
    // every way, so a 1 px residential street drew as a 5 px band of near-black
    // navy with a 1 px light core — four fifths of it casing. MEASURED on the
    // shipped korp-ui over Stockholm at zoom 12.7 (1254x724 canvas): the exact
    // casing colour `#191C24` alone covered 25 512 px = 2.81 % of the pane before
    // antialiasing, and 15.67 % of the pane was ink darker than grey 70. That is
    // the "gryn" — it is the road casing, not the labels and not the buildings.
    //
    // A motorway keeps its ribbon because the ratio gives it MORE than the floor;
    // a footpath gets a hairline edge instead of a black worm. `width_add` is now
    // the CEILING (the old constant), so nothing widens.
    var extra = 0.0;
    if (u.use_casing > 0.5) {
        extra = min(max(w_px * 0.5 * u.casing_ratio, u.casing_min_px), u.width_add);
    }
    let hw = w_px * 0.5 + extra;
    // Rasterise WIDER than the road by one feather on each side, so the AA ramp —
    // which `coverage_inside` centres on the true edge at `hw` — has fragments to
    // land on all the way out to zero coverage. Without this the quad boundary
    // truncates the ramp at 50% and the drawn width comes up `2·feather_px` short.
    // `hw` (the TRUE half-width) is what travels to the fragment stage; the extra
    // feather is geometry only.
    let hw_ext = hw + max(u.feather_px, 0.0);
    // ── THE INNER-MITER CLAMP (GFX_V2 §3.A) ──────────────────────────────────
    // A miter join's CONCAVE corner does not stick out, it retreats: the bisector
    // offset moves it `hw_ext · miter · sin(τ/2)` BACK along its segment, unbounded as
    // τ → 180°. Once the two ends of one segment have retreated past each other, that
    // segment's quad winds backwards and paints a bowtie — the self-intersection
    // GFX_V2 §2 credits deck.gl with handling and we did not.
    //
    // `inner_lim` is the ceiling the CPU baked for THIS vertex — `0.5·L / sin(τ/2)` on
    // the concave corner, `NO_INNER_LIMIT` on every other vertex — in MERCATOR units,
    // because the ceiling is a property of the POLYLINE and must not move with stroke
    // width, with zoom, or between the casing and fill passes. Converted to px here,
    // per frame. Rust twin: `resolve_join_distance_px` + `merc_to_px_scale`.
    let dist = min(hw_ext * miter_eff, inner_lim * merc_to_px_len(u.zoom_x, u.zoom_y));
    // A quad vertex offsets purely along the bisector. A ROUND END offsets in TWO
    // screen-space axes — `side` across `sbn`'s perpendicular, `cap_t` along `sbn` —
    // which is what makes `length(vec2(side, cap_t))` the fragment's radial position and
    // the silhouette an exact circle rather than a fan's polygon. The perpendicular is
    // taken in SCREEN space (after the ground rotation, which is rigid) so the disc is
    // round on the pane, which is where it is looked at.
    var off = sbn * side * dist;
    if (is_round) {
        let spn = vec2<f32>(-sbn.y, sbn.x);
        off = (spn * side + sbn * cap_t) * dist;
    }
    let ndc = px_to_ndc(vec2<f32>(sx + off.x, sy + off.y), vec2<f32>(u.viewport_w, u.viewport_h));
    var out_col = col;
    if (is_dashed) {
        // The alpha slot carried the arc length; the material is opaque.
        out_col.a = 1.0;
    }
    if (u.use_casing > 0.5) {
        out_col = u.casing_col;
    }
    // ── THE DASH TERM (HO-T3), gated by the WAY and by the PASS ──────────────
    // The arc length turns to px per frame with the same `merc_to_px_len` the inner-miter
    // clamp uses, so the dash is a property of the way (pan-stable) that rescales with the
    // camera like the width it is measured against. The period follows the RESOLVED width
    // — the one formula GG #27 made both lanes share — so a rail's dashes are the same
    // multiple of its stroke at every zoom. Only the FILL INSTANCE dashes — under GG #21
    // the casing and the fill are instance 0 and instance 1 of ONE draw, so the gate is
    // `inst`, not the slot's `use_casing`: instance 0 (the casing under it) stays whole
    // and is what shows through the gaps, and the single-instance outline draw (which
    // reads slot 0 with `use_casing = 0`) can never dash even in principle.
    let arc_px = arc_merc * merc_to_px_len(u.zoom_x, u.zoom_y);
    let dash_period_px = select(0.0, DASH_PERIOD_RATIO * w_px, is_dashed && inst == 1u);
    // The casing rides one bias BEHIND its own fill, so the dark outline never covers
    // the bright line it outlines. Rust twin: `paint_order::CASING_DEPTH_BIAS`.
    let z = clamp(paint_depth + select(0.0, CASING_DEPTH_BIAS, u.use_casing > 0.5), 0.0, 1.0);
    return VsOut(vec4<f32>(ndc, z, 1.0), out_col, side, hw, cap_t, arc_px, dash_period_px);
}

@fragment
fn fs_main(in: VsOut) -> FsOut {
    // The fragment half reads only `feather_px`, which the casing and fill blocks
    // share (and the outline holds in both slots), so slot 0 is the whole truth here.
    let u = u2[0];
    // Signed distance INWARD from the road's true edge, in px. `side` interpolates
    // over the FEATHER-EXPANDED quad (half-extent `hw_ext`), so the perpendicular
    // offset of this fragment is `|side| · hw_ext` and its inward distance from the
    // true edge at `hw` is `hw − |side|·hw_ext`. Negative outside the road, positive
    // inside, zero exactly on the boundary — which is where `coverage_inside` puts
    // its 50% crossing, so the profile integrates to `2·hw = w_px` exactly.
    let hw_ext = in.half_px + max(u.feather_px, 0.0);
    // **`length(vec2(side, cap_t))`, not `abs(side)`** — lane GG #25. On a cap or joint
    // half-disc the pair is the fragment's position in the disc's own screen frame, so
    // the same `coverage_inside` ramp that squares off a butt end now rounds it, and the
    // circle is exact rather than a fan's polygon.
    //
    // **The `cap_t == 0` arm is not an optimisation and it is not free either — it is
    // what keeps a road body bit-identical.** `cap_t` is 0 at every quad vertex and
    // interpolates to 0 across every quad, so `length` there is `sqrt(side·side)`:
    // mathematically `abs(side)`, and NOT bit-for-bit, because the square rounds and the
    // root rounds again. On a HARD (`feather = 0`) edge one ulp of `edge_px` is the whole
    // verdict, and this shader is measured against a CPU model at exactly that hardness
    // by `line_gpu::gpu_draws_exactly_the_clamped_join_geometry_the_cpu_model_predicts`.
    //
    // MEASURED on oden / RTX 4090, 2026-09-05: on the shipped (clamped) geometry that
    // model↔frame diagonal is 0 mismatches out of 170 041 confidently classified pixels
    // with the `select` in, with it out, and before this row existed — so the ulp is
    // below the noise of the fixtures we have. The arm is kept because "the road's body
    // does not move" is a property worth being able to state, not because a frame was
    // seen to move.
    let radial = select(abs(in.side), length(vec2<f32>(in.side, in.cap_t)), in.cap_t != 0.0);
    let edge_px = in.half_px - radial * hw_ext;
    // **The sub-pixel coverage, kept SEPARATE from the material alpha** — lane GG #2.
    var cov = coverage_inside(edge_px, u.feather_px);
    // ── THE DASH (HO-T3): in a gap the fill's coverage goes to zero and the fragment is
    // discarded below, so the casing painted under it is what the pixel keeps. A road and
    // the casing pass carry `dash_period_px = 0` and never enter this branch.
    if (in.dash_period_px > 0.0) {
        cov = cov * dash_coverage(in.arc_px, in.dash_period_px, u.feather_px);
    }
    let a = in.col.a * cov;
    // ── A TRANSPARENT FRAGMENT MUST NOT CLAIM A PIXEL (lane GG #2) ────────────
    // The quad is rasterised one feather WIDER than the road so the ramp has fragments
    // to land on — and depth writing is on, so without this every road carried a ~1 px
    // halo of INVISIBLE ink that reserved its pixel and depth-rejected any lower-ranked
    // way drawn afterwards. The loser is not blended away, it is discarded, so what was
    // left at that pixel was the bare pane background: a paper-coloured slit alongside
    // every road, cutting whatever crossed it.
    //
    // MEASURED on oden / RTX 4090, 2026-09-05, BEFORE the sample mask below existed: this
    // discard changed no pixel at all. Taken and painted were the same seven pixels with
    // it in and with it neutralised, because a fragment under half an alpha step needs its
    // centre within ~0.002 px of the quad's outer edge and essentially never rasterises.
    // It was kept on principle, and the audit's claim that this halo was the mechanism
    // behind GG #2 does not survive that measurement.
    //
    // **It is load-bearing now.** `coverage_mask` CEILS to whole samples, so a fragment at
    // any coverage above zero claims at least one of the four — a quarter of the pixel's
    // depth for ink nobody can see. This floor is what stops the ramp's outermost tail
    // from doing that. `tests/gpu_lane_paint_order.rs`'s taken-vs-painted oracle is the
    // one that would catch it going wrong, and it is no longer measuring a dead mechanism.
    if (a < MIN_COVERAGE_ALPHA) {
        discard;
    }
    // **Coverage to the RASTERISER, material alpha to the BLEND.**
    //
    // What used to be returned was `vec4(rgb, col.a · cov)`: one alpha carrying both,
    // blended over the whole pixel, and — since MP-a — stamping the whole pixel's depth.
    // A way drawn afterwards at a lower rank was then depth-REJECTED at that pixel, and a
    // rejected fragment is not blended away, it never runs; what survived was this way
    // over bare paper. MEASURED: across a motorway's entire 7 px footprint the frame
    // with a residential underneath was bit-identical to the frame without it.
    //
    // With the coverage in the sample mask, this fragment owns exactly the samples it
    // covers. The rest keep their clear depth, the road beneath fills them, and the 4×
    // resolve averages the two — which is the composite the depth test was refusing to
    // do. `col.a` alone goes to the blend, so a genuinely translucent way still blends
    // rather than dithering.
    return FsOut(vec4<f32>(in.col.rgb, in.col.a * coverage_alpha(cov)), coverage_mask(cov));
}