8 #import "flutter/testing/testing.h"
21 - (instancetype)init {
22 if (
self = [super init]) {
28 - (void)tickWithTimestamp:(CFTimeInterval)timestamp
29 targetTimestamp:(CFTimeInterval)targetTimestamp {
30 [
self.delegate onDisplayLink:timestamp targetTimestamp:targetTimestamp];
38 TEST(FlutterVSyncWaiterTest, RequestsInitialVSync) {
40 EXPECT_TRUE(displayLink.
paused);
43 initWithDisplayLink:displayLink
44 block:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp,
48 EXPECT_FALSE(displayLink.
paused);
49 [displayLink tickWithTimestamp:CACurrentMediaTime()
50 targetTimestamp:CACurrentMediaTime() + 1.0 / 60.0];
51 EXPECT_TRUE(displayLink.
paused);
54 static void BusyWait(CFTimeInterval duration) {
55 CFTimeInterval start = CACurrentMediaTime();
56 while (CACurrentMediaTime() < start + duration) {
63 TEST(FlutterVSyncWaiterTest, FirstVSyncIsSynthesized) {
67 auto test = [&](CFTimeInterval waitDuration, CFTimeInterval expectedDelay) {
68 __block CFTimeInterval timestamp = 0;
69 __block CFTimeInterval targetTimestamp = 0;
70 __block
size_t baton = 0;
71 const uintptr_t kWarmUpBaton = 0xFFFFFFFF;
73 initWithDisplayLink:displayLink
74 block:^(CFTimeInterval _timestamp, CFTimeInterval _targetTimestamp,
76 if (_baton == kWarmUpBaton) {
79 timestamp = _timestamp;
80 targetTimestamp = _targetTimestamp;
82 EXPECT_TRUE(CACurrentMediaTime() >= _timestamp - kTimerLatencyCompensation);
83 CFRunLoopStop(CFRunLoopGetCurrent());
89 CFTimeInterval now = CACurrentMediaTime();
91 [displayLink tickWithTimestamp:now + 0.5 * displayLink.nominalOutputRefreshPeriod
92 targetTimestamp:now + 2 * displayLink.nominalOutputRefreshPeriod];
93 EXPECT_EQ(displayLink.
paused, YES);
95 EXPECT_EQ(timestamp, 0);
100 CFTimeInterval expectedTimestamp = now + expectedDelay;
105 EXPECT_DOUBLE_EQ(timestamp, expectedTimestamp);
107 EXPECT_EQ(baton,
size_t(1));
117 TEST(FlutterVSyncWaiterTest, VSyncWorks) {
120 const uintptr_t kWarmUpBaton = 0xFFFFFFFF;
123 CFTimeInterval timestamp;
124 CFTimeInterval targetTimestamp;
127 __block std::vector<Entry> entries;
130 initWithDisplayLink:displayLink
131 block:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp,
133 entries.push_back({timestamp, targetTimestamp, baton});
134 if (baton == kWarmUpBaton) {
137 EXPECT_TRUE(CACurrentMediaTime() >= timestamp - kTimerLatencyCompensation);
138 CFRunLoopStop(CFRunLoopGetCurrent());
141 __block CFTimeInterval expectedStartUntil;
146 [[NSRunLoop currentRunLoop] performBlock:^{
147 expectedStartUntil = CACurrentMediaTime();
151 CFTimeInterval now = CACurrentMediaTime();
153 [displayLink tickWithTimestamp:now + 0.5 * displayLink.nominalOutputRefreshPeriod
154 targetTimestamp:now + 2 * displayLink.nominalOutputRefreshPeriod];
155 EXPECT_EQ(displayLink.
paused, YES);
161 [displayLink tickWithTimestamp:now + 1.5 * displayLink.nominalOutputRefreshPeriod
162 targetTimestamp:now + 3 * displayLink.nominalOutputRefreshPeriod];
166 [displayLink tickWithTimestamp:now + 2.5 * displayLink.nominalOutputRefreshPeriod
167 targetTimestamp:now + 4 * displayLink.nominalOutputRefreshPeriod];
170 EXPECT_FALSE(displayLink.
paused);
172 [displayLink tickWithTimestamp:now + 3.5 * displayLink.nominalOutputRefreshPeriod
173 targetTimestamp:now + 5 * displayLink.nominalOutputRefreshPeriod];
175 CFTimeInterval start = CACurrentMediaTime();
176 while (!displayLink.
paused) {
178 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.02, NO);
179 if (CACurrentMediaTime() - start > 1.0) {
183 ASSERT_TRUE(displayLink.
paused);
185 EXPECT_EQ(entries.size(),
size_t(4));
188 EXPECT_TRUE(entries[0].timestamp <= expectedStartUntil);
189 EXPECT_TRUE(entries[0].targetTimestamp <= expectedStartUntil);
190 EXPECT_EQ(entries[0].baton, kWarmUpBaton);
194 EXPECT_EQ(entries[1].baton,
size_t(1));
197 EXPECT_EQ(entries[2].baton,
size_t(2));
200 EXPECT_EQ(entries[3].baton,
size_t(3));