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

fix: rewrite winit loop #12669

Merged
merged 54 commits into from
May 2, 2024
Merged

Conversation

pietrosophya
Copy link
Contributor

@pietrosophya pietrosophya commented Mar 23, 2024

Objective

Solution

The Winit loop runs following this flow:

  • NewEvents
  • Any number of other events, that can be 0, including RequestRedraw
  • AboutToWait

Bevy also uses the UpdateMode, to define how the next loop has to run. It can be essentially:

  • Continuous, using ControlFlow::Wait for windowed apps, and ControlFlow::Poll for windowless apps
  • Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a specific wait delay

The changes are made to follow this pattern, so that

  • NewEvents define if the WaitUntil has been canceled because we received a Winit event.
  • AboutToWait:
    • checks if the window has to be redrawn
    • otherwise calls app.update() if the WaitUntil timeout has elapsed
    • updates the ControlFlow accordingly

To make the code more logical:

  • AboutToWait checks if any Bevy's RequestRedraw event has been emitted
  • create_windows is run every cycle, at the beginning of the loop
  • the ActiveState (that could be renamed ActivityState) is updated in AboutToWait, symmetrically for WillSuspend/WillResume
  • the AppExit events are checked every loop cycle, to exit the app early

Platform-specific testing

  • Windows
  • MacOs
  • Linux (x11)
  • Linux (Wayland)
  • Android
  • iOS
  • WASM/WebGL2 (Chrome)
  • WASM/WebGL2 (Firefox)
  • WASM/WebGL2 (Safari)
  • WASM/WebGpu (Chrome)

@alice-i-cecile
Copy link
Member

Does this also fix #12106?

@alice-i-cecile alice-i-cecile added A-Windowing Platform-agnostic interface layer to run your app in C-Code-Quality A section of code that is hard to understand or change labels Mar 23, 2024
@alice-i-cecile alice-i-cecile added the C-Bug An unexpected or incorrect behavior label Mar 23, 2024
@alice-i-cecile alice-i-cecile added this to the 0.14 milestone Mar 23, 2024
@pietrosophya
Copy link
Contributor Author

pietrosophya commented Mar 23, 2024

I don't have a Windows machine unfortunately.

I tested these successfully on MacOS:

  • the game_menu example (using the Quit button)
  • the ecs_guide example (windowless, it exits correctly when the game ends)
  • the low_power example (using both CTRL+C from the command line, and the window close button)
  • the desk_toy example (right click on the logo)

examples/window/low_power.rs Outdated Show resolved Hide resolved
@BD103
Copy link
Member

BD103 commented Mar 23, 2024

I tested this on my M1 Macbook, both by using ci and by running random examples. It all seems to work!

@alice-i-cecile
Copy link
Member

@pietrosophya I've added a section on platform-specific testing to the PR description: please feel free to update the checklist as reviewer reports come in :)

@pietrosophya
Copy link
Contributor Author

pietrosophya commented Mar 24, 2024

@alice-i-cecile thank you! I also tested WASM on both Chrome and Firefox, do I have to update the list or is it for reviewers only to check platforms off?

@alice-i-cecile
Copy link
Member

alice-i-cecile commented Mar 24, 2024

Go ahead and check this off yourself :) I've also added Safari: I forgot that its web support is also different and weird.

@mockersf
Copy link
Member

wasm/webgl2 support is mostly the same across browsers for the event loop, but wasm/webgpu needs to be tested too

@hymm
Copy link
Contributor

hymm commented Mar 29, 2024

Tested on windows 11 with most of the window example. Seems to work fine.

@kristoff3r
Copy link
Contributor

kristoff3r commented Mar 29, 2024

Tested every example relating to windows and a few other ones on Linux with X11 and XMonad, no issues found.

@wolf-in-space
Copy link

wolf-in-space commented Mar 29, 2024

