Open hgourvest opened 10 months ago
Thanks! Is it reproduced only on physical device? (or also on simulator) Is it reproduced on iPhone as well?
I only have a 9th generation iPad, and I'm developing on an Apple Mini M1. On the simulator I'm up to 50 frame seconds, which isn't too bad. But on the iPad I'm stuck at 30 frame seconds instead of 60.
Here's a video showing the expected rendering. https://youtu.be/8lltz_cENXY
And here's what I use to count frames. You have to move your finger very quickly
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.calculatePan
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.rememberTextMeasurer
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.coroutineScope
import kotlin.time.DurationUnit
import kotlin.time.TimeSource
@Composable
fun buggy() {
var pos by remember { mutableStateOf(0f) }
var count = 0
var mark = TimeSource.Monotonic.markNow()
var rate = 0
val precision = 120
Canvas(modifier = Modifier.fillMaxSize().background(Color.DarkGray).pointerInput(true){
coroutineScope {
awaitEachGesture {
do {
awaitFirstDown(requireUnconsumed = false)
do {
val event = awaitPointerEvent()
val panChange = event.calculatePan()
if (panChange != Offset.Zero) {
pos -= panChange.x
}
val canceled = event.changes.any { it.isConsumed }
} while (!canceled)
} while (false)
}
}
}){
if (count == precision) {
rate = (1000 * precision / mark.elapsedNow().toLong(DurationUnit.MILLISECONDS)).toInt()
count = 0
mark = TimeSource.Monotonic.markNow()
} else
count++
println("$rate")
drawRect(color = Color.Gray, size = Size((size.width - pos).coerceAtLeast(0f), size.height))
}
}
Can you measure FPS when adding withFrameNanos
with infinite loop inside LaunchedEffect?
It doesn't seem effective to me. It doesn't give me frames when I move fast.
If it helps, the animations don't seem to be affected by this bug.
I tested with Kotlin 1.9.20 and Compose 1.5.10. There is an improvement, it now run at 40 FPS. Unfortunately, the problem is still visible.
I found a workaround, by changing the state value in a coroutine
@Composable
fun buggy() {
var pos by remember { mutableStateOf(0f) }
Canvas(modifier = Modifier.fillMaxSize().background(Color.DarkGray).pointerInput(true){
coroutineScope {
awaitEachGesture {
do {
awaitFirstDown(requireUnconsumed = false)
do {
val event = awaitPointerEvent()
val panChange = event.calculatePan()
if (panChange != Offset.Zero) {
// iOS workaround
launch {
pos -= panChange.x
}
}
val canceled = event.changes.any { it.isConsumed }
} while (!canceled)
} while (false)
}
}
}){
drawRect(color = Color.Gray, size = Size((size.width - pos).coerceAtLeast(0f), size.height))
}
}
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.
Describe the problem
I experiencing low frame rate
Affected platforms
iOS
Versions
Sample code
Reproduction steps
move your finger from right to left
Video
https://youtu.be/NkknOuQljDo
Profiling data
I don't have that
Additional information
Use this component, which forces the frame rate to the maximum, to see the difference with the expected behavior.