From 1e8bfaa0ce3367b9a21ef16360d31324cef70999 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 14 Mar 2024 06:06:37 +0100 Subject: [PATCH 1/2] Fix FlutterVSyncWaiterTest.VSyncWorks flakyness --- .../Source/FlutterVSyncWaiterTest.mm | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterVSyncWaiterTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterVSyncWaiterTest.mm index 062452c60e84e..02448549627ad 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterVSyncWaiterTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterVSyncWaiterTest.mm @@ -140,7 +140,14 @@ static void BusyWait(CFTimeInterval duration) { CFRunLoopStop(CFRunLoopGetCurrent()); }]; + __block CFTimeInterval expectedStartUntil; + // Warm up tick is scheduled immediately in a scheduled block. Schedule another + // block here to determine the maximum time when the warm up tick should be + // scheduled. [waiter waitForVSync:kWarmUpBaton]; + [[NSRunLoop currentRunLoop] performBlock:^{ + expectedStartUntil = CACurrentMediaTime(); + }]; // Reference vsync to setup phase. CFTimeInterval now = CACurrentMediaTime(); @@ -166,15 +173,22 @@ static void BusyWait(CFTimeInterval duration) { // Vsync without baton should pause the display link. [displayLink tickWithTimestamp:now + 3.5 * displayLink.nominalOutputRefreshPeriod targetTimestamp:now + 5 * displayLink.nominalOutputRefreshPeriod]; - // Make sure to run the timer scheduled in display link callback. - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.02, NO); + + CFTimeInterval start = CACurrentMediaTime(); + while (!displayLink.paused) { + // Make sure to run the timer scheduled in display link callback. + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.02, NO); + if (CACurrentMediaTime() - start > 1.0) { + break; + } + } ASSERT_TRUE(displayLink.paused); EXPECT_EQ(entries.size(), size_t(4)); // Warm up frame should be presented as soon as possible. - EXPECT_TRUE(fabs(entries[0].timestamp - now) < 0.005); - EXPECT_TRUE(fabs(entries[0].targetTimestamp - now) < 0.005); + EXPECT_TRUE(entries[0].timestamp <= expectedStartUntil); + EXPECT_TRUE(entries[0].targetTimestamp <= expectedStartUntil); EXPECT_EQ(entries[0].baton, kWarmUpBaton); EXPECT_DOUBLE_EQ(entries[1].timestamp, now + displayLink.nominalOutputRefreshPeriod); From c9d1b7fd9d6d053011c0a18cdd46aafc3a5aa548 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 14 Mar 2024 06:51:15 +0100 Subject: [PATCH 2/2] Unregister notification before removing view --- .../darwin/macos/framework/Source/FlutterDisplayLink.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterDisplayLink.mm b/shell/platform/darwin/macos/framework/Source/FlutterDisplayLink.mm index 31b74ec36d4e6..ba07304292098 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterDisplayLink.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterDisplayLink.mm @@ -262,8 +262,11 @@ - (instancetype)initWithView:(NSView*)view { - (void)invalidate { @synchronized(self) { FML_DCHECK([NSThread isMainThread]); - [_view removeFromSuperview]; + // Unregister observer before removing the view to ensure + // that the viewDidChangeWindow notification is not received + // while in @synchronized block. [[NSNotificationCenter defaultCenter] removeObserver:self]; + [_view removeFromSuperview]; _view = nil; _delegate = nil; }