1 /*
2  * Copyright 2023 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 #include <ftl/optional.h>
18 #include <gtest/gtest.h>
19 
20 #include <common/test/FlagUtils.h>
21 #include <scheduler/Fps.h>
22 #include <scheduler/FrameTargeter.h>
23 #include <scheduler/IVsyncSource.h>
24 
25 #include <com_android_graphics_surfaceflinger_flags.h>
26 
27 using namespace com::android::graphics::surfaceflinger;
28 using namespace std::chrono_literals;
29 
30 namespace android::scheduler {
31 namespace {
32 
33 struct VsyncSource final : IVsyncSource {
VsyncSourceandroid::scheduler::__anon0953a8e10111::VsyncSource34     VsyncSource(Period period, Period minFramePeriod, TimePoint deadline)
35           : vsyncPeriod(period), framePeriod(minFramePeriod), vsyncDeadline(deadline) {}
36 
37     const Period vsyncPeriod;
38     const Period framePeriod;
39     const TimePoint vsyncDeadline;
40 
periodandroid::scheduler::__anon0953a8e10111::VsyncSource41     Period period() const override { return vsyncPeriod; }
vsyncDeadlineAfterandroid::scheduler::__anon0953a8e10111::VsyncSource42     TimePoint vsyncDeadlineAfter(TimePoint, ftl::Optional<TimePoint> = {}) const override {
43         return vsyncDeadline;
44     }
minFramePeriodandroid::scheduler::__anon0953a8e10111::VsyncSource45     Period minFramePeriod() const override { return framePeriod; }
46 };
47 
48 } // namespace
49 
50 class FrameTargeterTestBase : public testing::Test {
51 public:
FrameTargeterTestBase(FeatureFlags flags)52     FrameTargeterTestBase(FeatureFlags flags) : mTargeter(PhysicalDisplayId::fromPort(13), flags) {}
53 
target() const54     const auto& target() const { return mTargeter.target(); }
55 
wouldPresentEarly(Period minFramePeriod) const56     bool wouldPresentEarly(Period minFramePeriod) const {
57         return target().wouldPresentEarly(minFramePeriod);
58     }
59 
60     struct Frame {
Frameandroid::scheduler::FrameTargeterTestBase::Frame61         Frame(FrameTargeterTestBase* testPtr, VsyncId vsyncId, TimePoint& frameBeginTime,
62               Duration frameDuration, Fps refreshRate, Fps peakRefreshRate,
63               FrameTargeter::IsFencePendingFuncPtr isFencePendingFuncPtr = Frame::fenceSignaled,
64               const ftl::Optional<VsyncSource>& vsyncSourceOpt = std::nullopt)
65               : testPtr(testPtr),
66                 frameBeginTime(frameBeginTime),
67                 period(refreshRate.getPeriod()),
68                 minFramePeriod(peakRefreshRate.getPeriod()) {
69             const FrameTargeter::BeginFrameArgs args{.frameBeginTime = frameBeginTime,
70                                                      .vsyncId = vsyncId,
71                                                      .expectedVsyncTime =
72                                                              frameBeginTime + frameDuration,
73                                                      .sfWorkDuration = 10ms,
74                                                      .hwcMinWorkDuration = kHwcMinWorkDuration};
75 
76             testPtr->mTargeter.beginFrame(args,
77                                           vsyncSourceOpt
78                                                   .or_else([&] {
79                                                       return std::make_optional(
80                                                               VsyncSource(period, period,
81                                                                           args.expectedVsyncTime));
82                                                   })
83                                                   .value(),
84                                           isFencePendingFuncPtr);
85         }
86 
endandroid::scheduler::FrameTargeterTestBase::Frame87         FenceTimePtr end(CompositionCoverage coverage = CompositionCoverage::Hwc) {
88             if (ended) return nullptr;
89             ended = true;
90 
91             auto [fence, fenceTime] = testPtr->mFenceMap.makePendingFenceForTest();
92             testPtr->mTargeter.setPresentFence(std::move(fence), fenceTime);
93 
94             testPtr->mTargeter.endFrame({.compositionCoverage = coverage});
95             return fenceTime;
96         }
97 
~Frameandroid::scheduler::FrameTargeterTestBase::Frame98         ~Frame() {
99             end();
100             frameBeginTime += period;
101         }
102 
fencePendingandroid::scheduler::FrameTargeterTestBase::Frame103         static bool fencePending(const FenceTimePtr&, int) { return true; }
fenceSignaledandroid::scheduler::FrameTargeterTestBase::Frame104         static bool fenceSignaled(const FenceTimePtr&, int) { return false; }
105 
106         FrameTargeterTestBase* const testPtr;
107 
108         TimePoint& frameBeginTime;
109         const Period period;
110         const Period minFramePeriod;
111 
112         bool ended = false;
113     };
114 
115     static constexpr Duration kHwcMinWorkDuration = std::chrono::nanoseconds(5ns);
116 
117 private:
118     FenceToFenceTimeMap mFenceMap;
119 
120     FrameTargeter mTargeter;
121 };
122 
123 class FrameTargeterTest : public FrameTargeterTestBase {
124 public:
FrameTargeterTest()125     FrameTargeterTest() : FrameTargeterTestBase(Feature::kBackpressureGpuComposition) {}
126 };
127 
128 class FrameTargeterWithExpectedPresentSupportTest : public FrameTargeterTestBase {
129 public:
FrameTargeterWithExpectedPresentSupportTest()130     FrameTargeterWithExpectedPresentSupportTest()
131           : FrameTargeterTestBase(FeatureFlags(Feature::kBackpressureGpuComposition) |
132                                   Feature::kExpectedPresentTime) {}
133 };
134 
TEST_F(FrameTargeterTest,targetsFrames)135 TEST_F(FrameTargeterTest, targetsFrames) {
136     VsyncId vsyncId{42};
137     {
138         TimePoint frameBeginTime(989ms);
139         const Frame frame(this, vsyncId++, frameBeginTime, 10ms, 60_Hz, 60_Hz);
140 
141         EXPECT_EQ(target().vsyncId(), VsyncId{42});
142         EXPECT_EQ(target().frameBeginTime(), TimePoint(989ms));
143         EXPECT_EQ(target().expectedPresentTime(), TimePoint(999ms));
144         EXPECT_EQ(target().expectedFrameDuration(), 10ms);
145     }
146     {
147         TimePoint frameBeginTime(1100ms);
148         const Frame frame(this, vsyncId++, frameBeginTime, 11ms, 60_Hz, 60_Hz);
149 
150         EXPECT_EQ(target().vsyncId(), VsyncId{43});
151         EXPECT_EQ(target().frameBeginTime(), TimePoint(1100ms));
152         EXPECT_EQ(target().expectedPresentTime(), TimePoint(1111ms));
153         EXPECT_EQ(target().expectedFrameDuration(), 11ms);
154     }
155 }
156 
TEST_F(FrameTargeterTest,inflatesExpectedPresentTime)157 TEST_F(FrameTargeterTest, inflatesExpectedPresentTime) {
158     // Negative such that `expectedVsyncTime` is in the past.
159     constexpr Duration kFrameDuration = -3ms;
160     TimePoint frameBeginTime(777ms);
161 
162     constexpr Fps kRefreshRate = 120_Hz;
163     const VsyncSource vsyncSource(kRefreshRate.getPeriod(), kRefreshRate.getPeriod(),
164                                   frameBeginTime + 5ms);
165     const Frame frame(this, VsyncId{123}, frameBeginTime, kFrameDuration, kRefreshRate,
166                       kRefreshRate, Frame::fenceSignaled, vsyncSource);
167 
168     EXPECT_EQ(target().expectedPresentTime(), vsyncSource.vsyncDeadline + vsyncSource.vsyncPeriod);
169 }
170 
TEST_F(FrameTargeterTest,recallsPastVsync)171 TEST_F(FrameTargeterTest, recallsPastVsync) {
172     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
173     VsyncId vsyncId{111};
174     TimePoint frameBeginTime(1000ms);
175     constexpr Fps kRefreshRate = 60_Hz;
176     constexpr Period kPeriod = kRefreshRate.getPeriod();
177     constexpr Duration kFrameDuration = 13ms;
178 
179     for (int n = 5; n-- > 0;) {
180         Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
181         const auto fence = frame.end();
182 
183         EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - kPeriod);
184         EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), fence);
185     }
186 }
187 
TEST_F(FrameTargeterTest,recallsPastVsyncTwoVsyncsAhead)188 TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
189     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
190     VsyncId vsyncId{222};
191     TimePoint frameBeginTime(2000ms);
192     constexpr Fps kRefreshRate = 120_Hz;
193     constexpr Period kPeriod = kRefreshRate.getPeriod();
194     constexpr Duration kFrameDuration = 10ms;
195 
196     FenceTimePtr previousFence = FenceTime::NO_FENCE;
197 
198     for (int n = 5; n-- > 0;) {
199         Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
200         const auto fence = frame.end();
201 
202         EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
203         EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence);
204 
205         previousFence = fence;
206     }
207 }
208 
TEST_F(FrameTargeterTest,recallsPastNVsyncTwoVsyncsAhead)209 TEST_F(FrameTargeterTest, recallsPastNVsyncTwoVsyncsAhead) {
210     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
211     VsyncId vsyncId{222};
212     TimePoint frameBeginTime(2000ms);
213     constexpr Fps kRefreshRate = 120_Hz;
214     constexpr Period kPeriod = kRefreshRate.getPeriod();
215     constexpr Duration kFrameDuration = 10ms;
216 
217     FenceTimePtr previousFence = FenceTime::NO_FENCE;
218 
219     for (int n = 5; n-- > 0;) {
220         Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
221         const auto fence = frame.end();
222 
223         const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
224         EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
225         EXPECT_EQ(target().presentFenceForPastVsync(kFrameDuration), previousFence);
226 
227         frameBeginTime += kPeriod;
228         previousFence = fence;
229     }
230 }
231 
TEST_F(FrameTargeterTest,recallsPastVsyncTwoVsyncsAheadVrr)232 TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) {
233     SET_FLAG_FOR_TEST(flags::vrr_config, true);
234     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
235 
236     VsyncId vsyncId{222};
237     TimePoint frameBeginTime(2000ms);
238     constexpr Fps kRefreshRate = 120_Hz;
239     constexpr Fps kPeakRefreshRate = 240_Hz;
240     constexpr Period kPeriod = kRefreshRate.getPeriod();
241     constexpr Duration kFrameDuration = 10ms;
242 
243     FenceTimePtr previousFence = FenceTime::NO_FENCE;
244 
245     for (int n = 5; n-- > 0;) {
246         Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
247                     kPeakRefreshRate);
248         const auto fence = frame.end();
249 
250         EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
251         EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence);
252 
253         previousFence = fence;
254     }
255 }
256 
TEST_F(FrameTargeterTest,recallsPastNVsyncTwoVsyncsAheadVrr)257 TEST_F(FrameTargeterTest, recallsPastNVsyncTwoVsyncsAheadVrr) {
258     SET_FLAG_FOR_TEST(flags::vrr_config, true);
259     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
260 
261     VsyncId vsyncId{222};
262     TimePoint frameBeginTime(2000ms);
263     constexpr Fps kRefreshRate = 120_Hz;
264     constexpr Fps kPeakRefreshRate = 240_Hz;
265     constexpr Period kPeriod = kRefreshRate.getPeriod();
266     constexpr Duration kFrameDuration = 10ms;
267 
268     FenceTimePtr previousFence = FenceTime::NO_FENCE;
269 
270     for (int n = 5; n-- > 0;) {
271         Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
272                     kPeakRefreshRate);
273         const auto fence = frame.end();
274 
275         const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
276         EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
277         EXPECT_EQ(target().presentFenceForPastVsync(kFrameDuration), previousFence);
278 
279         frameBeginTime += kPeriod;
280         previousFence = fence;
281     }
282 }
283 
TEST_F(FrameTargeterTest,doesNotDetectEarlyPresentIfNoFence)284 TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
285     constexpr Period kPeriod = (60_Hz).getPeriod();
286     EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), FenceTime::NO_FENCE);
287     EXPECT_FALSE(wouldPresentEarly(kPeriod));
288 }
289 
TEST_F(FrameTargeterTest,detectsEarlyPresent)290 TEST_F(FrameTargeterTest, detectsEarlyPresent) {
291     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
292     VsyncId vsyncId{333};
293     TimePoint frameBeginTime(3000ms);
294     constexpr Fps kRefreshRate = 60_Hz;
295     constexpr Period kPeriod = kRefreshRate.getPeriod();
296 
297     // The target is not early while past present fences are pending.
298     for (int n = 3; n-- > 0;) {
299         const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
300         EXPECT_FALSE(wouldPresentEarly(kPeriod));
301         EXPECT_FALSE(target().earliestPresentTime());
302     }
303 
304     // The target is early if the past present fence was signaled.
305     Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
306     const auto fence = frame.end();
307     fence->signalForTest(frameBeginTime.ns());
308 
309     Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
310 
311     // `finalFrame` would present early, so it has an earliest present time.
312     EXPECT_TRUE(wouldPresentEarly(kPeriod));
313     ASSERT_NE(std::nullopt, target().earliestPresentTime());
314     EXPECT_EQ(*target().earliestPresentTime(),
315               target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
316 }
317 
318 // Same as `detectsEarlyPresent`, above, but verifies that we do not set an earliest present time
319 // when there is expected present time support.
TEST_F(FrameTargeterWithExpectedPresentSupportTest,detectsEarlyPresent)320 TEST_F(FrameTargeterWithExpectedPresentSupportTest, detectsEarlyPresent) {
321     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
322     VsyncId vsyncId{333};
323     TimePoint frameBeginTime(3000ms);
324     constexpr Fps kRefreshRate = 60_Hz;
325     constexpr Period kPeriod = kRefreshRate.getPeriod();
326 
327     // The target is not early while past present fences are pending.
328     for (int n = 3; n-- > 0;) {
329         const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
330         EXPECT_FALSE(wouldPresentEarly(kPeriod));
331         EXPECT_FALSE(target().earliestPresentTime());
332     }
333 
334     // The target is early if the past present fence was signaled.
335     Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
336     const auto fence = frame.end();
337     fence->signalForTest(frameBeginTime.ns());
338 
339     Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
340 
341     // `finalFrame` would present early, but we have expected present time support, so it has no
342     // earliest present time.
343     EXPECT_TRUE(wouldPresentEarly(kPeriod));
344     ASSERT_EQ(std::nullopt, target().earliestPresentTime());
345 }
346 
TEST_F(FrameTargeterTest,detectsEarlyPresentTwoVsyncsAhead)347 TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
348     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
349     VsyncId vsyncId{444};
350     TimePoint frameBeginTime(4000ms);
351     constexpr Fps kRefreshRate = 120_Hz;
352     constexpr Period kPeriod = kRefreshRate.getPeriod();
353 
354     // The target is not early while past present fences are pending.
355     for (int n = 3; n-- > 0;) {
356         const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
357         EXPECT_FALSE(wouldPresentEarly(kPeriod));
358         EXPECT_FALSE(target().earliestPresentTime());
359     }
360 
361     Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
362     const auto fence = frame.end();
363     fence->signalForTest(frameBeginTime.ns());
364 
365     // The target is two VSYNCs ahead, so the past present fence is still pending.
366     EXPECT_FALSE(wouldPresentEarly(kPeriod));
367     EXPECT_FALSE(target().earliestPresentTime());
368 
369     { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); }
370 
371     Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
372 
373     // The target is early if the past present fence was signaled.
374     EXPECT_TRUE(wouldPresentEarly(kPeriod));
375     ASSERT_NE(std::nullopt, target().earliestPresentTime());
376     EXPECT_EQ(*target().earliestPresentTime(),
377               target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
378 }
379 
TEST_F(FrameTargeterTest,detectsEarlyPresentNVsyncsAhead)380 TEST_F(FrameTargeterTest, detectsEarlyPresentNVsyncsAhead) {
381     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
382     VsyncId vsyncId{444};
383     TimePoint frameBeginTime(4000ms);
384     Fps refreshRate = 120_Hz;
385     Period period = refreshRate.getPeriod();
386 
387     // The target is not early while past present fences are pending.
388     for (int n = 5; n-- > 0;) {
389         const Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
390         EXPECT_FALSE(wouldPresentEarly(period));
391         EXPECT_FALSE(target().earliestPresentTime());
392     }
393 
394     Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
395     auto fence = frame.end();
396     frameBeginTime += period;
397     fence->signalForTest(frameBeginTime.ns());
398 
399     // The target is two VSYNCs ahead, so the past present fence is still pending.
400     EXPECT_FALSE(wouldPresentEarly(period));
401     EXPECT_FALSE(target().earliestPresentTime());
402 
403     { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate); }
404 
405     Frame oneEarlyPresentFrame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
406     // The target is early if the past present fence was signaled.
407     EXPECT_TRUE(wouldPresentEarly(period));
408     ASSERT_NE(std::nullopt, target().earliestPresentTime());
409     EXPECT_EQ(*target().earliestPresentTime(),
410               target().expectedPresentTime() - period - kHwcMinWorkDuration);
411 
412     fence = oneEarlyPresentFrame.end();
413     frameBeginTime += period;
414     fence->signalForTest(frameBeginTime.ns());
415 
416     // Change rate to track frame more than 2 vsyncs ahead
417     refreshRate = 144_Hz;
418     period = refreshRate.getPeriod();
419     Frame onePresentEarlyFrame(this, vsyncId++, frameBeginTime, 16ms, refreshRate, refreshRate);
420     // The target is not early as last frame as the past frame is tracked for pending.
421     EXPECT_FALSE(wouldPresentEarly(period));
422 }
423 
TEST_F(FrameTargeterTest,detectsEarlyPresentThreeVsyncsAhead)424 TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
425     SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
426     TimePoint frameBeginTime(5000ms);
427     constexpr Fps kRefreshRate = 144_Hz;
428     constexpr Period kPeriod = kRefreshRate.getPeriod();
429 
430     const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate);
431 
432     // The target is more than two VSYNCs ahead, but present fences are not tracked that far back.
433     EXPECT_TRUE(wouldPresentEarly(kPeriod));
434     EXPECT_TRUE(target().earliestPresentTime());
435     EXPECT_EQ(*target().earliestPresentTime(),
436               target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
437 }
438 
TEST_F(FrameTargeterTest,detectsMissedFrames)439 TEST_F(FrameTargeterTest, detectsMissedFrames) {
440     VsyncId vsyncId{555};
441     TimePoint frameBeginTime(5000ms);
442     constexpr Fps kRefreshRate = 60_Hz;
443     constexpr Period kPeriod = kRefreshRate.getPeriod();
444 
445     EXPECT_FALSE(target().isFramePending());
446     EXPECT_FALSE(target().didMissFrame());
447     EXPECT_FALSE(target().didMissHwcFrame());
448 
449     {
450         const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
451         EXPECT_FALSE(target().isFramePending());
452 
453         // The frame did not miss if the past present fence is invalid.
454         EXPECT_FALSE(target().didMissFrame());
455         EXPECT_FALSE(target().didMissHwcFrame());
456     }
457     {
458         Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
459                     Frame::fencePending);
460         EXPECT_TRUE(target().isFramePending());
461 
462         // The frame missed if the past present fence is pending.
463         EXPECT_TRUE(target().didMissFrame());
464         EXPECT_TRUE(target().didMissHwcFrame());
465 
466         frame.end(CompositionCoverage::Gpu);
467     }
468     {
469         const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
470                           Frame::fencePending);
471         EXPECT_TRUE(target().isFramePending());
472 
473         // The GPU frame missed if the past present fence is pending.
474         EXPECT_TRUE(target().didMissFrame());
475         EXPECT_FALSE(target().didMissHwcFrame());
476     }
477     {
478         Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
479         EXPECT_FALSE(target().isFramePending());
480 
481         const auto fence = frame.end();
482         const auto expectedPresentTime = target().expectedPresentTime();
483         fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2 + 1);
484     }
485     {
486         Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
487         EXPECT_FALSE(target().isFramePending());
488 
489         const auto fence = frame.end();
490         const auto expectedPresentTime = target().expectedPresentTime();
491         fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2);
492 
493         // The frame missed if the past present fence was signaled but not within slop.
494         EXPECT_TRUE(target().didMissFrame());
495         EXPECT_TRUE(target().didMissHwcFrame());
496     }
497     {
498         Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
499         EXPECT_FALSE(target().isFramePending());
500 
501         // The frame did not miss if the past present fence was signaled within slop.
502         EXPECT_FALSE(target().didMissFrame());
503         EXPECT_FALSE(target().didMissHwcFrame());
504     }
505 }
506 
507 } // namespace android::scheduler
508