Tested the window examples on Linux with Wayland and Sway, with the Wayland feature enabled and disabled: Only issue i noticed was transparent_window not working when the Wayland feature is enabled, but the issue is the same on main / 13.1, was also mentioned in #10929 already. Noticed no issues from this pr.

@pietrosophya
Copy link
Contributor Author

I fixed the suspension in Android, I had to test it on a previous forked version because of this. I took another refactoring opportunity and moved some comments to clarify them.

@eero-lehtinen could you try android again?

@eero-lehtinen
Copy link
Contributor

eero-lehtinen commented Apr 24, 2024

It works perfectly for me now on Android.

@pietrosophya
Copy link
Contributor Author

Tested on the iOS emulator, it works well (suspending and resuming music too).

@eero-lehtinen
Copy link
Contributor

winit 0.30 was released, so maybe we need more rewrites :D

@mockersf mockersf requested a review from Maximetinu May 1, 2024 00:11
@mockersf
Copy link
Member

mockersf commented May 1, 2024

looks OK to me, except for an enum name. Could you change it and resolve conflicts?

@Maximetinu I'm requesting a new review as the PR changed, please re-review if you can

Copy link
Contributor

@Maximetinu Maximetinu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Maximetinu I'm requesting a new review as the PR changed, please re-review if you can

Done! It still LGTM, approved ✅

There are some more ideas to clean up this part of the code that I think are interesting to consider, but they may be out of scope for this PR, specially if we don't want to introduce breaking changes:

  • The difference between UpdateModes Reactive and ReactiveLowPower is only the kind of events (window and/or device) that should trigger an update, so we could merge them into a single Reactive, with 2 booleans to expose this customizability. Maybe even Continuous could eventually converge into the same type as well. To keep the same current simplicity to the user, we could expose 2 different constructors for UpdateMode: UpdateMode::reactive() and UpdateMode::reactive_low_power() in the same way we have WinitSettings::desktop_app() and WinitSettings::game(). The reason for this is that the user may not want to update due to window or device events at all, so the update is controlled manually in some other way, like from an external host app by a request redraw user event through the event loop proxy.

  • The fact that the UserEvent of the Event Loop Proxy is named RequestRedraw makes it easy to confuse with the WindowEvent::RedrawRequested. I often mix that one up with Event::UserEvent(RequestRedraw). In fact, since the RequestRedraw event can now be sent through the Event Loop Proxy, should it still be an ECS event at all? From the user POV, we now have 2 different ways to request a redraw: through the proxy or through the ECS command, and it's unclear to me if the 2 are exactly the same or not. But I don't have an strong opinion on how to solve this or make this clearer tbh.

@pietrosophya
Copy link
Contributor Author

@mockersf I resolved conflicts and changed the name. I'll create another PR after this is merged to make this new UpdateState and the ApplicationLifecycle converge since they mean the same thing.

Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with the improvements to code quality and bug fixes here, and think this is adequately tested. I'm going to leave an approval and get this merged no later than next Monday to ensure that it gets into the hands of folks to test.

@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label May 2, 2024
@alice-i-cecile alice-i-cecile added this pull request to the merge queue May 2, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks May 2, 2024
@alice-i-cecile
Copy link
Member

error[E0277]: the trait bound Result<RawHandleWrapper, HandleError>: bevy_ecs::bundle::Bundle is not satisfied

https://github.com/bevyengine/bevy/actions/runs/8929016345/job/24525847476

@pietrosophya once that's fixed ping me and I'll retry the merge.

@pietrosophya
Copy link
Contributor Author

@alice-i-cecile argh, sorry about that, it's fixed now.

@mockersf mockersf added this pull request to the merge queue May 2, 2024
Merged via the queue into bevyengine:main with commit 5ee1b40 May 2, 2024
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Windowing Platform-agnostic interface layer to run your app in C-Bug An unexpected or incorrect behavior C-Code-Quality A section of code that is hard to understand or change S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CPU spikes when running the unfocused app in web