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: Delay the window creation until it's time to draw #2562

Merged
merged 11 commits into from
May 19, 2024

Conversation

fredizzimo
Copy link
Member

@fredizzimo fredizzimo commented May 18, 2024

What kind of change does this PR introduce?

Instead of creating a hidden window and then potentially resize and show it, we now create the windows inside the event loop with the correct size on demand.

This fixes a few macOS issues, and also some flickering and bad animation when the window is created. It also probably fixes some issues with tiling window managers

Did this PR introduce a breaking change?

  • No

@fredizzimo fredizzimo force-pushed the fsundvik/move-window-creation branch from 0fda75d to 133c54b Compare May 18, 2024 18:01
@fredizzimo
Copy link
Member Author

Sorry, this still need some fixing on macOS

@sid-6581
Copy link
Contributor

sid-6581 commented May 18, 2024

With regards to the white flickering, oddly enough I'm not experiencing this on my home system with a 4090, but I am experiencing it constantly on my work system with a 3070Ti. I'll check it on my work system on Monday. (Edit: When I say I'm not experiencing it, I meant even with the latest commit from the main branch, not this PR specifically.)

What I am seeing otherwise on this PR on my home system with a 4090, is that a window frame is created with the wrong size initially, then it flickers away and is resized to the correct size. The wrong size window frame is empty (meaning nothing is drawn inside the frame at all, it still just shows the apps underneath it), and after resizing, the frame is still hollow for a split second before the contents are drawn.

I'll try to debug it and see if it's an easy fix on Windows.

@fredizzimo
Copy link
Member Author

@sid-6581, I think I might know the reason. It's not taking the scale factor into account before the window is created. I'm actually fixing that now, since I noticed during the macOS fixing.

@fredizzimo
Copy link
Member Author

The monitor handle has a scale factor, https://rust-windowing.github.io/winit/winit/monitor/struct.MonitorHandle.html#method.scale_factor, but I don't know how to get the monitor where the Window is going to be created.

@fredizzimo
Copy link
Member Author

@sid-6581 Alacritty seem to resize the window immediately after it's created, so maybe we can get away with that?

https://github.com/alacritty/alacritty/blob/38fed9a7c233e11e5f62433298235281fc3de885/alacritty/src/display/mod.rs#L415-L418

Could you test by, callingself.renderer.grid_renderer.handle_scale_factor with the correct scale factor immediately after the window is crated.

Then do the size calculations, as before, and finally call window.set_inner_size()

@fredizzimo
Copy link
Member Author

@sid-6581, I made those changes, it does not seem to have any bad effects on Wayland at least

@fredizzimo fredizzimo force-pushed the fsundvik/move-window-creation branch from d7e1338 to 95fc3a1 Compare May 18, 2024 19:33
@sid-6581
Copy link
Contributor

@fredizzimo now it is actually worse for some reason. It still creates the big empty frame, then it resizes it down to a frame that is too small (but in the correct position), before it finally resizes it to the correct size. So one extra wrong sized frame in the middle compared to previously.

@fredizzimo
Copy link
Member Author

Strange, I guess the first thing to check is that neither of these are resizes do anything after the initial creation

if resize_requested {
// Resize requests (columns/lines) have priority over normal window sizing.
// So, deal with them first and resize the window programmatically.
// The new window size will then be processed in the following frame.
self.update_window_size_from_grid();
} else if skia_renderer.window().is_minimized() != Some(true) {
// NOTE: Only actually resize the grid when the window is not minimized
// Some platforms return a zero size when that is the case, so we should not try to resize to that.
let new_size = skia_renderer.window().inner_size();
if self.saved_inner_size != new_size || self.font_changed_last_frame || padding_changed
{
self.window_padding = window_padding;
self.saved_inner_size = new_size;
self.update_grid_size_from_window();
should_render = ShouldRender::Immediately;

Copy link

github-actions bot commented May 18, 2024

Test Results

  6 files  ±0    6 suites  ±0   21s ⏱️ +7s
110 tests ±0  110 ✅ ±0  0 💤 ±0  0 ❌ ±0 
644 runs  ±0  644 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 78df78f. ± Comparison against base commit 818ff73.

♻️ This comment has been updated with latest results.

@fredizzimo
Copy link
Member Author

fredizzimo commented May 18, 2024

On wayland everything is smooth with just one nice animation to the final size. I tested both without scaling and with scaling, and the following cases

  1. Starting normally, letting the window resize to the previous size
  2. Starting with --grid 100x50
  3. Starting with --size 500x500
  4. Starting with --grid and set lines and columns in my init.lua
  5. Starting with --maximized
  6. --grid 100x50 with columns=200 and lines=25, it ends up as 100x50
  7. --size 500x500withcolumns=200andlines=25, it ends up as 500x500` pixels

@sid-6581
Copy link
Contributor

@fredizzimo these changes fixed things on Windows for me (I have to confirm the white flashing on my work computer still):

image

Does that mess anything up on Wayland?

@fredizzimo
Copy link
Member Author

@sid-6581, it seems to work perfectly, I pushed the changes

@fredizzimo
Copy link
Member Author

fredizzimo commented May 18, 2024

Actually, I managed to test it on Windows through remote desktop. And I observed the following with the new changes.

  1. With D3D the window is transparent with a frame for a while before it's rendered
  2. With --opengl there's a quite bad white flash.

I guess we need to either render sooner after, or first clear the window with the Neovim background color and for D3D composition only enable it after the first frame has been rendered.

Edit: The size stays correct all the time.

@fredizzimo
Copy link
Member Author

I have not profiled it, but I guess it's loading the fonts, and therefore the first frame is delayed too much.

I don't think that can be avoided when the scale factor changes, or even when the guifont is updated right before the window is shown.

@fredizzimo
Copy link
Member Author

fredizzimo commented May 18, 2024

I did some profiling, and the loading of the font is fast, due to the caching, but the whole create window action takes a long time. And the first frame render also takes 140ms. So, I think the only option we have is to set the window color when creating the window to the background color.

image

@fredizzimo
Copy link
Member Author

I think I have resolved the flickering issues now on D3D. This also works well in Wayland.

On Windows OpenGL there's still a white flash, but I don't think there's much to do about it, I think we need lower-level access to the windows messages than winit provides to do that, for example paint inside the actual WM_PAINT message.

I have not tried X11 or macOS and how this interacts with tiling window managers. So, it would be nice if someone could test that.

@fredizzimo
Copy link
Member Author

fredizzimo commented May 19, 2024

As a side-note, it would be nice to have some splash screen or even just a mouse cursor indicating that Neovide is starting on Windows, especially when using WSL, when it can take 10s of seconds, especially when there's a cold start of WSL

But even just launching the native version is quite slow:
image

Most of the time is spent enumerating adapters and creating the D3D device. I'm not sure what happens before that, but on Linux the launching is al

On Linux on the other hand the launching is much faster, but I think it could still be optimized a bit if the font loading was not a blocking operation.

image

- add debug attribute to `titlebarclickhandler` struct
- add debug attribute to `macoswindowfeature` struct
- refactor code to initialize `window` variable using `skia_renderer` field
- refactor code to calculate `window_padding_top` with `macos_feature` field involvement
@sid-6581
Copy link
Contributor

@fredizzimo I can confirm that everything looks great right now on my home Windows 11 system. No empty frames with Direct3D. As you mentioned, there is a white flash with OpenGL, and from what I remember that is caused by the long initialization without processing WM_PAINT messages.

@falcucci
Copy link
Member

I've at least done some changes and committed here to compile on macOS for now.

I also have been through every issue mentioned here related to macOS and all of them seems to be gone.

@fredizzimo
Copy link
Member Author

I'm going to merge this now, to get a bit more testing on main before we do a release.

@fredizzimo fredizzimo merged commit 9d5a3e9 into neovide:main May 19, 2024
12 checks passed
@sid-6581
Copy link
Contributor

@fredizzimo I'm back on my work computer, and I can confirm that this also fixes the white flash on it, with Direct3D.

I'll also check Direct3D on my laptops, because I think it wasn't picking the right adapter before, so it was really slow. Hopefully some of the latest changes help with that, but if not I'll dig into the reason.

zbyna pushed a commit to zbyna/neovide that referenced this pull request Jun 1, 2024
* Create the error window inside the event loop

* Move the window creation inside the event loop

* Resize the window after creation for the correct scale factor

* Fix macOS build

* Create Window as hidden, show after resizing

* Add some profiling

* Resize and position window immediately after creation

* Move the macOS feature creation before the window resizing

* Show the window only after the first frame has renderered

* Show the window immediately on Wayland

* fix: debugging and window initialization improvements

- add debug attribute to `titlebarclickhandler` struct
- add debug attribute to `macoswindowfeature` struct
- refactor code to initialize `window` variable using `skia_renderer` field
- refactor code to calculate `window_padding_top` with `macos_feature` field involvement

---------

Co-authored-by: Alexsander Falcucci <alex.falcucci@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment