Skip to content

Commit d30a62f

Browse files
Bartlomiej Bloniarzfacebook-github-bot
authored andcommitted
Move AnimationBackend initialization from Animated
Summary: This diff decouples AnimationBackend from Animated. Now the backend is intialized in the Scheduler, from where it's passed to UIManager. Animation frontends (such as Animated) can then obtain a reference to the backend, and use it to schedule animation frame updates. # Changelog [General] [Changed] - Moved AnimationBackend initiailzation to `Scheduler` [General] [Added] - `AnimationChoreographer` interface with an implementation for fantom tests Differential Revision: D89663251
1 parent 33e1a9a commit d30a62f

22 files changed

+260
-95
lines changed

packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -559,10 +559,8 @@ void NativeAnimatedNodesManager::startRenderCallbackIfNeeded(bool isAsync) {
559559
if (ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
560560
#ifdef RN_USE_ANIMATION_BACKEND
561561
if (auto animationBackend = animationBackend_.lock()) {
562-
std::static_pointer_cast<AnimationBackend>(animationBackend)
563-
->start(
564-
[this](float /*f*/) { return pullAnimationMutations(); },
565-
isAsync);
562+
animationBackend->start(
563+
[this](float /*f*/) { return pullAnimationMutations(); }, isAsync);
566564
}
567565
#endif
568566

packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManagerProvider.cpp

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,24 +88,17 @@ NativeAnimatedNodesManagerProvider::getOrCreate(
8888

8989
if (ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
9090
#ifdef RN_USE_ANIMATION_BACKEND
91-
// TODO: this should be initialized outside of animated, but for now it
92-
// was convenient to do it here
93-
animationBackend_ = std::make_shared<AnimationBackend>(
94-
std::move(startOnRenderCallback_),
95-
std::move(stopOnRenderCallback_),
96-
std::move(directManipulationCallback),
97-
std::move(fabricCommitCallback),
98-
uiManager,
99-
jsInvoker);
91+
auto animationBackend = uiManager->unstable_getAnimationBackend().lock();
92+
react_native_assert(
93+
animationBackend != nullptr && "animationBackend is nullptr");
94+
animationBackend->registerJSInvoker(jsInvoker);
10095

10196
nativeAnimatedNodesManager_ =
102-
std::make_shared<NativeAnimatedNodesManager>(animationBackend_);
97+
std::make_shared<NativeAnimatedNodesManager>(animationBackend);
10398

10499
nativeAnimatedDelegate_ =
105100
std::make_shared<UIManagerNativeAnimatedDelegateBackendImpl>(
106-
animationBackend_);
107-
108-
uiManager->unstable_setAnimationBackend(animationBackend_);
101+
animationBackend);
109102
#endif
110103
} else {
111104
nativeAnimatedNodesManager_ =

packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManagerProvider.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#pragma once
99

1010
#include <react/renderer/animated/MergedValueDispatcher.h>
11+
#include <react/renderer/uimanager/UIManagerAnimationBackend.h>
1112
#include <react/renderer/uimanager/UIManagerNativeAnimatedDelegate.h>
1213
#include "NativeAnimatedNodesManager.h"
1314

@@ -32,7 +33,6 @@ class NativeAnimatedNodesManagerProvider {
3233
std::shared_ptr<EventEmitterListener> getEventEmitterListener();
3334

3435
private:
35-
std::shared_ptr<UIManagerAnimationBackend> animationBackend_;
3636
std::shared_ptr<NativeAnimatedNodesManager> nativeAnimatedNodesManager_;
3737

3838
std::shared_ptr<EventEmitterListenerContainer> eventEmitterListenerContainer_;

packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,6 @@
1515

1616
namespace facebook::react {
1717

18-
static const auto layoutProps = std::set<PropName>{
19-
WIDTH, HEIGHT, FLEX, MARGIN, PADDING,
20-
POSITION, BORDER_WIDTH, ALIGN_CONTENT, ALIGN_ITEMS, ALIGN_SELF,
21-
ASPECT_RATIO, BOX_SIZING, DISPLAY, FLEX_BASIS, FLEX_DIRECTION,
22-
ROW_GAP, COLUMN_GAP, FLEX_GROW, FLEX_SHRINK, FLEX_WRAP,
23-
JUSTIFY_CONTENT, MAX_HEIGHT, MAX_WIDTH, MIN_HEIGHT, MIN_WIDTH,
24-
STYLE_OVERFLOW, POSITION_TYPE, DIRECTION, Z_INDEX,
25-
};
26-
2718
UIManagerNativeAnimatedDelegateBackendImpl::
2819
UIManagerNativeAnimatedDelegateBackendImpl(
2920
std::weak_ptr<UIManagerAnimationBackend> animationBackend)
@@ -61,20 +52,15 @@ static inline Props::Shared cloneProps(
6152
}
6253

6354
AnimationBackend::AnimationBackend(
64-
StartOnRenderCallback&& startOnRenderCallback,
65-
StopOnRenderCallback&& stopOnRenderCallback,
6655
DirectManipulationCallback&& directManipulationCallback,
67-
FabricCommitCallback&& fabricCommitCallback,
68-
UIManager* uiManager,
69-
std::shared_ptr<CallInvoker> jsInvoker)
70-
: startOnRenderCallback_(std::move(startOnRenderCallback)),
71-
stopOnRenderCallback_(std::move(stopOnRenderCallback)),
72-
directManipulationCallback_(std::move(directManipulationCallback)),
73-
fabricCommitCallback_(std::move(fabricCommitCallback)),
56+
std::shared_ptr<UIManager> uiManager)
57+
: directManipulationCallback_(std::move(directManipulationCallback)),
7458
animatedPropsRegistry_(std::make_shared<AnimatedPropsRegistry>()),
7559
uiManager_(uiManager),
76-
jsInvoker_(std::move(jsInvoker)),
77-
commitHook_(uiManager, animatedPropsRegistry_) {}
60+
commitHook_(uiManager, animatedPropsRegistry_) {
61+
react_native_assert(directManipulationCallback_ != nullptr);
62+
react_native_assert(uiManager_ != nullptr);
63+
}
7864

7965
void AnimationBackend::onAnimationFrame(double timestamp) {
8066
std::unordered_map<SurfaceId, SurfaceUpdates> surfaceUpdates;
@@ -110,21 +96,18 @@ void AnimationBackend::onAnimationFrame(double timestamp) {
11096

11197
void AnimationBackend::start(const Callback& callback, bool isAsync) {
11298
callbacks.push_back(callback);
113-
// TODO: startOnRenderCallback_ should provide the timestamp from the
114-
// platform
115-
if (startOnRenderCallback_) {
116-
startOnRenderCallback_(
117-
[this]() {
118-
onAnimationFrame(
119-
std::chrono::steady_clock::now().time_since_epoch().count() /
120-
1000);
121-
},
122-
isAsync);
99+
if (!isRenderCallbackStarted_) {
100+
auto delegate = uiManager_->getDelegate();
101+
delegate->uiManagerShouldResumeAnimationBackend();
102+
isRenderCallbackStarted_ = true;
123103
}
124104
}
105+
125106
void AnimationBackend::stop(bool isAsync) {
126-
if (stopOnRenderCallback_) {
127-
stopOnRenderCallback_(isAsync);
107+
if (isRenderCallbackStarted_) {
108+
auto delegate = uiManager_->getDelegate();
109+
delegate->uiManagerShouldPauseAnimationBackend();
110+
isRenderCallbackStarted_ = false;
128111
}
129112
callbacks.clear();
130113
}
@@ -178,6 +161,9 @@ void AnimationBackend::synchronouslyUpdateProps(
178161

179162
void AnimationBackend::requestAsyncFlushForSurfaces(
180163
const std::set<SurfaceId>& surfaces) {
164+
react_native_assert(
165+
jsInvoker_ != nullptr ||
166+
surfaces.empty() && "jsInvoker_ was not provided");
181167
for (const auto& surfaceId : surfaces) {
182168
// perform an empty commit on the js thread, to force the commit hook to
183169
// push updated shadow nodes to react through RSNRU
@@ -199,4 +185,11 @@ void AnimationBackend::clearRegistry(SurfaceId surfaceId) {
199185
animatedPropsRegistry_->clear(surfaceId);
200186
}
201187

188+
void AnimationBackend::registerJSInvoker(
189+
std::shared_ptr<CallInvoker> jsInvoker) {
190+
if (!jsInvoker_) {
191+
jsInvoker_ = jsInvoker;
192+
}
193+
}
194+
202195
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.h

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,36 +50,28 @@ struct AnimationMutations {
5050
class AnimationBackend : public UIManagerAnimationBackend {
5151
public:
5252
using Callback = std::function<AnimationMutations(float)>;
53-
using StartOnRenderCallback = std::function<void(std::function<void()> &&, bool /* isAsync */)>;
54-
using StopOnRenderCallback = std::function<void(bool /* isAsync */)>;
53+
using ResumeCallback = std::function<void()>;
54+
using PauseCallback = std::function<void()>;
5555
using DirectManipulationCallback = std::function<void(Tag, const folly::dynamic &)>;
56-
using FabricCommitCallback = std::function<void(std::unordered_map<Tag, folly::dynamic> &)>;
5756

5857
std::vector<Callback> callbacks;
59-
const StartOnRenderCallback startOnRenderCallback_;
60-
const StopOnRenderCallback stopOnRenderCallback_;
6158
const DirectManipulationCallback directManipulationCallback_;
62-
const FabricCommitCallback fabricCommitCallback_;
6359
std::shared_ptr<AnimatedPropsRegistry> animatedPropsRegistry_;
64-
UIManager *uiManager_;
60+
std::shared_ptr<UIManager> uiManager_;
6561
std::shared_ptr<CallInvoker> jsInvoker_;
6662
AnimationBackendCommitHook commitHook_;
63+
bool isRenderCallbackStarted_{false};
6764

68-
AnimationBackend(
69-
StartOnRenderCallback &&startOnRenderCallback,
70-
StopOnRenderCallback &&stopOnRenderCallback,
71-
DirectManipulationCallback &&directManipulationCallback,
72-
FabricCommitCallback &&fabricCommitCallback,
73-
UIManager *uiManager,
74-
std::shared_ptr<CallInvoker> jsInvoker);
65+
AnimationBackend(DirectManipulationCallback &&directManipulationCallback, std::shared_ptr<UIManager> uiManager);
7566
void commitUpdates(SurfaceId surfaceId, SurfaceUpdates &surfaceUpdates);
7667
void synchronouslyUpdateProps(const std::unordered_map<Tag, AnimatedProps> &updates);
7768
void requestAsyncFlushForSurfaces(const std::set<SurfaceId> &surfaces);
7869
void clearRegistry(SurfaceId surfaceId) override;
70+
void registerJSInvoker(std::shared_ptr<CallInvoker> jsInvoker) override;
7971

8072
void onAnimationFrame(double timestamp) override;
8173
void trigger() override;
82-
void start(const Callback &callback, bool isAsync);
74+
void start(const Callback &callback, bool isAsync) override;
8375
void stop(bool isAsync) override;
8476
};
8577
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
namespace facebook::react {
1111

1212
AnimationBackendCommitHook::AnimationBackendCommitHook(
13-
UIManager* uiManager,
13+
std::shared_ptr<UIManager> uiManager,
1414
std::shared_ptr<AnimatedPropsRegistry> animatedPropsRegistry)
15-
: animatedPropsRegistry_(std::move(animatedPropsRegistry)) {
16-
uiManager->registerCommitHook(*this);
15+
: uiManager_(uiManager),
16+
animatedPropsRegistry_(std::move(animatedPropsRegistry)) {
17+
uiManager_->registerCommitHook(*this);
1718
}
1819

1920
RootShadowNode::Unshared AnimationBackendCommitHook::shadowTreeWillCommit(
@@ -73,4 +74,8 @@ RootShadowNode::Unshared AnimationBackendCommitHook::shadowTreeWillCommit(
7374
}));
7475
}
7576

77+
AnimationBackendCommitHook::~AnimationBackendCommitHook() {
78+
uiManager_->unregisterCommitHook(*this);
79+
}
80+
7681
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,21 @@
1616
namespace facebook::react {
1717

1818
class AnimationBackendCommitHook : public UIManagerCommitHook {
19+
std::shared_ptr<UIManager> uiManager_;
1920
std::shared_ptr<AnimatedPropsRegistry> animatedPropsRegistry_;
2021

2122
public:
22-
AnimationBackendCommitHook(UIManager *uiManager, std::shared_ptr<AnimatedPropsRegistry> animatedPropsRegistry);
23+
AnimationBackendCommitHook(
24+
std::shared_ptr<UIManager> uiManager,
25+
std::shared_ptr<AnimatedPropsRegistry> animatedPropsRegistry);
2326
RootShadowNode::Unshared shadowTreeWillCommit(
2427
const ShadowTree &shadowTree,
2528
const RootShadowNode::Shared &oldRootShadowNode,
2629
const RootShadowNode::Unshared &newRootShadowNode,
2730
const ShadowTreeCommitOptions &commitOptions) noexcept override;
2831
void commitHookWasRegistered(const UIManager &uiManager) noexcept override {}
2932
void commitHookWasUnregistered(const UIManager &uiManager) noexcept override {}
33+
~AnimationBackendCommitHook() override;
3034
};
3135

3236
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ Scheduler::Scheduler(
5555
auto uiManager =
5656
std::make_shared<UIManager>(runtimeExecutor_, contextContainer_);
5757

58+
auto directManipulationCallback = [delegate](
59+
Tag tag, const folly::dynamic& props) {
60+
delegate->schedulerShouldSynchronouslyUpdateViewOnUIThread(tag, props);
61+
};
62+
63+
animationBackend_ = std::make_shared<AnimationBackend>(
64+
std::move(directManipulationCallback), uiManager);
65+
uiManager->unstable_setAnimationBackend(animationBackend_);
66+
5867
auto eventOwnerBox = std::make_shared<EventBeat::OwnerBox>();
5968
eventOwnerBox->owner = eventDispatcher_;
6069

@@ -168,6 +177,8 @@ Scheduler::~Scheduler() {
168177
uiManager_->unregisterCommitHook(*commitHook);
169178
}
170179

180+
animationBackend_ = nullptr;
181+
171182
// All Surfaces must be explicitly stopped before destroying `Scheduler`.
172183
// The idea is that `UIManager` is allowed to call `Scheduler` only if the
173184
// corresponding `ShadowTree` instance exists.
@@ -355,6 +366,18 @@ void Scheduler::uiManagerShouldRemoveEventListener(
355366
removeEventListener(listener);
356367
}
357368

369+
void Scheduler::uiManagerShouldResumeAnimationBackend() {
370+
if (delegate_ != nullptr) {
371+
delegate_->schedulerShouldResumeAnimationFrameCallbacks();
372+
}
373+
}
374+
375+
void Scheduler::uiManagerShouldPauseAnimationBackend() {
376+
if (delegate_ != nullptr) {
377+
delegate_->schedulerShouldPauseAnimationFrameCallbacks();
378+
}
379+
}
380+
358381
void Scheduler::uiManagerDidStartSurface(const ShadowTree& shadowTree) {
359382
std::shared_lock lock(onSurfaceStartCallbackMutex_);
360383
if (onSurfaceStartCallback_) {

packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <react/performance/cdpmetrics/CdpMetricsReporter.h>
1414
#include <react/performance/cdpmetrics/CdpPerfIssuesReporter.h>
1515
#include <react/performance/timeline/PerformanceEntryReporter.h>
16+
#include <react/renderer/animationbackend/AnimationBackend.h>
1617
#include <react/renderer/componentregistry/ComponentDescriptorFactory.h>
1718
#include <react/renderer/core/ComponentDescriptor.h>
1819
#include <react/renderer/core/EventEmitter.h>
@@ -46,8 +47,6 @@ class Scheduler final : public UIManagerDelegate {
4647

4748
/*
4849
* Registers and unregisters a `SurfaceHandler` object in the `Scheduler`.
49-
* All registered `SurfaceHandler` objects must be unregistered
50-
* (with the same `Scheduler`) before their deallocation.
5150
*/
5251
void registerSurface(const SurfaceHandler &surfaceHandler) const noexcept;
5352
void unregisterSurface(const SurfaceHandler &surfaceHandler) const noexcept;
@@ -97,6 +96,8 @@ class Scheduler final : public UIManagerDelegate {
9796
void uiManagerDidUpdateShadowTree(const std::unordered_map<Tag, folly::dynamic> &tagToProps) override;
9897
void uiManagerShouldAddEventListener(std::shared_ptr<const EventListener> listener) final;
9998
void uiManagerShouldRemoveEventListener(const std::shared_ptr<const EventListener> &listener) final;
99+
void uiManagerShouldResumeAnimationBackend() override;
100+
void uiManagerShouldPauseAnimationBackend() override;
100101
void uiManagerDidStartSurface(const ShadowTree &shadowTree) override;
101102

102103
#pragma mark - ContextContainer
@@ -148,6 +149,7 @@ class Scheduler final : public UIManagerDelegate {
148149

149150
mutable std::shared_mutex onSurfaceStartCallbackMutex_;
150151
OnSurfaceStartCallback onSurfaceStartCallback_;
152+
std::shared_ptr<AnimationBackend> animationBackend_;
151153
};
152154

153155
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,8 @@ void UIManager::setNativeProps_DEPRECATED(
437437
if (family.nativeProps_DEPRECATED) {
438438
// Values in `rawProps` patch (take precedence over)
439439
// `nativeProps_DEPRECATED`. For example, if both `nativeProps_DEPRECATED`
440-
// and `rawProps` contain key 'A'. Value from `rawProps` overrides what was
441-
// previously in `nativeProps_DEPRECATED`.
440+
// and `rawProps` contain key 'A'. Value from `rawProps` overrides what
441+
// was previously in `nativeProps_DEPRECATED`.
442442
family.nativeProps_DEPRECATED =
443443
std::make_unique<folly::dynamic>(mergeDynamicProps(
444444
*family.nativeProps_DEPRECATED,
@@ -529,9 +529,9 @@ std::shared_ptr<const ShadowNode> UIManager::findShadowNodeByTag_DEPRECATED(
529529
// pointer to a root node because of the possible data race.
530530
// To work around this, we ask for a commit and immediately cancel it
531531
// returning `nullptr` instead of a new shadow tree.
532-
// We don't want to add a way to access a stored pointer to a root node
533-
// because this `findShadowNodeByTag` is deprecated. It is only added
534-
// to make migration to the new architecture easier.
532+
// We don't want to add a way to access a stored pointer to a root
533+
// node because this `findShadowNodeByTag` is deprecated. It is only
534+
// added to make migration to the new architecture easier.
535535
shadowTree.tryCommit(
536536
[&](const RootShadowNode& oldRootShadowNode) {
537537
rootShadowNode = &oldRootShadowNode;
@@ -687,12 +687,14 @@ void UIManager::setNativeAnimatedDelegate(
687687
}
688688

689689
void UIManager::unstable_setAnimationBackend(
690-
std::weak_ptr<UIManagerAnimationBackend> animationBackend) {
690+
std::shared_ptr<UIManagerAnimationBackend> animationBackend) {
691691
animationBackend_ = animationBackend;
692692
}
693693

694694
std::weak_ptr<UIManagerAnimationBackend>
695695
UIManager::unstable_getAnimationBackend() {
696+
react_native_assert(
697+
!animationBackend_.expired() && "Animation Backend was not initialized");
696698
return animationBackend_;
697699
}
698700

0 commit comments

Comments
 (0)