Animate with Vsync

I’m keen to use Vsync because without it movement can be a bit stuttery. What’s the best approach to make go.animate play back at the same duration on various devices (iPhone on low power mode, external monitors)? Is using delta time the only option?

ps. This is slightly related to this post, but this is a more general question about animations not taking physics into account.

This kind of works, but is a bit choppy on desktop only (for some reason).

Maybe one option would be to control all important animations completely with code and multiply by delta time?

If go.animate() doesn’t respect the duration and delay given when the function is called it should be considered a bug that we need to fix. I’m not really sure of what problems we might have, if any. @Johan_Beck-Noren knows.

It seems to me that when using animate vs. moving the sprite “manually” each frame, the animate stutters a bit, as if it’s skipping frames. I’ll see if I can work up a minimal example to make sure the stutter isn’t IN MY MIND.

1 Like

Conclusion: I can’t see any difference between animate and frame by frame. The stuttery issue happens when run on an external monitor, regardless of Vsync.

Vsync unticked and Frame cap 0 seems to be smooth on mobile and the laptop screen.

The project if anyone wants to tinker: AnimateVsFramebyframe.zip (66.2 KB)

Would it be possible to control Vsync and frame cap at runtime? Then I’d be able to cater for devices manually, so all players don’t get the “lowest denominator”.

Bump?

Vsync is controllable from runtime via message set_vsync; https://www.defold.com/ref/sys/#set_vsync:swap_interval.

Frame cap maps to the (old) name for it, update_frequency and can be set in runtime; https://www.defold.com/ref/sys/#set_update_frequency:frequency

If you haven’t seen it already, you can find out more here; https://www.defold.com/manuals/project-settings/#_vsync_frame_cap_and_swap_interval

I think for us to cover all these corner cases we need to measure actual time in the engine. For this to be viable we need to be able to keep physics running with a fixed timestep regardless of the engine time-step (DEF-3796). This work is ongoing but it’s a big task that we want to get right, and it’s not planned to be released in the next few releases.

2 Likes

Amazing answer. Thanks!

1 Like

Setting Vsync on and frame cap to 60:
msg.post("@system:", "set_vsync", { swap_interval = 1 } )
msg.post("@system:", "set_update_frequency", { frequency = 60 } )

Setting Vsync off and frame cap to 0:
msg.post("@system:", "set_vsync", { swap_interval = 0 } )
msg.post("@system:", "set_update_frequency", { frequency = 0 } )

Is this right? When turning off Vsync with the code above, I get very stuttery movement.

1 Like

Bump

Can you expand on this? Is the timing off or are you just seeing tearing? Tearing would be an expected result when turning vsync off since drawing to the back buffer is no longer in sync with the monitor’s vblank.

So when I say stuttery I actually mean frame rate drops to 5fps or so; things still work but update very slowly. I’m assuming the syntax I’m using is wrong, so would like to know how to set Vsync off and frame cap to 0 programmatically?

If you disable vsync in game.project instead, is the behaviour the same?

When I set it in game.project (and not in code) it works as expected. I’d rather not do this, though, because on most devices Vsync at 60fps would work fine, so I’d prefer to detect the edge cases and set those to Vsync off and frame cap 0.

1 Like

Sure, I was just trying to figure out where the problem is :slight_smile:

It seems you found a case where we don’t use the correct state in the engine when vsync/framcap is set in runtime. Could you try swapping the order of the messages? E.g. set update frequency first and then swap interval.

2 Likes

Cool, will try that tomorrow!

Same result I’m afraid. I tested with @britzl’s metrics extension, and the framerate drops and keeps dropping to around 1fps with this code:

msg.post("@system:", "set_update_frequency", { frequency = 0 } )
msg.post("@system:", "set_vsync", { swap_interval = 0 } )

Hmm that sounds really strange, the above messages shouldn’t affect performance in that way at all. Are you doing lots of heavy-lifting in any script update? If you send me the project I can have a look.