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  [waiter waitForVSync:kWarmUpBaton];
144 
145  // Reference vsync to setup phase.
146  CFTimeInterval now = CACurrentMediaTime();
147  // CVDisplayLink callback is called one and a half frame before the target.
148  [displayLink tickWithTimestamp:now + 0.5 * displayLink.nominalOutputRefreshPeriod
149  targetTimestamp:now + 2 * displayLink.nominalOutputRefreshPeriod];
150  EXPECT_EQ(displayLink.paused, YES);
151 
152  [waiter waitForVSync:1];
153  CFRunLoopRun();
154 
155  [waiter waitForVSync:2];
156  [displayLink tickWithTimestamp:now + 1.5 * displayLink.nominalOutputRefreshPeriod
157  targetTimestamp:now + 3 * displayLink.nominalOutputRefreshPeriod];
158  CFRunLoopRun();
159 
160  [waiter waitForVSync:3];
161  [displayLink tickWithTimestamp:now + 2.5 * displayLink.nominalOutputRefreshPeriod
162  targetTimestamp:now + 4 * displayLink.nominalOutputRefreshPeriod];
163  CFRunLoopRun();
164 
165  EXPECT_FALSE(displayLink.paused);
166  // Vsync without baton should pause the display link.
167  [displayLink tickWithTimestamp:now + 3.5 * displayLink.nominalOutputRefreshPeriod
168  targetTimestamp:now + 5 * displayLink.nominalOutputRefreshPeriod];
169  // Make sure to run the timer scheduled in display link callback.
170  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.02, NO);
171  ASSERT_TRUE(displayLink.paused);
172 
173  EXPECT_EQ(entries.size(), size_t(4));
174 
175  // Warm up frame should be presented as soon as possible.
176  EXPECT_TRUE(fabs(entries[0].timestamp - now) < 0.001);
177  EXPECT_TRUE(fabs(entries[0].targetTimestamp - now) < 0.001);
178  EXPECT_EQ(entries[0].baton, kWarmUpBaton);
179 
180  EXPECT_DOUBLE_EQ(entries[1].timestamp, now + displayLink.nominalOutputRefreshPeriod);
181  EXPECT_DOUBLE_EQ(entries[1].targetTimestamp, now + 2 * displayLink.nominalOutputRefreshPeriod);
182  EXPECT_EQ(entries[1].baton, size_t(1));
183  EXPECT_DOUBLE_EQ(entries[2].timestamp, now + 2 * displayLink.nominalOutputRefreshPeriod);
184  EXPECT_DOUBLE_EQ(entries[2].targetTimestamp, now + 3 * displayLink.nominalOutputRefreshPeriod);
185  EXPECT_EQ(entries[2].baton, size_t(2));
186  EXPECT_DOUBLE_EQ(entries[3].timestamp, now + 3 * displayLink.nominalOutputRefreshPeriod);
187  EXPECT_DOUBLE_EQ(entries[3].targetTimestamp, now + 4 * displayLink.nominalOutputRefreshPeriod);
188  EXPECT_EQ(entries[3].baton, size_t(3));
189 }

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