-
Notifications
You must be signed in to change notification settings - Fork 925
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
Rethinking RedrawRequested #1041
Comments
My gut impulse is that you're trying to make winit do more than it needs to here. It seems like, from the application's perspective, the right thing to do is set a flag if you get a resize event, and then when you get to the point when you decide whether or not to draw, you draw if your application needs to redraw, or if the OS has told you to redraw via a resize event. Either way, from the application writer's perspective, your drawing only happens in one place and only when it's actually necessary. I will have to think about this more, since I still haven't internalized the new event loop as much as you have. |
Part of the confusion with Have you considered decoupling these? I think ideally there would be only one "meta" event that indicates that the event loop has come full circle, but this proposal is adding more. What if |
@icefoxen That's actually not entirely correct! Doing that works fine for games, but it leads to visual issues when resizing the window (at least on Windows) which isn't great for desktop applications. If you want to avoid those visual issues, you must perform all redrawing inside of There's a bit of vagueness in my description there, since it's harder to concretely describe what happens without concrete examples. Luckily, I've prepared some! Check out this repository and run the examples to (hopefully) see what I'm talking about - they illustrate my point nicely on my Windows machine, and I'd be curious to see what they look like on other platforms.
@aloucks Wait, what? They are decoupled.
Here's my rationale behind all the meta-events, for clarity:
|
What is After thinking more about my initial suggestion (single meta event), I can see where it might be problematic for the non-game-loop style app. I think the problem though is still centered around Here's another thought:
And adjust the API usage recommendation to something more like:
And finally (some bikeshedding)... Rename:
I think this naming makes them stand out more as being very closely related. EDIT 1: I definitely think EDIT 2: I just changed one of my projects and could definitely see that resizing wasn't as nice 😢. Back to the drawing board I guess. match event {
Event::EventsCleared => {
if Instant::now() - min_duration >= self.last_frame_time {
self.window.request_redraw();
}
}
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
} => {
self.last_frame_time = Instant::now();
*control_flow = ControlFlow::WaitUntil(self.last_frame_time + min_duration);
for event_handler in event_handlers.iter_mut() {
event_handler.on_frame(&mut self);
}
on_frame(&mut self).expect("on_frame error");
}
_ => {}
} to match event {
Event::EventsCleared => {
if Instant::now() - min_duration >= self.last_frame_time {
self.last_frame_time = Instant::now();
*control_flow = ControlFlow::WaitUntil(self.last_frame_time + min_duration);
for event_handler in event_handlers.iter_mut() {
event_handler.on_frame(&mut self);
}
on_frame(&mut self).expect("on_frame error");
}
}
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
} => {}
_ => {}
} So I'm guessing that repainting from |
@aloucks The issue is, the current API can't do that because it doesn't always unify application-requested and OS-requested redraws. The redesign proposed here fixes that.
That is correct. I don't know if it has the exact same semantics on other platforms, but I'd be extremely surprised if no other platform made similar assumptions that resulted in similar behavior when |
Could this be fixed by injecting another |
Injecting another |
@Osspial Can we also pass a vector of damage reports with |
@zegentzy It's definitely worthwhile to expose the damage report. We may want to expose it via some sort of platform-specific |
Well, for Linux, we got these three things: Afaik, on windows, you just need to call this function here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getupdaterect And macOS seams to pass a rect: winit/src/platform_impl/macos/view.rs Line 283 in a195ce8
Given the similarities, I propose the following:
I think this solution is simple enough. Unresolved issues:
|
Note that (as often), the Wayland semantics are quite different. The wayland server is supposed to keep an internal copy of the contents of the client windows, and as such the client never receives any damage information.
Instead, tne client sends damage information to the server to notify which part of its contents it modified, so that the server can only update this part for better performance. This is automatically handled by Mesa, so winit does not need to worry about it.
|
@zegentzy I wonder why you added the "good first issue" label, to me it looks like the opposite. |
Implementing the solution as suggested by the OP I think is simple enough. You just* need to shuffle some code around to make sure Handling damage information, I'd think, isn't a "good first issue", but, well, I hadn't mentioned that when I labeled it =p. *Maybe a slight understatement. |
@murarth Do you have time to implement this for X? Possibly with damage regions as proposed? |
@zegentzy: Yes, I'll see what I can do. |
I'd like to handle damage regions in a separate PR, since it's logically a separate issue than what's brought up here. As to the
|
That is a good idea. I'll draft something more detailed later this week. |
Implements the changes described in rust-windowing#1041 for the X11 platform and for platform-independent public-facing code.
I've made a branch for handling this: https://github.com/rust-windowing/winit/tree/redraw-requested-2.0 |
Hey, @ jlogandavison, I noticed you said you wanted to gain some experience with wayland. I think this issue would be a great one to dip your toes in. Also, please be sure to add yourself to this table: https://github.com/rust-windowing/winit/wiki/Testers-and-Contributors |
@jlogandavison Thanks for contacting me.
|
If I understand correctly, the new API expects that other platforms with that assumption will also send |
Adding |
* Implement changes to `RedrawRequested` event Implements the changes described in #1041 for the X11 platform and for platform-independent public-facing code. * Fix `request_redraw` example * Fix examples in lib docs * Only issue `RedrawRequested` on final `Expose` event
Really? I've looked through the cocoa documentation, and it seems to suggest otherwise:
I'd consider that a major bug that should be fixed. The Windows API exhibits similar behavior by default, and we do some fairly significant hoop-jumping to avoid exposing that behavior publicly.
Admittedly, this redesign assumes that that's the case. However, since it's pretty much the only sensible way to dispatch redraw events in the context of the broader application, I'd be extremely surprised if other platforms didn't enforce similar ordering. |
Sorry, the apple situation isn't as bad as I made it out to be. iOS's docs say a similar thing as macos's: I wasn't considering redraw events triggered by I haven't yet tested macos, but it sounds like they typically send redraws at the top of the eventloop? I guess that can be worked around somehow. |
* Implement changes to `RedrawRequested` event Implements the changes described in rust-windowing#1041 for the X11 platform and for platform-independent public-facing code. * Fix `request_redraw` example * Fix examples in lib docs * Only issue `RedrawRequested` on final `Expose` event
* Implement changes to `RedrawRequested` event Implements the changes described in rust-windowing#1041 for the X11 platform and for platform-independent public-facing code. * Fix `request_redraw` example * Fix examples in lib docs * Only issue `RedrawRequested` on final `Expose` event
* Implement changes to `RedrawRequested` event Implements the changes described in #1041 for the X11 platform and for platform-independent public-facing code. * Fix `request_redraw` example * Fix examples in lib docs * Only issue `RedrawRequested` on final `Expose` event
* Implement changes to `RedrawRequested` event Implements the changes described in rust-windowing#1041 for the X11 platform and for platform-independent public-facing code. * Fix `request_redraw` example * Fix examples in lib docs * Only issue `RedrawRequested` on final `Expose` event
* Implement changes to `RedrawRequested` event Implements the changes described in #1041 for the X11 platform and for platform-independent public-facing code. * Fix `request_redraw` example * Fix examples in lib docs * Only issue `RedrawRequested` on final `Expose` event
* Implement changes to `RedrawRequested` event Implements the changes described in #1041 for the X11 platform and for platform-independent public-facing code. * Fix `request_redraw` example * Fix examples in lib docs * Only issue `RedrawRequested` on final `Expose` event
* Implement changes to `RedrawRequested` event Implements the changes described in #1041 for the X11 platform and for platform-independent public-facing code. * Fix `request_redraw` example * Fix examples in lib docs * Only issue `RedrawRequested` on final `Expose` event
The current
RedrawRequested
event is currently hard to understand, which makes it difficult to implement and difficult to use. This issue will outline why I believe that is the case, and how I think we should fix it.The current problems
RedrawRequested
is extremely inconsistent with the rest of our API. This is exhibited in a couple ways:request_redraw
is called, but isn't explicitly guaranteed to be the last event if the OS requested the redraw.WindowEvent
, since no other window event provides any sort of ordering guarantees.EventsCleared
, since it can be dispatched afterEventsCleared
if queued withrequest_redraw
during theEventsCleared
handler.Some of that inconsistency is intentional (point 3), and some isn't (point 1), but the end result is that the API is difficult to explain and difficult to implement. Even beyond the complexity those inconsistencies introduce, the current model can result in duplication of
RedrawRequested
events when using the recommended event loop structure described in the root docs. Consider the following chain of events, with an application using the linked event loop structure:RequestRedraw
event.RequestRedraw
betweenNewEvents
andEventsCleared
, as part of the standard control flow.EventsCleared
gets dispatched, upon which the user updates the application's state and callsrequest_redraw
.RequestRedraw
gets dispatched immediately afterEventsCleared
.The above situation has a couple problems: the first
RedrawRequested
is dispatched before the application has a chance to update its internal state, and the application goes through the expensive process of rendering a frame twice in a single iteration of the event loop. Ideally, our API wouldn't exhibit either issue, allowing the user to update their application state before all redraws occur and allowing Winit to unify redraw requests from the user and OS into a single event.Proposed changes
EventsCleared
toMainEventsCleared
RedrawRequested
fromWindowEvent
.RedrawRequested(WindowId)
toEvent
.RedrawRequested
get dispatched betweenMainEventsCleared
andRedrawEventsCleared
.RedrawEventsCleared
toEvent
.The rough event loop would end up behaving something like this (adapted from @icefoxen's example in #1032):
This results in numerous usability improvements over the current model:
RedrawRequested
's status as a special event is made more clear, as it's structurally distinct from standard window events.RedrawRequested
is now guaranteed to be dispatched after event processing and application update code has been run, fitting it more naturally into the application update/render loop.Feedback is encouraged on the above designs, especially WRT naming - I'm not entirely happy with the names I've provided, and mainly included them because I can't think of anything better right now. There may be a better solution to the current API's problems, but I'm presently unable to think of one and we should certainly address them before 0.20's full release.
The text was updated successfully, but these errors were encountered: