Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4b26d3e31 | ||
|
|
5f5b87ca60 |
No files matched your search
@@ -671,22 +671,44 @@ Two lines of the self-check output are assertions in disguise:
|
|||||||
blinking green. The `mode ...` lines carry the rest of the status line, so `rate` and
|
blinking green. The `mode ...` lines carry the rest of the status line, so `rate` and
|
||||||
`last event ... ago` are checked there.
|
`last event ... ago` are checked there.
|
||||||
- `frame cost: tick A/B ms over N, draw C/D ms (max at frame F), paint E/G ms over M` and
|
- `frame cost: tick A/B ms over N, draw C/D ms (max at frame F), paint E/G ms over M` and
|
||||||
`frame path: raw=R lod=L frames, segments S/T (mean/max), visible max V samples` — the
|
`frame path: raw=R lod=L columns=C graded=G frames, segments S/T (mean/max), visible max V samples`
|
||||||
|
— the
|
||||||
drawing cost, split into the frame tick, `PlotArea`'s own draw (timed from the frame
|
drawing cost, split into the frame tick, `PlotArea`'s own draw (timed from the frame
|
||||||
clock's `before-paint` to the end of the host's `render` handler) and the whole GTK
|
clock's `before-paint` to the end of the host's `render` handler) and the whole GTK
|
||||||
paint. **`segments` max must stay in the tens of thousands and `lod` must dominate `raw`
|
paint. **`segments` max must stay in the low thousands and `lod` must dominate `raw`
|
||||||
on any run holding a large capture**: a max in the *millions* with `lod=0` is the
|
on any run holding a large capture**: a max in the *millions* with `lod=0` is the
|
||||||
empty-pyramid defect (see the `MinMaxPyramid` invariant below) — the renderer drawing
|
empty-pyramid defect (see the `MinMaxPyramid` invariant below) — the renderer drawing
|
||||||
every raw sample of a held event on every frame, which measured 6,000,073 segments and
|
every raw sample of a held event on every frame, which measured 6,000,073 segments and
|
||||||
100–230 ms a frame at 1 MS/s. `raw` frames are expected and cheap below 64 samples per
|
100–230 ms a frame at 1 MS/s. `raw` frames are expected and cheap below 64 samples per
|
||||||
pixel, which is where `level_for()`'s own gate puts the boundary. **`draw`'s max must sit
|
pixel, which is where `level_for()`'s own gate puts the boundary.
|
||||||
|
**`columns` must equal the frames that drew a trace at all on any run at a high rate**, and
|
||||||
|
it is the reading that says *why* `segments` is small: a dense gathered window is reduced
|
||||||
|
onto the pixel grid upstream (one snapped vertical segment per column — see the moiré
|
||||||
|
invariant below), so the geometry is bounded by `axes.w`, and a `columns=0` beside a large
|
||||||
|
`segments` is that reduction gone rather than a narrower window. Measured on
|
||||||
|
`--rate 1300000 --batch 2000 --freq 3000` over 20 s: `raw=2 lod=1198 columns=1200 frames,
|
||||||
|
segments 2041/2237` over 1201 painted frames, against `columns=0 ... segments
|
||||||
|
10960/216093` over 263 before it existed — the same run at 4.6× the frame rate.
|
||||||
|
**`graded` must equal `columns`**: this app turns `Style::intensity_grading` on, and grading is
|
||||||
|
a way of *drawing* the reduction rather than a third path, so a `graded` below `columns` is the
|
||||||
|
style not reaching a frame. **`UDPSCOPE_NO_PHOSPHOR=1` is the A/B** and the only way to read
|
||||||
|
either of these two lines against the ungraded path, since a frame mean cannot attribute its own
|
||||||
|
cost: measured on `--rate 1300000 --batch 2000`, `columns=1166 graded=1166` with
|
||||||
|
`draw 3.24/21.43 ms` and `segments 1340/4157` against `graded=0`, `draw 2.30/25.76 ms` and
|
||||||
|
`segments 131/4306` over the same `lod=453` frames. The segment rise *is* the gradient (alpha is
|
||||||
|
quantised into steps, one `LineBatch` and one draw call each, because the line pipeline's colour
|
||||||
|
is a uniform) and the ~1 ms is its cost; a `raw` that *grows* when the grading is on is the
|
||||||
|
level-floor invariant below gone, which measured `raw=1154 lod=0` and 6.36 ms.
|
||||||
|
**`draw`'s max must sit
|
||||||
at a frame near 0** — that is the warm-up (glyph atlas, first vertex-buffer growth); a
|
at a frame near 0** — that is the warm-up (glyph atlas, first vertex-buffer growth); a
|
||||||
late `F` is a frame whose own geometry was expensive and worth tracing. `tick`'s max is
|
late `F` is a frame whose own geometry was expensive and worth tracing. `tick`'s max is
|
||||||
the publish stall: `publish_event()` builds the snapshot's pyramids under `mutex()`, so a
|
the publish stall: `publish_event()` builds the snapshot's pyramids under `mutex()`, so a
|
||||||
latch at over 1 MS/s costs one ~40 ms tick, which must not produce `gaps`. Both these
|
latch at over 1 MS/s costs one ~40 ms tick, which must not produce `gaps`. Both these
|
||||||
lines and the disarm probe's `axis=`/`snap=` need a fast source to say anything —
|
lines and the disarm probe's `axis=`/`snap=` need a fast source to say anything —
|
||||||
`tools/mock_udpstreamer.py --rate 1300000 --batch 20000` — since at the default 10 kS/s a
|
`tools/mock_udpstreamer.py --rate 1300000 --batch 2000` — since at the default 10 kS/s a
|
||||||
whole window fits in the raw path and the publish is too short to lose a race.
|
whole window fits in the raw path and the publish is too short to lose a race. (Do not
|
||||||
|
raise `--batch` to chase the rate: a batch of 20000 exceeds the datagram limit and the mock
|
||||||
|
dies with `OSError: [Errno 90] Message too long`.)
|
||||||
- `trace ink: N paints checked, C collapsed, S staircase, H short, worst cover P%, worst
|
- `trace ink: N paints checked, C collapsed, S staircase, H short, worst cover P%, worst
|
||||||
drawn-vs-quoted D px over R raw paints` plus a
|
drawn-vs-quoted D px over R raw paints` plus a
|
||||||
`[ink] paint N <flags> mode=.. axis=[..] n=.. idx=[..) spp=.. level=.. pts=.. kept=..
|
`[ink] paint N <flags> mode=.. axis=[..] n=.. idx=[..) spp=.. level=.. pts=.. kept=..
|
||||||
@@ -1111,6 +1133,67 @@ far the largest file.
|
|||||||
draw a bucket's extremes. It needs no index rebasing, unlike the ring: the snapshot's
|
draw a bucket's extremes. It needs no index rebasing, unlike the ring: the snapshot's
|
||||||
pyramid is built from sample 0 and nothing is ever dropped from it, so `window_base()` is
|
pyramid is built from sample 0 and nothing is ever dropped from it, so `window_base()` is
|
||||||
0 and a window index *is* the absolute one.
|
0 and a window index *is* the absolute one.
|
||||||
|
- **A trace denser than the axis is drawn one pixel column at a time, and that is what keeps
|
||||||
|
the plots free of moiré.** The envelope staged as a polyline banded visibly and *crawled*
|
||||||
|
under a pan on exactly the signals this app is pointed at — a high rate, a high frequency or
|
||||||
|
noise — and three things compound to produce it, none a bug alone: `level_for()` sizes a
|
||||||
|
bucket at one to two pixel columns, `Envelope` emits two points per bucket so each
|
||||||
|
contributes a near-vertical min→max hairline *and* a near-vertical connector (≈3.6 per
|
||||||
|
column per trace), and every one lands at a **fractional** x because a trace is deliberately
|
||||||
|
not snapped. Under src-alpha compositing a column's brightness is then a non-linear function
|
||||||
|
of the sub-pixel phases overlapping it, the pattern repeats at the beat between the bucket
|
||||||
|
pitch and the pixel pitch, and a pan sweeps the beat. `deps/plotter`'s
|
||||||
|
`Renderer::stage_trace_columns()` emits one snapped vertical segment per integer column
|
||||||
|
instead, so the trace has **one** phase and there is nothing left to beat. Four things to
|
||||||
|
know before touching it, all upstream in `docs/data-and-performance.md`: the gate is the
|
||||||
|
gathered **density** (≥2 points per column) and `Envelope`, never the LOD level — the raw
|
||||||
|
path at 1.5–64 spp beats the same way, and the density term is also what keeps the reduction
|
||||||
|
off a *sparse* window whose trace is the two segments entering and leaving the frame; a hole
|
||||||
|
stays a hole; disjoint neighbours are joined so a fast edge keeps its join; and it is the one
|
||||||
|
carve-out in `u_snap`'s "never anything drawn at a data position" rule, because a column *is*
|
||||||
|
a pixel column.
|
||||||
|
**It needs a thin ribbon to be visible at all** — a window whose buckets span several periods
|
||||||
|
paints a saturated block and hides the beat — so a screenshot of a slow sine at a whole-window
|
||||||
|
view says nothing either way. The guards are upstream's
|
||||||
|
`a_dense_trace_is_drawn_as_whole_pixel_columns`, which counts the **distinct coverage levels**
|
||||||
|
in the ink (4 against the polyline's 126; a count of *partially covered* pixels separates
|
||||||
|
nothing, 577 against 652, because a 1.5 px stroke's fringe always spills into the next
|
||||||
|
column), and `frame path:`'s `columns=` field here. `trace ink:` deliberately cannot see this
|
||||||
|
path: it recomputes the **gathered** points, which the reduction is downstream of, so its
|
||||||
|
`drawn-vs-quoted` reads 0.0000 either way and remains the guard for the gather origin alone.
|
||||||
|
- **A reduced column is graded by dwell, and the grading may not undo the reduction.** The
|
||||||
|
column above is honest about *where* the signal went and silent about *how long it was there*
|
||||||
|
— a column's 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 flat band. `Style::intensity_grading` grades it instead
|
||||||
|
(bright where the signal sits, faint where it only passes through, the digital-phosphor look),
|
||||||
|
and **udpscope turns it on; the library's default is off**, so other hosts are not restyled by
|
||||||
|
an upgrade. The switch is a one-shot in `tick()` guarded by `App::style_stated`, not a line in
|
||||||
|
the window build: `PlotArea::renderer()` is null until the area is realized, so there is no
|
||||||
|
earlier place to state a style. Three things to know here, the rest upstream in
|
||||||
|
`docs/data-and-performance.md` (the `1/height` dwell weighting, the one-column accumulator, the
|
||||||
|
per-column-peak normalisation, the quantised alpha steps):
|
||||||
|
* **The finer gather level is floored at 1 whenever the flat path would have used the
|
||||||
|
pyramid.** Grading asks for `samples_per_pixel / intensity_sub_columns`, and
|
||||||
|
`MinMaxPyramid::level_for()` answers **0 — raw samples** — as soon as that falls under one
|
||||||
|
bucket (`kBucket` is 64). Unfloored, every moderately dense frame became an O(visible)
|
||||||
|
gather: at 1.3 MS/s over a 2 s window, 172 samples a pixel, `raw=1154 lod=0` against the flat
|
||||||
|
path's `raw=710 lod=453`, and 2.30 → 6.36 ms of draw mean. The floor degrades the *look*
|
||||||
|
(fewer sub-columns than asked for, down to what the coarsest buckets give — still two or
|
||||||
|
three per column at 64 samples a bucket) and never the path. It is also why
|
||||||
|
`intensity_sub_columns` past about 8 buys nothing: the bucket size is the limit.
|
||||||
|
* **`graded=` must equal `columns=`** in `frame path:`, and `UDPSCOPE_NO_PHOSPHOR=1` is the A/B
|
||||||
|
that makes either line readable against the ungraded path (see Verification).
|
||||||
|
* **The steps are draw calls, not per-segment alpha.** `LineInstance` is four floats of
|
||||||
|
geometry and the colour is a **uniform** (only `TextInstance` carries `a_colour`), so the
|
||||||
|
gradient is `intensity_steps` `LineBatch`es flushed at different alphas. That is why the
|
||||||
|
segment mean rises from 131 to 1340 on the same frames — the rise is the tiers, not extra
|
||||||
|
geometry per column, and the bound is still `axes.w` (measured 14.5 runs a column in the
|
||||||
|
library's own guard, 8303 segments over a 572 px axis).
|
||||||
|
The guard is upstream's `a_dense_trace_can_be_graded_by_dwell`, which draws one frame both ways
|
||||||
|
and profiles the band's outer fifths against its middle: flat reads **191/191**, graded
|
||||||
|
**191/131**. That 0.69 is a *tier* ratio, not the dwell ratio — `intensity_gamma` (0.45) and
|
||||||
|
`intensity_floor` (0.3) compress it deliberately, the floor so that a fast riser, one
|
||||||
|
sub-bucket deep everywhere, is never dimmed out of existence.
|
||||||
- **The time ring is `f64` and the value rings are `f32`, and the asymmetry is the point.**
|
- **The time ring is `f64` and the value rings are `f32`, and the asymmetry is the point.**
|
||||||
A value's precision is a property of the signal (24 bits is plenty for a sample); a
|
A value's precision is a property of the signal (24 bits is plenty for a sample); a
|
||||||
timestamp's is a property of *how long the scope has been running*, because the stamps are
|
timestamp's is a property of *how long the scope has been running*, because the stamps are
|
||||||
|
|||||||
@@ -939,6 +939,71 @@ into the tick, the plot's own draw and the whole GTK paint, and report the segme
|
|||||||
and whether the LOD path was taken at all. A segment count in the millions is this defect
|
and whether the LOD path was taken at all. A segment count in the millions is this defect
|
||||||
returning.
|
returning.
|
||||||
|
|
||||||
|
**A dense trace is drawn one pixel column at a time, which is what cured the moiré.** At a
|
||||||
|
high sample rate, a high signal frequency or on a noisy signal the plots showed strong,
|
||||||
|
*crawling* banding — and three things compounded to produce it, none of which is a bug on its
|
||||||
|
own. `MinMaxPyramid::level_for()` sizes a bucket at one to two pixel columns; `Envelope`
|
||||||
|
emits two points per bucket, so each bucket contributes a near-vertical min→max hairline
|
||||||
|
*and* a near-vertical connector to the next, about 3.6 near-vertical hairlines per column per
|
||||||
|
trace; and every one of them lands at a *fractional* x, because a trace is deliberately not
|
||||||
|
snapped. With src-alpha compositing a column's brightness is then a non-linear function of
|
||||||
|
the sub-pixel phases overlapping it, the phase pattern repeats at the beat between the bucket
|
||||||
|
pitch and the pixel pitch, and a pan sweeps the beat. It needs a *thin ribbon* to be visible:
|
||||||
|
a window whose buckets each span several periods paints a saturated block and hides it
|
||||||
|
entirely, which is why it showed up on fast and noisy signals and not on a slow sine at a
|
||||||
|
whole-window view.
|
||||||
|
|
||||||
|
`deps/plotter`'s `Renderer::draw_traces` now reduces such a window onto the pixel grid: one
|
||||||
|
exactly vertical segment per integer column, from the lowest to the highest screen y any
|
||||||
|
gathered point put in it, flushed in framebuffer pixels with the snap on. The whole trace
|
||||||
|
then has **one** sub-pixel phase, so there is nothing left to beat. See the upstream
|
||||||
|
`docs/data-and-performance.md` for the four rules it keeps (a hole stays a hole, disjoint
|
||||||
|
neighbours are joined so a fast edge keeps its join, a span under the stroke is drawn *as*
|
||||||
|
the stroke, and the gate is the gathered density rather than the LOD level) and for why this
|
||||||
|
is the one carve-out in `u_snap`'s rule that chrome may be snapped and data may not.
|
||||||
|
|
||||||
|
It is also a large speed-up, because the geometry becomes O(axes.w) instead of O(buckets).
|
||||||
|
Measured on the fast mock (`--rate 1300000 --batch 2000 --freq 3000`, a 20 s run): `frame
|
||||||
|
path: raw=1 lod=262 columns=0 frames, segments 10960/216093` and **263 painted frames**
|
||||||
|
before, `raw=2 lod=1198 columns=1200 frames, segments 2041/2237` and **1201 painted frames**
|
||||||
|
after — the same run at 4.6× the frame rate, with `trace ink:` reading `0 collapsed, 0
|
||||||
|
staircase, 0 short, worst drawn-vs-quoted 0.0000 px` either way. `frame path:`'s
|
||||||
|
`columns=` field is the reading that separates "the segment count collapsed because the
|
||||||
|
reduction ran" from "the window got narrower".
|
||||||
|
|
||||||
|
**Those columns are then graded by dwell, which is the rest of the answer.** A reduced column
|
||||||
|
is honest about *where* the signal went and silent about *how long it was there*: its min and
|
||||||
|
max are the same whether its samples fill the span evenly or pile at its two ends, so a ramp
|
||||||
|
and a pulse are one flat band. `Style::intensity_grading` — off in the library, which udpscope
|
||||||
|
turns on at the first tick, since the renderer does not exist until the area is realized —
|
||||||
|
draws each column graded instead: bright where the signal sits, faint where it only passes
|
||||||
|
through, the way a digital-phosphor scope reads. The distribution cannot be recovered from the
|
||||||
|
band, so the gather is asked at a level finer than the pixel grid and the dwell read from those
|
||||||
|
sub-buckets; the measure is dwell *per row*, each segment depositing one unit spread over the
|
||||||
|
rows it spans, and normalisation is against the column's own peak. See the upstream
|
||||||
|
`docs/data-and-performance.md` for the five things that carry it and for the two that were
|
||||||
|
wrong first (counting rows at +1 each inverts the pattern, grading a sine's fast middle as
|
||||||
|
brightly as its rails; a frame-wide scale needs a 33 MB density image *and* fades the trace out
|
||||||
|
exactly where it moves fastest).
|
||||||
|
|
||||||
|
It costs about a millisecond a frame and the A/B is the only way to read that, because a frame
|
||||||
|
mean cannot attribute its own cost: **`UDPSCOPE_NO_PHOSPHOR=1` puts the style back to the
|
||||||
|
library's default**, and the same probe run on the fast mock (`--rate 1300000 --batch 2000`)
|
||||||
|
reads `draw 3.24/21.43 ms` with the grading against `draw 2.30/25.76 ms` without, over the same
|
||||||
|
`lod=453` frames. **`frame path:`'s `graded=` must equal `columns=`** — grading is a way of
|
||||||
|
drawing the reduction and not a third path, so the two counts agreeing is what says the look
|
||||||
|
reaches every reduced frame (`columns=1166 graded=1166` in that run, `graded=0` under the env
|
||||||
|
var). The segment count rises with it, from a mean of 131 to 1340, which is the gradient's
|
||||||
|
tiers: alpha is quantised into steps because the line pipeline's colour is a uniform and a
|
||||||
|
per-segment alpha is inexpressible, and each step is its own draw call.
|
||||||
|
|
||||||
|
The one performance trap here is worth stating because only the A/B found it. Asking for a
|
||||||
|
finer level drops straight to **raw samples** once a sub-column falls under one pyramid bucket
|
||||||
|
(64 samples), which at the run's 172 samples a pixel it did: `raw=1154 lod=0` and 6.4 ms a
|
||||||
|
frame, i.e. grading undoing the very reduction it draws. The finer ask is floored at level 1
|
||||||
|
whenever the flat path would have used the pyramid, so what degrades is the *look* — fewer
|
||||||
|
sub-columns than asked for — and never the path.
|
||||||
|
|
||||||
**The panels and the toolbar.** The header bar carries only what you reach for
|
**The panels and the toolbar.** The header bar carries only what you reach for
|
||||||
*while watching a signal*: the time window, pause/resume, the trigger toggle, the
|
*while watching a signal*: the time window, pause/resume, the trigger toggle, the
|
||||||
side-panel toggle and an overflow menu. Those
|
side-panel toggle and an overflow menu. Those
|
||||||
|
|||||||
Vendored
+1
-1
Submodule deps/plotter updated: bee318870f...cc908efa36.
@@ -35,6 +35,19 @@ The full table is in the shortcut overview (<tt>Ctrl+/</tt>).
|
|||||||
• Zooming hard into a held capture is exact. The renderer finds the visible samples by binary
|
• Zooming hard into a held capture is exact. The renderer finds the visible samples by binary
|
||||||
search over the real timestamps, never over a nominal sample grid, so a capture whose clock
|
search over the real timestamps, never over a nominal sample grid, so a capture whose clock
|
||||||
wandered does not drift away from its axis as you zoom.
|
wandered does not drift away from its axis as you zoom.
|
||||||
|
• A trace holding far more samples than the plot has pixels is drawn <i>one pixel column at a
|
||||||
|
time</i>: each column is a single vertical line from the lowest to the highest value that falls
|
||||||
|
in it. Drawn as a polyline instead, such a window puts three or four near-vertical lines in
|
||||||
|
every column at slightly different sub-pixel positions, and how they overlap beats against the
|
||||||
|
pixel grid — which reads as bands of light and dark that <i>crawl</i> as you pan. One line per
|
||||||
|
column removes the beat, and it is also much faster: a 1 MS/s view costs a couple of thousand
|
||||||
|
line segments a frame instead of a couple of hundred thousand.
|
||||||
|
• Those columns are <i>graded by brightness</i>, the way a digital-phosphor scope reads: bright
|
||||||
|
where the signal spent its time, faint where it only passed through. A column's highest and
|
||||||
|
lowest value are the same whether the samples in it are spread evenly or piled at its two ends,
|
||||||
|
so the grading is what tells the two apart — the flat parts of a square wave come out solid and
|
||||||
|
the edges between them faint. It is read from a finer division of each column rather than from
|
||||||
|
the line that is drawn, and it costs about a millisecond a frame.
|
||||||
|
|
||||||
<b>Example</b>
|
<b>Example</b>
|
||||||
|
|
||||||
|
|||||||
+36
-3
@@ -311,6 +311,9 @@ struct App {
|
|||||||
unsigned signal_generation = ~0u;
|
unsigned signal_generation = ~0u;
|
||||||
bool updating_panels = false; ///< guards signal handlers during a rebuild
|
bool updating_panels = false; ///< guards signal handlers during a rebuild
|
||||||
bool relayout_pending = false;
|
bool relayout_pending = false;
|
||||||
|
/// True once the renderer's `Style` has been stated (see `tick()`): the renderer does not
|
||||||
|
/// exist until the area is realized, so the one-shot has to be a tick's job.
|
||||||
|
bool style_stated = false;
|
||||||
bool signals_panel_initialised = false;
|
bool signals_panel_initialised = false;
|
||||||
/// Set once the user edits the trigger level, so the panel stops defaulting it
|
/// Set once the user edits the trigger level, so the panel stops defaulting it
|
||||||
/// into the middle of the declared range.
|
/// into the middle of the declared range.
|
||||||
@@ -411,6 +414,17 @@ struct App {
|
|||||||
std::uint64_t dbg_visible_max = 0;
|
std::uint64_t dbg_visible_max = 0;
|
||||||
int dbg_raw_frames = 0;
|
int dbg_raw_frames = 0;
|
||||||
int dbg_lod_frames = 0;
|
int dbg_lod_frames = 0;
|
||||||
|
/// Frames on which at least one trace's geometry was reduced onto the pixel grid (one
|
||||||
|
/// vertical segment per column). It is orthogonal to `raw`/`lod` on purpose -- the
|
||||||
|
/// reduction is gated on the *density* of the gathered points, not on which level
|
||||||
|
/// produced them -- and it is the only reading that distinguishes "the segment count
|
||||||
|
/// collapsed because the reduction ran" from "the window got narrower".
|
||||||
|
int dbg_column_frames = 0;
|
||||||
|
/// Frames on which at least one reduced column was drawn **graded by dwell** rather than
|
||||||
|
/// as one flat band (`Style::intensity_grading`, which this app turns on). A subset of
|
||||||
|
/// `columns`: grading is a way of drawing the reduction, not a third path, so the two
|
||||||
|
/// counts being equal is what says the look is reaching every reduced frame.
|
||||||
|
int dbg_graded_frames = 0;
|
||||||
/// Painted frames on which `draw_traces` drew **no trace at all**, and the last one's index.
|
/// Painted frames on which `draw_traces` drew **no trace at all**, and the last one's index.
|
||||||
/// This is the observable for "the plot flickers as if there were no data": `staged_segments`
|
/// This is the observable for "the plot flickers as if there were no data": `staged_segments`
|
||||||
/// cannot see it, because the grid and the instruments stage geometry of their own, so a frame
|
/// cannot see it, because the grid and the instruments stage geometry of their own, so a frame
|
||||||
@@ -1247,6 +1261,8 @@ int on_render_probe(GtkGLArea*, GdkGLContext*, gpointer user) {
|
|||||||
app->dbg_seg_last = s.staged_segments;
|
app->dbg_seg_last = s.staged_segments;
|
||||||
if (s.raw_traces > 0) ++app->dbg_raw_frames;
|
if (s.raw_traces > 0) ++app->dbg_raw_frames;
|
||||||
if (s.lod_traces > 0) ++app->dbg_lod_frames;
|
if (s.lod_traces > 0) ++app->dbg_lod_frames;
|
||||||
|
if (s.column_traces > 0) ++app->dbg_column_frames;
|
||||||
|
if (s.graded_traces > 0) ++app->dbg_graded_frames;
|
||||||
if (s.raw_traces > 0 || s.lod_traces > 0) check_frame_ink(*app);
|
if (s.raw_traces > 0 || s.lod_traces > 0) check_frame_ink(*app);
|
||||||
if (s.raw_traces == 0 && s.lod_traces == 0) {
|
if (s.raw_traces == 0 && s.lod_traces == 0) {
|
||||||
++app->dbg_notrace_frames;
|
++app->dbg_notrace_frames;
|
||||||
@@ -4865,6 +4881,22 @@ gboolean tick(gpointer user) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The trace look, stated on the first tick that finds a renderer -- there is none until
|
||||||
|
// the area is realized, and this is the same "claim it when it exists" shape as the frame
|
||||||
|
// clock above. `intensity_grading` is off in the library by default (it is a change of
|
||||||
|
// look, not a correction, and other hosts must not be restyled by an upgrade); an
|
||||||
|
// oscilloscope is exactly the host it is for, so udpscope turns it on. A one-shot rather
|
||||||
|
// than a per-frame write because `Style` is plain data and nothing else touches it.
|
||||||
|
if (!app->style_stated && app->area != nullptr) {
|
||||||
|
if (plot::Renderer* r = app->area->renderer()) {
|
||||||
|
// `UDPSCOPE_NO_PHOSPHOR` puts it back to the library's default, which is the only way
|
||||||
|
// to read `frame cost:` and `frame path:` against the ungraded path -- a frame mean
|
||||||
|
// cannot attribute its own cost, so the A/B is the measurement.
|
||||||
|
r->style().intensity_grading = g_getenv("UDPSCOPE_NO_PHOSPHOR") == nullptr;
|
||||||
|
app->style_stated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (app->relayout_pending) {
|
if (app->relayout_pending) {
|
||||||
app->relayout_pending = false;
|
app->relayout_pending = false;
|
||||||
relayout_areas(*app);
|
relayout_areas(*app);
|
||||||
@@ -8212,9 +8244,10 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit
|
|||||||
app.dbg_draw_ms_max, app.dbg_draw_max_frame,
|
app.dbg_draw_ms_max, app.dbg_draw_max_frame,
|
||||||
app.dbg_paint_n > 0 ? app.dbg_paint_ms_sum / app.dbg_paint_n : 0.0,
|
app.dbg_paint_n > 0 ? app.dbg_paint_ms_sum / app.dbg_paint_n : 0.0,
|
||||||
app.dbg_paint_ms_max, app.dbg_paint_n);
|
app.dbg_paint_ms_max, app.dbg_paint_n);
|
||||||
std::printf("[udpscope] frame path: raw=%d lod=%d frames, segments %llu/%u "
|
std::printf("[udpscope] frame path: raw=%d lod=%d columns=%d graded=%d frames, segments "
|
||||||
"(mean/max), visible max %llu samples\n",
|
"%llu/%u (mean/max), visible max %llu samples\n",
|
||||||
app.dbg_raw_frames, app.dbg_lod_frames,
|
app.dbg_raw_frames, app.dbg_lod_frames, app.dbg_column_frames,
|
||||||
|
app.dbg_graded_frames,
|
||||||
static_cast<unsigned long long>(app.dbg_paint_n > 0
|
static_cast<unsigned long long>(app.dbg_paint_n > 0
|
||||||
? app.dbg_seg_sum / app.dbg_paint_n
|
? app.dbg_seg_sum / app.dbg_paint_n
|
||||||
: 0),
|
: 0),
|
||||||
|
|||||||
Reference in new issue
Block a user