opened
SenseiRalph
username_0
The concurrent key press issue has been fixed by [reverting back to winit](https://github.com/username_2/neovide/issues/244#issuecomment-865750061), but this introduced somewhat laggy cursor animations. They look like they have a lower framerate to them, like 30 fps instead of 60.

I built Neovide today (2021-05-06) on Windows 21H1. My previous build was from 2021-05-06 and had smooth cursor animations but had [this](https://github.com/username_2/neovide/issues/244) issue (now fixed). Both builds were made following the instructions on the repo main page.
Lower framerate cursor animations with winit
issue
created
shaunsingh
username_1
Hi, could you please provide a screenrecording if possible?
comment
created
Kethku
username_2
I think I've also noticed this problem. I believe it has to do with the way that the animation loop works. Currently it uses the WaitUntil https://docs.rs/winit/0.25.0/winit/event_loop/enum.ControlFlow.html#variant.WaitUntil to run the animation loop. Either this should be swapped to RequestAnimationFrame style looping or we should swap to Poll and try to sleep at appropriate time to make sure we don't just spin the cpu.

I took a stab at this earlier this week, but gave up with my initial approach using Wait and RequestAnimationFrame because I was trying too hard to hack it in.

If anybody has any thoughts in this regard I'm all ears as I think this should probably block the next release.
comment
created
fredizzimo
username_3
I suggest that you try to decouple the rendering loop from the event loop. Yes I know that's not an easy task, but that would give you much more control, you can for example enable vsync, and get very precise timing.

But even with the current loop, or with a separate render thread, but vsync disabled, you should be able to do much better if you fix your timestep to the display refresh rate, or a divisor of it. That can be done using an accumulator like Glenn Fiedler describes in this excellent article https://gafferongames.com/post/fix_your_timestep/. But forget the "The final touchup section" with interpolation, that's not applicable here, since you can decide your timestep, even on the fly.

You also need to make sure that you try to render the frame at least at this rate, preferably twice the rate, because it does not matter that you render the same frame twice in a vblank interval, it's still only going to be displayed once and look smooth. Otherwise it's very easy to miss a frame.  

With vsync that's easy to do, but without vsync, you need to simulate it. So instead of letting the time drift, like you do with `previous_frame_start + frame_duration`, you do `expected_frame_length_seconds * ceil(current_time / expected_frame_length_seconds)`, which should wait until the next time exactly divisible by the frame length. `current_time` should be read just before calling `WaitUntil`, since the most important thing is to come out of the wait at an as consistent rate as possible.

If the `expected_frame_length_seconds`, corresponds exactly to the monitor refresh rate, then the above technique might jitter quite a bit if you are unlucky, since it's possible that the expected frame starts are very close to the vsync times, and then it can constantly jump between the previous and next frames. That's why twice the rate is better. Alternatively you could try using 59 Hz instead of 60 Hz for example (for the rendering, the update stays at 60Hz), then you would only see a skipped frame once per second, which is much better.

I hope this at least helps you get some ideas, since improvements can likely be seen even when just implementing parts of this. I also can't guarantee that it will work in your case, since I'm taking the general ideas from the top of my head , but with some experience after working almost 20 years in the games industry.
comment
created
Kethku
username_2
Super valuable insight. Another part of it that may be valuable is to make the frame drops visible in some way. Lots of systems display graphs of frame times via some sort of spark line. I can't help but think having an option which overlays information like that would make addressing this issue easier.

Currently all we have to go on is "it feels slower" which is hard to turn into actionable changes, and even if we make a change, its not obvious how to verify that it worked.

I figure something as simple as just putting the frame length in a rolling buffer and then displaying that on the screen would be valuable, but I'm curious if you have any thoughts or insight to give for verifying responsiveness.
comment
created
fredizzimo
username_3
I just tested it. The Game Bar built into Windows can show graphs and FPS https://www.howtogeek.com/706162/how-to-see-fps-in-any-windows-10-game-without-extra-software/.  I'm getting between 30-40 FPS on a Ryzen 5 5600 with  RX3060... 

I have never used it, since we use custom tools, but this profiler looks very cool https://github.com/wolfpld/tracy, for really digging into performance problems. I found it when I was checking out  this library https://github.com/ocornut/imgui, which is often used for making ingame graphs and counters like that, but probably not usable for you since it's for c++.

And yes rolling buffers, are usually used for that. With them you can can also track other statistics like, min, max, median 90 percentile and so on. But at least for this project it's best to stay simple, since implementing those can take quite some time. And hopefully the Game Bar is enough.
comment
created
Kethku
username_2
Hadn't thought to use the game bar. Thats a fantastic idea. And 30-40 fps is absolutely not sufficient. Again, thanks so much for the thoughts. An extra set of experienced eyes on the system makes a world of difference
comment
created
Kethku
username_2
https://github.com/neovide/neovide/pull/1201 addresses this issue by restructuring our event loop to poll by default and fall back to waiting when not animating. On my machine, I regularly hit close to my monitors refresh rate (modulo some occasional frame drops).

This doesn't implement rendering on a background thread though as that would involve a much larger change which I don't fully understand yet. The system also does not implement keeping track of a rolling frame offset, but instead just changes the current system to render at 1.1 the requested framerate 😅 This isn't correct... but is good enough for now and we can improve it later.

@username_3 if you have the time, could you take a look at the changes? Its not what you suggested, but related and I figure you may have ideas to improve it further.
comment