Reduce animation registry copying and allocation (#58775) - #58775
Open
bartlomiejbloniarz wants to merge 4 commits into
Open
bartlomiejbloniarz wants to merge 4 commits into
bartlomiejbloniarz wants to merge 4 commits into
Conversation
|
@bartlomiejbloniarz has exported this pull request. If you are a Meta employee, you can view the originating Diff in D122570619. |
meta-codesync
Bot
force-pushed
the
export-D122570619
branch
from
October 2, 2026 12:07
7620e3a to
c5d2e33
Compare
meta-codesync Bot
pushed a commit
that referenced
this pull request
Oct 2, 2026
Summary: Pull Request resolved: #58775 For every raw update, `AnimatedPropsRegistry::update` copied the incoming props before merging them, and it built a full typed view-props snapshot even when no typed prop was animated. It now merges from the incoming `folly::dynamic` without copying it and allocates typed props only when a typed update arrives. The merge semantics (Folly's merge-patch) and the caller's input are unchanged. On a low-end Android phone (4× Cortex-A53) with 12 views animating opacity, the registry update per frame dropped from about 0.22 ms to 0.13 ms. The new registry tests are excluded from React-Fabric's CocoaPods and Swift Package Manager production sources. ## Changelog: [General] [Changed] - Reduce animation registry copying and allocation Differential Revision: D122570619
added 3 commits
October 2, 2026 05:58
… animates layout (#58772) Summary: Pull Request resolved: #58772 The shared animation backend decided per surface whether a frame's animated props go through a shadow tree commit or straight to the mounted views. As soon as one view animated a layout prop, every animated view on that surface went through the commit path for the whole animation, including views that only animate `transform` or `opacity`. Besides the extra commit work, on Android this moved those views from `updatePropsSynchronously` to regular mounts. There the synchronous mount props cache (`overrideBySynchronousMountPropsAtMountingAndroid`) replaced the incoming transform with its last synchronously written value, so the view froze while the other view's layout animation ran and jumped when it ended. The decision is now made per view. `applySurfaceUpdates` splits a surface's mutations, keyed by view tag, into views with layout updates, which go through `commitUpdates`, and the rest, which are applied synchronously. Views with layout updates are also written synchronously, as the non-shared Animated path already does, so a view that starts animating a layout prop while animating `opacity` doesn't freeze its opacity behind the cache either. `AnimationMutation` and `AnimationMutations` move to `AnimationMutation.h`, still included by `AnimationBackend.h`. `AnimatedPropsRegistry::update` reads the frame's batches instead of the merged per-surface map. When the same view receives several mutations in one frame, they are merged, so the mounted view and the registry stay in sync. Raw animated props are now merged per key, like the animation drivers merge them, instead of with merge-patch, which dropped `null` values meant to reset a prop. `RawProps::getDynamic` exposes a dynamic source without copying it. ## Changelog: [General] [Fixed] - Non-layout props animated on the shared animation backend no longer freeze while the same view or another view on the surface animates a layout prop Differential Revision: D122570616
Summary: Pull Request resolved: #58773 The animation backend hands its synchronous updates to the platform one view at a time. This adds `UIManager::synchronouslyUpdateAnimatedProps` and a matching `SchedulerDelegate` call that receive a whole frame's updates at once, continuing #56771. The backend uses it when `optimizedAnimatedPropUpdates` is on, and that flag's description now only promises what is implemented. The default `SchedulerDelegate` implementation forwards to the existing per-view update, so platforms that don't override it are unaffected. `UIManagerDelegate` gains a required method, implemented by `Scheduler`. ## Changelog: [Internal] Differential Revision: D122570617
Summary: Pull Request resolved: #58774 With the batched delegate from the previous diff, Android applied the backend's synchronous updates with one JNI call and one `ReadableNativeMap` per view per frame. When `optimizedAnimatedPropUpdates` is on, a surface's updates now go to the UI thread in a single call: `FabricMountingManager::synchronouslyUpdateAnimatedProps` encodes them into int and double buffers, and `BatchedAnimatedPropsMountItem` decodes and applies them. This continues the encoder and mount item from #56468. Views that are not mounted yet are still queued. A view is packed only when every prop it carries has a command. Unsupported props, null resets, platform colors, malformed values and typed props send the whole view through the existing `packAnimatedProps` serializer as a map instead. The commands cover the props Reanimated applies synchronously on Android, following the parity review in #56468 (comment). Angles are converted to radians in C++, and radii and translations keep their px or percent units. Because the decoder produces `JavaOnlyArray` transforms, `TransformHelper`'s Kotlin conversion now applies a uniform scale to Z as well as X and Y, matching the native conversion when scale is combined with 3D rotation. This conversion is also used by native-driven Animated transforms built as Java-only arrays, so those now render scale combined with 3D rotation the same way as JS-driven transforms, whether or not `optimizedAnimatedPropUpdates` is enabled. On a low-end Android phone (4× Cortex-A53) with 12 views animating opacity, UI-thread time per frame's synchronous batch dropped from about 6.5 ms to 3.4 ms. ## Changelog: [Android] [Fixed] - Apply uniform `scale` to the Z axis in Java-only transforms, so native-driven Animated transforms combining `scale` with 3D rotation match JS-driven ones Differential Revision: D122570618
meta-codesync
Bot
force-pushed
the
export-D122570619
branch
from
October 2, 2026 13:57
c5d2e33 to
8e34e80
Compare
meta-codesync Bot
pushed a commit
that referenced
this pull request
Oct 2, 2026
Summary: Pull Request resolved: #58775 For every raw update, `AnimatedPropsRegistry::update` copied the incoming props before merging them, and it built a full typed view-props snapshot even when no typed prop was animated. It now merges from the incoming `folly::dynamic` without copying it and allocates typed props only when a typed update arrives. The merge semantics and the caller's input are unchanged. On a low-end Android phone (4× Cortex-A53) with 12 views animating opacity, the registry update per frame dropped from about 0.22 ms to 0.13 ms. The new registry tests are excluded from React-Fabric's CocoaPods and Swift Package Manager production sources. ## Changelog: [Internal] Differential Revision: D122570619
Summary: Pull Request resolved: #58775 For every raw update, `AnimatedPropsRegistry::update` copied the incoming props before merging them, and it built a full typed view-props snapshot even when no typed prop was animated. It now merges from the incoming `folly::dynamic` without copying it and allocates typed props only when a typed update arrives. The merge semantics and the caller's input are unchanged. On a low-end Android phone (4× Cortex-A53) with 12 views animating opacity, the registry update per frame dropped from about 0.22 ms to 0.13 ms. The new registry tests are excluded from React-Fabric's CocoaPods and Swift Package Manager production sources. ## Changelog: [Internal] Differential Revision: D122570619
meta-codesync
Bot
force-pushed
the
export-D122570619
branch
from
October 2, 2026 14:01
8e34e80 to
4f6243b
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
For every raw update,
AnimatedPropsRegistry::updatecopied the incoming props before merging them, and it built a full typed view-props snapshot even when no typed prop was animated. It now merges from the incomingfolly::dynamicwithout copying it and allocates typed props only when a typed update arrives. The merge semantics and the caller's input are unchanged.On a low-end Android phone (4× Cortex-A53) with 12 views animating opacity, the registry update per frame dropped from about 0.22 ms to 0.13 ms.
The new registry tests are excluded from React-Fabric's CocoaPods and Swift Package Manager production sources.
Changelog:
[Internal]
Differential Revision: D122570619