Skip to content

app,internal/d3d11: [Windows] present with the flip model - #4

Merged
omartelo merged 1 commit into
lichfrom
windows-flip-swap-chain
Nov 8, 2026
Merged

omartelo merged 1 commit into
lichfrom
windows-flip-swap-chain

Conversation

@omartelo

@omartelo omartelo commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Windows presented through the blit model (DXGI_SWAP_EFFECT_DISCARD, one buffer). This moves the swap chain to the flip model to cut typing latency, and makes a resize present its new-size frame at once.

  • CreateSwapChain tries FLIP_DISCARD with 2 UNORM buffers, then falls back to the previous DISCARD chain with its _SRGB buffer.
  • IDXGIDevice1::SetMaximumFrameLatency(1) on the device, best effort. No waitable object.
  • The render target view carries R8G8B8A8_UNORM_SRGB, valid over both buffer formats, so Gio's linear output stays sRGB encoded.
  • Refresh unbinds the view and flushes before ResizeBuffers. Lock already rebinds it every frame, after Present unbinds it.
  • Release clears and flushes the context so a new flip chain can be created on the same window after a lost device.
  • The first Present after a size change uses sync interval 0, which replaces any queued frame.

Buffer contents after Present are not read: Direct3D has no BufferAge, so every frame is drawn whole, and the window clears at the start of each frame.

Test plan

  • go test ./internal/d3d11/ ./gpu/ on Linux: pass, including the new config and fallback tests
  • GOOS=windows go build ./...: clean
  • GOOS=windows go vet ./app/... ./internal/d3d11/... ./gpu/...: no finding in changed code
  • A throwaway test under wine 11.21 in Xvfb created the device, a FLIP_DISCARD chain with 2 UNORM buffers, set the frame latency, resized, bound the sRGB view, presented at intervals 0 and 1, and created a second chain on the same window after release: pass
  • lich native/ against this branch through a local replace: go build ./... and go vet ./... on Linux clean

The swap chain used the old blit model with one buffer, which adds a
copy and a frame of queueing between a keystroke and the screen. Create
a FLIP_DISCARD chain of two buffers instead and set the maximum frame
latency to 1, falling back to the previous DISCARD chain where a flip
chain cannot be created.

Flip-model buffers cannot have an _SRGB format, so the buffers are
UNORM and the render target view carries the sRGB format. ResizeBuffers
now runs with the view unbound and its deferred destruction flushed,
and Release clears and flushes the context, since a window holds one
flip chain and a new one after a lost device would otherwise fail.

The first frame of a new size presents with sync interval 0, replacing
any queued frame so the window does not show an older one stretched.
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