Flutter Engine
 
Loading...
Searching...
No Matches
FlutterVSyncWaiterTest.mm File Reference
import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDisplayLink.h"
import "flutter/shell/platform/darwin/macos/InternalFlutterSwift/InternalFlutterSwift.h"
import "flutter/shell/platform/darwin/macos/framework/Source/FlutterVSyncWaiter.h"
import "flutter/testing/testing.h"

Go to the source code of this file.

Classes

class  TestDisplayLink
 
class  FlutterVSyncWaiterTest
 

Functions

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

Variables

static const CFTimeInterval kTimerLatencyCompensation = 0.001
 

Function Documentation

◆ BusyWait()

static void BusyWait ( CFTimeInterval  duration)
static

Definition at line 61 of file FlutterVSyncWaiterTest.mm.

61 {
62 CFTimeInterval start = CACurrentMediaTime();
63 while (CACurrentMediaTime() < start + duration) {
64 }
65}
const size_t start

References start.

Referenced by TEST_F().

◆ TEST_F() [1/3]

TEST_F ( FlutterVSyncWaiterTest  ,
FirstVSyncIsSynthesized   
)

Definition at line 70 of file FlutterVSyncWaiterTest.mm.

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

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

◆ TEST_F() [2/3]

TEST_F ( FlutterVSyncWaiterTest  ,
RequestsInitialVSync   
)

Definition at line 44 of file FlutterVSyncWaiterTest.mm.

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

References FlutterVSyncWaiter::invalidate, and FlutterDisplayLink::paused.

◆ TEST_F() [3/3]

TEST_F ( FlutterVSyncWaiterTest  ,
VSyncWorks   
)

Definition at line 126 of file FlutterVSyncWaiterTest.mm.

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

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

Variable Documentation

◆ kTimerLatencyCompensation

const CFTimeInterval kTimerLatencyCompensation = 0.001
static

Definition at line 68 of file FlutterVSyncWaiterTest.mm.