feat(render): a reduced column can be graded by dwell, not drawn as one flat band
A pixel column reduced from a dense envelope is honest about where the signal went and silent about how long it was there: its min and max are identical whether its samples fill the span or pile at its two ends, so a ramp and a pulse are one band. Style::intensity_grading grades it instead -- bright where the signal sits, faint where it only passes through -- by asking the gather for a level finer than the pixel grid and reading the distribution from those sub-buckets. Off by default: a change of look, not a correction of one. The measure is dwell per row, each segment depositing one unit spread over the rows it spans; counting +1 per row instead grades a sine's fast middle as brightly as its rails, which is the pattern inverted. The accumulator is one column wide (a full w*h density image is 33 MB at 4K) with each span written as two delta writes, and normalisation is against the column's own peak -- a frame-wide scale fades the trace out exactly where it moves fastest. Alpha is quantised into tiers, one LineBatch and one draw call each, because the line pipeline's colour is a uniform and a per-segment alpha is inexpressible. The finer ask is floored at level 1 whenever the flat path would have used the pyramid: level_for() answers 0 -- raw samples -- as soon as a sub-column falls under one bucket, so an unfloored ask turns a moderately dense frame into an O(visible) gather (measured at 172 samples a pixel: raw=1154 lod=0 and 6.4 ms a frame against raw=710 lod=453 and 2.3 ms). Grading is a way of drawing a reduction and may not undo it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
e81e84645f
commit
cc908efa36
6 files changed
+629
-13
No files matched your search
@@ -34,6 +34,10 @@ struct FrameStats {
|
||||
/// path above -- the reduction is about the *density* of the gathered points,
|
||||
/// not about which level produced them.
|
||||
u32 column_traces = 0;
|
||||
/// Traces whose columns were graded by dwell rather than drawn as one flat band
|
||||
/// (`Style::intensity_grading`). A subset of `column_traces`: grading is a way of
|
||||
/// drawing the reduction, not a third path.
|
||||
u32 graded_traces = 0;
|
||||
u64 visible_samples = 0; ///< samples the gathered windows covered, summed
|
||||
u32 staged_segments = 0; ///< line segments staged, all colour groups
|
||||
u32 staged_markers = 0; ///< marker shapes staged over the traces
|
||||
@@ -409,6 +413,13 @@ class Renderer {
|
||||
/// axis-aligned line by up to half a pixel. Set on every flush, like `dash`.
|
||||
void flush_lines(const Mapping& map, Color color, f32 width, Vec2 dash = Vec2{},
|
||||
bool snap = false) noexcept;
|
||||
/// The same, for a batch other than the renderer's own `lines_`. The graded trace
|
||||
/// pass stages one batch per alpha step, and a step has to be a draw call of its
|
||||
/// own because the line pipeline takes its colour from a uniform -- so it needs to
|
||||
/// flush a batch it chose rather than the member one. Every other caller flushes
|
||||
/// `lines_` and uses the overload above.
|
||||
void flush_lines(render::LineBatch& batch, const Mapping& map, Color color, f32 width,
|
||||
Vec2 dash = Vec2{}, bool snap = false) noexcept;
|
||||
/// Draws every staged glyph in `batch` -- each instance carries its own tint
|
||||
/// (`a_colour`) -- and empties the batch. Text is texture-bound, so this runs
|
||||
/// once per text batch, after the line geometry it belongs over.
|
||||
@@ -515,6 +526,19 @@ class Renderer {
|
||||
/// series for. See `draw_traces` for when this path is taken and why.
|
||||
u32 stage_trace_columns(const Plot& plot, const PlotLayout& layout, const Trace& trace,
|
||||
f64 x_origin, u32 points);
|
||||
/// The same reduction, graded by **dwell**: a column is drawn as a stack of runs,
|
||||
/// each at the alpha step its own share of the column's samples earns, so a flat
|
||||
/// top is bright and the edge leading to it is faint (`Style::intensity_grading`).
|
||||
///
|
||||
/// Stages into `steps_`, one `LineBatch` per alpha step, which the caller flushes
|
||||
/// in turn -- the line pipeline's colour is a uniform, so a step is a draw call.
|
||||
/// Returns the segments staged across all steps (0 stages nothing).
|
||||
///
|
||||
/// `gather_` is the input and must have been asked for at the *finer* level
|
||||
/// `Style::intensity_sub_columns` implies; a column's dwell is not recoverable
|
||||
/// from its own min and max (see `Style::intensity_grading`).
|
||||
u32 stage_trace_density(const Plot& plot, const PlotLayout& layout, const Trace& trace,
|
||||
f64 x_origin, u32 points);
|
||||
/// The cursors, both orientations: one stroke per cursor, placed at the coordinate its own
|
||||
/// orientation owns (`Plot::cursor_screen_coordinate()`) and spanning the other axis' whole
|
||||
/// range, in its own colour -- or in the accent at handle width while it is hovered or
|
||||
@@ -631,6 +655,20 @@ class Renderer {
|
||||
/// axis is 64 kB -- bounded by the *screen*, where `gather_` is bounded by the
|
||||
/// window.
|
||||
std::vector<f32> columns_;
|
||||
/// `stage_trace_density()`'s working set, and deliberately **one column wide**: the
|
||||
/// gathered points arrive in x order, so a column can be accumulated, read and
|
||||
/// cleared before the next one starts. A full-axes density image would be
|
||||
/// `axes.w * axes.h` (33 MB at 4K); this is `axes.h` (a few kB) and stays in L1.
|
||||
///
|
||||
/// Each sub-bucket's span is written as a +1 at its first row and a -1 one past
|
||||
/// its last, so accumulating a span costs two writes whatever its height; the
|
||||
/// running sum over the column is then how many sub-buckets cover each row, which
|
||||
/// is the dwell.
|
||||
std::vector<f32> column_rows_;
|
||||
/// One batch per alpha step of the grading (`Style::intensity_steps`), re-used
|
||||
/// across frames: the line pipeline takes its colour from a uniform, so segments
|
||||
/// at different alphas cannot share a draw call and must be staged apart.
|
||||
std::vector<render::LineBatch> steps_;
|
||||
mutable std::vector<u8> readback_; ///< dump_frame_ppm's row buffer
|
||||
|
||||
/// The host's `GL_COLOR_CLEAR_VALUE`, queried on the first `begin_frame()` (GL
|
||||
|
||||
Reference in new issue
Block a user