Skip to content

bugfix(dx8): Fix corner rendering and resolution switching rollback#2539

Open
githubawn wants to merge 1 commit intoTheSuperHackers:mainfrom
githubawn:fix/setdisplaymode-tiny-bugs
Open

bugfix(dx8): Fix corner rendering and resolution switching rollback#2539
githubawn wants to merge 1 commit intoTheSuperHackers:mainfrom
githubawn:fix/setdisplaymode-tiny-bugs

Conversation

@githubawn
Copy link
Copy Markdown

This PR addresses stability issues in the resolution switching logic.
These changes particularly improve stability when running under Wine but also resolve rare race conditions on native Windows.

  • Defer Render2D resolution update until after successful D3D reset
  • Snapshot current mode before Set_Device_Resolution for correct rollback
  • Fix fullscreen window failing to cover desktop by removing SWP_NOSIZE/NOMOVE
  • Remove dead D3DInterface release block in Shutdown

- Defer Render2D resolution update until after successful D3D reset
- Snapshot current mode before Set_Device_Resolution for correct rollback
- Fix fullscreen window failing to cover desktop by removing SWP_NOSIZE/NOMOVE
- Remove dead D3DInterface release block in Shutdown
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 5, 2026

Greptile Summary

This PR fixes four real bugs in the DirectX 8 resolution-switching pipeline, mirrored symmetrically across Generals/ (vanilla) and GeneralsMD/ (Zero Hour). The changes improve stability under Wine and fix rare race conditions on native Windows by: snapshotting the current display mode before attempting a device reset (preventing corrupt rollback values), deferring the Render2DClass screen-resolution update until after a confirmed successful D3D reset, correcting fullscreen window sizing that was silently broken by contradictory Win32 flags, and pruning an unreachable double-release of the D3D interface.

Key changes:

  • W3DDisplay.cpp: Snapshot oldWidth/oldHeight/oldBitDepth/oldWindowed before calling WW3D::Set_Device_Resolution. Prior to this, Set_Render_Device unconditionally overwrote ResolutionWidth/ResolutionHeight with the new values at the top of the function; if the D3D reset then failed, the rollback path called getWidth()/getHeight() which now returned the failed new values instead of the working old ones.
  • dx8wrapper.cpp (both): Move Render2DClass::Set_Screen_Resolution from unconditional early-in-function placement to a if (ret) guard after Reset_Device/Create_Device, ensuring the 2D renderer only tracks a resolution that a live D3D device is actually running at.
  • dx8wrapper.cpp (both): Replace SWP_NOSIZE | SWP_NOMOVE with SWP_SHOWWINDOW in the fullscreen SetWindowPos call. SWP_NOSIZE | SWP_NOMOVE instructs Win32 to ignore the x/y/cx/cy parameters entirely, so the fullscreen window was never actually repositioned or resized — only promoted to HWND_TOPMOST. The fix allows the intended (0, 0, width, height) arguments to take effect.
  • dx8wrapper.cpp (both): Remove a second D3DInterface->Release() block in Shutdown() that was unreachable: the preceding block already called Release() and set D3DInterface = nullptr, so the removed block's if (D3DInterface) guard was always false. The removed block also stored the return value of Release() in an unused newRefCount local, a secondary code smell.

Confidence Score: 4/5

This PR is safe to merge — all four changes fix genuine bugs with no new API surface, no interface contract changes, and no regressions introduced.

Score of 4/5 reflects well-targeted bug fixes that are logically sound and symmetrically applied across both game directories. A point is withheld because the rollback path in setDisplayMode still silently ignores a failure of the second Set_Device_Resolution call (pre-existing, not introduced here), leaving the device in an indeterminate state if rollback also fails. This is a latent risk worth tracking but is not caused by this PR.

dx8wrapper.cpp in both directories contains three distinct changes; the SetWindowPos flag correction is the most impactful for end users and the deferred Render2D update is most relevant for Wine stability.

Important Files Changed

Filename Overview
Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp Snapshots current display mode before resolution switch attempt, fixing incorrect rollback values when Set_Render_Device overwrites resolution state early
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp Defers Render2D resolution update to post-success D3D reset, fixes fullscreen window sizing (SWP_NOSIZE
GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp Mirror of Generals fix: snapshots display mode before Set_Device_Resolution for correct rollback in Zero Hour code
GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp Mirror of Generals fix: deferred Render2D update, correct fullscreen window sizing, and dead code removal in Zero Hour code

Sequence Diagram

sequenceDiagram
    participant W3D as W3DDisplay
    participant WW3D as WW3D
    participant DX8 as DX8Wrapper
    participant R2D as Render2DClass

    Note over W3D: Snapshot oldWidth/oldHeight/oldBitDepth/oldWindowed
    W3D->>WW3D: Set_Device_Resolution(xres, yres, bitdepth, windowed)
    WW3D->>DX8: Set_Render_Device(width, height, bits, windowed, ...)
    Note over DX8: Writes new values to ResolutionWidth/Height (always)
    DX8->>DX8: Resize_And_Position_Window() [SetWindowPos with correct flags]
    DX8->>DX8: Reset_Device() or Create_Device()
    alt D3D reset SUCCESS (ret == true)
        DX8->>R2D: Set_Screen_Resolution(ResolutionWidth, ResolutionHeight)
        DX8-->>WW3D: true
        WW3D-->>W3D: WW3D_ERROR_OK
        W3D->>R2D: Set_Screen_Resolution(xres, yres)
        W3D->>W3D: Display::setDisplayMode(xres, yres, ...)
        W3D-->>W3D: return TRUE
    else D3D reset FAILED (ret == false)
        Note over DX8: Render2DClass NOT updated
        DX8-->>WW3D: false
        WW3D-->>W3D: error
        Note over W3D: Use snapshots for rollback (not stale getters)
        W3D->>WW3D: Set_Device_Resolution(oldWidth, oldHeight, ...)
        W3D->>R2D: Set_Screen_Resolution(oldWidth, oldHeight)
        W3D->>W3D: Display::setDisplayMode(oldWidth, oldHeight, ...)
        W3D-->>W3D: return FALSE
    end
Loading

Reviews (1): Last reviewed commit: "dx8: Fix resolution switching, windowing..." | Re-trigger Greptile

@xezon xezon added Bug Something is not working right, typically is user facing Rendering Is Rendering related labels Apr 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something is not working right, typically is user facing Rendering Is Rendering related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants