diff --git a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm index 5da1d1b75ca8..ab8f3c490780 100644 --- a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm +++ b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm @@ -9,6 +9,7 @@ #import #import +#import #import #import @@ -42,8 +43,28 @@ using namespace facebook::react; @interface RCTSurfacePresenter () +- (void)_drainPendingReactRevisionMerges; @end +namespace { +class ReactRevisionMergeRunLoopObserverDelegate final : public RunLoopObserver::Delegate { + public: + explicit ReactRevisionMergeRunLoopObserverDelegate(RCTSurfacePresenter *surfacePresenter) + : surfacePresenter_(surfacePresenter) + { + } + + void activityDidChange(const RunLoopObserver::Delegate * /*delegate*/, RunLoopObserver::Activity /*activity*/) + const noexcept override + { + [surfacePresenter_ _drainPendingReactRevisionMerges]; + } + + private: + __weak RCTSurfacePresenter *surfacePresenter_; +}; +} // namespace + @implementation RCTSurfacePresenter { RCTMountingManager *_mountingManager; // Thread-safe. RCTSurfaceRegistry *_surfaceRegistry; // Thread-safe. @@ -57,6 +78,12 @@ @implementation RCTSurfacePresenter { std::shared_mutex _observerListMutex; std::vector<__weak id> _observers; // Protected by `_observerListMutex`. + + std::mutex _pendingReactRevisionMergesMutex; + // Pending React revision merges, drained on the main run loop just before it sleeps. + std::unordered_set _pendingReactRevisionMerges; // Protected by `_pendingReactRevisionMergesMutex`. + std::shared_ptr _mergeRunLoopObserverDelegate; + std::unique_ptr _mergeRunLoopObserver; } - (instancetype)initWithContextContainer:(std::shared_ptr)contextContainer @@ -74,6 +101,14 @@ - (instancetype)initWithContextContainer:(std::shared_ptr(self); + _mergeRunLoopObserver = std::make_unique( + RunLoopObserver::Activity::BeforeWaiting, _mergeRunLoopObserverDelegate); + _mergeRunLoopObserver->setDelegate(_mergeRunLoopObserverDelegate.get()); + _mergeRunLoopObserver->enable(); + } + _scheduler = [self _createScheduler]; [[NSNotificationCenter defaultCenter] addObserver:self @@ -309,11 +344,49 @@ - (void)schedulerShouldRenderTransactions:(std::shared_ptrgetShadowTreeRegistry().visit( - surfaceId, [](const ShadowTree &shadowTree) { shadowTree.mergeReactRevision(); }); - }); + if (RCTIsMainQueue()) { + [self _mergeReactRevisionForSurfaceId:surfaceId]; + return; + } + + std::lock_guard lock(_pendingReactRevisionMergesMutex); + _pendingReactRevisionMerges.insert(surfaceId); +} + +- (void)_mergeReactRevisionForSurfaceId:(SurfaceId)surfaceId +{ + RCTAssertMainQueue(); + RCTScheduler *scheduler = [self scheduler]; + if (!scheduler) { + return; + } + + auto uiManager = scheduler.uiManager; + if (!uiManager) { + return; + } + + uiManager->getShadowTreeRegistry().visit( + surfaceId, [](const ShadowTree &shadowTree) { shadowTree.mergeReactRevision(); }); +} + +- (void)_drainPendingReactRevisionMerges +{ + RCTAssertMainQueue(); + + std::unordered_set pending; + { + std::lock_guard lock(_pendingReactRevisionMergesMutex); + if (_pendingReactRevisionMerges.empty()) { + return; + } + + pending.swap(_pendingReactRevisionMerges); + } + + for (auto surfaceId : pending) { + [self _mergeReactRevisionForSurfaceId:surfaceId]; + } } - (void)schedulerDidDispatchCommand:(const ShadowView &)shadowView