You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Dragging the waterfall to pan (horizontal frequency scroll) is choppy again on high-resolution / wide displays, with the UI thread stalling ~60–80 ms per pan step. By inspection this traces to #3668 (clean-room KiwiSDR integration), merged 2026-06-20 — the same day. It re-introduces, by a different mechanism, the per-pan-step waterfall cost that #3578 had removed (which itself fixed the same class of choppiness, #3575, on wide displays).
Root cause
#3578 made per-pan reproject cheap: the waterfall history image is no longer globally reprojected — each history row records its own capture frame and only the visible viewport is remapped.
#3668 changed SpectrumWidget::handleWaterfallFrequencyFrameChange() from a single reprojectWaterfall() into an unconditional native + kiwi double reproject, each wrapped in a waterfall-stream-state save/restore:
reprojectStream(false); // nativereprojectStream(true); // kiwi — runs every pan step even with no KiwiSDR receiver
On every pan mouse-move, even when KiwiSDR is inactive, this costs two things:
A second, wasted reproject pass for a stream with no on-screen data.
saveCurrentWaterfallStreamState() does state.waterfall = m_waterfall — a QImage assignment, so the buffer is now shared (copy-on-write). The next m_waterfall.fill(Qt::black) inside rebuildWaterfallViewportForFrame() therefore detaches = deep-copies the entire waterfall image (large on wide/high-DPI displays) on every pan step. That deep-copy is exactly the per-step cost perf(spectrum): per-row waterfall-history frequency frames (no per-pan reproject) #3578 had eliminated.
i9-13900K / RTX 4090, FLEX-6600, wide high-resolution panadapter, D3D11/GPU path. Same binary; one env var (AETHER_WF_KIWI_ALWAYS) toggles only the second pass. During a continuous hand pan:
fftRestarts/wfRestarts = 0 and packet loss = 0 in both runs — the radio/stream is not involved. renderP95 ~7 ms in both — the GPU render is not the bottleneck. The cost is purely the second pass + the deep-copy.
What did you expect?
Pan to stay smooth (as after #3578), regardless of whether a KiwiSDR receiver is connected.
Steps to reproduce
Connect to a FLEX radio; open a panadapter with a waterfall on a wide / high-resolution display.
Grab the waterfall and pan (drag horizontally) continuously for a few seconds.
Panning is choppy/laggy. With aether.perf enabled (Help → Support → "Performance"), wfUpdateP95Ms spikes to ~60–80 ms and panAgeP95Ms to ~150–170 ms during the drag.
A/B from one binary: launch with AETHER_WF_KIWI_ALWAYS=1 → stall reproduces; without it (active-stream-only) → stall gone.
Fix PR incoming (reproject only the active stream; remap the other on stream-switch). Couldn't self-assign — this account has no triage permission here.
What happened?
Dragging the waterfall to pan (horizontal frequency scroll) is choppy again on high-resolution / wide displays, with the UI thread stalling ~60–80 ms per pan step. By inspection this traces to #3668 (clean-room KiwiSDR integration), merged 2026-06-20 — the same day. It re-introduces, by a different mechanism, the per-pan-step waterfall cost that #3578 had removed (which itself fixed the same class of choppiness, #3575, on wide displays).
Root cause
#3578 made per-pan reproject cheap: the waterfall history image is no longer globally reprojected — each history row records its own capture frame and only the visible viewport is remapped.
#3668 changed
SpectrumWidget::handleWaterfallFrequencyFrameChange()from a singlereprojectWaterfall()into an unconditional native + kiwi double reproject, each wrapped in a waterfall-stream-statesave/restore:On every pan mouse-move, even when KiwiSDR is inactive, this costs two things:
saveCurrentWaterfallStreamState()doesstate.waterfall = m_waterfall— a QImage assignment, so the buffer is now shared (copy-on-write). The nextm_waterfall.fill(Qt::black)insiderebuildWaterfallViewportForFrame()therefore detaches = deep-copies the entire waterfall image (large on wide/high-DPI displays) on every pan step. That deep-copy is exactly the per-step cost perf(spectrum): per-row waterfall-history frequency frames (no per-pan reproject) #3578 had eliminated.Measured (
aether.perf, same telemetry as #3578)i9-13900K / RTX 4090, FLEX-6600, wide high-resolution panadapter, D3D11/GPU path. Same binary; one env var (
AETHER_WF_KIWI_ALWAYS) toggles only the second pass. During a continuous hand pan:wfUpdateP95MspanAgeP95Ms(display lag)inputP95MsuiLagMaxMsPerfStall(comparable pan)fftRestarts/wfRestarts= 0 and packet loss = 0 in both runs — the radio/stream is not involved.renderP95~7 ms in both — the GPU render is not the bottleneck. The cost is purely the second pass + the deep-copy.What did you expect?
Pan to stay smooth (as after #3578), regardless of whether a KiwiSDR receiver is connected.
Steps to reproduce
aether.perfenabled (Help → Support → "Performance"),wfUpdateP95Msspikes to ~60–80 ms andpanAgeP95Msto ~150–170 ms during the drag.A/B from one binary: launch with
AETHER_WF_KIWI_ALWAYS=1→ stall reproduces; without it (active-stream-only) → stall gone.AetherSDR version
26.6.3
Radio model & firmware
FLEX-6600
Operating system
Windows
OS version and hardware
Windows 11 (build 26200), Qt 6.8.3 msvc2022_64; i9-13900K / RTX 4090, wide high-resolution panadapter.
Fix PR incoming (reproject only the active stream; remap the other on stream-switch). Couldn't self-assign — this account has no triage permission here.