Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seconds-long delay in processing keyboard events. OK on Linux/X11, fails on Wine/Windows. #4097

Closed
John-Nagle opened this issue Jan 28, 2025 · 9 comments
Labels
B - bug Dang, that shouldn't have happened DS - windows

Comments

@John-Nagle
Copy link

John-Nagle commented Jan 28, 2025

Description

Just converted to Winit 0.30.8, switching to the new "object-oriented" API. Seeing 2 to 3 second delays in character echo in the GUI. Linux/X11 works fine, Windows/Wine 9.0 fails.

It's a game-type program, refreshing endlessly. So it processes events until the event queue runs out, then, when winit calls about_to_wait(), the application makes a redraw request. So all queued events should be handled before each refresh cycle.

This area has had touchy problems in the past. A old version called request_redraw on every redraw, but you don't really want to do that. The documentation for Winit suggests doing it that way, but the Winit examples don't do that any more. We went through this issue last year, and it seemed to be fixed. There was also a problem with keyboard events coming through twice. That was also fixed.

This is built cross-compiled on Linux. That's worked fine for years.

Reproduce on Linux by:

git clone https://github.com/John-Nagle/ui-mock.git
cd ui-mock
git checkout wgpu23newwinit
cargo build --examples --target x86_64-pc-windows-gnu
cd target/x86_64-pc-windows-gnu/debug/examples
wine ui-mock

It's a dummy of a game API. Click on the "Placeholder metaverse" bar, which gets you to a login box. Doesn't matter what you type there. Observe character echo speed. Delays of one second or more are appearing. If you complete the "login", you get a 3D cube. It's a test case used to exercise the Egui/Rend3/Wgpu/Winit stack to see if they play well together.

If you have a Windows system available, you might try this on that platform, without Wine. Please post the results.

Windows version

Wine 9.0

Winit version

0.30.8

@John-Nagle John-Nagle added B - bug Dang, that shouldn't have happened DS - windows labels Jan 28, 2025
@John-Nagle
Copy link
Author

I'd really appreciate it if someone tried this on real Windows. Then we'd know more about the platform problem. I don't have a Microsoft machine.

There's a long history of trouble with event/redraw ordering. See #2900

@John-Nagle
Copy link
Author

Tested by someone else on real Windows. Works there. But not on Wine 9.0.
Will test against other Wine versions.

@John-Nagle
Copy link
Author

Also works OK on MacOS. Only Wine fails.

The puzzling thing is that many games work on Wine, and they have the same event processing problem.

The basic event processing logic I use is:

  • Process events as Winit feeds them to the program via callbacks from ApplicationHandler.
  • When ApplicationHandler calls WindowEvent, Egui's on_window_event is called to handle it, if it Egui wants it.
  • When AppilcationHandler calls about_to_wait, the application calls request_redraw.
  • Redraw is done only when ApplicationHandler delivers a RedrawRequested event.

Is that correct?

@kchibisov
Copy link
Member

Asking from about_to_wait will deliver it to the next event loop frame, thus adding a latency, but it really depends how your logic is structured, etc. Like it's generally fine, but given that on windows we do use WM_PAINT for that it gets a bit broken in some cases and WM_PAINT is getting delayed.

In general, you should ask for drawing once you've figured that you'll be doing so, and if you want to always draw, asking from RequestRedraw should be preferred, though, AboutToWait in such case is fine as well, but keep in mind that it's for contiguous drawing.

For lazy drawing you should call your request_redraw before AboutToWait to draw on the current iteration of the event loop.

@John-Nagle
Copy link
Author

This is a game-type program, always drawing and computing new positions on each draw. That part seems to work. It's simple Egui character echo that's broken under Wine.

Requesting a redraw from about_to_wait is to insure that all other events on the event queue get processed before the redraw. Last year, there was trouble when my redraw itself called request_redraw, because that seemed to be able to starve out event queue processing.

My test program, ui-mock, is single thread, so this isn't the Wine memory allocator futex congestion bug from 2024. (The locking around Wine's "malloc" can be forced into congestion collapse by doing "push" on Rust vectors from multiple threads, because they use a spinlock in the allocator and the lock is held during the copy of a "realloc". It's not that problem this time. One thread.)

I realize that Winit is basically just delivering whatever event queue semantics the platform provides. Much of this depends on how
Wine has its own event queue processing; it's not running Windows code for that. Somehow Wine and Winit are not playing well together. As mentioned, Linux/X11, real Windows, and MacOS have been tested and work. (I use Wine for testing because I don't have a Windows machine with a decent GPU available.)

Is there a test facility in Winit for logging all the events that come from the platform, before Winit does its fanout into callbacks? That would help here. I need to see what Wine is sending to Winit. Thanks.

@kchibisov
Copy link
Member

I bet that WM_PAINT is getting delayed, which you could track by checking if RedrawRequested got delayed. But generally no, there's no logging, since platforms do provide their ways to log all of that.

@John-Nagle
Copy link
Author

Found out how to enable Wine event logging:

WINEDEBUG+event wine ui-mock.exe

This just dumps too much info to standard error. More later after I figure out what Wine is trying to tell me.

@John-Nagle
Copy link
Author

timing3r.txt

Wine is delaying KeyPress events about two seconds per key press. I have no idea why.

Winit seems to be processing the AboutToWait->request_redraw->redraw sequence just fine. In release mode, there's about a 100 microsecond delay between AboutToWait and redraw starting. More like a millisecond in debug mode. Redraws are ticking along at screen refresh rate, while KeyPress events get held up somewhere over many redraw cycles.

Reproduce by building as above, then running with

WINEDEBUG=+event wine ui-mock.exe 2> /tmp/timing3r.txt

which is how the attached log was generated. The items with timestamps are from my code; the ones without are Wine logging.

I'm going to point the Wine guys over here. On the one hand, if it works on Windows, it's supposed to work on Wine. On the other hand, if this happened for other programs, no game would work on Wine, yet most of them do work.

Are there any funny Win32 event loop modes that Winit uses differently than most programs?

@John-Nagle
Copy link
Author

Tried Wine 10.0 (stable) Previously was using 9.0. No key delays with Wine 10.0

But something funny is going on with mouse position info. The program, under Wine only, seems to be getting mouse positions as if they are about 10 pixels below where they really are. That's new.

Anyway, probably not a Winit problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B - bug Dang, that shouldn't have happened DS - windows
Development

No branches or pull requests

2 participants