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));
static const CFTimeInterval kTimerLatencyCompensation
TEST(FlutterVSyncWaiterTest, RequestsInitialVSync)
static void BusyWait(CFTimeInterval duration)
void invalidate()
Invalidates the display link. Must be called on the main thread.
BOOL paused
Pauses and resumes the display link. May be called from any thread.
void waitForVSync:(uintptr_t baton)
CFTimeInterval nominalOutputRefreshPeriod