Flutter macOS Embedder
FlutterVSyncWaiterTest.mm File Reference

Go to the source code of this file.

Classes

class  TestDisplayLink
 

Functions

 TEST (FlutterVSyncWaiterTest, RequestsInitialVSync)
 
static void BusyWait (CFTimeInterval duration)
 
 TEST (FlutterVSyncWaiterTest, FirstVSyncIsSynthesized)
 
 TEST (FlutterVSyncWaiterTest, VSyncWorks)
 

Variables

static const CFTimeInterval kTimerLatencyCompensation = 0.001
 

Function Documentation

◆ BusyWait()

static void BusyWait ( CFTimeInterval  duration)
static

Definition at line 56 of file FlutterVSyncWaiterTest.mm.

56  {
57  CFTimeInterval start = CACurrentMediaTime();
58  while (CACurrentMediaTime() < start + duration) {
59  }
60 }

Referenced by TEST().

◆ TEST() [1/3]

TEST ( FlutterVSyncWaiterTest  ,
FirstVSyncIsSynthesized   
)

Definition at line 65 of file FlutterVSyncWaiterTest.mm.

65  {
66  TestDisplayLink* displayLink = [[TestDisplayLink alloc] init];
67  displayLink.nominalOutputRefreshPeriod = 1.0 / 60.0;
68 
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;
74  FlutterVSyncWaiter* waiter = [[FlutterVSyncWaiter alloc]
75  initWithDisplayLink:displayLink
76  block:^(CFTimeInterval _timestamp, CFTimeInterval _targetTimestamp,
77  uintptr_t _baton) {
78  if (_baton == kWarmUpBaton) {
79  return;
80  }
81  timestamp = _timestamp;
82  targetTimestamp = _targetTimestamp;
83  baton = _baton;
84  EXPECT_TRUE(CACurrentMediaTime() >= _timestamp - kTimerLatencyCompensation);
85  CFRunLoopStop(CFRunLoopGetCurrent());
86  }];
87 
88  [waiter waitForVSync:kWarmUpBaton];
89 
90  // Reference vsync to setup phase.
91  CFTimeInterval now = CACurrentMediaTime();
92  // CVDisplayLink callback is called one and a half frame before the target.
93  [displayLink tickWithTimestamp:now + 0.5 * displayLink.nominalOutputRefreshPeriod
94  targetTimestamp:now + 2 * displayLink.nominalOutputRefreshPeriod];
95  EXPECT_EQ(displayLink.paused, YES);
96  // Vsync was not requested yet, block should not have been called.
97  EXPECT_EQ(timestamp, 0);
98 
99  BusyWait(waitDuration);
100 
101  // Synthesized vsync should come in 1/60th of a second after the first.
102  CFTimeInterval expectedTimestamp = now + expectedDelay;
103  [waiter waitForVSync:1];
104 
105  CFRunLoopRun();
106 
107  EXPECT_DOUBLE_EQ(timestamp, expectedTimestamp);
108  EXPECT_DOUBLE_EQ(targetTimestamp, expectedTimestamp + displayLink.nominalOutputRefreshPeriod);
109  EXPECT_EQ(baton, size_t(1));
110  };
111 
112  // First argument if the wait duration after reference vsync.
113  // Second argument is the expected delay between reference vsync and synthesized vsync.
114  test(0.005, displayLink.nominalOutputRefreshPeriod);
115  test(0.025, 2 * displayLink.nominalOutputRefreshPeriod);
116  test(0.040, 3 * displayLink.nominalOutputRefreshPeriod);
117 }

References BusyWait(), TestDisplayLink::nominalOutputRefreshPeriod, FlutterDisplayLink::paused, and FlutterVSyncWaiter::waitForVSync:.

◆ TEST() [2/3]

TEST ( FlutterVSyncWaiterTest  ,
RequestsInitialVSync   
)

Definition at line 40 of file FlutterVSyncWaiterTest.mm.

40  {
41  TestDisplayLink* displayLink = [[TestDisplayLink alloc] init];
42  EXPECT_TRUE(displayLink.paused);
43  // When created waiter requests a reference vsync to determine vsync phase.
44  FlutterVSyncWaiter* waiter = [[FlutterVSyncWaiter alloc]
45  initWithDisplayLink:displayLink
46  block:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp,
47  uintptr_t baton){
48  }];
49  (void)waiter;
50  EXPECT_FALSE(displayLink.paused);
51  [displayLink tickWithTimestamp:CACurrentMediaTime()
52  targetTimestamp:CACurrentMediaTime() + 1.0 / 60.0];
53  EXPECT_TRUE(displayLink.paused);
54 }

References FlutterDisplayLink::paused.

◆ TEST() [3/3]

TEST ( FlutterVSyncWaiterTest  ,
VSyncWorks   
)

Definition at line 119 of file FlutterVSyncWaiterTest.mm.

