-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Fix jittering when live resizing the main window #5013
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
Conversation
Set `CAOpenGLLayer.isAsynchronous` to true when live resizing Reference implementation: https://github.com/mpv-player/mpv/blob/4ec060f9465ad1b2151fdf36671681cd9900fc63/video/out/mac/gl_layer.swift
Not bad, but looks like only a partial fix for #4667. Anything which calls |
Oh, I was searching for that issue but I didn't find that. I'll try to extend the fix for that issue. |
Added fix for pinch-to-zoom. I've tried to set async when entering/exiting full screen, but that didn't help. I think the animation of fullscreen should be another problem. |
Very nice! And yeah, looks like when
I think you might be right. Can say it's out of scope. |
When I was testing to resize the window, I also notice that, with this PR, when the OSC is not displayed, we got the smoothest resizing. However, if the OSC is displayed while resizing (especially the top and bottom one), the framerate drops. I profiled IINA while resizing the window, and the most time-consuming part on main thread is on autolayout. For every frame when the window is live resizing, the system triggers a If my hypothesis is correct, then I don't see a simple solution to this. This should be a separate issue as well. I put it here because it's easier to observe using this PR. |
Mmm yes. I did some similar profiling, and also did a bunch of work rendering thumbnails, and my conclusion is: anything starting with But I also found this blog post which suggests changing the From that post I created this thing, which I executed on extension NSView {
/// Recursive func which configures all views in the given subtree for smoother animation.
///
/// By configuring each view to use a layer with the correct redraw policy, AppKit will use Core Animation to draw
/// them, which uses a dedicated background thread instead of the main thread and does not make excessive draws.
func configureSubtreeForCoreAnimation() {
if self is NSButton || self is NSSlider || self is NSProgressIndicator {
// these still need to be redrawn on every resize or they get very buggy
return
}
self.wantsLayer = true
self.layerContentsRedrawPolicy = .onSetNeedsDisplay
for subview in self.subviews {
subview.configureSubtreeForCoreAnimation()
}
}
} With this, resizing does appear smoother to me, but I feel like it needs more exploration. |
Oh wow thanks for pointing this out, I always assumed that layer backed views did this by default because I observed during live resizes that the video layer content was being scaled (instead of rerendered at the new frame size), but maybe what it's actually doing for CAOpenGLLayer at least is triggering a re-draw but with a target opengl viewport size as the initial frame size. I don't know much about rest of iina, but at least for the video layer it would seem like an easy performance win to set this to "onSetNeedsDisplay" since redrawing at the original frame size is completely redundant. Only thing to check is that when the video layer is in async mode we still periodically get called during a live-resize even when set to |
@krackers hope you see this comment since the PR is now closed - I have noticed this as well. In particular, if the video is left paused ~~ for at least 6 seconds (i.e., so that the display link has stopped)~~ then when resizing the window, the I think what is happening in this case is:
So even if a window resize results in extra unneeded calls to It looks to be the case (as relating to window resizing at least) that the performance problems are coming the But coming back to the video scaling issue you identified...while I don't think it's a serious performance concern, it is certainly visually unpleasant and it would be nice to improve it, so I am open to any ideas. EDIT 1: I realized I didn't talk about the case where the video is playing during resize. But the result is essentially the same as the paused case - the video will rerender when there is a frame to render, not necessarily when the window has resized. This could result in some redraws of the window for which the rendered video's scale is from a previous window size and thus is mismatched. Could this be the cause of the problem? |
For window resize wobbling, the root cause of wobble was that the drawing was not coordinated with the resizing. Resizing happens on the main thread, and before this PR the drawing happened on the separate thread mostly independently. Because of this, you could have cases where the the system resizes the frame but the last draw was for the older frame size. (Now CAOpenGLLayer resizes things so it's not as noticeable in most cases, but for low-fps video where draw is less often, this mismatch is responsible for jittering.) Traditional (non layer backed) openglviews have this issue too. It's not very well documented so I had to piece together this, but if you draw to opengl on a non-main thread you run into similar issues getting proper live resize to work: you essentially need to ensure that in a live resize the main thread only unblocks after a frame with the proper size is rendered, or you get glitches (this can be done either by just drawing in the main thread [with proper locking], or making the main thread wait until the 2nd thread finishes rendering). You could try to fix sync CAOpenGLlayer use by forcing a redraw whenever the window size changes in a live resize, but this also technically still exhibits the same issue because it's not being synchronized with the frame resizing of the main thread (although any resulting wobble is likely negligible enough to be unnoticeable). It is also more likely to exhibit performance issues because now you're essentially redrawing at resize fps (which may be the screen fps?). This PR fixes it by making drawing async. It seems when CAOpenGLLayer is marked async, during a live-resize the system never updates the glViewport until the end. Not sure why you say it has to do with displayLink, I've never tested IINA in particular but for mpv at least it's purely a property of being async and is reproducible: the gl viewport is unchanged during live resize. This fixes wobbles, at the cost of introducing blurriness. I wonder if theoretically instead of using |
@krackers I did some more investigation on the blurriness issue and it looks like it might be another problem entirely. Forget the display link - I had that mixed up in my mind with a separate issue which is no longer relevant. Let's move this conversation to #5022 which I just opened which is more relevant and also not closed. |
Description:
Fix #4667
When resizing the player window if the video is playing on a modern macOS, the rendering is unstable and jittering. Note this issue cannot be reproduced on a x86 macOS 10.15.
Set
CAOpenGLLayer.isAsynchronous
to true when live resizing.Reference implementation: https://github.com/mpv-player/mpv/blob/4ec060f9465ad1b2151fdf36671681cd9900fc63/video/out/mac/gl_layer.swift
Before:
jittering.mov
After:
stable.mov