2222#import " flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h"
2323#import " flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
2424#import " flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h"
25+ #import " flutter/shell/platform/darwin/macos/framework/Source/FlutterVSyncWaiter.h"
2526#import " flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
2627#import " flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.h"
2728
@@ -459,6 +460,10 @@ @implementation FlutterEngine {
459460
460461 // Proxy to allow plugins, channels to hold a weak reference to the binary messenger (self).
461462 FlutterBinaryMessengerRelay* _binaryMessenger;
463+
464+ // Map from ViewId to vsync waiter. Note that this is modified on main thread
465+ // but accessed on UI thread, so access must be @synchronized.
466+ NSMapTable <NSNumber *, FlutterVSyncWaiter*>* _vsyncWaiters;
462467}
463468
464469- (instancetype )initWithName : (NSString *)labelPrefix project : (FlutterDartProject*)project {
@@ -528,6 +533,8 @@ - (instancetype)initWithName:(NSString*)labelPrefix
528533 _terminationHandler = nil ;
529534 }
530535
536+ _vsyncWaiters = [NSMapTable strongToStrongObjectsMapTable ];
537+
531538 return self;
532539}
533540
@@ -721,6 +728,22 @@ - (void)registerViewController:(FlutterViewController*)controller forId:(Flutter
721728 [controller setUpWithEngine: self viewId: viewId threadSynchronizer: _threadSynchronizer];
722729 NSAssert (controller.viewId == viewId, @" Failed to assign view ID." );
723730 [_viewControllers setObject: controller forKey: @(viewId)];
731+
732+ __weak FlutterEngine* weakSelf = self;
733+ FlutterVSyncWaiter* waiter = [[FlutterVSyncWaiter alloc ]
734+ initWithView: controller.view
735+ block: ^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp, uintptr_t baton) {
736+ // CAMediaTime and flutter time are both mach_absolute_time.
737+ uint64_t timeNanos = timestamp * 1000000000 ;
738+ uint64_t targetTimeNanos = targetTimestamp * 1000000000 ;
739+ FlutterEngine* engine = weakSelf;
740+ if (engine) {
741+ engine->_embedderAPI .OnVsync (_engine, baton, timeNanos, targetTimeNanos);
742+ }
743+ }];
744+ @synchronized (_vsyncWaiters) {
745+ [_vsyncWaiters setObject: waiter forKey: @(viewId)];
746+ }
724747}
725748
726749- (void )deregisterViewControllerForId : (FlutterViewId)viewId {
@@ -729,6 +752,9 @@ - (void)deregisterViewControllerForId:(FlutterViewId)viewId {
729752 [oldController detachFromEngine ];
730753 [_viewControllers removeObjectForKey: @(viewId)];
731754 }
755+ @synchronized (_vsyncWaiters) {
756+ [_vsyncWaiters removeObjectForKey: @(viewId)];
757+ }
732758}
733759
734760- (void )shutDownIfNeeded {
@@ -1048,21 +1074,14 @@ - (void)engineCallbackOnPreEngineRestart {
10481074}
10491075
10501076- (void )onVSync : (uintptr_t )baton {
1051- FlutterViewController* controller = [self viewControllerForId: kFlutterImplicitViewId ];
1052- if (controller) {
1053- [controller waitForVSync: baton];
1077+ @synchronized (_vsyncWaiters) {
1078+ FlutterVSyncWaiter* waiter = [_vsyncWaiters objectForKey: @(kFlutterImplicitViewId )];
1079+ if (waiter) {
1080+ [waiter waitForVSync: baton];
1081+ }
10541082 }
10551083}
10561084
1057- - (void )onVSyncWithTimestamp : (CFTimeInterval)timestamp
1058- targetTimestamp : (CFTimeInterval)targetTimestamp
1059- baton : (uintptr_t )baton {
1060- // CAMediaTime and flutter time are both mach_absolute_time.
1061- uint64_t timeNanos = timestamp * 1000000000 ;
1062- uint64_t targetTimeNanos = targetTimestamp * 1000000000 ;
1063- _embedderAPI.OnVsync (_engine, baton, timeNanos, targetTimeNanos);
1064- }
1065-
10661085/* *
10671086 * Note: Called from dealloc. Should not use accessors or other methods.
10681087 */
0 commit comments