119  {
120  TestDisplayLink* displayLink = [[TestDisplayLink alloc] init];
121  displayLink.nominalOutputRefreshPeriod = 1.0 / 60.0;
122  const uintptr_t kWarmUpBaton = 0xFFFFFFFF;
123 
124  struct Entry {
125  CFTimeInterval timestamp;
126  CFTimeInterval targetTimestamp;
127  size_t baton;
128  };
129  __block std::vector<Entry> entries;
130 
131  FlutterVSyncWaiter* waiter = [[FlutterVSyncWaiter alloc]
132  initWithDisplayLink:displayLink
133  block:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp,
134  uintptr_t baton) {
135  entries.push_back({timestamp, targetTimestamp, baton});
136  if (baton == kWarmUpBaton) {
137  return;
138  }
139  EXPECT_TRUE(CACurrentMediaTime() >= timestamp - kTimerLatencyCompensation);
140  CFRunLoopStop(CFRunLoopGetCurrent());
141  }];
142 
143  __block CFTimeInterval expectedStartUntil;
144  // Warm up tick is scheduled immediately in a scheduled block. Schedule another
145  // block here to determine the maximum time when the warm up tick should be
146  // scheduled.
147  [waiter waitForVSync:kWarmUpBaton];
148  [[NSRunLoop currentRunLoop] performBlock:^{
149  expectedStartUntil = CACurrentMediaTime();
150  }];
151 
152  // Reference vsync to setup phase.
153  CFTimeInterval now = CACurrentMediaTime();
154  // CVDisplayLink callback is called one and a half frame before the target.
155  [displayLink tickWithTimestamp:now + 0.5 * displayLink.nominalOutputRefreshPeriod
156  targetTimestamp:now + 2 * displayLink.nominalOutputRefreshPeriod];
157  EXPECT_EQ(displayLink.paused, YES);
158 
159  [waiter waitForVSync:1];
160  CFRunLoopRun();
161 
162  [waiter waitForVSync:2];
163  [displayLink tickWithTimestamp:now + 1.5 * displayLink.nominalOutputRefreshPeriod
164  targetTimestamp:now + 3 * displayLink.nominalOutputRefreshPeriod];
165  CFRunLoopRun();
166 
167  [waiter waitForVSync:3];
168  [displayLink tickWithTimestamp:now + 2.5 * displayLink.nominalOutputRefreshPeriod
169  targetTimestamp:now + 4 * displayLink.nominalOutputRefreshPeriod];
170  CFRunLoopRun();
171 
172  EXPECT_FALSE(displayLink.paused);
173  // Vsync without baton should pause the display link.
174  [displayLink tickWithTimestamp:now + 3.5 * displayLink.nominalOutputRefreshPeriod
175  targetTimestamp:now + 5 * displayLink.nominalOutputRefreshPeriod];
176 
177  CFTimeInterval start = CACurrentMediaTime();
178  while (!displayLink.paused) {
179  // Make sure to run the timer scheduled in display link callback.
180  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.02, NO);
181  if (CACurrentMediaTime() - start > 1.0) {
182  break;
183  }
184  }
185  ASSERT_TRUE(displayLink.paused);
186 
187  EXPECT_EQ(entries.size(), size_t(4));
188 
189  // Warm up frame should be presented as soon as possible.
190  EXPECT_TRUE(entries[0].timestamp <= expectedStartUntil);
191  EXPECT_TRUE(entries[0].targetTimestamp <= expectedStartUntil);
192  EXPECT_EQ(entries[0].baton, kWarmUpBaton);
193 
194  EXPECT_DOUBLE_EQ(entries[1].timestamp, now + displayLink.nominalOutputRefreshPeriod);
195  EXPECT_DOUBLE_EQ(entries[1].targetTimestamp, now + 2 * displayLink.nominalOutputRefreshPeriod);
196  EXPECT_EQ(entries[1].baton, size_t(1));
197  EXPECT_DOUBLE_EQ(entries[2].timestamp, now + 2 * displayLink.nominalOutputRefreshPeriod);
198  EXPECT_DOUBLE_EQ(entries[2].targetTimestamp, now + 3 * displayLink.nominalOutputRefreshPeriod);
199  EXPECT_EQ(entries[2].baton, size_t(2));
200  EXPECT_DOUBLE_EQ(entries[3].timestamp, now + 3 * displayLink.nominalOutputRefreshPeriod);
201  EXPECT_DOUBLE_EQ(entries[3].targetTimestamp, now + 4 * displayLink.nominalOutputRefreshPeriod);
202  EXPECT_EQ(entries[3].baton, size_t(3));
203 }

References TestDisplayLink::nominalOutputRefreshPeriod, FlutterDisplayLink::paused, and FlutterVSyncWaiter::waitForVSync:.

Variable Documentation

◆ kTimerLatencyCompensation

const CFTimeInterval kTimerLatencyCompensation = 0.001
static

Definition at line 63 of file FlutterVSyncWaiterTest.mm.

FlutterVSyncWaiter
Definition: FlutterVSyncWaiter.h:8
kTimerLatencyCompensation
static const CFTimeInterval kTimerLatencyCompensation
Definition: FlutterVSyncWaiterTest.mm:63
BusyWait
static void BusyWait(CFTimeInterval duration)
Definition: FlutterVSyncWaiterTest.mm:56