1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20 #pragma clang diagnostic ignored "-Wextra"
21
22 #undef LOG_TAG
23 #define LOG_TAG "LibSurfaceFlingerUnittests"
24 #define LOG_NDEBUG 0
25
26 #include <common/test/FlagUtils.h>
27 #include "Scheduler/VSyncPredictor.h"
28 #include "mock/DisplayHardware/MockDisplayMode.h"
29
30 #include <gmock/gmock.h>
31 #include <gtest/gtest.h>
32 #include <algorithm>
33 #include <chrono>
34 #include <optional>
35 #include <utility>
36
37 #include <com_android_graphics_surfaceflinger_flags.h>
38
39 using namespace testing;
40 using namespace std::literals;
41 using namespace com::android::graphics::surfaceflinger;
42
43 using NotifyExpectedPresentConfig =
44 ::aidl::android::hardware::graphics::composer3::VrrConfig::NotifyExpectedPresentConfig;
45
46 using android::mock::createDisplayMode;
47 using android::mock::createDisplayModeBuilder;
48 using android::mock::createVrrDisplayMode;
49
50 namespace android::scheduler {
51
52 namespace {
53 MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") {
54 return arg <= value + tolerance && arg >= value - tolerance;
55 }
56
57 MATCHER_P(FpsMatcher, value, "equals") {
58 using fps_approx_ops::operator==;
59 return arg == value;
60 }
61
generateVsyncTimestamps(size_t count,nsecs_t period,nsecs_t bias)62 std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) {
63 std::vector<nsecs_t> vsyncs(count);
64 std::generate(vsyncs.begin(), vsyncs.end(),
65 [&, n = 0]() mutable { return n++ * period + bias; });
66 return vsyncs;
67 }
68
69 constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
70
displayMode(nsecs_t period)71 ftl::NonNull<DisplayModePtr> displayMode(nsecs_t period) {
72 const int32_t kGroup = 0;
73 const auto kResolution = ui::Size(1920, 1080);
74 const auto refreshRate = Fps::fromPeriodNsecs(period);
75 return ftl::as_non_null(createDisplayMode(DisplayModeId(0), refreshRate, kGroup, kResolution,
76 DEFAULT_DISPLAY_ID));
77 }
78
79 class TestClock : public Clock {
80 public:
81 TestClock() = default;
82
now() const83 nsecs_t now() const override { return mNow; }
setNow(nsecs_t now)84 void setNow(nsecs_t now) { mNow = now; }
85
86 private:
87 nsecs_t mNow = 0;
88 };
89
90 class ClockWrapper : public Clock {
91 public:
ClockWrapper(std::shared_ptr<Clock> const & clock)92 ClockWrapper(std::shared_ptr<Clock> const& clock) : mClock(clock) {}
93
now() const94 nsecs_t now() const { return mClock->now(); }
95
96 private:
97 std::shared_ptr<Clock> const mClock;
98 };
99
100 } // namespace
101
102 struct VSyncPredictorTest : testing::Test {
103 nsecs_t mNow = 0;
104 nsecs_t mPeriod = 1000;
105 ftl::NonNull<DisplayModePtr> mMode = displayMode(mPeriod);
106 static constexpr size_t kHistorySize = 10;
107 static constexpr size_t kMinimumSamplesForPrediction = 6;
108 static constexpr size_t kOutlierTolerancePercent = 25;
109 static constexpr nsecs_t mMaxRoundingError = 100;
110
111 std::shared_ptr<TestClock> mClock{std::make_shared<TestClock>()};
112
113 VSyncPredictor tracker{std::make_unique<ClockWrapper>(mClock), mMode, kHistorySize,
114 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
115 };
116
TEST_F(VSyncPredictorTest,reportsAnticipatedPeriod)117 TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) {
118 auto model = tracker.getVSyncPredictionModel();
119
120 EXPECT_THAT(model.slope, Eq(mPeriod));
121 EXPECT_THAT(model.intercept, Eq(0));
122
123 auto const changedPeriod = 2000;
124 tracker.setDisplayModePtr(displayMode(changedPeriod));
125 model = tracker.getVSyncPredictionModel();
126 EXPECT_THAT(model.slope, Eq(changedPeriod));
127 EXPECT_THAT(model.intercept, Eq(0));
128 }
129
TEST_F(VSyncPredictorTest,reportsSamplesNeededWhenHasNoDataPoints)130 TEST_F(VSyncPredictorTest, reportsSamplesNeededWhenHasNoDataPoints) {
131 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
132 EXPECT_TRUE(tracker.needsMoreSamples());
133 tracker.addVsyncTimestamp(mNow += mPeriod);
134 }
135 EXPECT_FALSE(tracker.needsMoreSamples());
136 }
137
TEST_F(VSyncPredictorTest,reportsSamplesNeededAfterExplicitRateChange)138 TEST_F(VSyncPredictorTest, reportsSamplesNeededAfterExplicitRateChange) {
139 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
140 tracker.addVsyncTimestamp(mNow += mPeriod);
141 }
142 EXPECT_FALSE(tracker.needsMoreSamples());
143
144 auto const changedPeriod = mPeriod * 2;
145 tracker.setDisplayModePtr(displayMode(changedPeriod));
146 EXPECT_TRUE(tracker.needsMoreSamples());
147
148 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
149 EXPECT_TRUE(tracker.needsMoreSamples());
150 tracker.addVsyncTimestamp(mNow += changedPeriod);
151 }
152 EXPECT_FALSE(tracker.needsMoreSamples());
153 }
154
TEST_F(VSyncPredictorTest,transitionsToModelledPointsAfterSynthetic)155 TEST_F(VSyncPredictorTest, transitionsToModelledPointsAfterSynthetic) {
156 auto last = mNow;
157 auto const bias = 10;
158 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
159 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
160 mNow += mPeriod - bias;
161 last = mNow;
162 tracker.addVsyncTimestamp(mNow);
163 mNow += bias;
164 }
165
166 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod - bias));
167 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
168 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
169 }
170
TEST_F(VSyncPredictorTest,uponNotifiedOfInaccuracyUsesSynthetic)171 TEST_F(VSyncPredictorTest, uponNotifiedOfInaccuracyUsesSynthetic) {
172 auto const slightlyLessPeriod = mPeriod - 10;
173 auto const changedPeriod = mPeriod - 1;
174 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
175 tracker.addVsyncTimestamp(mNow += slightlyLessPeriod);
176 }
177
178 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyLessPeriod));
179 tracker.setDisplayModePtr(displayMode(changedPeriod));
180 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + changedPeriod));
181 }
182
183 // b/159882858
TEST_F(VSyncPredictorTest,updatesTimebaseForSyntheticAfterIdleTime)184 TEST_F(VSyncPredictorTest, updatesTimebaseForSyntheticAfterIdleTime) {
185 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
186 EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
187 }
188
189 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
190
191 auto const halfPeriod = mPeriod >> 2;
192 nsecs_t relativelyLongGapWithDrift = mPeriod * 100 + halfPeriod;
193
194 EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += relativelyLongGapWithDrift));
195
196 tracker.resetModel();
197 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
198 }
199
TEST_F(VSyncPredictorTest,uponBadVsyncWillSwitchToSyntheticWhileRecalibrating)200 TEST_F(VSyncPredictorTest, uponBadVsyncWillSwitchToSyntheticWhileRecalibrating) {
201 auto const slightlyMorePeriod = mPeriod + 10;
202 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
203 EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += slightlyMorePeriod));
204 }
205
206 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyMorePeriod));
207
208 auto const halfPeriod = mPeriod >> 2;
209 EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += halfPeriod));
210
211 tracker.resetModel();
212 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
213 }
214
TEST_F(VSyncPredictorTest,adaptsToFenceTimelines_60hzHighVariance)215 TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_60hzHighVariance) {
216 // these are precomputed simulated 16.6s vsyncs with uniform distribution +/- 1.6ms error
217 std::vector<nsecs_t> const simulatedVsyncs{
218 15492949, 32325658, 49534984, 67496129, 84652891,
219 100332564, 117737004, 132125931, 149291099, 165199602,
220 };
221 auto constexpr idealPeriod = 16600000;
222 auto constexpr expectedPeriod = 16639242;
223 auto constexpr expectedIntercept = 1049341;
224
225 tracker.setDisplayModePtr(displayMode(idealPeriod));
226 for (auto const& timestamp : simulatedVsyncs) {
227 tracker.addVsyncTimestamp(timestamp);
228 }
229 auto [slope, intercept] = tracker.getVSyncPredictionModel();
230 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
231 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
232 }
233
TEST_F(VSyncPredictorTest,adaptsToFenceTimelines_90hzLowVariance)234 TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_90hzLowVariance) {
235 // these are precomputed simulated 11.1 vsyncs with uniform distribution +/- 1ms error
236 std::vector<nsecs_t> const simulatedVsyncs{
237 11167047, 22603464, 32538479, 44938134, 56321268,
238 66730346, 78062637, 88171429, 99707843, 111397621,
239 };
240 auto idealPeriod = 11110000;
241 auto expectedPeriod = 11089413;
242 auto expectedIntercept = 94421;
243
244 tracker.setDisplayModePtr(displayMode(idealPeriod));
245 for (auto const& timestamp : simulatedVsyncs) {
246 tracker.addVsyncTimestamp(timestamp);
247 }
248 auto [slope, intercept] = tracker.getVSyncPredictionModel();
249 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
250 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
251 }
252
TEST_F(VSyncPredictorTest,adaptsToFenceTimelinesDiscontinuous_22hzLowVariance)253 TEST_F(VSyncPredictorTest, adaptsToFenceTimelinesDiscontinuous_22hzLowVariance) {
254 // these are 11.1s vsyncs with low variance, randomly computed, between -1 and 1ms
255 std::vector<nsecs_t> const simulatedVsyncs{
256 45259463, // 0
257 91511026, // 1
258 136307650, // 2
259 1864501714, // 40
260 1908641034, // 41
261 1955278544, // 42
262 4590180096, // 100
263 4681594994, // 102
264 5499224734, // 120
265 5591378272, // 122
266 };
267 auto idealPeriod = 45454545;
268 auto expectedPeriod = 45450152;
269 auto expectedIntercept = 469647;
270
271 tracker.setDisplayModePtr(displayMode(idealPeriod));
272 for (auto const& timestamp : simulatedVsyncs) {
273 tracker.addVsyncTimestamp(timestamp);
274 }
275 auto [slope, intercept] = tracker.getVSyncPredictionModel();
276 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
277 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
278 }
279
TEST_F(VSyncPredictorTest,againstOutliersDiscontinuous_500hzLowVariance)280 TEST_F(VSyncPredictorTest, againstOutliersDiscontinuous_500hzLowVariance) {
281 std::vector<nsecs_t> const simulatedVsyncs{
282 1992548, // 0
283 4078038, // 1
284 6165794, // 2
285 7958171, // 3
286 10193537, // 4
287 2401840200, // 1200
288 2403000000, // an outlier that should be excluded (1201 and a half)
289 2405803629, // 1202
290 2408028599, // 1203
291 2410121051, // 1204
292 };
293 auto idealPeriod = 2000000;
294 auto expectedPeriod = 1999892;
295 auto expectedIntercept = 86342;
296
297 tracker.setDisplayModePtr(displayMode(idealPeriod));
298 for (auto const& timestamp : simulatedVsyncs) {
299 tracker.addVsyncTimestamp(timestamp);
300 }
301
302 auto [slope, intercept] = tracker.getVSyncPredictionModel();
303 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
304 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
305 }
306
TEST_F(VSyncPredictorTest,recoverAfterDriftedVSyncAreReplacedWithCorrectVSync)307 TEST_F(VSyncPredictorTest, recoverAfterDriftedVSyncAreReplacedWithCorrectVSync) {
308 SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, true);
309 auto constexpr idealPeriodNs = 4166666;
310 auto constexpr minFrameIntervalNs = 8333333;
311 auto constexpr idealPeriod = Fps::fromPeriodNsecs(idealPeriodNs);
312 auto constexpr minFrameRate = Fps::fromPeriodNsecs(minFrameIntervalNs);
313 hal::VrrConfig vrrConfig{.minFrameIntervalNs = minFrameIntervalNs};
314 ftl::NonNull<DisplayModePtr> mode =
315 ftl::as_non_null(createVrrDisplayMode(DisplayModeId(0), idealPeriod, vrrConfig));
316 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), mode, kHistorySize,
317 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
318 vrrTracker.setRenderRate(minFrameRate, /*applyImmediately*/ true);
319 // Curated list of VSyncs that causes the VSync drift.
320 std::vector<nsecs_t> const simulatedVsyncs{74473665741, 74481774375, 74489911818, 74497993491,
321 74506000833, 74510002150, 74513904390, 74517748707,
322 74521550947, 74525383187, 74529165427, 74533067667,
323 74536751484, 74540653724, 74544282649, 74548084889,
324 74551917129, 74555699369, 74559601609, 74563601611,
325 74567503851, 74571358168, 74575260408, 74578889333,
326 74582691573, 74586523813, 74590306053, 74593589870,
327 74597492110, 74601121035, 74604923275, 74608755515,
328 74612537755, 74616166680, 74619795605, 74623424530,
329 74627043455, 74630645695, 74634245935, 74637778175,
330 74641291992, 74644794232, 74648275157, 74651575397,
331 74654807637, 74658007877, 74661176117, 74664345357};
332 for (auto const& timestamp : simulatedVsyncs) {
333 vrrTracker.addVsyncTimestamp(timestamp);
334 }
335 auto slope = vrrTracker.getVSyncPredictionModel().slope;
336 // Without using the idealPeriod for the calculation of the VSync predictor mode the
337 // the slope would be 3343031
338 EXPECT_THAT(slope, IsCloseTo(4347805, mMaxRoundingError));
339 EXPECT_FALSE(vrrTracker.needsMoreSamples());
340
341 auto lastVsync = 74664345357;
342 // Add valid VSyncs to replace the drifted VSyncs
343 for (int i = 0; i <= kHistorySize; i++) {
344 lastVsync += minFrameIntervalNs;
345 EXPECT_TRUE(vrrTracker.addVsyncTimestamp(lastVsync));
346 }
347 EXPECT_FALSE(vrrTracker.needsMoreSamples());
348 slope = vrrTracker.getVSyncPredictionModel().slope;
349 // Corrected slop is closer to the idealPeriod
350 // when valid vsync are inserted otherwise this would still be 3349673
351 EXPECT_THAT(slope, IsCloseTo(idealPeriodNs, mMaxRoundingError));
352 }
353
TEST_F(VSyncPredictorTest,handlesVsyncChange)354 TEST_F(VSyncPredictorTest, handlesVsyncChange) {
355 auto const fastPeriod = 100;
356 auto const fastTimeBase = 100;
357 auto const slowPeriod = 400;
358 auto const slowTimeBase = 800;
359 auto const simulatedVsyncsFast =
360 generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
361 auto const simulatedVsyncsSlow =
362 generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
363
364 tracker.setDisplayModePtr(displayMode(fastPeriod));
365 for (auto const& timestamp : simulatedVsyncsFast) {
366 tracker.addVsyncTimestamp(timestamp);
367 }
368
369 auto const mMaxRoundingError = 100;
370 auto model = tracker.getVSyncPredictionModel();
371 EXPECT_THAT(model.slope, IsCloseTo(fastPeriod, mMaxRoundingError));
372 EXPECT_THAT(model.intercept, IsCloseTo(0, mMaxRoundingError));
373
374 tracker.setDisplayModePtr(displayMode(slowPeriod));
375 for (auto const& timestamp : simulatedVsyncsSlow) {
376 tracker.addVsyncTimestamp(timestamp);
377 }
378 model = tracker.getVSyncPredictionModel();
379 EXPECT_THAT(model.slope, IsCloseTo(slowPeriod, mMaxRoundingError));
380 EXPECT_THAT(model.intercept, IsCloseTo(0, mMaxRoundingError));
381 }
382
TEST_F(VSyncPredictorTest,willBeAccurateUsingPriorResultsForRate)383 TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) {
384 auto const fastPeriod = 101000;
385 auto const fastTimeBase = fastPeriod - 500;
386 auto const fastPeriod2 = 99000;
387
388 auto const slowPeriod = 400000;
389 auto const slowTimeBase = 800000 - 201;
390 auto const simulatedVsyncsFast =
391 generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
392 auto const simulatedVsyncsSlow =
393 generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
394 auto const simulatedVsyncsFast2 =
395 generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod2, fastTimeBase);
396
397 auto idealPeriod = 100000;
398 tracker.setDisplayModePtr(displayMode(idealPeriod));
399 for (auto const& timestamp : simulatedVsyncsFast) {
400 tracker.addVsyncTimestamp(timestamp);
401 }
402 auto model = tracker.getVSyncPredictionModel();
403 EXPECT_THAT(model.slope, Eq(fastPeriod));
404 EXPECT_THAT(model.intercept, Eq(0));
405
406 tracker.setDisplayModePtr(displayMode(slowPeriod));
407 for (auto const& timestamp : simulatedVsyncsSlow) {
408 tracker.addVsyncTimestamp(timestamp);
409 }
410
411 // we had a model for 100ns mPeriod before, use that until the new samples are
412 // sufficiently built up
413 tracker.setDisplayModePtr(displayMode(idealPeriod));
414 model = tracker.getVSyncPredictionModel();
415 EXPECT_THAT(model.slope, Eq(fastPeriod));
416 EXPECT_THAT(model.intercept, Eq(0));
417
418 for (auto const& timestamp : simulatedVsyncsFast2) {
419 tracker.addVsyncTimestamp(timestamp);
420 }
421 model = tracker.getVSyncPredictionModel();
422 EXPECT_THAT(model.slope, Eq(fastPeriod2));
423 EXPECT_THAT(model.intercept, Eq(0));
424 }
425
TEST_F(VSyncPredictorTest,idealModelPredictionsBeforeRegressionModelIsBuilt)426 TEST_F(VSyncPredictorTest, idealModelPredictionsBeforeRegressionModelIsBuilt) {
427 auto const simulatedVsyncs =
428 generateVsyncTimestamps(kMinimumSamplesForPrediction + 1, mPeriod, 0);
429 nsecs_t const mNow = 0;
430 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mPeriod));
431
432 nsecs_t const aBitOfTime = 422;
433
434 for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
435 tracker.addVsyncTimestamp(simulatedVsyncs[i]);
436 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
437 Eq(mPeriod + simulatedVsyncs[i]));
438 }
439
440 for (auto i = kMinimumSamplesForPrediction; i < simulatedVsyncs.size(); i++) {
441 tracker.addVsyncTimestamp(simulatedVsyncs[i]);
442 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
443 Eq(mPeriod + simulatedVsyncs[i]));
444 }
445 }
446
447 // See b/145667109, and comment in prod code under test.
TEST_F(VSyncPredictorTest,doesNotPredictBeforeTimePointWithHigherIntercept)448 TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
449 std::vector<nsecs_t> const simulatedVsyncs{
450 158929578733000,
451 158929306806205, // oldest TS in ringbuffer
452 158929650879052, 158929661969209, 158929684198847, 158929695268171, 158929706370359,
453 };
454 auto const idealPeriod = 11111111;
455 auto const expectedPeriod = 11113919;
456 auto const expectedIntercept = -1195945;
457
458 tracker.setDisplayModePtr(displayMode(idealPeriod));
459 for (auto const& timestamp : simulatedVsyncs) {
460 tracker.addVsyncTimestamp(timestamp);
461 }
462
463 auto [slope, intercept] = tracker.getVSyncPredictionModel();
464 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
465 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
466
467 // (timePoint - oldestTS) % expectedPeriod works out to be: 10702663
468 // (timePoint - oldestTS) / expectedPeriod works out to be: 37.96
469 // so failure to account for the offset will floor the ordinal to 37, which was in the past.
470 auto const timePoint = 158929728723871;
471 auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
472 EXPECT_THAT(prediction, Ge(timePoint));
473 }
474
475 // See b/151146131
TEST_F(VSyncPredictorTest,hasEnoughPrecision)476 TEST_F(VSyncPredictorTest, hasEnoughPrecision) {
477 const auto mode = displayMode(mPeriod);
478 VSyncPredictor tracker{std::make_unique<ClockWrapper>(mClock), mode, 20,
479 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
480 std::vector<nsecs_t> const simulatedVsyncs{840873348817, 840890049444, 840906762675,
481 840923581635, 840940161584, 840956868096,
482 840973702473, 840990256277, 841007116851,
483 841023722530, 841040452167, 841057073002,
484 841073800920, 841090474360, 841107278632,
485 841123898634, 841140750875, 841157287127,
486 841591357014, 840856664232
487
488 };
489 auto const idealPeriod = 16666666;
490 auto const expectedPeriod = 16698426;
491 auto const expectedIntercept = 58055;
492
493 tracker.setDisplayModePtr(displayMode(idealPeriod));
494 for (auto const& timestamp : simulatedVsyncs) {
495 tracker.addVsyncTimestamp(timestamp);
496 }
497
498 auto [slope, intercept] = tracker.getVSyncPredictionModel();
499 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
500 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
501 }
502
TEST_F(VSyncPredictorTest,resetsWhenInstructed)503 TEST_F(VSyncPredictorTest, resetsWhenInstructed) {
504 auto const idealPeriod = 10000;
505 auto const realPeriod = 10500;
506 tracker.setDisplayModePtr(displayMode(idealPeriod));
507 for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
508 tracker.addVsyncTimestamp(i * realPeriod);
509 }
510
511 EXPECT_THAT(tracker.getVSyncPredictionModel().slope, IsCloseTo(realPeriod, mMaxRoundingError));
512 tracker.resetModel();
513 EXPECT_THAT(tracker.getVSyncPredictionModel().slope, IsCloseTo(idealPeriod, mMaxRoundingError));
514 }
515
TEST_F(VSyncPredictorTest,slopeAlwaysValid)516 TEST_F(VSyncPredictorTest, slopeAlwaysValid) {
517 constexpr auto kNumVsyncs = 100;
518 auto invalidPeriod = mPeriod;
519 auto now = 0;
520 for (int i = 0; i < kNumVsyncs; i++) {
521 tracker.addVsyncTimestamp(now);
522 now += invalidPeriod;
523 invalidPeriod *= 0.9f;
524
525 auto [slope, intercept] = tracker.getVSyncPredictionModel();
526 EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f));
527
528 // When VsyncPredictor returns the period it means that it doesn't know how to predict and
529 // it needs to get more samples
530 if (slope == mPeriod && intercept == 0) {
531 EXPECT_TRUE(tracker.needsMoreSamples());
532 }
533 }
534 }
535
operator ""_years(unsigned long long years)536 constexpr nsecs_t operator""_years(unsigned long long years) noexcept {
537 using namespace std::chrono_literals;
538 return years * 365 * 24 * 3600 *
539 std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
540 }
TEST_F(VSyncPredictorTest,aPhoneThatHasBeenAroundAWhileCanStillComputePeriod)541 TEST_F(VSyncPredictorTest, aPhoneThatHasBeenAroundAWhileCanStillComputePeriod) {
542 constexpr nsecs_t timeBase = 100_years;
543
544 for (auto i = 0; i < kHistorySize; i++) {
545 tracker.addVsyncTimestamp(timeBase + i * mPeriod);
546 }
547 auto [slope, intercept] = tracker.getVSyncPredictionModel();
548 EXPECT_THAT(slope, IsCloseTo(mPeriod, mMaxRoundingError));
549 EXPECT_THAT(intercept, Eq(0));
550 }
551
TEST_F(VSyncPredictorTest,isVSyncInPhase)552 TEST_F(VSyncPredictorTest, isVSyncInPhase) {
553 auto last = mNow;
554 auto const bias = 10;
555 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
556 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
557 mNow += mPeriod - bias;
558 last = mNow;
559 tracker.addVsyncTimestamp(mNow);
560 mNow += bias;
561 }
562
563 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod - bias));
564 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
565 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
566
567 const auto maxDivisor = 5;
568 const auto maxPeriods = 15;
569 for (int divisor = 1; divisor < maxDivisor; divisor++) {
570 for (int i = 0; i < maxPeriods; i++) {
571 const bool expectedInPhase = ((kMinimumSamplesForPrediction - 1 + i) % divisor) == 0;
572 EXPECT_THAT(expectedInPhase,
573 tracker.isVSyncInPhase(mNow + i * mPeriod - bias,
574 Fps::fromPeriodNsecs(divisor * mPeriod)))
575 << "vsync at " << mNow + (i + 1) * mPeriod - bias << " is "
576 << (expectedInPhase ? "not " : "") << "in phase for divisor " << divisor;
577 }
578 }
579 }
580
TEST_F(VSyncPredictorTest,isVSyncInPhaseWithRenderRate)581 TEST_F(VSyncPredictorTest, isVSyncInPhaseWithRenderRate) {
582 SET_FLAG_FOR_TEST(flags::vrr_bugfix_24q4, true);
583 auto last = mNow;
584 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
585 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
586 mNow += mPeriod;
587 last = mNow;
588 tracker.addVsyncTimestamp(mNow);
589 }
590
591 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
592 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + mPeriod), Eq(mNow + 2 * mPeriod));
593
594 const auto renderRateFps = Fps::fromPeriodNsecs(mPeriod * 2);
595 tracker.setRenderRate(renderRateFps, /*applyImmediately*/ true);
596
597 EXPECT_FALSE(tracker.isVSyncInPhase(mNow, renderRateFps));
598 EXPECT_TRUE(tracker.isVSyncInPhase(mNow + mPeriod, renderRateFps));
599 EXPECT_FALSE(tracker.isVSyncInPhase(mNow + 2 * mPeriod, renderRateFps));
600 EXPECT_TRUE(tracker.isVSyncInPhase(mNow + 3 * mPeriod, renderRateFps));
601 }
602
TEST_F(VSyncPredictorTest,isVSyncInPhaseForDivisors)603 TEST_F(VSyncPredictorTest, isVSyncInPhaseForDivisors) {
604 auto last = mNow;
605 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
606 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
607 mNow += mPeriod;
608 last = mNow;
609 tracker.addVsyncTimestamp(mNow);
610 }
611
612 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
613
614 EXPECT_TRUE(tracker.isVSyncInPhase(mNow + 1 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 2)));
615 EXPECT_FALSE(tracker.isVSyncInPhase(mNow + 2 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 2)));
616 EXPECT_TRUE(tracker.isVSyncInPhase(mNow + 3 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 2)));
617
618 EXPECT_FALSE(tracker.isVSyncInPhase(mNow + 5 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
619 EXPECT_TRUE(tracker.isVSyncInPhase(mNow + 3 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
620 EXPECT_FALSE(tracker.isVSyncInPhase(mNow + 4 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
621 EXPECT_FALSE(tracker.isVSyncInPhase(mNow + 6 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
622 EXPECT_TRUE(tracker.isVSyncInPhase(mNow + 7 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
623 }
624
TEST_F(VSyncPredictorTest,inconsistentVsyncValueIsFlushedEventually)625 TEST_F(VSyncPredictorTest, inconsistentVsyncValueIsFlushedEventually) {
626 EXPECT_TRUE(tracker.addVsyncTimestamp(600));
627 EXPECT_TRUE(tracker.needsMoreSamples());
628
629 EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
630
631 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
632 EXPECT_TRUE(tracker.needsMoreSamples());
633 EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
634 }
635
636 EXPECT_FALSE(tracker.needsMoreSamples());
637 }
638
TEST_F(VSyncPredictorTest,knownVsyncIsUpdated)639 TEST_F(VSyncPredictorTest, knownVsyncIsUpdated) {
640 EXPECT_TRUE(tracker.addVsyncTimestamp(600));
641 EXPECT_TRUE(tracker.needsMoreSamples());
642 EXPECT_EQ(600, tracker.nextAnticipatedVSyncTimeFrom(mNow));
643
644 EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
645 EXPECT_EQ(mNow + 1000, tracker.nextAnticipatedVSyncTimeFrom(mNow));
646
647 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
648 EXPECT_TRUE(tracker.needsMoreSamples());
649 EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
650 EXPECT_EQ(mNow + 1000, tracker.nextAnticipatedVSyncTimeFrom(mNow));
651 }
652
653 EXPECT_FALSE(tracker.needsMoreSamples());
654 EXPECT_EQ(mNow + 1000, tracker.nextAnticipatedVSyncTimeFrom(mNow));
655 }
656
TEST_F(VSyncPredictorTest,robustToDuplicateTimestamps_60hzRealTraceData)657 TEST_F(VSyncPredictorTest, robustToDuplicateTimestamps_60hzRealTraceData) {
658 // these are real vsync timestamps from b/190331974 which caused vsync predictor
659 // period to spike to 18ms due to very close timestamps
660 std::vector<nsecs_t> const simulatedVsyncs{
661 198353408177, 198370074844, 198371400000, 198374274000, 198390941000, 198407565000,
662 198540887994, 198607538588, 198624218276, 198657655939, 198674224176, 198690880955,
663 198724204319, 198740988133, 198758166681, 198790869196, 198824205052, 198840871678,
664 198857715631, 198890885797, 198924199640, 198940873834, 198974204401,
665 };
666 auto constexpr idealPeriod = 16'666'666;
667 auto constexpr expectedPeriod = 16'644'742;
668 auto constexpr expectedIntercept = 125'626;
669
670 tracker.setDisplayModePtr(displayMode(idealPeriod));
671 for (auto const& timestamp : simulatedVsyncs) {
672 tracker.addVsyncTimestamp(timestamp);
673 }
674 auto [slope, intercept] = tracker.getVSyncPredictionModel();
675 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
676 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
677 }
678
TEST_F(VSyncPredictorTest,setRenderRateIsRespected)679 TEST_F(VSyncPredictorTest, setRenderRateIsRespected) {
680 auto last = mNow;
681 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
682 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
683 mNow += mPeriod;
684 last = mNow;
685 tracker.addVsyncTimestamp(mNow);
686 }
687
688 tracker.setRenderRate(Fps::fromPeriodNsecs(3 * mPeriod), /*applyImmediately*/ false);
689
690 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 3 * mPeriod));
691 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + 3 * mPeriod));
692 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1100), Eq(mNow + 3 * mPeriod));
693 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 2100), Eq(mNow + 3 * mPeriod));
694 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3100), Eq(mNow + 6 * mPeriod));
695 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 4100), Eq(mNow + 6 * mPeriod));
696 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 6 * mPeriod));
697 }
698
TEST_F(VSyncPredictorTest,setRenderRateIsIgnoredIfNotDivisor)699 TEST_F(VSyncPredictorTest, setRenderRateIsIgnoredIfNotDivisor) {
700 auto last = mNow;
701 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
702 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
703 mNow += mPeriod;
704 last = mNow;
705 tracker.addVsyncTimestamp(mNow);
706 }
707
708 tracker.setRenderRate(Fps::fromPeriodNsecs(3.5f * mPeriod), /*applyImmediately*/ false);
709
710 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
711 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod));
712 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1100), Eq(mNow + 2 * mPeriod));
713 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 2100), Eq(mNow + 3 * mPeriod));
714 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3100), Eq(mNow + 4 * mPeriod));
715 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 4100), Eq(mNow + 5 * mPeriod));
716 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 6 * mPeriod));
717 }
718
TEST_F(VSyncPredictorTest,setRenderRateWhenRenderRateGoesDown)719 TEST_F(VSyncPredictorTest, setRenderRateWhenRenderRateGoesDown) {
720 SET_FLAG_FOR_TEST(flags::vrr_config, true);
721 SET_FLAG_FOR_TEST(flags::vrr_bugfix_24q4, true);
722
723 const int32_t kGroup = 0;
724 const auto kResolution = ui::Size(1920, 1080);
725 const auto vsyncRate = Fps::fromPeriodNsecs(500);
726 const auto minFrameRate = Fps::fromPeriodNsecs(1000);
727 hal::VrrConfig vrrConfig;
728 vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
729 const ftl::NonNull<DisplayModePtr> kMode =
730 ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), vsyncRate, kGroup,
731 kResolution, DEFAULT_DISPLAY_ID)
732 .setVrrConfig(std::move(vrrConfig))
733 .build());
734
735 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
736 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
737
738 Fps frameRate = Fps::fromPeriodNsecs(1000);
739 vrrTracker.setRenderRate(frameRate, /*applyImmediately*/ false);
740 vrrTracker.addVsyncTimestamp(0);
741 EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
742 EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000, 1000));
743
744 frameRate = Fps::fromPeriodNsecs(3000);
745 vrrTracker.setRenderRate(frameRate, /*applyImmediately*/ false);
746 EXPECT_TRUE(vrrTracker.isVSyncInPhase(2000, frameRate));
747 }
748
TEST_F(VSyncPredictorTest,setRenderRateHighIsAppliedImmediately)749 TEST_F(VSyncPredictorTest, setRenderRateHighIsAppliedImmediately) {
750 SET_FLAG_FOR_TEST(flags::vrr_config, true);
751
752 const int32_t kGroup = 0;
753 const auto kResolution = ui::Size(1920, 1080);
754 const auto vsyncRate = Fps::fromPeriodNsecs(500);
755 const auto minFrameRate = Fps::fromPeriodNsecs(1000);
756 hal::VrrConfig vrrConfig;
757 vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
758 const ftl::NonNull<DisplayModePtr> kMode =
759 ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), vsyncRate, kGroup,
760 kResolution, DEFAULT_DISPLAY_ID)
761 .setVrrConfig(std::move(vrrConfig))
762 .build());
763
764 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
765 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
766
767 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(1000), /*applyImmediately*/ false);
768 vrrTracker.addVsyncTimestamp(0);
769 EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
770 EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000, 1000));
771
772 // commit to a vsync in the future
773 EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
774
775 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(2000), /*applyImmediately*/ false);
776 EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4000, 4000));
777 EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
778 EXPECT_EQ(8000, vrrTracker.nextAnticipatedVSyncTimeFrom(6000, 6000));
779
780 EXPECT_EQ(12000, vrrTracker.nextAnticipatedVSyncTimeFrom(10000, 10000));
781
782 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(3500), /*applyImmediately*/ false);
783 EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4000, 4000));
784 EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
785 EXPECT_EQ(8000, vrrTracker.nextAnticipatedVSyncTimeFrom(6000, 6000));
786 EXPECT_EQ(10000, vrrTracker.nextAnticipatedVSyncTimeFrom(8000, 8000));
787 EXPECT_EQ(12000, vrrTracker.nextAnticipatedVSyncTimeFrom(10000, 10000));
788 EXPECT_EQ(15500, vrrTracker.nextAnticipatedVSyncTimeFrom(12000, 12000));
789 EXPECT_EQ(19000, vrrTracker.nextAnticipatedVSyncTimeFrom(15500, 15500));
790
791 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(2500), /*applyImmediately*/ false);
792 EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4000, 4000));
793 EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
794 EXPECT_EQ(8000, vrrTracker.nextAnticipatedVSyncTimeFrom(6000, 6000));
795 EXPECT_EQ(10000, vrrTracker.nextAnticipatedVSyncTimeFrom(8000, 8000));
796 EXPECT_EQ(12000, vrrTracker.nextAnticipatedVSyncTimeFrom(10000, 10000));
797 EXPECT_EQ(15500, vrrTracker.nextAnticipatedVSyncTimeFrom(12000, 12000));
798 EXPECT_EQ(19000, vrrTracker.nextAnticipatedVSyncTimeFrom(15500, 15500));
799 EXPECT_EQ(21500, vrrTracker.nextAnticipatedVSyncTimeFrom(19000, 19000));
800
801 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(1000), /*applyImmediately*/ false);
802 EXPECT_EQ(5500, vrrTracker.nextAnticipatedVSyncTimeFrom(4000, 4000));
803 EXPECT_EQ(6500, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
804 EXPECT_EQ(7500, vrrTracker.nextAnticipatedVSyncTimeFrom(6000, 6000));
805 EXPECT_EQ(9500, vrrTracker.nextAnticipatedVSyncTimeFrom(8000, 8000));
806 EXPECT_EQ(11500, vrrTracker.nextAnticipatedVSyncTimeFrom(10000, 10000));
807 EXPECT_EQ(13500, vrrTracker.nextAnticipatedVSyncTimeFrom(12000, 12000));
808 EXPECT_EQ(16500, vrrTracker.nextAnticipatedVSyncTimeFrom(15500, 15500));
809 EXPECT_EQ(20500, vrrTracker.nextAnticipatedVSyncTimeFrom(19000, 19000));
810
811 // matches the previous cadence
812 EXPECT_EQ(21500, vrrTracker.nextAnticipatedVSyncTimeFrom(20500, 20500));
813 }
814
TEST_F(VSyncPredictorTest,minFramePeriodDoesntApplyWhenSameWithRefreshRate)815 TEST_F(VSyncPredictorTest, minFramePeriodDoesntApplyWhenSameWithRefreshRate) {
816 SET_FLAG_FOR_TEST(flags::vrr_config, true);
817
818 const int32_t kGroup = 0;
819 const auto kResolution = ui::Size(1920, 1080);
820 const auto vsyncRate = Fps::fromPeriodNsecs(1000);
821 const auto minFrameRate = Fps::fromPeriodNsecs(1000);
822 hal::VrrConfig vrrConfig;
823 vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
824 const ftl::NonNull<DisplayModePtr> kMode =
825 ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), vsyncRate, kGroup,
826 kResolution, DEFAULT_DISPLAY_ID)
827 .setVrrConfig(std::move(vrrConfig))
828 .build());
829
830 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
831 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
832
833 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(1000), /*applyImmediately*/ false);
834 vrrTracker.addVsyncTimestamp(0);
835 EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
836 EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000, 1000));
837
838 // Assume that the last vsync is wrong due to a vsync drift. It shouldn't matter.
839 EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000, 1700));
840 }
841
TEST_F(VSyncPredictorTest,setRenderRateExplicitAppliedImmediately)842 TEST_F(VSyncPredictorTest, setRenderRateExplicitAppliedImmediately) {
843 SET_FLAG_FOR_TEST(flags::vrr_config, true);
844
845 const int32_t kGroup = 0;
846 const auto kResolution = ui::Size(1920, 1080);
847 const auto vsyncRate = Fps::fromPeriodNsecs(500);
848 const auto minFrameRate = Fps::fromPeriodNsecs(1000);
849 hal::VrrConfig vrrConfig;
850 vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
851 const ftl::NonNull<DisplayModePtr> kMode =
852 ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), vsyncRate, kGroup,
853 kResolution, DEFAULT_DISPLAY_ID)
854 .setVrrConfig(std::move(vrrConfig))
855 .build());
856
857 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
858 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
859
860 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(1000), /*applyImmediately*/ false);
861 vrrTracker.addVsyncTimestamp(0);
862 EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
863 EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000, 1000));
864
865 // commit to a vsync in the future
866 EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 2000));
867
868 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(2000), /*applyImmediately*/ true);
869 EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4000));
870 EXPECT_EQ(7000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
871 EXPECT_EQ(9000, vrrTracker.nextAnticipatedVSyncTimeFrom(7000, 7000));
872 }
873
TEST_F(VSyncPredictorTest,selectsClosestVsyncAfterInactivity)874 TEST_F(VSyncPredictorTest, selectsClosestVsyncAfterInactivity) {
875 SET_FLAG_FOR_TEST(flags::vrr_config, true);
876
877 const int32_t kGroup = 0;
878 const auto kResolution = ui::Size(1920, 1080);
879 const auto vsyncRate = Fps::fromPeriodNsecs(500);
880 const auto minFrameRate = Fps::fromPeriodNsecs(1000);
881 hal::VrrConfig vrrConfig;
882 vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
883 const ftl::NonNull<DisplayModePtr> kMode =
884 ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), vsyncRate, kGroup,
885 kResolution, DEFAULT_DISPLAY_ID)
886 .setVrrConfig(std::move(vrrConfig))
887 .build());
888
889 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
890 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
891
892 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(5000), /*applyImmediately*/ false);
893 vrrTracker.addVsyncTimestamp(0);
894 EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4700));
895 EXPECT_EQ(10000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
896
897 mClock->setNow(50000);
898 EXPECT_EQ(50500, vrrTracker.nextAnticipatedVSyncTimeFrom(50000, 10000));
899 }
900
TEST_F(VSyncPredictorTest,returnsCorrectVsyncWhenLastIsNot)901 TEST_F(VSyncPredictorTest, returnsCorrectVsyncWhenLastIsNot) {
902 SET_FLAG_FOR_TEST(flags::vrr_config, true);
903
904 const int32_t kGroup = 0;
905 const auto kResolution = ui::Size(1920, 1080);
906 const auto vsyncRate = Fps::fromPeriodNsecs(500);
907 const auto minFrameRate = Fps::fromPeriodNsecs(1000);
908 hal::VrrConfig vrrConfig;
909 vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
910 const ftl::NonNull<DisplayModePtr> kMode =
911 ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), vsyncRate, kGroup,
912 kResolution, DEFAULT_DISPLAY_ID)
913 .setVrrConfig(std::move(vrrConfig))
914 .build());
915
916 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
917 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
918
919 vrrTracker.setRenderRate(Fps::fromPeriodNsecs(1000), /*applyImmediately*/ false);
920 vrrTracker.addVsyncTimestamp(0);
921 EXPECT_EQ(2500, vrrTracker.nextAnticipatedVSyncTimeFrom(1234, 1234));
922 }
923
TEST_F(VSyncPredictorTest,adjustsVrrTimeline)924 TEST_F(VSyncPredictorTest, adjustsVrrTimeline) {
925 SET_FLAG_FOR_TEST(flags::vrr_config, true);
926
927 const int32_t kGroup = 0;
928 const auto kResolution = ui::Size(1920, 1080);
929 const auto refreshRate = Fps::fromPeriodNsecs(500);
930 const auto minFrameRate = Fps::fromPeriodNsecs(1000);
931 hal::VrrConfig vrrConfig;
932 vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
933 const ftl::NonNull<DisplayModePtr> kMode =
934 ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), refreshRate, kGroup,
935 kResolution, DEFAULT_DISPLAY_ID)
936 .setVrrConfig(std::move(vrrConfig))
937 .build());
938
939 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
940 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
941
942 vrrTracker.setRenderRate(minFrameRate, /*applyImmediately*/ false);
943 vrrTracker.addVsyncTimestamp(0);
944 EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
945 EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000));
946
947 vrrTracker.onFrameBegin(TimePoint::fromNs(2000),
948 {TimePoint::fromNs(1500), TimePoint::fromNs(1500)});
949 EXPECT_EQ(3500, vrrTracker.nextAnticipatedVSyncTimeFrom(2000, 2000));
950 EXPECT_EQ(4500, vrrTracker.nextAnticipatedVSyncTimeFrom(3500, 3500));
951
952 // Miss when starting 4500 and expect the next vsync will be at 5000 (next one)
953 vrrTracker.onFrameBegin(TimePoint::fromNs(3500),
954 {TimePoint::fromNs(2500), TimePoint::fromNs(2500)});
955 vrrTracker.onFrameMissed(TimePoint::fromNs(4500));
956 EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4500, 4500));
957 EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
958
959 vrrTracker.onFrameBegin(TimePoint::fromNs(7000),
960 {TimePoint::fromNs(6500), TimePoint::fromNs(6500)});
961 EXPECT_EQ(8500, vrrTracker.nextAnticipatedVSyncTimeFrom(8000, 7000));
962 EXPECT_EQ(9500, vrrTracker.nextAnticipatedVSyncTimeFrom(9000, 7000));
963 }
964
TEST_F(VSyncPredictorTest,adjustsVrrTimelineTwoClients)965 TEST_F(VSyncPredictorTest, adjustsVrrTimelineTwoClients) {
966 SET_FLAG_FOR_TEST(flags::vrr_config, true);
967
968 const int32_t kGroup = 0;
969 const auto kResolution = ui::Size(1920, 1080);
970 const auto refreshRate = Fps::fromPeriodNsecs(500);
971 const auto minFrameRate = Fps::fromPeriodNsecs(1000);
972 hal::VrrConfig vrrConfig;
973 vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
974 const ftl::NonNull<DisplayModePtr> kMode =
975 ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), refreshRate, kGroup,
976 kResolution, DEFAULT_DISPLAY_ID)
977 .setVrrConfig(std::move(vrrConfig))
978 .build());
979
980 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
981 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
982
983 vrrTracker.setRenderRate(minFrameRate, /*applyImmediately*/ false);
984 vrrTracker.addVsyncTimestamp(0);
985
986 // App runs ahead
987 EXPECT_EQ(3000, vrrTracker.nextAnticipatedVSyncTimeFrom(2700));
988 EXPECT_EQ(4000, vrrTracker.nextAnticipatedVSyncTimeFrom(3000, 3000));
989 EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4000, 4000));
990
991 // SF starts to catch up
992 EXPECT_EQ(3000, vrrTracker.nextAnticipatedVSyncTimeFrom(2700));
993 vrrTracker.onFrameBegin(TimePoint::fromNs(3000), {TimePoint::fromNs(0), TimePoint::fromNs(0)});
994
995 // SF misses last frame (3000) and observes that when committing (4000)
996 EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
997 EXPECT_EQ(4000, vrrTracker.nextAnticipatedVSyncTimeFrom(3700));
998 vrrTracker.onFrameMissed(TimePoint::fromNs(4000));
999
1000 // SF wakes up again instead of the (4000) missed frame
1001 EXPECT_EQ(4500, vrrTracker.nextAnticipatedVSyncTimeFrom(4000, 4000));
1002 vrrTracker.onFrameBegin(TimePoint::fromNs(4500),
1003 {TimePoint::fromNs(4500), TimePoint::fromNs(4500)});
1004
1005 // Timeline shifted. The app needs to get the next frame at (7500) as its last frame (6500) will
1006 // be presented at (7500)
1007 EXPECT_EQ(7500, vrrTracker.nextAnticipatedVSyncTimeFrom(6000, 6000));
1008 EXPECT_EQ(5500, vrrTracker.nextAnticipatedVSyncTimeFrom(4500, 4500));
1009 vrrTracker.onFrameBegin(TimePoint::fromNs(5500),
1010 {TimePoint::fromNs(4500), TimePoint::fromNs(4500)});
1011
1012 EXPECT_EQ(8500, vrrTracker.nextAnticipatedVSyncTimeFrom(7500, 7500));
1013 EXPECT_EQ(6500, vrrTracker.nextAnticipatedVSyncTimeFrom(5500, 5500));
1014 vrrTracker.onFrameBegin(TimePoint::fromNs(6500),
1015 {TimePoint::fromNs(5500), TimePoint::fromNs(5500)});
1016 }
1017
TEST_F(VSyncPredictorTest,renderRateIsPreservedForCommittedVsyncs)1018 TEST_F(VSyncPredictorTest, renderRateIsPreservedForCommittedVsyncs) {
1019 tracker.addVsyncTimestamp(1000);
1020
1021 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1), Eq(1000));
1022 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(5001), Eq(6000));
1023 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(6001), Eq(7000));
1024
1025 tracker.setRenderRate(Fps::fromPeriodNsecs(2000), /*applyImmediately*/ false);
1026 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1), Eq(1000));
1027 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(5001), Eq(6000));
1028 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(6001), Eq(7000));
1029 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(7001), Eq(9000));
1030 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(8001), Eq(9000));
1031 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(9001), Eq(11000));
1032 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(10001), Eq(11000));
1033
1034 tracker.setRenderRate(Fps::fromPeriodNsecs(3000), /*applyImmediately*/ false);
1035 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1), Eq(1000));
1036 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(5001), Eq(6000));
1037 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(6001), Eq(7000));
1038 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(7001), Eq(9000));
1039 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(8001), Eq(9000));
1040 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(9001), Eq(11000));
1041 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(10001), Eq(11000));
1042 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(11001), Eq(14000));
1043 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(12001), Eq(14000));
1044
1045 // Check the purge logic works
1046 mClock->setNow(20000);
1047 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1), Eq(2000));
1048 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(5001), Eq(8000));
1049 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(6001), Eq(8000));
1050 }
1051
1052 // b/329310308
TEST_F(VSyncPredictorTest,renderRateChangeAfterAppliedImmediately)1053 TEST_F(VSyncPredictorTest, renderRateChangeAfterAppliedImmediately) {
1054 tracker.addVsyncTimestamp(1000);
1055
1056 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1), Eq(1000));
1057 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1001), Eq(2000));
1058 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(2001), Eq(3000));
1059
1060 tracker.setRenderRate(Fps::fromPeriodNsecs(2000), /*applyImmediately*/ true);
1061 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1), Eq(1000));
1062 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1001), Eq(3000));
1063 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(3001), Eq(5000));
1064
1065 tracker.setRenderRate(Fps::fromPeriodNsecs(4000), /*applyImmediately*/ false);
1066 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1), Eq(1000));
1067 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(1001), Eq(3000));
1068 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(3001), Eq(5000));
1069 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(5001), Eq(9000));
1070 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(9001), Eq(13000));
1071 }
1072
TEST_F(VSyncPredictorTest,timelineNotAdjustedForEarlyPresent)1073 TEST_F(VSyncPredictorTest, timelineNotAdjustedForEarlyPresent) {
1074 SET_FLAG_FOR_TEST(flags::vrr_config, true);
1075
1076 const int32_t kGroup = 0;
1077 const auto kResolution = ui::Size(1920, 1080);
1078 const auto refreshRate = Fps::fromPeriodNsecs(500);
1079 const auto minFrameRate = Fps::fromPeriodNsecs(1000);
1080 hal::VrrConfig vrrConfig;
1081 vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
1082 const ftl::NonNull<DisplayModePtr> kMode =
1083 ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), refreshRate, kGroup,
1084 kResolution, DEFAULT_DISPLAY_ID)
1085 .setVrrConfig(std::move(vrrConfig))
1086 .build());
1087
1088 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
1089 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
1090
1091 vrrTracker.setRenderRate(minFrameRate, /*applyImmediately*/ false);
1092 vrrTracker.addVsyncTimestamp(0);
1093 EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
1094
1095 constexpr auto kLastConfirmedExpectedPresentTime = TimePoint::fromNs(1000);
1096 constexpr auto kLastActualSignalTime = TimePoint::fromNs(700); // presented early
1097 vrrTracker.onFrameBegin(TimePoint::fromNs(1400),
1098 {kLastActualSignalTime, kLastConfirmedExpectedPresentTime});
1099 EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1400, 1000));
1100 EXPECT_EQ(3000, vrrTracker.nextAnticipatedVSyncTimeFrom(2000, 1000));
1101 }
1102
TEST_F(VSyncPredictorTest,adjustsOnlyMinFrameViolatingVrrTimeline)1103 TEST_F(VSyncPredictorTest, adjustsOnlyMinFrameViolatingVrrTimeline) {
1104 const auto refreshRate = Fps::fromPeriodNsecs(500);
1105 auto minFrameRate = Fps::fromPeriodNsecs(1000);
1106 hal::VrrConfig vrrConfig{.minFrameIntervalNs =
1107 static_cast<int32_t>(minFrameRate.getPeriodNsecs())};
1108 ftl::NonNull<DisplayModePtr> mode =
1109 ftl::as_non_null(createVrrDisplayMode(DisplayModeId(0), refreshRate, vrrConfig));
1110 VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), mode, kHistorySize,
1111 kMinimumSamplesForPrediction, kOutlierTolerancePercent};
1112 vrrTracker.setRenderRate(minFrameRate, /*applyImmediately*/ false);
1113 vrrTracker.addVsyncTimestamp(0);
1114
1115 EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
1116 EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000));
1117 auto lastConfirmedSignalTime = TimePoint::fromNs(1500);
1118 auto lastConfirmedExpectedPresentTime = TimePoint::fromNs(1000);
1119 vrrTracker.onFrameBegin(TimePoint::fromNs(2000),
1120 {lastConfirmedSignalTime, lastConfirmedExpectedPresentTime});
1121 EXPECT_EQ(3500, vrrTracker.nextAnticipatedVSyncTimeFrom(3000, 1500));
1122
1123 minFrameRate = Fps::fromPeriodNsecs(2000);
1124 vrrTracker.setRenderRate(minFrameRate, /*applyImmediately*/ false);
1125 lastConfirmedSignalTime = TimePoint::fromNs(2500);
1126 lastConfirmedExpectedPresentTime = TimePoint::fromNs(2500);
1127 vrrTracker.onFrameBegin(TimePoint::fromNs(3000),
1128 {lastConfirmedSignalTime, lastConfirmedExpectedPresentTime});
1129 // Enough time without adjusting vsync to present with new rate on time, no need of adjustment
1130 EXPECT_EQ(5500, vrrTracker.nextAnticipatedVSyncTimeFrom(4000, 3500));
1131 }
1132 } // namespace android::scheduler
1133
1134 // TODO(b/129481165): remove the #pragma below and fix conversion issues
1135 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
1136