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

Very slow event processing (seconds) #570

Closed
John-Nagle opened this issue Jan 18, 2024 · 9 comments · Fixed by #576
Closed

Very slow event processing (seconds) #570

John-Nagle opened this issue Jan 18, 2024 · 9 comments · Fixed by #576

Comments

@John-Nagle
Copy link
Contributor

The Windows event queue, as emulated under Wine, appears to work differently than the real one under Windows 10.

If you build my Rust test program, ui-mock, arc branch:

[code]
git clone https://github.com/John-Nagle/ui-mock.git
cd ui-mock
git checkout arc
cargo build --release --target x86_64-pc-windows-gnu --examples
cd target/x86_64-pc-windows-gnu/release/examples
wine ui-mock.exe
[/code]

it will run fine under real Windows 10. But, built on Ubuntu 22.04 LTS with current Rust, it behaves strangely.
Click on one of the big bars that says "placeholder", and you get get a login popup. It doesn't do anything; this is just a GUI dummy.
Type something into the user name box.

On real Windows, characters are echoed at full speed.

[b]Under Wine 8 or 9, character echo is delayed about 3-4 seconds.[/b]

What seems to be happening is that the endless refreshing of the screen (this is a game-type program) is starving out event processing.

This uses the Rust crates Rend3, Winit, egui, and wgpu, all of which work cross-platform.
A newer version of Rend3 (see the Cargo.toml file for the rev number) has a different approach to the event loop. There are two callback functions - "event", and "redraw" in Rend3's framework. The framework itself does a request-redraw at the end of each redraw. This seems to starve out non-redraw event processing.

An earlier version of Rend3 did not have this problem. That older version can be built as above, by removing the line

git checkout arc

This uses a different version of the Rend3 framework, one which only redraws when the event queue is empty.

"winit", a standard Rust crate, claims in its documentation that non-redraw events are always processed before redraws. But "winit", which has platform-dependent code for Windows, seems to assume, in the Windows platform code, that the underlying platform event queue does that. For real Windows, it does seem to do that. But Wine's event queue does not seem to work that way.

Also reported as a Wine bug: https://bugs.winehq.org/show_bug.cgi?id=56210

@John-Nagle
Copy link
Contributor Author

I think this is broken due to changes in Winit's Event Loop 3.0. See

rust-windowing/winit#2900

"Document that RedrawRequested is no longer guaranteed to be delivered in order with respect to any other event - it is platform specific".

I don't think this is working right for LInux, either - it takes several redraw cycles before keyboard input gets processed. Not as bad as Wine, though.

I think that implies that RedrawRequested should be called only in MainEventsCleared, to avoid problems. That's what the Winit docs seem to indicate is correct behavior.

@dev-rain
Copy link

dev-rain commented Feb 14, 2024

Hi @John-Nagle,

Came by your issue here by reading winit el 3.0 thread which backlinks to this, I just wanted to clarify that it is indeed recommended that continuous rendering be achieved from RedrawRequested.

rust-windowing/winit#2900 (comment)

In response to the bullet point you cited, as clarity on it has been needed before:

"Technically, yes NewEvents is going to be called before RedrawRequested, and AboutToWait should be called afterwards but there's no precise relationship guaranteed. NewEvents + AboutToWait may be dispatched many times e.g. due to input or other events and RedrawRequested isn't necessarily going to be called each time the event loop wakes up."

To paraphrase; here rib is clearing up that there is no guarantees about the ordering of delivery of a typical NewEvent -> RedrawRequested -> AboutToWait sequence might come in through each iteration of the event loop - but they will all come through on each iteration (be they intercepted by the OS internal loop or otherwise). Further to this from kchibisov:

Calling redraw_requested from RedrawRequested itself is supported and guaranteed to work on all the platforms. It'll properly send it on the next frame.

I don't mean to suggest that I can say for sure that wine isn't losing track of the winit event input somehow, and it would seem on the surface there is an apparent correlation between your issue and the old/new winit event loop.

I think that implies that RedrawRequested should be called only in MainEventsCleared, to avoid problems. That's what the Winit docs seem to indicate is correct behavior.

Yeah, the docs are out of step in places. MainEventsCleared no longer exists as per this: rust-windowing/winit#2976.

Just wanted to clarify these points, not sure I actually helped except to say winit would expect that rend calls for redraws in RedrawRequested, and rend is doing so.

edit: fixed the link to pr2976

@John-Nagle
Copy link
Contributor Author

Hm. I suspect, but am not sure, that Winit is relying on the underlying platform to un-duplicate redraw events.
Wine may not be doing that. The Winit people say they don't test with Wine. The Wine people keep asking me for more info. Is there some way to get an event log out of Winit?

MainEventsCleared is not totally gone; it was renamed to AboutToWait, but current documentation discourages its use.

"and it would seem on the surface there is an apparent correlation between your issue and the old/new winit event loop."

There definitely is. You can build both and try them; they're on different branches of ui-mock, my dummy GUI test program.

@John-Nagle
Copy link
Contributor Author

The Rend3 event loop now makes the request redraw call unconditionally. So I can't even try workarounds.

@maroider
Copy link

Is there some way to get an event log out of Winit?

Would this be a log of WM_* messages?

@John-Nagle
Copy link
Contributor Author

Something like that. Then I could figure out if this is Winit or Wine or Rend3.

@maroider
Copy link

I basically haven't paid attention to Winit since mid-September last year, but there wasn't a built-in way to get a log like that at that time. I have this gist I used to paste in on the rare occasion I needed it myself. IIRC, you should be able to stick a call to dbg_msg here-ish, filling in the recurse_depth with userdata.recurse_depth.

@John-Nagle
Copy link
Contributor Author

If I do that, I create an environment that others cannot reproduce, and the Wine people will close my bug report as UNCONFIRMED. In a finger-pointing situation like this, where Rend3, Winit, and Wine all blame each other, there has to be clarity.

@John-Nagle
Copy link
Contributor Author

John-Nagle commented Feb 16, 2024

I've tested with a modified version of rend3-framework. I took out the call to window.request_redraw at the end of the framework's redraw. In the application, I added an event case for winit::event::Event::AboutToWait which calls window.request_redraw();

That fixed the slow echo.

So, regardless of claims to the contrary in the Winit documentation, doing request_redraw on every redraw doesn't work, and this does.

So I would like window.request_redraw taken out of the framework. That doesn't work as a mandatory action. Let the application control this.

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 a pull request may close this issue.

3 participants