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

Improve waiting for messages on Windows [PR to 0.30.x branch] #3949

Conversation

AngelicosPhosphoros
Copy link

@AngelicosPhosphoros AngelicosPhosphoros commented Oct 13, 2024

Previous version used CreateTimer with GetMessageW for waiting. The downside of UI timers like ones created by CreateTimer, is that they may be late by up to 15-16 ms.

To fix this behaviour, I added use of high precision timers created by CreateWaitableTimerExW with the flag CREATE_WAITABLE_TIMER_HIGH_RESOLUTION. In my previous experience, waiting on such timers have precision of roundly 0.5 ms which is the best available on Windows at the moment. I use MsgWaitForMultipleObjectsEx to wait simultaneously for both timer and newly arriving events.

Unfortunately, high precision timers are available only since Windows 10 1803. However:

  1. Win 10 is already getting to the end of support, like all previous versions, so it is OK to rely on APIs introduced in it;
  2. I use dwMilliseconds parameter of MsgWaitForMultipleObjectsEx as a fallback. It should perform not worse compared to waiting for events from [CreateTimer].

I also refactored code to remove event dispatching from function responsible for waiting for events. This provides more clear separations of concern and avoids unnecessary duplication of dispatching logic.

I have tested behaviour using a egui app with Vulkan rendering with VK_PRESENT_MODE_IMMEDIATE_KHR, and older version consistently have twice less FPS than requested (e.g. 30 FPS when limit is 60 and 60 FPS when limit is 120) while newer version works more correctly (almost always 60 FPS when limit is 60, and only 5-10 frames missing whne FPS is set to 120 or more).

Fixes #1610

  • Tested on all platforms changed
  • Added an entry to the changelog module if knowledge of this change could be valuable to users
  • Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
  • Created or updated an example program if it would help users understand this functionality
  • Updated feature matrix, if new features were added or implemented

@AngelicosPhosphoros
Copy link
Author

Current version in crates.io:

TestWith0.30.5.mp4

With my changes:

TestWithPatch.mp4

@AngelicosPhosphoros
Copy link
Author

AngelicosPhosphoros commented Oct 13, 2024

I don't know why but when I run cargo fmt locally, it changes bunch of files except the one changed in PR.

I would manually change formatting.

Previous version used `CreateTimer` with `GetMessageW` for waiting.
The downside of UI timers like ones created by `CreateTimer`,
is that they may be late by up to 15-16 ms.

To fix this behaviour, I added use of high precision timers created by [`CreateWaitableTimerExW`] with the flag `CREATE_WAITABLE_TIMER_HIGH_RESOLUTION`.
In my previous experience, waiting on such timers have precision of roundly 0.5 ms which is the best available on Windows at the moment.
I use [`MsgWaitForMultipleObjectsEx`] to wait simultaneously for both timer and newly arriving events.

Unfortunately, high precision timers are available only since Windows 10 1803. However:

1. Win 10 is already getting to the end of support, like all previous versions, so it is OK to rely on APIs introduced in it;
2. I use `dwMilliseconds` parameter of `MsgWaitForMultipleObjectsEx` as a fallback. It should perform not worse compared to waiting for events from [`CreateTimer`].

I also refactored code to remove event dispatching from function responsible for waiting for events. This provides more clear separations of concern and avoids unnecessary duplication of dispatching logic.

I have tested behaviour using a egui app with Vulkan rendering with `VK_PRESENT_MODE_IMMEDIATE_KHR`, and older version consistently have twice less FPS than requested (e.g. 30 FPS when limit is 60 and 60 FPS when limit is 120) while newer version works more correctly (almost always 60 FPS when limit is 60, and only 5-10 frames missing whne FPS is set to 120 or more).

Fixes rust-windowing#1610

[`CreateWaitableTimerExW`]: https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createwaitabletimerexw
[`MsgWaitForMultipleObjectsEx`]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-msgwaitformultipleobjectsex
@kchibisov
Copy link
Member

Please, open your changes against the master branch.

You should use the nightly formatting.

@AngelicosPhosphoros
Copy link
Author

@kchibisov If my code gets merged to master, would those changes be ported and released as 0.30.x? I just finished migration to 0.30.x and I fear that I would need to wait long time for egui and egui-winit to catch up.

@AngelicosPhosphoros AngelicosPhosphoros changed the title Improve waiting for messages on Windows Improve waiting for messages on Windows [PR to 0.30.x branch] Oct 13, 2024
@AngelicosPhosphoros
Copy link
Author

Opened PR to master: #3950

@kchibisov
Copy link
Member

I don't see why not. The only issue is that we currently lack active windows maintainer, so getting things reviewed could be a bit hard, unless e.g. @notgull wants to look into that.

I myself don't really look into windows stuff.

@kchibisov
Copy link
Member

Closing in favor of #3950.

@kchibisov kchibisov closed this Oct 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants