Skip to content

Fix inverted vsync latch from the implicit swapchain present interval#149

Open
BinqAdams wants to merge 1 commit into
NVIDIAGameWorks:mainfrom
BinqAdams:fix/d3d9-vsync-latch-immediate
Open

Fix inverted vsync latch from the implicit swapchain present interval#149
BinqAdams wants to merge 1 commit into
NVIDIAGameWorks:mainfrom
BinqAdams:fix/d3d9-vsync-latch-immediate

Conversation

@BinqAdams

@BinqAdams BinqAdams commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

When rtx.enableVsync is in its default WaitingForImplicitSwapchain state, the vsync default is latched from the first swapchain's PresentationInterval using a truthiness check:

RtxOptions::enableVsyncState = m_presentParams.PresentationInterval ? EnableVsync::On : EnableVsync::Off;

In D3D9, D3DPRESENT_INTERVAL_IMMEDIATE (the only "present unsynchronized" request) is 0x80000000, i.e. nonzero, so a game explicitly asking for no vsync latches vsync On. Conversely D3DPRESENT_INTERVAL_DEFAULT (0), which presents synchronized, latches Off. The two most common values map backwards.

Observable symptom: a game requesting IMMEDIATE at device creation runs capped to display refresh with elevated present latency (FIFO queue depth) from boot. With DLFG enabled the cap silently clears on the first interpolated 3D frame, since dispatchDLFG forces vsync off; this disguises the bug as "menus/loading only". With DLFG off it persists. Native present-interval overrides (d3d9.presentInterval) cannot help because enableVsyncState overrides the interval at Present time.

Fix: latch Off only for D3DPRESENT_INTERVAL_IMMEDIATE; DEFAULT, ONE, and TWO through FOUR latch On, matching D3D9 presentation-interval semantics. An explicit rtx.enableVsync user setting still takes precedence, and the developer-menu V-Sync toggle behaves as before.

Testing

Test game: Painkiller Black Edition (D3D9; its device requests a nonzero presentation interval at creation, and IMMEDIATE on the level-load Reset).

  1. Launch the game and stay on the first main menu. Do not load a level.
  2. Observe the frame rate (external overlay or the dev menu HUD).

Before the fix: the menu frame rate is locked to the display refresh rate (observed 60 on a 60 Hz display; observed as 30/60/120 across different displays in the original report), and cannot be raised by the game's own frame limiter, by d3d9.presentInterval = 0, or by any present-interval request from the game. Loading a level with frame generation enabled releases the cap; returning to the menu it stays released, since the latch only runs while the option is in its startup state.

After the fix: the first menu runs uncapped from the first frame. Verified on the same machine and display as the before measurement, same build otherwise. Setting rtx.enableVsync = True re-engages vsync as expected.

When rtx.enableVsync is in its default WaitingForImplicitSwapchain
state, the vsync default is latched from the first swapchain's
PresentationInterval with a truthiness check. In D3D9,
D3DPRESENT_INTERVAL_IMMEDIATE (the only "present unsynchronized"
request) is 0x80000000, i.e. nonzero, so a game explicitly asking for
no vsync latches vsync On; D3DPRESENT_INTERVAL_DEFAULT (0), which
presents synchronized, latches Off. The two most common values map
backwards.

A game requesting IMMEDIATE at device creation therefore runs capped
to the display refresh with elevated present latency from boot. With
DLFG enabled the cap silently clears on the first interpolated 3D
frame (dispatchDLFG forces vsync off), which disguises the bug as
affecting menus and loading screens only; with DLFG off it persists.
The d3d9.presentInterval config cannot help because enableVsyncState
overrides the present interval at Present time.

Latch Off only for D3DPRESENT_INTERVAL_IMMEDIATE; DEFAULT, ONE and
TWO through FOUR latch On, matching D3D9 presentation interval
semantics. An explicit rtx.enableVsync user setting still takes
precedence.
@BinqAdams BinqAdams force-pushed the fix/d3d9-vsync-latch-immediate branch from 3f5ae6b to ae33976 Compare July 8, 2026 23:21
@BinqAdams BinqAdams changed the title D3D9: fix inverted vsync latch from the implicit swapchain's PresentationInterval Fix inverted vsync latch from the implicit swapchain present interval Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant