-
Notifications
You must be signed in to change notification settings - Fork 279
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
Way of rendering synchronously for resizing on macOS #1640
Comments
Since the mac resize loop occurs on the main rendering thread, it should be fine to call |
@mstange can explain what we do in Firefox |
Oh I might be misunderstanding how Webrender works. Does I was under the impression that telling Webrender to render a frame just submitted work to another thread that did the actual work and called Then the question is: Why do I get the delay that creates the wobbly effect when other apps don't seem to have the delay? |
The The The general flow is:
Because of this, it's safe to call You might like to check Servo and see if the resize is working correctly (it did previously, but I wouldn't be surprised if it's broken). If it's working, that may be a reasonable way to compare what you're seeing (although we are of course on a terribly old glutin fork right now). |
Okay that explains the behaviour I'm seeing, where the background is extended immediately on resizing but the resized content lags behind. What's happening is that when I get the resize event, I create a new display list based on the new size, and I need to synchronously wait for the backend to build the frame from that display list before calling As far as I can tell there's no built in way to do this. But provided that the Does this sound like the intended kind of way to do something like this? |
I just tested the latest nightly of Servo and resizing no longer works on macOS. I tried my older version of Servo and resize doesn't seem to lag at all, so it's doing something right. I know Servo uses some hacked up custom version of glutin to do live resize though, from before normal glutin supported it. But it still had to have been waiting for frames properly somehow. |
It's not the most elegant solution, but it sounds like that would work. We probably need to consider the "right" way to do this... |
I can explain what we do in pre-webrender Firefox. Firefox with webrender is still broken in this respect. In pre-webrender Firefox, whenever we paint for window resizes or for the first paint of a window during window opening, our NSView's drawRect handler is called. During that handler, we generate a new frame on the main thread, send it to the compositor, and then block while we wait for the compositor to execute the draw calls and to call flushBuffer for that frame. Only then we allow the drawRect handler to complete. We'll have to do something similar with webrender. Compositing whatever processed frame we have at the time of window resizing is not sufficient. When the window resizes, we layout the window at the new size, and we want the result of that layout to be presented to the screen during that same drawRect handler, so we need to synchronously wait for the newly generated frame to be processed and presented. |
@mstange thanks for the insight! My follow up question is that I notice that Chrome, Safari and Firefox all continue to animate during resizes, which is another difficult problem on macOS since resizing enters a different event loop. There's a version of winit that solves this problem by using stack-switching coroutines. I'm wondering if Firefox has to do anything special to solve this? Does it just let whatever run loop macOS is currently in drive Firefox and have a |
We run our compositor on a separate thread, and our CVDisplayLink callback (which gets invoked on the CVDisplayLink IOThread) can notify that thread directly (without going through the main thread), so compositor-side animations don't need to worry about the macOS run loop. On the main thread, we have a CFRunLoopSource which, when called, processes our internal Gecko event queue (with some timeout in order to prevent starving the native event loop). This CFRunLoopSource is registered for kCFRunLoopCommonModes and seems to be called even during window resizing. |
@mstange That's interesting. So if I understand correctly: all OpenGL calls, including swapping buffers, are done in the non-main compositor thread. Freeing time on the main thread for other things and allowing smooth animation during resizing. Does the OpenGL context have to be created on the compositor thread or is it okay to create it on the main thread and do all future calls on the compositor thread? This seems like something I should do in my demo of setting up Webrender properly. Unfortunately, it seems that the current main version of glutin may not support that pattern. It ties the window rather tightly to the OpenGL context. I read the macOS docs on the topic and it seems that all I need to do is activate and call the other context on one thread. Unfortunately, glutin's |
In servo/webrender#1640 we discussed how Firefox (and probably also other browsers) have a compositor thread, which is not the main thread, that does all their OpenGL calls. In glutin this kind of architecture doesn't seem to be possible right now since it's not possible to split the `GlWindow` into the window and the context, and the `Context` doesn't implement `Send` on macOS. The following two changes allow such architectures: - Implement `Send` for `Context` on macOS. The Apple docs suggest that this is correct. - Add a `split` method to `GlWindow` that allows obtaining an owned `Window` and `Context`.
I think it should be OK to create the OpenGL context on the main thread, but we create it on the compositor thread. We also call setView and update on the compositor thread. The only thing that we call on the main thread is Our NSViewGlobalFrameDidChangeNotification observer only flips a bool flag that tells the compositor thread that setView and update need to be called before the next composition. It doesn't do anything with the NSOpenGLContext itself on the main thread. |
As far as I can tell, on macOS in order to look good during window resizing, apps have to paint a frame before returning from the resize callback.
I currently have a prototype using webrender with the latest glutin, which supports live resize. However, the resizing feels bad because the content resizing lags a frame or two behind the window frame changing size. This creates the effect of the content borders looking wobbly. I don't notice this effect in other apps, including Chrome. Using this version of winit doesn't help.
There may be other hacky ways to solve this, but the thing macOS seems to want apps to do is to render synchronously within the resize callback. Currently I can't figure out a good way to do so in Webrender. I'm not sure it's possible if
RenderNotifier
is called on the main thread.Is there a good way to wait synchronously for a frame to be rendered after submitting a new display list? Or does one have to be added? I imagine Servo and Firefox should run into this problem too.
The text was updated successfully, but these errors were encountered: