Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07a66114 authored by Omar Miatello's avatar Omar Miatello
Browse files

MM: fast path to calculate output/target in MotionValues when stable

When a MotionValue is stable (i.e., there's no animation happening), we
can calculate the output and the targetOutput directly from the previous
mapping or animation.

The fast path enabled performance gains of up to 20x in some of our
tests.

Test: MotionValueBenchmark (run on AS, results go/mm-microbenchmarks)
Test: atest MotionValueTest
Bug: 404975090
Flag: com.android.systemui.scene_container
Change-Id: I041ddb8411832e746924b7c6ada0771d02656de9
parent 8c5e4b54
Loading
Loading
Loading
Loading
+18 −16
Original line number Diff line number Diff line
@@ -376,7 +376,8 @@ private class ObservableComputations(
                    directMappedVelocity = 0f
                }

                var scheduleNextFrame = !isStable
                var scheduleNextFrame = false
                if (!isSameSegmentAndAtRest) {
                    if (capturedSegment != currentSegment) {
                        capturedSegment = currentSegment
                        scheduleNextFrame = true
@@ -396,6 +397,7 @@ private class ObservableComputations(
                        capturedSpringState = currentSpringState
                        scheduleNextFrame = true
                    }
                }

                if (capturedInput != currentInput) {
                    capturedInput = currentInput
+39 −6
Original line number Diff line number Diff line
@@ -423,22 +423,55 @@ internal interface ComputeSpringState : ComputeAnimation {
internal interface Computations : ComputeSpringState {
    val currentSpringState: SpringState

    val isSameSegmentAndAtRest: Boolean
        get() =
            lastAnimation.isAtRest &&
                lastSegment.spec == spec &&
                lastSegment.isValidForInput(currentInput, currentDirection)

    val currentDirectMapped: Float
        get() = currentSegment.mapping.map(currentInput) - currentAnimation.targetValue
        get() =
            if (isSameSegmentAndAtRest) {
                lastSegment.mapping.map(currentInput)
            } else {
                currentSegment.mapping.map(currentInput) - currentAnimation.targetValue
            }

    val currentAnimatedDelta: Float
        get() = currentAnimation.targetValue + currentSpringState.displacement
        get() =
            if (isSameSegmentAndAtRest) {
                0f
            } else {
                currentAnimation.targetValue + currentSpringState.displacement
            }

    val output: Float
        get() = currentDirectMapped + currentAnimatedDelta
        get() =
            if (isSameSegmentAndAtRest) {
                lastSegment.mapping.map(currentInput)
            } else {
                currentDirectMapped + currentAnimatedDelta
            }

    val outputTarget: Float
        get() = currentDirectMapped + currentAnimation.targetValue
        get() =
            if (isSameSegmentAndAtRest) {
                lastAnimation.targetValue
            } else {
                currentDirectMapped + currentAnimation.targetValue
            }

    val isStable: Boolean
        get() = currentSpringState == SpringState.AtRest
        get() =
            if (isSameSegmentAndAtRest) {
                true
            } else {
                currentSpringState == SpringState.AtRest
            }

    fun <T> semanticState(semanticKey: SemanticKey<T>): T? {
        return with(currentSegment) { spec.semanticState(semanticKey, key) }
        return with(if (isSameSegmentAndAtRest) lastSegment else currentSegment) {
            spec.semanticState(semanticKey, key)
        }
    }
}
+6 −4
Original line number Diff line number Diff line
@@ -277,10 +277,12 @@ private class ImperativeComputations(

        currentAnimationTimeNanos = frameTimeMillis * 1_000_000L

        if (!isSameSegmentAndAtRest) {
            currentSegment = computeCurrentSegment()
            currentGuaranteeState = computeCurrentGuaranteeState()
            currentAnimation = computeCurrentAnimation()
            currentSpringState = computeCurrentSpringState()
        }

        debugInspector?.run {
            frame =