Skip to content

gpui_windows: Fix dropped frames under sustained input - #61632

Closed
J0R6IT0 wants to merge 2 commits into
zed-industries:mainfrom
J0R6IT0:fix-wm-paint-starvation
Closed

J0R6IT0 wants to merge 2 commits into
zed-industries:mainfrom
J0R6IT0:fix-wm-paint-starvation

Conversation

@J0R6IT0

@J0R6IT0 J0R6IT0 commented Jul 25, 2026

Copy link
Copy Markdown

Objective

Addresses the WM_PAINT starvation described in #61469.

On Windows, frames stop reaching the display while input is arriving continuously. The vsync thread invalidates each window once per tick with RedrawWindow(hwnd, None, None, RDW_INVALIDATE), and the frame is then only drawn when the run loop receives WM_PAINT. But WM_PAINT is synthesized rather than queued, so a thread only receives one once its message queue holds nothing else. Any sustained input source keeps the queue non-empty and starves it, so the invalidations never become dispatched paints.

I encountered this issue when dragging a scrollbar with a high-polling mouse in my own GPUI application. #61469 describes the same mechanism at the same line. However I have not verified that this resolves the keyboard case as I have not been able to reproduce it, so I'm not including a closing keyworkd.

Solution

Keep the existing invalidation and additionally post a real message, WM_GPUI_VSYNC_FRAME, from the vsync thread. A posted message queues behind the input rather than losing to it. Its handler calls UpdateWindow, which delivers the pending paint directly and is a no-op when the update region is empty.

Testing

I added a counter to check the number of messages that arrive, and another one to check how many times the window actually paints. Windows 11, 240Hz display.

mouse messages/s paints/s
Before, dragging by hand 663 147
Before, synthetic 1000Hz mouse ~880 13-21
After, synthetic 1000Hz mouse ~855 240

The window should paint 240 times a second. Before the fix it manages 147 with a real hand on the mouse, and as few as 13 when the input never pauses (tested via PowerShell script). After the fix it holds a steady 240 no matter how much input arrives.

Nothing here is actually slow. A complete paint (building the element tree, layout, GPU submit and present)
takes about 120us out of the 4170us available per frame. The frames were not late, they were just never dispatched.

Self-Review Checklist:

  • I've reviewed my own diff for quality, security, and reliability
  • Unsafe blocks (if any) have justifying comments
  • The content adheres to Zed's UI standards
  • Tests cover the new/changed behavior
  • Performance impact has been considered and is acceptable

Release Notes:

  • Fixed dropped frames on Windows while the mouse or keyboard is in continuous use.

@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Jul 25, 2026
@zed-community-bot zed-community-bot Bot added the first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions label Jul 25, 2026
@RemcoSmitsDev RemcoSmitsDev added platform:windows happens only on Windows, not other OS area:gpui GPUI rendering framework support labels Jul 26, 2026
@reflectronic reflectronic self-assigned this Jul 26, 2026
@ChristopherBiscardi

Copy link
Copy Markdown
Contributor

Thanks! The issue here is valid, but this fix doesn't seem to be the right one. I've labelled the relevant issue as zed-team-only as I believe we need to take this on

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:gpui GPUI rendering framework support cla-signed The user has signed the Contributor License Agreement first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions platform:windows happens only on Windows, not other OS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants