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

App time variance #37

Open
UkoeHB opened this issue Apr 18, 2023 · 6 comments
Open

App time variance #37

UkoeHB opened this issue Apr 18, 2023 · 6 comments

Comments

@UkoeHB
Copy link

UkoeHB commented Apr 18, 2023

Framepacing adds a delay between the previous frame's presentation and the beginning of the current frame's update cycle. It calculates that delay based on the duration of the previous frame's update cycle.

If the current frame's update cycle takes longer than the previous frame, then the current frame's duration (from previous frame's presentation to current frame's presentation), will be longer than the target duration. This is a problem when vsync is enabled, because the current frame will miss the frame buffer refresh that comes after the previous frame's presentation step (the previous frame was 'just in time' for the buffer swap, but the current frame is 'just too late'). As a result, the previous frame will be presented twice. Depending on the vsync buffering strategy and how many frames are buffered, the current frame may be stuck on the frame presentation step all the way until the next buffer refresh.

Even very low variance in update cycle times can therefore lead to frequent frame drops on machines with unbuffered vsync. On machines with buffered vsync I think you will instead see occasional stutter based on desync between frame presentation and the time stamps of the beginning of update cycles.

Frame loss for unbuffered vsync can be solved by adding a 'buffer' to the framepace sleep based on the variance of app times (e.g. 2 standard deviations).

Since vsync is not always on, you'd need an additional framerate limiter just prior to the frame presentation step, which can absorb any remaining time to reach the target frametime. @aevyrie has observed that on machines with buffered vsync you get better results by targeting a slower framerate than the monitor refresh period -> a framerate limiter would allow compile-time configuration to achieve the best strategy for any given machine.

@aevyrie
Copy link
Owner

aevyrie commented Apr 18, 2023

Since vsync is not always on, you'd need an additional framerate limiter just prior to the frame presentation step, which can absorb any remaining time to reach the target frametime.

FWIW, this was actually the initial design of this plugin.

0ms -----------------------
            Estimate how long the next frame will take, minus a small margin to give us space if it takes longer
            Sleep for this duration. (Forward estimation)
8ms         Start of event loop. Get input. Do stuff.
11.8ms      See how close our estimate was to the requested frame time, sleep if required to get the frametime just right
12ms        Send to GPU, present frame (input is 4ms out of date)
16ms ----------------------

That was taken from my comments in the initial discussion that spawned this plugin: bevyengine/bevy#3317

However, in practice I had a lot of trouble getting good results from it. This may have predated my use of spin_sleep, so it may be worth revisiting that approach.

@UkoeHB
Copy link
Author

UkoeHB commented Apr 18, 2023

However, in practice I had a lot of trouble getting good results from it. This may have predated my use of spin_sleep, so it may be worth revisiting that approach.

Yeah you'd essentially need to duplicate the framepace PID controller for the framerate limiter. You need very accurate sleep times.

@aevyrie
Copy link
Owner

aevyrie commented Apr 18, 2023

Yup, I did play around with writing a PID controller, but I may have been limited by platform sleep time accuracy/variance. Definitely worth revisiting this, I appreciate your deep-dive.

@MatthewScholefield
Copy link

Appreciate the investigation into this. Would be great to get this improved. I can replicate frequent stutters on my machine under Wayland.

@UkoeHB
Copy link
Author

UkoeHB commented Nov 7, 2023

@MatthewScholefield a comprehensive rework of this crate is blocked by bevy's render code, which doesn't currently expose timing information for presenting frames.

@aevyrie
Copy link
Owner

aevyrie commented Nov 10, 2023

Unfortunately that is the case. I can take another look at the PID impl if I get the time, but it's low on my priority list as I expect improvements will be minor until we can properly measure vblanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants