Flutter macOS Embedder
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
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 54 of file FlutterVSyncWaiterTest.mm.

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

Referenced by TEST().

◆ TEST() [1/3]

TEST ( FlutterVSyncWaiterTest  ,
FirstVSyncIsSynthesized   
)

Definition at line 63 of file FlutterVSyncWaiterTest.mm.

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

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

◆ TEST() [2/3]

TEST ( FlutterVSyncWaiterTest  ,
RequestsInitialVSync   
)

Definition at line 38 of file FlutterVSyncWaiterTest.mm.

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

References FlutterDisplayLink::paused.

◆ TEST() [3/3]

TEST ( FlutterVSyncWaiterTest  ,
VSyncWorks   
)

Definition at line 117 of file FlutterVSyncWaiterTest.mm.

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

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

Variable Documentation

◆ kTimerLatencyCompensation

const CFTimeInterval kTimerLatencyCompensation = 0.001
static

Definition at line 61 of file FlutterVSyncWaiterTest.mm.