Skip to content

Commit

Permalink
Window: Fix live-lock when animationFrame is slow
Browse files Browse the repository at this point in the history
If the window is sufficiently complex, it's possible for the average
`animationFrame` to take so long we'll start falling behind with no way to ever
catch up. And the amount of frames we're behind will quickly grow to the point
where we'll be spending five seconds in `animationFrame` before we can get a
real frame on the screen.
Or even worse with the old while-loop, we'll be stuck indefinitely because the
five seconds check only happens outside the loop and we never get to exit the
loop if we never catch up, effectively locking up the game.

To prevent that, we limit the `animationFrame` calls we make per real frame such
that we'll still be able to render approximately 30 real frames per second at
the cost of animations slowing down.

GitHub: #104
  • Loading branch information
Johni0702 authored Apr 20, 2023
1 parent 3f8c2b5 commit 3ffa44f
Showing 1 changed file with 9 additions and 1 deletion.
10 changes: 9 additions & 1 deletion src/main/kotlin/gg/essential/elementa/components/Window.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,15 @@ class Window @JvmOverloads constructor(
if (System.currentTimeMillis() - this.systemTime > TimeUnit.SECONDS.toMillis(5))
this.systemTime = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(5)

while (this.systemTime < System.currentTimeMillis() + 1000 / animationFPS) {
val target = System.currentTimeMillis() + 1000 / animationFPS
val animationFrames = (target - this.systemTime).toInt() / animationFPS
// If the window is sufficiently complex, it's possible for the average `animationFrame` to take so long
// we'll start falling behind with no way to ever catch up. And the amount of frames we're behind will
// quickly grow to the point where we'll be spending five seconds in `animationFrame` before we can get a
// real frame on the screen.
// To prevent that, we limit the `animationFrame` calls we make per real frame such that we'll still be able
// to render approximately 30 real frames per second at the cost of animations slowing down.
repeat(animationFrames.coerceAtMost((animationFPS / 30).coerceAtLeast(1))) {
animationFrame()
this.systemTime += 1000 / animationFPS
}
Expand Down

0 comments on commit 3ffa44f

Please sign in to comment.