Repository navigation
Description
Summary
On Windows 11 with an NVIDIA GPU, the clean latest main build can enter a prolonged Direct3D 8 lost-device state shortly after startup while the game is foreground and not minimized.
During the fault, render FPS drops to roughly 5-8 FPS, DX8Wrapper::IsDeviceLost remains true, and DX8Wrapper::FrameCount stays at zero. The process is responsive and game logic is not the bottleneck. The behavior disappears completely in windowed/windowed-fullscreen presentation.
This appears related to the lost-device recovery discussed in #28 / #846, but is not a crash: the game can remain in the recovery loop for approximately 45-50 seconds before recovering by itself.
Tested build
- Repository: clean
TheSuperHackers/GeneralsGameCodemain - Commit:
bb5168c8d0685f0fc0628f6b1b74e49a91258e41 - Release executable SHA-256:
C1069626F2B354C5B0505C9EC314D1D21D5E7C6D705CAB2611C96254856FE785 - Steam Zero Hour 1.04 data
System
- Windows 11 Pro
10.0.26200(build 26200) - Intel Core i9-13900KF
- NVIDIA GeForce RTX 4090
- NVIDIA drivers reproduced: 610.74 and 610.88 (
32.0.16.1088) - Desktop/game resolution: 2560x1440 at 239 Hz
Reproduction
- Build current
mainin Release. - Launch
generalszh.exein the default exclusive-fullscreen mode at the desktop resolution. - Keep the window foreground and not minimized.
- Within roughly 10-20 seconds, observe repeated device resets followed by a sustained lost-device state and ~5-8 render FPS.
Representative clean-upstream monitor output after activating the game window:
16:51:07 fps=10.2 cap=30 frame=1 lost=0 resets=11 foreground=true
16:51:10 fps=30.0 cap=30 frame=0 lost=1 resets=13 foreground=true
16:51:20 fps=6.4 cap=30 frame=0 lost=1 resets=16 foreground=true
16:51:28 fps=5.9 cap=30 frame=0 lost=1 resets=16 foreground=true
16:51:44 fps=5.5 cap=30 frame=0 lost=1 resets=16 foreground=true
On the GeneralsOnline fork (which contains the same upstream rendering code), monitoring from process creation shows the full recovery cycle:
16:19:39 fps=9.3 cap=60 frame=0 lost=1 foreground=true
16:19:47 fps=6.0 cap=60 frame=0 lost=1 foreground=true
...
16:20:26 fps=4.6 cap=60 frame=0 lost=1 foreground=true
16:20:27 fps=60.0 cap=60 frame=46 lost=0 foreground=true
A/B results
| Configuration | Result |
|---|---|
Clean upstream main, exclusive fullscreen |
Reproduces |
Clean upstream main, -win -nologo -noshellmap |
Stable 30 FPS, lost=0, no resets |
GeneralsOnline latest main, normal launcher |
Reproduces |
| GeneralsOnline executable launched directly | Reproduces |
GeneralsOnline with -nologo |
Reproduces |
GeneralsOnline with -nologo -noshellmap |
Reproduces |
GeneralsOnline with GENERALS_ONLINE_WINDOWED_FULLSCREEN |
Stable 60 FPS, lost=0, no resets |
This rules out the launcher, startup movie, shell map, terrain rendering changes, FPS limiter, CPU/GPU load, and a single NVIDIA driver version.
Source observation
DX8Wrapper::End_Scene() does this after Present() returns D3DERR_DEVICELOST:
hr = _Get_D3D_Device8()->TestCooperativeLevel();
if (hr == D3DERR_DEVICENOTRESET)
Reset_Device();
else
ThreadClass::Sleep_Ms(200);The measured ~5 FPS cadence exactly matches the 200 ms sleep path. During the fault, IsDeviceLost stays true and FrameCount remains zero until recovery.
PR #846 removed the old Reset_D3D_Device(bool active) activation hack and relies on the cooperative-level recovery path. Its discussion already contains a closely related observation:
This is even happening if I launch the game and never leave the game window.
Related work:
- Windows 10: Game crashes on ALT+Tab #28
- [GEN][ZH] Fixed crash when alt-tabbing out of the game #801
- [GEN][ZH] Fix Alt-tabbing crash #846
- Add "-noborder" launch argument for borderless windowed mode #327 (
-noborderborderless windowed mode) - feat(input): Enhance window management capabilities #2608 (live window/fullscreen management)
Expected behavior
Exclusive-fullscreen startup should not remain device-lost for tens of seconds while foreground. Alternatively, fullscreen-at-desktop-resolution could use a supported windowed/borderless presentation path, which avoids the failure in all measurements above.
Activity
sailro commentedon Aug 2, 2026
cc @xezon given the context.
mirelle7 commentedon Aug 2, 2026
About the "Alternatively": DX8 severely increases latency when it does borderless fullscreen. The first version to support this properly is dx9ex. Which also fixes this lost device stuff.
sailro commentedon Aug 2, 2026
Ok I see. I don't really understand why I've only been having this problem recently. Rebooting seems to fix the issue as well, but that makes it pretty annoying.
mrtnptrs commentedon Oct 6, 2026
I can still reproduce this on latest vanilla Steam ZH, TSH and GO. Does anyone have any info on what might be the specific cause of this issue? I heard on the GO-Discord (Command Center), that this might be due to a Windows Update, but sadly no one can provide specifics. It is also said that more older games suffer from issues like these. So, I was curious if anyone here is able to provide some insights on the cause of this issue?
I know, switching to windowed mode as a workaround (and likely using a wrapper) works, but I'm more interested to get to know the possible root cause of this issue.
coconutbird commentedon Nov 5, 2026
Also reproducing here, on both TheSuperHackers
weekly-2026-10-30(3fcbbb4) and retail Steam game.dat.System: Windows 11 10.0.26200, RTX 5070 + AMD Radeon iGPU (both active), Parsec Virtual Display Adapter installed, 2x ASUS 2560x1440 @ 144 Hz, 125% scaling.
Symptoms (exclusive fullscreen, launched from Steam, no
Resolutionin Options.ini so 800x600):Other observations on the same PC:
generalsv.exe) fullscreen was intermittent: two Steam launches exited with code 1 after 93 s and 34 s, a later one ran fine for hours.game.datproduced an AppHangB1 ("stopped interacting with Windows").Workaround:
-win+Resolution = 2560 1440(client area fills the monitor, title bar is pushed off-screen) is stable on both games.Extra data:
game.daton this PC crashed with "Uncaught exception in Main::WndProc", access violation reading 0x0 atd3d8!CD3DBase::DeletePixelShader+0xB9(SysWOW64 d3d8.dll RVA 0x50F89, PDB 1680DBE07E5EC781E2FA8676D9ED4B91/1, symbolized with Microsoft public symbols), about 13 s after launch. That is the old WM_ACTIVATEAPP -> Reset_Device path removed in [GEN][ZH] Fix Alt-tabbing crash #846, so it suggests the window gets an activation change during fullscreen startup.GetProcAddress Direct3DCreate8 returned wrong module (apphelp.dll), i.e. a Windows compat shim hooks Direct3DCreate8 for ZH'sGenerals.exe. Not seen for the Generals process. sysmain.sdb has entries forgenerals.exe/game.dat; the WM_ACTIVATEAPP comment in WinMain.cpp already mentions DXMaximizedWindowedMode.Code notes (weekly-2026-10-30):
DX8Wrapper::Reset_Devicereleases all non-managed resources before checkingTestCooperativeLevel. OnD3DERR_DEVICELOSTor a failedReset()it returns false without reacquiring anything and without logging in Release. All callers ignore the result:End_SceneL1705,Flip_To_PrimaryL1753,WW3D::Begin_RenderL822. So every retry re-releases and re-uploads everything, which would explain the climbingresets=counter.End_SceneL1696-1711 sleeps 200 ms per frame while lost, which gives the ~5 FPS "frozen" picture while the message pump keeps running.D3DPRESENT_RATE_DEFAULTand falls back to 800x600 when noResolutionis saved, forcing a full mode change that re-lays out multi-monitor desktops. Not required for the bug (it reproduces at desktop res above), but it adds activation churn on multi-monitor setups.initializeAppWindowspassesWS_EX_TOPMOST(an extended style) indwStylefor fullscreen. It's a no-op there; topmost is applied later bySetWindowPos(HWND_TOPMOST). Same in Generals/Code/Main/WinMain.cpp.coconutbird commentedon Nov 5, 2026
Follow-up to my comment above: I found what keeps the device lost on my system and opened #3656.
In fullscreen the game uses a
D3DFMT_A8R8G8B8back buffer, while the display mode isD3DFMT_X8R8G8B8.CSwapChain::Resetind3d8.dllcompares the back buffer format with the current display format to decide whether the display mode has to change. The two never match, so every fullscreenReset()callsChangeDisplaySettingsExA, even when the display already is in that mode. On my system a display mode change loses the device again shortly afterwards, so the game resets forever and never presents a frame. EveryReset()returnsD3D_OK: 66 resets in about 30 seconds. A minimal D3D8 app shows the same loop with anA8R8G8B8back buffer and runs stable withX8R8G8B8. Details and the disassembly are in #3656.#3656 switches the back buffer to the display format when a fullscreen reset does not last until a frame is presented. On my system the game then starts in fullscreen after 2 resets.
If you can reproduce this issue, testing #3656 would help, especially on setups different from mine (single monitor, 239 Hz like the original report). Once CI has run, the build artifacts of the PR can be used. Worth checking: