Hello, is it expected that `ImageComposeScene` ren...
# compose-desktop
l
Hello, is it expected that
ImageComposeScene
renders one frame late, or just renders wrong? I am using this composable where I call
render
repeatedly on the same
ImageComposeScene
, but with ever increasing
nanoTime
values, and I only get the correct render if I call
render
a second time, which is quite of a dirty workaround.
Copy code
@Composable
fun JustFrameNumberComposable() {
    val frameNumber by produceState(0L) {
        while (true) withFrameMillis { frameTimeMillis ->
            value = frameTimeMillis * 60L / 1000L
        }
    }
    Text("Frame number: $frameNumber")
}
a
It’s expected, given this code. The phases of rendering are composition, layout, drawing, effects. In the code you gave, produceState runs in an effect, so the first time render is called, it sets the value, but composition and drawing (with the default value) has already happened.
👍🏼 1
It’s not about ImageComposeScene; the same will be with a regular window - the first frame will show the default value.
l
Is calling render twice the correct way to handle this?
It's not the most expensive part of what I'm doing anyway… The bottleneck is saving those to WEBPs in parallel based on the number of CPU cores so they can be fed to FFMPEG and generate a transparent .mov with Apple ProRes 4444 encoding.
a
You don’t have to call it twice, just take into account that after each call, the text will be with the previous value.
l
There's no way to do pixel & time perfect animations?
a
Not sure what you mean by that.
l
I'd like that at a given frame time, I know exactly what will be shown
I'm generating overlays based on timecodes for video editing (not live)
a
You do. It’s just always the value of the previous render call.
l
Isn't the issue caused by this in
Application.desktop.kt
?
Copy code
private object YieldFrameClock : MonotonicFrameClock {
    override suspend fun <R> withFrameNanos(
        onFrame: (frameTimeNanos: Long) -> R
    ): R {
        // We call `yield` to avoid blocking UI thread. If we don't call this then application
        // can be frozen for the user in some cases as it will not receive any input events.
        //
        // Swing dispatcher will process all pending events and resume after `yield`.
        yield()
        return onFrame(System.nanoTime())
    }
}
To me, the
yield()
should come after
onFrame(…)
in a
finally
block, or after with the result of
onFrame
being put in a local
val
.
a
I’m afk so can’t be sure, but I don’t think that code is relevant when you use ImageComposeScene. You drive the render loop manually, with your own frame times, when you use ImageComposeScene.
👍🏼 1