winit: Winit `run_return` and Android does not get `Resumed` and `Suspended`
Hi!
I have noticed there are some inconsistencies (or at least it appears so) when running an event loop using run_return compared to run. I have tried creating as small as possible repro example Android Activity Winit Glutin where I have taken a working example and replaced the run with run_return and I cannot get the messages Resumed or Suspended to arrive.
More specifically see this commit diff
I can get the Resumed event to arrive if I don’t exit the loop when I get Event::MainEventsCleared, however that is a bit unexpected.
Please let me know if I have missed something important that will make the events appear.
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 99 (97 by maintainers)
Commits related to this issue
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Re-work event loop run APIs Overall this re-works the APIs for how an `EventLoop` is run to cover these use-cases, with varying portability caveats: 1. A portable `run()` API that consumes the `Even... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
- Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand This adds two new extensions for running a Winit event loop which will replace `EventLoopExtRunReturn` The `run_return` API is trying to solve ... — committed to rib/winit by rib a year ago
Yeah, no rush with it.
After syncing internally two things are clear about the needs from our engine
Our current logic relies on an exit code to report errors, flush queued up logs and other things may not have fully completed. Comment: This can be reworked to worked to be included into a event loop and nothing appears to be preventing this. Just needs a bit of work.
We need tight control over frame phasing, at least on traditional desktop platforms. Mobile is a bit unclear how much we need/can control frame phasing at the moment but might change in the future. Comment: I cannot emphasize enough how important the rendering timing for a game engine, maybe this is already accounted for on relevant platforms? Another long term thing we consider is having some support for technologies like Nvidia Reflex
Summary
From the information I have gathered it appears that nothing is blocking us from ultimately switching to a pure
runimplementation. Given that requirement 2 is either already possible or can be fleshed out in the future. Though short term its probably not the solution to switch directly, but rather investigate and poke at the problem internally. Short to mid term, it would beneficial to haverunthat can return with an exit code and not be called again. Especially considering the requirement mentioned here #2709. Where on iOS and Web, that does not return, special treatment will have to done on these platforms on the application layer if the application assumes a return is expected.okey, I’d like to clarify a couple of things in the discussion with @kchibisov and then take a step back considering @Hoodad’s follow up…
1st, another ambiguity with what “polling” means…
@kchibisov I think we still have some semantic ambiguity around what “polling” means (separate from the ondemand confusion we had) which is still making it tricky to be clear in this discussion…
At the moment when you’re talking about “polling” you’re focused on the lower-level OS polling, e.g. as done in
mio, such asepollon Linux, and that’s is relevant to this discussion but we also need a way to be clear when we’re talking about the higher level polling that was illustrated in the example for this issue, usingrun_return.I’m going to borrow the term event “pumping” from SDL here because it seems like a good parallel that gives us a separate word from “polling”.
So in this context (based on the example linked for this issue) we can say that (for some platforms) it’s possible to try and integrate Winit into an external even loop by calling
run_returnas a way to “pump” the events for each iteration of the external event loop. In this variation of polling then the app or engine still receives its events via the regular event loop closure/callback and if the app wants to move any event handling outside of winit, into their own event loop, then it’s actually their responsibility to buffer those events however they want, to be processed afterrun_returnexits (such as with theResumedevent in the example).So for this “event pumping” use case, the OS doesn’t necessarily need to support a direct equivalent to
epoll(not possible with RunLoops on MacOS) so long as there is some way to trigger a flush, read, check and process sequence to handle any pending events (basically run the event loop for a very short amount of time).So to answer your question about “How would you do polling on macOS though or on Windows” we need to clarify that we were talking about different kinds of polling and my proposal was really to enable “event pumping” as above (as done in the example for this issue)
To align terms here, lets tweak the API from my proposal to
.start(),.event_pump()and.finish().Event pumping effectively just requires that it’s possible to call (something like)
run_return()to process a single iteration of the event loop with a timeout so that it doesn’t block indefinitely if there are no pending events. The main desktop OS where that’s fiddly is MacOS but it is possible to start a RunLoop with a timeout, so it would run the loop just long enough to dispatch pending events. This is what SDL does: https://github.com/rust-windowing/winit/issues/2706#issuecomment-1464051125 and would be a pretty small change (I’d guess) to the existing macos backend.Break down of use cases + terms that are intertwined with this issue / discussion
run_returnto run the event loop temporarily and handle events normally (inside the Winit closure). After the event loop exits it’s possible the app may want to re-run the event loop for a new, temporary UI.run_return(or.event_pump()) once per iteration of their external loop. This will run the event loop for a very short period of time to flush and handle events (via the event loop closure). It’s assumed that the app or engine may try to buffer events and move the real handling outside of the Winit closure into their external loop instead (unsynchronized event processing). (It’s that last step that causes the majority of the portability hazards here)mioor similar so an external component will handle polling for events. When events are available then a function similar torun_return(such as.event_pump()) can be called that will handle all events normally (inside the Winit closure). I guess for this use case that events are handled, properly synchronized, inside Winit, not unsynchronized, like with (3)/event pumping.I think that my proposal to add
.start(),.event_pump()and.finish()APIs would be applicable for (3) and (4) but I was only thinking about (3) initially. The Smithy use case (4) would also need a way to pump events when the external polling sees that there are events are available.@kchibisov It would be good if you can clarify whether the Smithy use case deals with all event handling synchronized, inside the Winit event loop closure, to see if (3) is the only use case that is trying to handle events unsynchronized, outside of the Winit event loop.
What to do?
Based on being able to handle each of the above use cases, I do generally still think my proposal at the end of https://github.com/rust-windowing/winit/issues/2706#issuecomment-1462423107 was viable - and potentially not that complex to implement either. (and it also sounds OK to not fully consolidating
runacross iOS / web, as discussed).That said though, the use case (3) for this issue depends on unsynchonized handling of events which is not a recommendable, portable design in general.
I think it would technically be relatively simple to support the use case for this issue across Windows, Linux, MacOS and Android with the various caveats and portability hazards discussed earlier - but I tend to think this usage model should only be endorsed if:
One thing to consider is that it may be feasible to incrementally move handling inside Winit until getting to a point where you could hopefully then switch over to just using
runinstead of event pumping.In terms of:
I would certainly say that the use case (3) illustrated by the example for this issue is not a recommendable portable design if it can be avoided (at the very least it would be impossible to support on Web and iOS and has a list of hazards on other OSs too)
But still, it would be possible (and potentially not difficult) to enable some pragmatic support for it (and the same solution looks like it would also be applicable to the Smithy use case (4))
Having read through all the posts, thoughts and suggestions I now start to get a clearer picture of the why certain things are the way the are. When I started this thread I, in my admittingly naïve world view, assumed that polling was the way you would preferably handle events, like as mentioned GetMessage and PollNextEvent. I can see that most of my experiences using polling API’s may just be coming from polling events from an input device. And learning more about how different platforms like iOS and Android handles the system events I can understand the reasoning better why they do what they do. I also get a sense of there being a bit of a shift towards doing more event based loops in the more modern takes on window API’s, but that may just boil down to the newer API’s being more focused on mobile and energy efficiency by giving more control to the OS over the applications lifetime and resources.
With this being said, I’m open to adjust my previous stated stance about trying to stick to
run_return. However, reading through what’s been said it feels likerunisn’t ideal for Android, Windows and in general platforms that can return an exit code. In my particular case the current biggest unknown feels like if there is code that needs to run after the event loop has finished. I will investigate next week.In the end I think what should be the driving factor for a change is the drive to make
winitas cross-platform as possible. Which may end up withwinitnot being the most perfect choice for our particular use-case. Or it may just be that things workout just fine.Not familiar with the history of
run_return, I’d be fine with deprecating it in0.28and removing it in0.29(unless we get reports that we shouldn’t).Linking the lightning talk that
@Osspialdid three years ago about this problem. I think the issue with not having!as the return type is that users kind of expect that they can do stuff afterrun, which they can’t.