blob: 5448eecc600ca201aa05b55c6168aa5771cc1734 [file] [log] [blame]
Dominik Laskowskib418dd72023-06-13 17:31:04 -04001/*
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
Ady Abraham3db8a3c2023-11-20 17:53:47 -080020#include <common/test/FlagUtils.h>
Dominik Laskowskib418dd72023-06-13 17:31:04 -040021#include <scheduler/Fps.h>
22#include <scheduler/FrameTargeter.h>
23#include <scheduler/IVsyncSource.h>
24
Ady Abraham3db8a3c2023-11-20 17:53:47 -080025#include <com_android_graphics_surfaceflinger_flags.h>
26
ramindani513e6502024-04-10 15:22:19 -070027using namespace com::android::graphics::surfaceflinger;
Dominik Laskowskib418dd72023-06-13 17:31:04 -040028using namespace std::chrono_literals;
29
30namespace android::scheduler {
31namespace {
32
33struct VsyncSource final : IVsyncSource {
Ady Abraham3db8a3c2023-11-20 17:53:47 -080034 VsyncSource(Period period, Period minFramePeriod, TimePoint deadline)
35 : vsyncPeriod(period), framePeriod(minFramePeriod), vsyncDeadline(deadline) {}
Dominik Laskowskib418dd72023-06-13 17:31:04 -040036
37 const Period vsyncPeriod;
Ady Abraham3db8a3c2023-11-20 17:53:47 -080038 const Period framePeriod;
Dominik Laskowskib418dd72023-06-13 17:31:04 -040039 const TimePoint vsyncDeadline;
40
41 Period period() const override { return vsyncPeriod; }
Leon Scroggins IIIa0785012024-01-23 16:05:59 -050042 TimePoint vsyncDeadlineAfter(TimePoint, ftl::Optional<TimePoint> = {}) const override {
43 return vsyncDeadline;
44 }
Ady Abraham3db8a3c2023-11-20 17:53:47 -080045 Period minFramePeriod() const override { return framePeriod; }
Dominik Laskowskib418dd72023-06-13 17:31:04 -040046};
47
48} // namespace
49
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050050class FrameTargeterTestBase : public testing::Test {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040051public:
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050052 FrameTargeterTestBase(FeatureFlags flags) : mTargeter(PhysicalDisplayId::fromPort(13), flags) {}
53
Dominik Laskowskib418dd72023-06-13 17:31:04 -040054 const auto& target() const { return mTargeter.target(); }
55
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050056 bool wouldPresentEarly(Period minFramePeriod) const {
57 return target().wouldPresentEarly(minFramePeriod);
58 }
59
Dominik Laskowskib418dd72023-06-13 17:31:04 -040060 struct Frame {
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050061 Frame(FrameTargeterTestBase* testPtr, VsyncId vsyncId, TimePoint& frameBeginTime,
Ady Abraham3db8a3c2023-11-20 17:53:47 -080062 Duration frameDuration, Fps refreshRate, Fps peakRefreshRate,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040063 FrameTargeter::IsFencePendingFuncPtr isFencePendingFuncPtr = Frame::fenceSignaled,
64 const ftl::Optional<VsyncSource>& vsyncSourceOpt = std::nullopt)
Ady Abraham3db8a3c2023-11-20 17:53:47 -080065 : testPtr(testPtr),
66 frameBeginTime(frameBeginTime),
67 period(refreshRate.getPeriod()),
68 minFramePeriod(peakRefreshRate.getPeriod()) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040069 const FrameTargeter::BeginFrameArgs args{.frameBeginTime = frameBeginTime,
70 .vsyncId = vsyncId,
71 .expectedVsyncTime =
72 frameBeginTime + frameDuration,
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050073 .sfWorkDuration = 10ms,
74 .hwcMinWorkDuration = kHwcMinWorkDuration};
Dominik Laskowskib418dd72023-06-13 17:31:04 -040075
76 testPtr->mTargeter.beginFrame(args,
77 vsyncSourceOpt
78 .or_else([&] {
79 return std::make_optional(
Ady Abraham3db8a3c2023-11-20 17:53:47 -080080 VsyncSource(period, period,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040081 args.expectedVsyncTime));
82 })
83 .value(),
84 isFencePendingFuncPtr);
85 }
86
87 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
98 ~Frame() {
99 end();
100 frameBeginTime += period;
101 }
102
103 static bool fencePending(const FenceTimePtr&, int) { return true; }
104 static bool fenceSignaled(const FenceTimePtr&, int) { return false; }
105
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500106 FrameTargeterTestBase* const testPtr;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400107
108 TimePoint& frameBeginTime;
109 const Period period;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800110 const Period minFramePeriod;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400111
112 bool ended = false;
113 };
114
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500115 static constexpr Duration kHwcMinWorkDuration = std::chrono::nanoseconds(5ns);
116
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400117private:
118 FenceToFenceTimeMap mFenceMap;
119
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500120 FrameTargeter mTargeter;
121};
122
123class FrameTargeterTest : public FrameTargeterTestBase {
124public:
125 FrameTargeterTest() : FrameTargeterTestBase(Feature::kBackpressureGpuComposition) {}
126};
127
128class FrameTargeterWithExpectedPresentSupportTest : public FrameTargeterTestBase {
129public:
130 FrameTargeterWithExpectedPresentSupportTest()
131 : FrameTargeterTestBase(FeatureFlags(Feature::kBackpressureGpuComposition) |
132 Feature::kExpectedPresentTime) {}
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400133};
134
135TEST_F(FrameTargeterTest, targetsFrames) {
136 VsyncId vsyncId{42};
137 {
138 TimePoint frameBeginTime(989ms);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800139 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400140
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);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800148 const Frame frame(this, vsyncId++, frameBeginTime, 11ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400149
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
157TEST_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;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800163 const VsyncSource vsyncSource(kRefreshRate.getPeriod(), kRefreshRate.getPeriod(),
164 frameBeginTime + 5ms);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400165 const Frame frame(this, VsyncId{123}, frameBeginTime, kFrameDuration, kRefreshRate,
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800166 kRefreshRate, Frame::fenceSignaled, vsyncSource);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400167
168 EXPECT_EQ(target().expectedPresentTime(), vsyncSource.vsyncDeadline + vsyncSource.vsyncPeriod);
169}
170
171TEST_F(FrameTargeterTest, recallsPastVsync) {
ramindani513e6502024-04-10 15:22:19 -0700172 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400173 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;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800180 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400181 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
188TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
ramindani513e6502024-04-10 15:22:19 -0700189 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400190 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;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800199 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
ramindani513e6502024-04-10 15:22:19 -0700209TEST_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
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800232TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) {
ramindani513e6502024-04-10 15:22:19 -0700233 SET_FLAG_FOR_TEST(flags::vrr_config, true);
234 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800235
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);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400248 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
ramindani513e6502024-04-10 15:22:19 -0700257TEST_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
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400284TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
285 constexpr Period kPeriod = (60_Hz).getPeriod();
286 EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), FenceTime::NO_FENCE);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500287 EXPECT_FALSE(wouldPresentEarly(kPeriod));
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400288}
289
290TEST_F(FrameTargeterTest, detectsEarlyPresent) {
ramindani513e6502024-04-10 15:22:19 -0700291 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400292 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;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800299 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500300 EXPECT_FALSE(wouldPresentEarly(kPeriod));
301 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400302 }
303
304 // The target is early if the past present fence was signaled.
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800305 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400306 const auto fence = frame.end();
307 fence->signalForTest(frameBeginTime.ns());
308
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500309 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.
320TEST_F(FrameTargeterWithExpectedPresentSupportTest, detectsEarlyPresent) {
ramindani513e6502024-04-10 15:22:19 -0700321 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500322 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());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400345}
346
347TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
ramindani513e6502024-04-10 15:22:19 -0700348 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400349 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;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800356 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500357 EXPECT_FALSE(wouldPresentEarly(kPeriod));
358 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400359 }
360
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800361 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400362 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.
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500366 EXPECT_FALSE(wouldPresentEarly(kPeriod));
367 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400368
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800369 { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400370
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500371 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
372
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400373 // The target is early if the past present fence was signaled.
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500374 EXPECT_TRUE(wouldPresentEarly(kPeriod));
375 ASSERT_NE(std::nullopt, target().earliestPresentTime());
376 EXPECT_EQ(*target().earliestPresentTime(),
377 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400378}
379
ramindani513e6502024-04-10 15:22:19 -0700380TEST_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
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400424TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
ramindani513e6502024-04-10 15:22:19 -0700425 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400426 TimePoint frameBeginTime(5000ms);
427 constexpr Fps kRefreshRate = 144_Hz;
428 constexpr Period kPeriod = kRefreshRate.getPeriod();
429
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800430 const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400431
432 // The target is more than two VSYNCs ahead, but present fences are not tracked that far back.
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500433 EXPECT_TRUE(wouldPresentEarly(kPeriod));
434 EXPECT_TRUE(target().earliestPresentTime());
435 EXPECT_EQ(*target().earliestPresentTime(),
436 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400437}
438
439TEST_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 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800450 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400451 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 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800458 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
459 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400460 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 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800469 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
470 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400471 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 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800478 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400479 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 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800486 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400487 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 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800498 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400499 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