8 #import "flutter/testing/testing.h"
13 @property(nonatomic) CFTimeInterval nominalOutputRefreshPeriod;
21 @synthesize paused = _paused;
23 - (instancetype)init {
24 if (
self = [super init]) {
30 - (void)tickWithTimestamp:(CFTimeInterval)timestamp
31 targetTimestamp:(CFTimeInterval)targetTimestamp {
32 [_delegate onDisplayLink:timestamp targetTimestamp:targetTimestamp];
40 TEST(FlutterVSyncWaiterTest, RequestsInitialVSync) {
42 EXPECT_TRUE(displayLink.
paused);
45 initWithDisplayLink:displayLink
46 block:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp,
50 EXPECT_FALSE(displayLink.
paused);
51 [displayLink tickWithTimestamp:CACurrentMediaTime()
52 targetTimestamp:CACurrentMediaTime() + 1.0 / 60.0];
53 EXPECT_TRUE(displayLink.
paused);
56 static void BusyWait(CFTimeInterval duration) {
57 CFTimeInterval start = CACurrentMediaTime();
58 while (CACurrentMediaTime() < start + duration) {
65 TEST(FlutterVSyncWaiterTest, FirstVSyncIsSynthesized) {
69 auto test = [&](CFTimeInterval waitDuration, CFTimeInterval expectedDelay) {
70 __block CFTimeInterval timestamp = 0;
71 __block CFTimeInterval targetTimestamp = 0;
72 __block
size_t baton = 0;
73 const uintptr_t kWarmUpBaton = 0xFFFFFFFF;
75 initWithDisplayLink:displayLink
76 block:^(CFTimeInterval _timestamp, CFTimeInterval _targetTimestamp,
78 if (_baton == kWarmUpBaton) {
81 timestamp = _timestamp;
82 targetTimestamp = _targetTimestamp;
84 EXPECT_TRUE(CACurrentMediaTime() >= _timestamp - kTimerLatencyCompensation);
85 CFRunLoopStop(CFRunLoopGetCurrent());
91 CFTimeInterval now = CACurrentMediaTime();
93 [displayLink tickWithTimestamp:now + 0.5 * displayLink.nominalOutputRefreshPeriod
94 targetTimestamp:now + 2 * displayLink.nominalOutputRefreshPeriod];
95 EXPECT_EQ(displayLink.
paused, YES);
97 EXPECT_EQ(timestamp, 0);
102 CFTimeInterval expectedTimestamp = now + expectedDelay;
107 EXPECT_DOUBLE_EQ(timestamp, expectedTimestamp);
109 EXPECT_EQ(baton,
size_t(1));
119 TEST(FlutterVSyncWaiterTest, VSyncWorks) {
122 const uintptr_t kWarmUpBaton = 0xFFFFFFFF;
125 CFTimeInterval timestamp;
126 CFTimeInterval targetTimestamp;
129 __block std::vector<Entry> entries;
132 initWithDisplayLink:displayLink
133 block:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp,
135 entries.push_back({timestamp, targetTimestamp, baton});
136 if (baton == kWarmUpBaton) {
139 EXPECT_TRUE(CACurrentMediaTime() >= timestamp - kTimerLatencyCompensation);
140 CFRunLoopStop(CFRunLoopGetCurrent());
143 __block CFTimeInterval expectedStartUntil;
148 [[NSRunLoop currentRunLoop] performBlock:^{
149 expectedStartUntil = CACurrentMediaTime();
153 CFTimeInterval now = CACurrentMediaTime();
155 [displayLink tickWithTimestamp:now + 0.5 * displayLink.nominalOutputRefreshPeriod
156 targetTimestamp:now + 2 * displayLink.nominalOutputRefreshPeriod];
157 EXPECT_EQ(displayLink.
paused, YES);
163 [displayLink tickWithTimestamp:now + 1.5 * displayLink.nominalOutputRefreshPeriod
164 targetTimestamp:now + 3 * displayLink.nominalOutputRefreshPeriod];
168 [displayLink tickWithTimestamp:now + 2.5 * displayLink.nominalOutputRefreshPeriod
169 targetTimestamp:now + 4 * displayLink.nominalOutputRefreshPeriod];
172 EXPECT_FALSE(displayLink.
paused);
174 [displayLink tickWithTimestamp:now + 3.5 * displayLink.nominalOutputRefreshPeriod
175 targetTimestamp:now + 5 * displayLink.nominalOutputRefreshPeriod];
177 CFTimeInterval start = CACurrentMediaTime();
178 while (!displayLink.
paused) {
180 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.02, NO);
181 if (CACurrentMediaTime() - start > 1.0) {
185 ASSERT_TRUE(displayLink.
paused);
187 EXPECT_EQ(entries.size(),
size_t(4));
190 EXPECT_TRUE(entries[0].timestamp <= expectedStartUntil);
191 EXPECT_TRUE(entries[0].targetTimestamp <= expectedStartUntil);
192 EXPECT_EQ(entries[0].baton, kWarmUpBaton);
196 EXPECT_EQ(entries[1].baton,
size_t(1));
199 EXPECT_EQ(entries[2].baton,
size_t(2));
202 EXPECT_EQ(entries[3].baton,
size_t(3));