feat: grade a sparse window's polyline by slope, so phosphor does not switch off on zoom

Intensity grading was gated on the column reduction, which is gated on a
density whose only job is killing the moire beat. Dwell has nothing to do
with that, so narrowing a window past the threshold turned the whole
phosphor model off and a discontinuity went from a third of a flat top's
ink to all of it in one pixel of zoom.

stage_trace_slopes() grades each segment by its own slope instead, with a
measure that agrees with the dense path at the boundary, and reports
itself as FrameStats::slope_traces -- disjoint from column_traces, so a
host asserting graded_traces == column_traces reads the same as before.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Opus 4.6 committed 2026-10-08 16:56:10 +02:00
1 parent cc908efa36
commit 37e414bcc5
8 files changed
+442 -13

No files matched your search

+6 -3
View File
@@ -48,7 +48,10 @@ run touched a GPU, so read it as an upper bound and a record of the software pat
signal sits, faint where it only passes through, the way a digital-phosphor scope reads. It is
what puts back the information the reduction throws away — a column's min and max are the same
whether its samples fill the span or pile at its two ends — so the gather is asked at a level
finer than the pixel grid and the distribution read from those sub-buckets;
finer than the pixel grid and the distribution read from those sub-buckets. Below the density at
which columns are reduced the same switch grades the **polyline** by each segment's slope
(`FrameStats::slope_traces`), so the look does not change as a window narrows past the
threshold;
- sample **markers** when a window is sparse enough that its samples are the shape
(`Style::marker_below_samples`, 50 by default, `marker_px` across, in the trace's own colour);
- grid with independent major/minor line classes (`Style::grid_major_visible`,
@@ -184,12 +187,12 @@ documentation.
```sh
cmake --preset linux-debug
cmake --build build/debug
ctest --test-dir build/debug --output-on-failure # 350 cases, 0 failed
ctest --test-dir build/debug --output-on-failure # 377 cases, 0 failed
tools/coverage.sh # configure+build+run+capture+floor check
```
The `linux-debug` suite runs **350 cases**; the `linux-coverage` preset builds **333** of
The `linux-debug` suite runs **377 cases**; the `linux-coverage` preset builds **360** of
them, because its adapters are off and 17 cases need an adapter target (11 in
`test_imgui_widget.cpp`, 6 in `test_glfw_host.cpp`). Coverage is enforced by
`tools/coverage.sh` against `tools/coverage_floor.py`: **80%** per file under `src/` and