JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.99k stars 1.16k forks source link

Scroll functionality in LWJGL example causes unexplained freeze #4930

Closed Decencies closed 3 months ago

Decencies commented 3 months ago

Description Scroll functionality in LWJGL example causes unexplained freeze.

Affected platforms

Versions

To Reproduce Steps to reproduce the behavior:

  1. Run this code snippet:

    @Composable
    fun App() {
    val gridState = rememberLazyGridState()
    
    LazyVerticalGrid(
        state = gridState,
        columns = GridCells.Fixed(1)
    ) {
        items(100) {
            BasicText("Scroll me to crash!")
        }
    }
    }
  2. Scroll up or down
  3. Ponder

Expected behavior The process does not unexpectedly hang, and handles the scroll event the same way as it does in the default Desktop implementation.

Screenshots

https://github.com/JetBrains/compose-multiplatform/assets/66835910/c0c1b926-2f23-440f-84da-a672872a5d24

Decencies commented 3 months ago

Thread dump yields:

(this thread dump uses a slight variation of the code, replacing LazyGridState with ScrollableState and using the scrollable modifier with Orientation.Vertical)

"main@1" prio=5 tid=0x1 nid=NA waiting for monitor entry
  java.lang.Thread.State: BLOCKED
     blocks AWT-EventQueue-0@3741
     waiting for AWT-EventQueue-0@3741 to release lock on <0xf52> (a androidx.compose.runtime.SynchronizedObject)
      at androidx.compose.runtime.Recomposer$recompositionRunner$2$unregisterApplyObserver$1.invoke(Synchronization.kt:33)
      at androidx.compose.runtime.Recomposer$recompositionRunner$2$unregisterApplyObserver$1.invoke(Recomposer.kt:976)
      at androidx.compose.runtime.snapshots.SnapshotKt.advanceGlobalSnapshot(Snapshot.kt:1816)
      at androidx.compose.runtime.snapshots.SnapshotKt.takeNewSnapshot(Snapshot.kt:1834)
      at androidx.compose.runtime.snapshots.SnapshotKt.access$takeNewSnapshot(Snapshot.kt:1)
      at androidx.compose.runtime.snapshots.GlobalSnapshot.takeNestedMutableSnapshot(Snapshot.kt:1344)
      at androidx.compose.runtime.snapshots.TransparentObserverMutableSnapshot.takeNestedMutableSnapshot(Snapshot.kt:1553)
      at androidx.compose.runtime.snapshots.TransparentObserverMutableSnapshot.takeNestedMutableSnapshot(Snapshot.kt:1541)
      at androidx.compose.runtime.snapshots.Snapshot$Companion.takeMutableSnapshot(Snapshot.kt:405)
      at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1220)
      at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime(Composer.kt:3600)
      at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:633)
      at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:619)
      at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcomposeInto(SubcomposeLayout.kt:500)
      at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:472)
      at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:463)
      at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:447)
      at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose(SubcomposeLayout.kt:872)
      at androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScopeImpl.measure-0kLqBqw(LazyLayoutMeasureScope.kt:125)
      at androidx.compose.foundation.lazy.grid.LazyGridMeasuredItemProvider.getAndMeasure-3p2s80s(LazyGridMeasuredItemProvider.kt:45)
      at androidx.compose.foundation.lazy.grid.LazyGridMeasuredLineProvider.getAndMeasure(LazyGridMeasuredLineProvider.kt:78)
      at androidx.compose.foundation.lazy.grid.LazyGridMeasureKt.measureLazyGrid-W2FL7xs(LazyGridMeasure.kt:170)
      at androidx.compose.foundation.lazy.grid.LazyGridKt$rememberLazyGridMeasurePolicy$1$1.invoke-0kLqBqw(LazyGrid.kt:341)
      at androidx.compose.foundation.lazy.grid.LazyGridKt$rememberLazyGridMeasurePolicy$1$1.invoke(LazyGrid.kt:177)
      at androidx.compose.foundation.lazy.layout.LazyLayoutKt$LazyLayout$3$2$1.invoke-0kLqBqw(LazyLayout.kt:107)
      at androidx.compose.foundation.lazy.layout.LazyLayoutKt$LazyLayout$3$2$1.invoke(LazyLayout.kt:100)
      at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:709)
      at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
      at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:646)
      at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
      at androidx.compose.foundation.layout.PaddingNode.measure-3p2s80s(Padding.kt:397)
      at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
      at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
      at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
      at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:132)
      at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
      at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
      at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
      at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
      at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
      at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
      at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
      at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui(LayoutNode.kt:1145)
      at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:354)
      at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout-0kLqBqw(MeasureAndLayoutDelegate.kt:439)
      at androidx.compose.ui.node.RootNodeOwner$OwnerImpl.measureAndLayout-0kLqBqw(RootNodeOwner.skiko.kt:322)
      at androidx.compose.ui.node.LayoutNode.forceRemeasure(LayoutNode.kt:1219)
      at androidx.compose.foundation.lazy.grid.LazyGridState.onScroll$foundation(LazyGridState.kt:333)
      at androidx.compose.foundation.lazy.grid.LazyGridState$scrollableState$1.invoke(LazyGridState.kt:177)
      at androidx.compose.foundation.lazy.grid.LazyGridState$scrollableState$1.invoke(LazyGridState.kt:177)
      at androidx.compose.foundation.gestures.DefaultScrollableState$scrollScope$1.scrollBy(ScrollableState.kt:166)
      at androidx.compose.foundation.gestures.ScrollingLogic$dispatchScroll$performScroll$1.invoke-MK-Hz9U(Scrollable.kt:693)
      at androidx.compose.foundation.gestures.ScrollingLogic$dispatchScroll$performScroll$1.invoke(Scrollable.kt:683)
      at androidx.compose.foundation.gestures.ScrollingLogic.dispatchScroll-3eAAhYA(Scrollable.kt:707)
      at androidx.compose.foundation.gestures.MouseWheelScrollNode.dispatchMouseWheelScroll(MouseWheelScrollable.kt:312)
      at androidx.compose.foundation.gestures.MouseWheelScrollNode.access$dispatchMouseWheelScroll(MouseWheelScrollable.kt:54)
      at androidx.compose.foundation.gestures.MouseWheelScrollNode$animateMouseWheelScroll$2.invoke(MouseWheelScrollable.kt:297)
      at androidx.compose.foundation.gestures.MouseWheelScrollNode$animateMouseWheelScroll$2.invoke(MouseWheelScrollable.kt:287)
      at androidx.compose.animation.core.SuspendAnimationKt.doAnimationFrame(SuspendAnimation.kt:361)
      at androidx.compose.animation.core.SuspendAnimationKt.doAnimationFrameWithScale(SuspendAnimation.kt:339)
      at androidx.compose.animation.core.SuspendAnimationKt.access$doAnimationFrameWithScale(SuspendAnimation.kt:1)
      at androidx.compose.animation.core.SuspendAnimationKt$animate$9.invoke(SuspendAnimation.kt:279)
      at androidx.compose.animation.core.SuspendAnimationKt$animate$9.invoke(SuspendAnimation.kt:278)
      at androidx.compose.animation.core.SuspendAnimationKt$callWithFrameNanos$2.invoke(SuspendAnimation.kt:304)
      at androidx.compose.animation.core.SuspendAnimationKt$callWithFrameNanos$2.invoke(SuspendAnimation.kt:303)
      at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
      at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
      - locked <0xf50> (a androidx.compose.runtime.SynchronizedObject)
      at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:558)
      at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:551)
      at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
      at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
      - locked <0xf51> (a androidx.compose.runtime.SynchronizedObject)
      at androidx.compose.ui.scene.BaseComposeScene.render(BaseComposeScene.skiko.kt:161)
      at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:262)
      at MainKt.main$render(main.kt:40)
      at MainKt.access$main$render(main.kt:1)
      at MainKt$main$frameDispatcher$1.invokeSuspend(main.kt:46)
      at MainKt$main$frameDispatcher$1.invoke(main.kt:-1)
      at MainKt$main$frameDispatcher$1.invoke(main.kt:-1)
      at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
      at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
      at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
      at GlfwCoroutineDispatcher.runLoop(GlfwCoroutineDispatcher.kt:18)
      at MainKt.main(main.kt:66)
      at MainKt.main(main.kt:-1)
Decencies commented 3 months ago

Minimum reproduction:

@Composable
fun App() {
    val gridState = rememberLazyGridState()

    LazyVerticalGrid(
        state = gridState,
        columns = GridCells.Fixed(1)
    ) {
        items(100) {
            BasicText("Scroll me to crash!")
        }
    }
}
terrakok commented 3 months ago

It seems windows specific. On macos works fine issues-4930.zip

m-sasha commented 3 months ago

This is likely to be the same as https://github.com/JetBrains/compose-multiplatform/issues/4788

Decencies commented 3 months ago

This is likely to be the same as https://github.com/JetBrains/compose-multiplatform/issues/4788

Yep, seems to suffer the same SnapshotManager issue.

terrakok commented 3 months ago

I close it as a duplicate.

okushnikov commented 2 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.