Skip to content

Choppy frequency scrolling on wide displays: full ~0.5 GB waterfall-history reprojected on every pan step #3575

@svabi79

Description

@svabi79

Summary

On wide displays, horizontal frequency scrolling (mouse wheel) of the panadapter is choppy because the entire waterfall history image is reprojected on the CPU on every pan step — even though that history is only ever displayed during time-scrollback, never in the live view.

At ultrawide widths the history image is enormous: capacity is kWaterfallHistoryMs (20 min) ÷ 50 ms/row = 24 000 rows, so at ~4860 px wide it is ~0.5 GB (4860 × 24000 × 4). reprojectWaterfall() runs a QPainter::drawImage over both the visible waterfall and this full history image on every center-frequency change (SpectrumWidget.cpp reprojectWaterfall).

Evidence (instrumented, RTX 4090 / i9-13900K, 4860×… panadapter)

Timing the two reprojections separately during a 10 s scroll:

WfReprojectSplit visMs=3.21 visPx=4860x728 histMs=107.52 histPx=4860x24000
WfReprojectSplit visMs=2.99 visPx=4860x728 histMs=101.96 histPx=4860x24000
...
histMs: n=91 min=73 max=118 avg=108     <- full history reproject, per pan step
visMs:  n=91 max=4.0 avg=3.3            <- visible waterfall reproject

The history reprojection (avg 108 ms/step) is ~33× the visible one and blows the 16 ms frame budget ~7×. Built-in PerfSummary telemetry during continuous scrolling confirmed the user-visible effect:

metric (continuous-scroll windows) value
uiLagMaxMs 110–164 ms
panAgeP95Ms / wfAgeP95Ms 120–155 ms
renderP95Ms (GPU) 6–8 ms ✅ (GPU is healthy)

The GPU render path is not the bottleneck; the synchronous CPU history reproject on the main thread is.

Impact

Frequency scrolling stutters badly on wide/ultrawide panadapters; the wider the window, the worse (cost scales with pixel width). The live view does not even use the history image, so the work is entirely wasted during normal tuning.

Root cause

reprojectWaterfall() keeps the full history continuously aligned to the current frequency frame so newly-appended rows stay consistent. That correctness goal is real, but paying ~0.5 GB of drawImage per pan step to maintain it — for data only shown on time-scrollback — is the wrong trade.

Proposed fix (PR to follow)

Reproject the visible waterfall immediately (cheap, ~3 ms) but defer + coalesce the history reprojection: remember the net transform and apply it once after scrolling settles (debounced), pausing history appends while pending and flushing on demand before a viewport rebuild (time-scrollback). The live view is visually unchanged.

After-fix telemetry (continuous scroll, up to 49 tune-cmds/s): uiLagMaxMs 27–38 ms, panAgeP95Ms/wfAgeP95Ms 24–30 ms — a 4–5× improvement. A small residual (one ~108 ms reproject per scroll gesture, on stop) remains and will be tracked separately.

Related

Distinct root cause from #3283 (which covers QPainter widget rasterization and GPU texture re-upload); this is specifically the history-image reprojection. Cross-referencing for the broader perf picture.

Environment

Windows 11, Qt 6.8.3 (msvc2022_64), RTX 4090 / i9-13900K, ultrawide (5144×1440). Platform-independent code path (reprojectWaterfall is plain Qt) — affects all platforms with wide panadapters.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GUIUser interfacebugSomething isn't workingmaintainer-reviewRequires maintainer review before any action is takenpriority: mediumMedium priorityspectrumPanadapter and waterfall

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions