-
-
Notifications
You must be signed in to change notification settings - Fork 34
Description
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.