Repository navigation
Register animation frontends with the animation backend (#59585) - #59585
bartlomiejbloniarz wants to merge 2 commits into
Conversation
|
@bartlomiejbloniarz has imported this pull request. If you are a Meta employee, you can view this in D128154522. |
253f3c9 to
87935af
Compare
87935af to
907988d
Compare
Summary: Stacked on #59584. Review the last two commits: the change and its tests. Producers of animation mutations, such as C++ Animated and Reanimated, use the shared animation backend through anonymous frame callbacks. Settings that differ between producers have nowhere to live. A producer can now register once as an `AnimationFrontend` with its frame callback, then start and stop it by id with `startFrontend` and `stopFrontend`. Each frame runs the callbacks passed to `start(callback)` first, then the started frontends in registration order. `start(callback)`, `stop(callbackId)` and `pushAnimationMutations(callback)` are unchanged. C++ Animated now registers a frontend instead of starting a callback. Its frame callback therefore runs after other producers' `start(callback)` callbacks instead of in the order they were started. The next PR adds the first frontend setting. ## Changelog: [INTERNAL] [ADDED] - Let animation producers register with the animation backend as frontends Pull Request resolved: #59585 Test Plan: - `AnimationBackendFrontendTest`: a started frontend runs once per frame, starting and stopping are idempotent, frames are requested while any frontend or callback is started, a frontend without a frame callback is not started, and frames run in registration order after the callbacks. - `NativeAnimatedFrontendTests.registersAndStartsAFrontend`: C++ Animated registers and starts a frontend with the backend instead of starting a callback. - The other `animationbackend` and `animated` gtests pass. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js` and `yarn fantom packages/react-native/Libraries/Animated/__tests__/Animated-itest.js` pass. Differential Revision: D128154522 Pulled By: bartlomiejbloniarz
Summary: Stacked on #59584. Review the last two commits: the change and its tests. Producers of animation mutations, such as C++ Animated and Reanimated, use the shared animation backend through anonymous frame callbacks. Settings that differ between producers have nowhere to live. A producer can now register once as an `AnimationFrontend` with its frame callback, then start and stop it by id with `startFrontend` and `stopFrontend`. Each frame runs the callbacks passed to `start(callback)` first, then the started frontends in registration order. `start(callback)`, `stop(callbackId)` and `pushAnimationMutations(callback)` are unchanged. C++ Animated now registers a frontend instead of starting a callback. Its frame callback therefore runs after other producers' `start(callback)` callbacks instead of in the order they were started. The next PR adds the first frontend setting. ## Changelog: [INTERNAL] [ADDED] - Let animation producers register with the animation backend as frontends Pull Request resolved: #59585 Test Plan: - `AnimationBackendFrontendTest`: a started frontend runs once per frame, starting and stopping are idempotent, frames are requested while any frontend or callback is started, a frontend without a frame callback is not started, and frames run in registration order after the callbacks. - `NativeAnimatedFrontendTests.registersAndStartsAFrontend`: C++ Animated registers and starts a frontend with the backend instead of starting a callback. - The other `animationbackend` and `animated` gtests pass. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js` and `yarn fantom packages/react-native/Libraries/Animated/__tests__/Animated-itest.js` pass. Differential Revision: D128154522 Pulled By: bartlomiejbloniarz
…ation backend (#59586) Summary: Stacked on #59585, which is stacked on #59584. Review the last two commits: the change and its tests. With the shared animation backend, the backend's commit hook writes C++ Animated's latest values into every React commit made while it animates. C++ Animated without the backend does not do this. It writes non-layout props straight to the views, keeps them over React's mounts with `AnimatedMountingOverrideDelegate`, and commits the final values when an animation finishes. This PR adds a way to experiment with the second approach on the backend. It adds `commitDirectProps` to `AnimationFrontend` and the `enableCxxAnimatedDirectPathInBackend` flag. With the flag, C++ Animated registers with `commitDirectProps = false` and behaves as it does without the backend: - The commit hook does not write its direct values into React commits. Layout updates are unchanged. - `AnimatedMountingOverrideDelegate` keeps the values of connected props nodes over React mounts. - The last update of an animation is recorded apart, and the end-of-animation commit writes it. - One end-of-animation commit per surface is scheduled at a time. Without the flag, C++ Animated registers with `commitDirectProps = true` and the end-of-animation commit is unchanged. Turning `commitDirectProps` off without the flag asserts. ## Changelog: [INTERNAL] [ADDED] - Add `enableCxxAnimatedDirectPathInBackend` to keep C++ Animated's direct updates out of React commits with the shared animation backend Pull Request resolved: #59586 Test Plan: **Unit tests.** `AnimatedPropsRegistryTest`, `AnimationBackendFrontendTest` and `NativeAnimatedFrontendTests` cover which values the commit hook writes, when final values are written, taken and restored, that older recorded values do not overwrite a final value, and one end-of-animation commit per surface. The tests for final values and for one commit per surface fail without the code they cover. **Fantom.** - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js` runs with the flag on and off and passes. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackendDirectUpdates-itest.js` checks that a React commit of an animated view keeps its animated value mounted, with the flag on and off. It fails without the mount override delegate. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/Animated-itest.js` passes. I also ran it locally with the backend and the flag forced on. Fantom allows at most 12 flag combinations per file, so that run is not encoded in the file. **Devices.** RNTester on an Android emulator and an iOS simulator, with the backend and C++ Animated on, once with the flag on and once with it off. I tracked a square frame by frame in screen recordings: | Check | Android, flag on | Android, flag off | iOS, flag on | iOS, flag off | |---|---|---|---|---| | React re-renders the view every 50 ms during a looping native animation | No backward jumps | No backward jumps | No backward jumps | No backward jumps | | The animation finishes, then React keeps re-rendering | Keeps the final values | Keeps the final values | Keeps the final values | Keeps the final values | | `setValue(0)`, then React keeps re-rendering | Stays reset | Stays reset | Stays reset | Stays reset | Differential Revision: D128154682 Pulled By: bartlomiejbloniarz
|
@bartlomiejbloniarz has exported this pull request. If you are a Meta employee, you can view the originating Diff in D128154522. |
|
This pull request was successfully merged by @bartlomiejbloniarz in 907988d When will my fix make it into a release? | How to file a pick request? |
|
This pull request was successfully merged by @bartlomiejbloniarz in 6a44efa When will my fix make it into a release? | How to file a pick request? |
Summary: Stacked on #59584. Review the last two commits: the change and its tests. Producers of animation mutations, such as C++ Animated and Reanimated, use the shared animation backend through anonymous frame callbacks. Settings that differ between producers have nowhere to live. A producer can now register once as an `AnimationFrontend` with its frame callback, then start and stop it by id with `startFrontend` and `stopFrontend`. Each frame runs the callbacks passed to `start(callback)` first, then the started frontends in registration order. `start(callback)`, `stop(callbackId)` and `pushAnimationMutations(callback)` are unchanged. C++ Animated now registers a frontend instead of starting a callback. Its frame callback therefore runs after other producers' `start(callback)` callbacks instead of in the order they were started. The next PR adds the first frontend setting. ## Changelog: [INTERNAL] [ADDED] - Let animation producers register with the animation backend as frontends Pull Request resolved: #59585 Test Plan: - `AnimationBackendFrontendTest`: a started frontend runs once per frame, starting and stopping are idempotent, frames are requested while any frontend or callback is started, a frontend without a frame callback is not started, and frames run in registration order after the callbacks. - `NativeAnimatedFrontendTests.registersAndStartsAFrontend`: C++ Animated registers and starts a frontend with the backend instead of starting a callback. - The other `animationbackend` and `animated` gtests pass. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js` and `yarn fantom packages/react-native/Libraries/Animated/__tests__/Animated-itest.js` pass. Differential Revision: D128154522 Pulled By: bartlomiejbloniarz
…ation backend (#59586) Summary: Stacked on #59585, which is stacked on #59584. Review the last two commits: the change and its tests. With the shared animation backend, the backend's commit hook writes C++ Animated's latest values into every React commit made while it animates. C++ Animated without the backend does not do this. It writes non-layout props straight to the views, keeps them over React's mounts with `AnimatedMountingOverrideDelegate`, and commits the final values when an animation finishes. This PR adds a way to experiment with the second approach on the backend. It adds `commitDirectProps` to `AnimationFrontend` and the `enableCxxAnimatedDirectPathInBackend` flag. With the flag, C++ Animated registers with `commitDirectProps = false` and behaves as it does without the backend: - The commit hook does not write its direct values into React commits. Layout updates are unchanged. - `AnimatedMountingOverrideDelegate` keeps the values of connected props nodes over React mounts. - The last update of an animation is recorded apart, and the end-of-animation commit writes it. - One end-of-animation commit per surface is scheduled at a time. Without the flag, C++ Animated registers with `commitDirectProps = true` and the end-of-animation commit is unchanged. Turning `commitDirectProps` off without the flag asserts. ## Changelog: [INTERNAL] [ADDED] - Add `enableCxxAnimatedDirectPathInBackend` to keep C++ Animated's direct updates out of React commits with the shared animation backend Pull Request resolved: #59586 Test Plan: **Unit tests.** `AnimatedPropsRegistryTest`, `AnimationBackendFrontendTest` and `NativeAnimatedFrontendTests` cover which values the commit hook writes, when final values are written, taken and restored, that older recorded values do not overwrite a final value, and one end-of-animation commit per surface. The tests for final values and for one commit per surface fail without the code they cover. **Fantom.** - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js` runs with the flag on and off and passes. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackendDirectUpdates-itest.js` checks that a React commit of an animated view keeps its animated value mounted, with the flag on and off. It fails without the mount override delegate. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/Animated-itest.js` passes. I also ran it locally with the backend and the flag forced on. Fantom allows at most 12 flag combinations per file, so that run is not encoded in the file. **Devices.** RNTester on an Android emulator and an iOS simulator, with the backend and C++ Animated on, once with the flag on and once with it off. I tracked a square frame by frame in screen recordings: | Check | Android, flag on | Android, flag off | iOS, flag on | iOS, flag off | |---|---|---|---|---| | React re-renders the view every 50 ms during a looping native animation | No backward jumps | No backward jumps | No backward jumps | No backward jumps | | The animation finishes, then React keeps re-rendering | Keeps the final values | Keeps the final values | Keeps the final values | Keeps the final values | | `setValue(0)`, then React keeps re-rendering | Stays reset | Stays reset | Stays reset | Stays reset | Differential Revision: D128154682 Pulled By: bartlomiejbloniarz
Visual regression2 visual difference(s) at ios
|
Summary: `UIManager::startSurface` runs the callbacks registered with `UIManager::addOnSurfaceStartCallback` after adding the shadow tree. `UIManager::startEmptySurface`, which `SurfaceHandler` uses when a surface has no module name, only added the shadow tree, so those callbacks never ran for such surfaces. The shared animation backend, `ViewTransitionModule` and C++ Animated set up per-surface state in that callback. C++ Animated installs `AnimatedMountingOverrideDelegate` there. Fantom starts all its surfaces without a module name, so none of them saw a surface start in Fantom tests. `startEmptySurface` now notifies the delegate the same way `startSurface` does. ## Changelog: [GENERAL] [FIXED] - Surfaces started without a module name now run the callbacks registered with `UIManager::addOnSurfaceStartCallback` Pull Request resolved: #59584 Test Plan: - `SchedulerDelegateInvalidationTest.EmptySurfaceStartRunsSurfaceStartCallbacks`: starting a surface with no module name runs a registered surface-start callback with that surface's shadow tree. It fails without this change. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js` passes. Differential Revision: D128154376 Pulled By: bartlomiejbloniarz
Summary: Stacked on #59584. Review the last two commits: the change and its tests. Producers of animation mutations, such as C++ Animated and Reanimated, use the shared animation backend through anonymous frame callbacks. Settings that differ between producers have nowhere to live. A producer can now register once as an `AnimationFrontend` with its frame callback, then start and stop it by id with `startFrontend` and `stopFrontend`. Each frame runs the callbacks passed to `start(callback)` first, then the started frontends in registration order. `start(callback)`, `stop(callbackId)` and `pushAnimationMutations(callback)` are unchanged. C++ Animated now registers a frontend instead of starting a callback. Its frame callback therefore runs after other producers' `start(callback)` callbacks instead of in the order they were started. The next PR adds the first frontend setting. ## Changelog: [INTERNAL] [ADDED] - Let animation producers register with the animation backend as frontends Pull Request resolved: #59585 Test Plan: - `AnimationBackendFrontendTest`: a started frontend runs once per frame, starting and stopping are idempotent, frames are requested while any frontend or callback is started, a frontend without a frame callback is not started, and frames run in registration order after the callbacks. - `NativeAnimatedFrontendTests.registersAndStartsAFrontend`: C++ Animated registers and starts a frontend with the backend instead of starting a callback. - The other `animationbackend` and `animated` gtests pass. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js` and `yarn fantom packages/react-native/Libraries/Animated/__tests__/Animated-itest.js` pass. Differential Revision: D128154522 Pulled By: bartlomiejbloniarz
Summary: Stacked on #59584. Review the last two commits: the change and its tests. Producers of animation mutations, such as C++ Animated and Reanimated, use the shared animation backend through anonymous frame callbacks. Settings that differ between producers have nowhere to live. A producer can now register once as an `AnimationFrontend` with its frame callback, then start and stop it by id with `startFrontend` and `stopFrontend`. Each frame runs the callbacks passed to `start(callback)` first, then the started frontends in registration order. `start(callback)`, `stop(callbackId)` and `pushAnimationMutations(callback)` are unchanged. C++ Animated now registers a frontend instead of starting a callback. Its frame callback therefore runs after other producers' `start(callback)` callbacks instead of in the order they were started. The next PR adds the first frontend setting. ## Changelog: [INTERNAL] [ADDED] - Let animation producers register with the animation backend as frontends Pull Request resolved: #59585 Test Plan: - `AnimationBackendFrontendTest`: a started frontend runs once per frame, starting and stopping are idempotent, frames are requested while any frontend or callback is started, a frontend without a frame callback is not started, and frames run in registration order after the callbacks. - `NativeAnimatedFrontendTests.registersAndStartsAFrontend`: C++ Animated registers and starts a frontend with the backend instead of starting a callback. - The other `animationbackend` and `animated` gtests pass. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js` and `yarn fantom packages/react-native/Libraries/Animated/__tests__/Animated-itest.js` pass. Differential Revision: D128154522 Pulled By: bartlomiejbloniarz
…ation backend (#59586) Summary: Stacked on #59585, which is stacked on #59584. Review the last two commits: the change and its tests. With the shared animation backend, the backend's commit hook writes C++ Animated's latest values into every React commit made while it animates. C++ Animated without the backend does not do this. It writes non-layout props straight to the views, keeps them over React's mounts with `AnimatedMountingOverrideDelegate`, and commits the final values when an animation finishes. This PR adds a way to experiment with the second approach on the backend. It adds `commitDirectProps` to `AnimationFrontend` and the `enableCxxAnimatedDirectPathInBackend` flag. With the flag, C++ Animated registers with `commitDirectProps = false` and behaves as it does without the backend: - The commit hook does not write its direct values into React commits. Layout updates are unchanged. - `AnimatedMountingOverrideDelegate` keeps the values of connected props nodes over React mounts. - The last update of an animation is recorded apart, and the end-of-animation commit writes it. - One end-of-animation commit per surface is scheduled at a time. Without the flag, C++ Animated registers with `commitDirectProps = true` and the end-of-animation commit is unchanged. Turning `commitDirectProps` off without the flag asserts. ## Changelog: [INTERNAL] [ADDED] - Add `enableCxxAnimatedDirectPathInBackend` to keep C++ Animated's direct updates out of React commits with the shared animation backend Pull Request resolved: #59586 Test Plan: **Unit tests.** `AnimatedPropsRegistryTest`, `AnimationBackendFrontendTest` and `NativeAnimatedFrontendTests` cover which values the commit hook writes, when final values are written, taken and restored, that older recorded values do not overwrite a final value, and one end-of-animation commit per surface. The tests for final values and for one commit per surface fail without the code they cover. **Fantom.** - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js` runs with the flag on and off and passes. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackendDirectUpdates-itest.js` checks that a React commit of an animated view keeps its animated value mounted, with the flag on and off. It fails without the mount override delegate. - `yarn fantom packages/react-native/Libraries/Animated/__tests__/Animated-itest.js` passes. I also ran it locally with the backend and the flag forced on. Fantom allows at most 12 flag combinations per file, so that run is not encoded in the file. **Devices.** RNTester on an Android emulator and an iOS simulator, with the backend and C++ Animated on, once with the flag on and once with it off. I tracked a square frame by frame in screen recordings: | Check | Android, flag on | Android, flag off | iOS, flag on | iOS, flag off | |---|---|---|---|---| | React re-renders the view every 50 ms during a looping native animation | No backward jumps | No backward jumps | No backward jumps | No backward jumps | | The animation finishes, then React keeps re-rendering | Keeps the final values | Keeps the final values | Keeps the final values | Keeps the final values | | `setValue(0)`, then React keeps re-rendering | Stays reset | Stays reset | Stays reset | Stays reset | Differential Revision: D128154682 Pulled By: bartlomiejbloniarz
907988d to
3eb25a1
Compare
|
This pull request was successfully merged by @bartlomiejbloniarz in 3eb25a1 When will my fix make it into a release? | How to file a pick request? |






Summary:
Stacked on #59584. Review the last two commits: the change and its tests.
Producers of animation mutations, such as C++ Animated and Reanimated, use the shared animation backend through anonymous frame callbacks. Settings that differ between producers have nowhere to live.
A producer can now register once as an
AnimationFrontendwith its frame callback, then start and stop it by id withstartFrontendandstopFrontend. Each frame runs the callbacks passed tostart(callback)first, then the started frontends in registration order.start(callback),stop(callbackId)andpushAnimationMutations(callback)are unchanged.C++ Animated now registers a frontend instead of starting a callback. Its frame callback therefore runs after other producers'
start(callback)callbacks instead of in the order they were started.The next PR adds the first frontend setting.
Changelog:
[INTERNAL] [ADDED] - Let animation producers register with the animation backend as frontends
Test Plan:
AnimationBackendFrontendTest: a started frontend runs once per frame, starting and stopping are idempotent, frames are requested while any frontend or callback is started, a frontend without a frame callback is not started, and frames run in registration order after the callbacks.NativeAnimatedFrontendTests.registersAndStartsAFrontend: C++ Animated registers and starts a frontend with the backend instead of starting a callback.animationbackendandanimatedgtests pass.yarn fantom packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.jsandyarn fantom packages/react-native/Libraries/Animated/__tests__/Animated-itest.jspass.Differential Revision: D128154522
Pulled By: bartlomiejbloniarz