fix: prefer discrete GPU on Windows hybrid laptops Principle XI.#3299
Conversation
Request discrete GPU at process startup via NvOptimusEnablement and AmdPowerXpressRequestHighPerformance DLL exports. Intel iGPU D3D11 driver corrupts its stack during QRhiWidget reparenting; discrete GPU path does not trigger the bug. Reporter-verified on RTX 4090 laptop. Fixes #1921
|
Hi @NF0T — thanks for tackling this one! The hybrid-GPU crash in #1921 is a nasty bug and the Optimus/PowerXpress export trick is exactly the right mechanism for it. 👍 The good news: this is a one-line fix, and it's in the new code (not CI infra). Here's what's happening. What failedOnly Root causeextern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 1;
// ^^^^^ undeclared identifier under MSVC
( How to fixThe cleanest fix is to drop #ifdef Q_OS_WIN
// Request discrete GPU on hybrid laptops (NVIDIA Optimus / AMD PowerXpress).
// Intel iGPU D3D11 driver corrupts its stack during QRhiWidget reparenting (#1921).
extern "C" __declspec(dllexport) unsigned long NvOptimusEnablement = 1;
extern "C" __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
#endif // Q_OS_WINI'd recommend this over The export name and the No reviewer/Copilot comments to flag on this one. After the swap, push and 🤖 aethersdr-agent · cost: $24.1900 · model: claude-opus-4-8 |
MSVC does not see DWORD at file scope before windows.h is explicitly included. Qt headers pulled in above provide it on some paths but not reliably in this translation unit at file scope. Adding the include inside the Q_OS_WIN guard (matching the pattern of the __linux__ block above) fixes the three C4430/C2146/C2059 errors from check-windows CI.
|
Thanks for the detailed triage — root cause diagnosis is correct, and the We went with Macro pollution risk is lower than it looks here. Our include sits after all Qt and project headers. Qt on Windows already manages
CI is green. All five checks pass on the current form ( That said, this is a cosmetic preference and the maintainer may reasonably prefer |
jensenpat
left a comment
There was a problem hiding this comment.
Signal hybrid GPU flags on app start for Windows users. Approved
…ayDirty() (#3338) (#3411) ## Problem The 9 spot-display setters in `SpectrumWidget.h` call `update()`, which on the GPU path reuses the cached `m_overlayStatic` chrome texture without re-baking it. `drawSpotMarkers()` never re-runs, so toggling **Spot Lines** (or changing spot font size, start %, colours, etc.) has no immediate visual effect — the change only takes hold when something else triggers `markOverlayDirty()` (e.g. a new incoming spot). This regression was introduced by #3124 (GPU path caches the chrome overlay) and became consistently visible after #3299 (discrete GPU preference on Windows) caused more users to hit the GPU path. ## Fix Replace `update()` with `markOverlayDirty()` in all 9 setters. `markOverlayDirty()` calls `update()` internally — identical behaviour on the CPU path, correct invalidation on the GPU path. All other display setters in the file (background opacity, MQTT display, prop forecast, etc.) already use `markOverlayDirty()`. The spot setters were the only outliers. ## Testing Verified build compiles cleanly on macOS. GPU-path visual verification (toggle Spot Lines with spots visible → lines appear/disappear immediately) requires Windows with discrete GPU — the reporter in #3338 should be able to confirm. Fixes #3338
…hersdr#3299) ## Summary Fixes aethersdr#1921 — `STATUS_STACK_BUFFER_OVERRUN` crash on every pop-out attempt on Windows hybrid-GPU laptops (Intel iGPU + discrete NVIDIA/AMD GPU). ### Root cause Intel's D3D11 user-mode driver (`igd10um64xe.dll`) corrupts its own stack during `UpdateSubresource`, called from `QRhi::endOffscreenFrame` during the swap-chain teardown/recreate cycle that `SpectrumWidget::resizeEvent` triggers on widget reparenting (`floatPanadapter` / `dockPanadapter`). This is an Intel driver bug, but AetherSDR's pop-out flow reliably triggers it when the process is running on the Intel GPU. ### Fix Add the standard NVIDIA Optimus / AMD PowerXpress DLL exports to `src/main.cpp`. The vendor driver loaders inspect the PE export table at process startup and bind the discrete GPU instead of the Intel iGPU when these symbols are present with value `1`. ```cpp #ifdef Q_OS_WIN // Request discrete GPU on hybrid laptops (NVIDIA Optimus / AMD PowerXpress). // Intel iGPU D3D11 driver corrupts its stack during QRhiWidget reparenting (aethersdr#1921). extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 1; extern "C" __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; #endif // Q_OS_WIN ``` **Scope:** the exports are no-ops on Intel-only hardware (no dGPU present) and are compiled out on macOS and Linux. This is the same mechanism used by Qt Quick, Chromium, and every major game engine for this problem. **Reporter-verified:** reporter confirmed AetherSDR launches on the RTX 4090 and the pop-out crash does not reproduce with this change applied (see issue aethersdr#1921). ### What this does NOT fix Intel-only laptops (no discrete GPU) are unaffected. The double `resetGpuResources()` call pattern in `PanadapterStack::floatPanadapter()` and `dockPanadapter()` (immediate + deferred via `refreshAfterReparent()`) is the structural trigger on the Windows D3D11 path — that is a separate follow-up issue requiring cross-backend testing. ## Files changed - `src/main.cpp` — +7 lines (one `#ifdef Q_OS_WIN` block + surrounding blank lines) ## Test plan - [ ] Linux build clean (no new warnings — `#ifdef Q_OS_WIN` compiles out) - [ ] `check-windows` CI green (MSVC build, no `C4190` or related warnings) - [ ] Windows: `dumpbin /EXPORTS AetherSDR.exe | findstr -i "Optimus\|HighPerf"` shows both exports - [ ] Windows hybrid-GPU: AetherSDR starts on discrete GPU; pop-out does not crash 🤖 Implemented with [Claude Code](https://claude.com/claude-code)
…ayDirty() (aethersdr#3338) (aethersdr#3411) ## Problem The 9 spot-display setters in `SpectrumWidget.h` call `update()`, which on the GPU path reuses the cached `m_overlayStatic` chrome texture without re-baking it. `drawSpotMarkers()` never re-runs, so toggling **Spot Lines** (or changing spot font size, start %, colours, etc.) has no immediate visual effect — the change only takes hold when something else triggers `markOverlayDirty()` (e.g. a new incoming spot). This regression was introduced by aethersdr#3124 (GPU path caches the chrome overlay) and became consistently visible after aethersdr#3299 (discrete GPU preference on Windows) caused more users to hit the GPU path. ## Fix Replace `update()` with `markOverlayDirty()` in all 9 setters. `markOverlayDirty()` calls `update()` internally — identical behaviour on the CPU path, correct invalidation on the GPU path. All other display setters in the file (background opacity, MQTT display, prop forecast, etc.) already use `markOverlayDirty()`. The spot setters were the only outliers. ## Testing Verified build compiles cleanly on macOS. GPU-path visual verification (toggle Spot Lines with spots visible → lines appear/disappear immediately) requires Windows with discrete GPU — the reporter in aethersdr#3338 should be able to confirm. Fixes aethersdr#3338
Summary
Fixes #1921 —
STATUS_STACK_BUFFER_OVERRUNcrash on every pop-out attempt on Windows hybrid-GPU laptops (Intel iGPU + discrete NVIDIA/AMD GPU).Root cause
Intel's D3D11 user-mode driver (
igd10um64xe.dll) corrupts its own stack duringUpdateSubresource, called fromQRhi::endOffscreenFrameduring the swap-chain teardown/recreate cycle thatSpectrumWidget::resizeEventtriggers on widget reparenting (floatPanadapter/dockPanadapter). This is an Intel driver bug, but AetherSDR's pop-out flow reliably triggers it when the process is running on the Intel GPU.Fix
Add the standard NVIDIA Optimus / AMD PowerXpress DLL exports to
src/main.cpp. The vendor driver loaders inspect the PE export table at process startup and bind the discrete GPU instead of the Intel iGPU when these symbols are present with value1.Scope: the exports are no-ops on Intel-only hardware (no dGPU present) and are compiled out on macOS and Linux. This is the same mechanism used by Qt Quick, Chromium, and every major game engine for this problem.
Reporter-verified: reporter confirmed AetherSDR launches on the RTX 4090 and the pop-out crash does not reproduce with this change applied (see issue #1921).
What this does NOT fix
Intel-only laptops (no discrete GPU) are unaffected. The double
resetGpuResources()call pattern inPanadapterStack::floatPanadapter()anddockPanadapter()(immediate + deferred viarefreshAfterReparent()) is the structural trigger on the Windows D3D11 path — that is a separate follow-up issue requiring cross-backend testing.Files changed
src/main.cpp— +7 lines (one#ifdef Q_OS_WINblock + surrounding blank lines)Test plan
#ifdef Q_OS_WINcompiles out)check-windowsCI green (MSVC build, noC4190or related warnings)dumpbin /EXPORTS AetherSDR.exe | findstr -i "Optimus\|HighPerf"shows both exports🤖 Implemented with Claude Code