fix(gui): use R16F unconditionally for FFT column texture — fixes blurry 2D trace on old D3D11 GPUs (#3967). Principle II.#3968
Conversation
…rry 2D trace on old D3D11 GPUs (#3967). Principle II. Regression from #3958 (per-pixel GPU FFT trace). initSpectrumPipeline preferred R32F whenever isTextureFormatSupported(R32F) returned true, but that predicate only reports create/sample support — NOT linear filterability. On older Windows GPUs (Intel iGPUs, D3D11 feature level <= 10.0) R32_FLOAT is sample-supported but not linearly filterable, so the Linear column sampler silently degrades to point sampling. panscope.frag then slope-corrects stroke width from dFdx(yTrace)/fwidth() of the sampled trace; point-sampled columns step between texels, dFdx spikes on every step, and the perpendicular-distance stroke fattens into the blurred band the reporter sees. Fix: use R16F unconditionally — the only float format QRhi guarantees is linear-filterable on every backend. The stored value is a normalized 0..1 amplitude, for which half-float has ample precision, so this removes the unreliable hardware-parity fork with no shader change and no visible quality loss on hardware where R32F was previously filterable. Also drops the now-dead R32F upload branch in renderGpuFrame. Honors Principle II (radio is authoritative on live state): the panadapter must faithfully mirror the FFT the radio reports across all client hardware, not a GPU-degraded approximation of it. Blast radius: risk_score=0.272, 19 high-risk affected (top: MainWindow::MainWindow, MainWindow::wirePanadapter, MainWindow::buildMenuBar). All are file-level SpectrumWidget callers that construct/wire the widget and are agnostic to the FFT column texture's internal pixel format; the change is confined to the GPU render path and reaches none of them behaviorally. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Closing this without merge — the root-cause analysis here doesn't hold up against git history. The blurry 2D FFT trace reported in #3967 is not a D3D11 texture-format problem, so switching the column texture to R16F unconditionally wouldn't fix it (and would only change precision, not sharpness). The softened trace reproduces on all platforms/GPUs and traces back to rendering changes merged 2026-06-26:
So the "blur" is a deliberate-but-unconditional cosmetic smoothing regression, not a hardware fallback. The right fix is to expose the spatial smoothing as a user-facing Display option (off/light/heavy) next to "FFT Line", separable from #3836's legitimate zoomed-flatline fix (the See #3967 for the full root-cause writeup. |
…u-gated smoothing — Principle XI. (#3975) ## Summary Fixes #3967. Also fixes #3932. Root-caused with per-commit builds (pre-#3836, post-#3836, 26.7.1-main, this fix) captured minutes apart against the same live AM broadcast band on a FLEX-8400M:  ## The regression chain (two releases, two causes) **26.6.5 — #3836's unconditional spatial smoothing ("out of focus", #3932).** `buildFftDisplayTrace`'s 5-tap binomial smooth at a fixed 0.75 blend exists to melt the radio's RBW stair-steps when zoomed in. Applied to every frame at every span, it rounds narrow carriers (visible height loss on AM carriers, panel 2) and defocuses the noise floor. **Fix:** gate the blend on the measured plateau fraction (adjacent equal-pixel bins). Zoomed-in plateau runs (frac ≳0.65) keep the full blend — #3836's stair-step fix is preserved; busy wide spans (frac ≲0.35) get zero — the pre-#3836 crispness returns; the ramp between prevents a visible mode flip while zooming. **26.7.1 — #3958's per-pixel stroke ("spiky above and below the line", the rest of #3967).** The stroke distance was approximated as vertical distance scaled by a `dFdx`-derived slope — i.e. distance to the segment's **infinite line**. On steep segments that line passes near the entire pixel column, so the stroke drew full-height needles above and below the trace (panel 3), and the fixed ±0.75 px smoothstep band read as a soft fat stroke at 1× DPI. **Fix:** true endpoint-clamped distance to the three adjacent polyline segments (4 column samples — matches the coverage the old geometry quads had), plus falloff parity with the old `spectrum.frag`: solid to `halfWidth−1`, 1 px fade, 1 px feather annulus at α 0.22. Also folds in #3968's R16F-unconditional column format as hardening (float32 linear filtering is optional on GLES and `isTextureFormatSupported()` can't detect filterability). Note it could **not** have caused #3967: the reporter's own About screenshot shows `D3D11; Intel(R) HD Graphics 520` — feature level 12.1 hardware where R32F linear filtering is mandatory. With this folded in, #3968 can be closed. Not implicated (left untouched, documented for the record): #3836's `decodeFFT` over-range renormalization only fires on radio/client `y_pixels` mismatch (transient), and the DPR-scaled `x_pixels`/`y_pixels` requests are orthogonal to trace sharpness. ## Why our platforms missed it The #3958 parity checks ran on 2× Retina, where the extra AA softness is half the logical size and the spike needles read as band activity in static grabs. The 4-way same-band comparison above is exactly the test that should have been run: panel 4 (this fix) restores panel 1 (pre-#3836). ## Verification - 4-way live comparison above (same band, same radio pan, same display settings; three grabs per build). - `get panstats 0`: frame prep unchanged at ~121 µs/frame, 58 presents/s, `fftBuildMsPerSec` 0.28 (plateau gate skips the smoothing copy on wide spans). - 3D stacked-trace mode, lean mode, line-width 0, heat/solid fill: unaffected paths re-checked by inspection; the software (non-QRhi-build) QPainter renderer shares `buildFftDisplayTrace` and picks up the plateau gate automatically. ## Also on the #3967 thread (separate follow-ups, not in this PR) - "3D option no longer exists": the 2D/3D combo is the **last row of the Display panel**, below Background — on short screens (768p laptops) it clips off the bottom of the panadapter. Needs a scrollable/compacted Display panel; the option itself ships fine in 26.7.1. - The 60 fps FFT slider ceiling from #3958 is unrelated to this report but worth an explicit release-notes mention. 💻 Generated with Claude Code (claude-fable-5 7/2/26) with architecture by @jensenpat 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
Fixes #3967
What was changed
fix(gui): use R16F unconditionally for FFT column texture — fixes blurry 2D trace on old D3D11 GPUs (#3967). Principle II.
Files modified
src/gui/SpectrumWidget.cppGenerated by AetherClaude (automated agent for AetherSDR)
🤖 aethersdr-agent · cost: $2.1436 · model: claude-opus-4-8