blob: 190d0621d0bea28f06700266bab01fac21d96afa [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
ramindani7b32b3a2024-07-02 10:17:47 -070060 FrameTarget::FenceWithFenceTime presentFenceForPastVsync(Period minFramePeriod) const {
61 return target().presentFenceForPastVsync(minFramePeriod);
62 }
63
Dominik Laskowskib418dd72023-06-13 17:31:04 -040064 struct Frame {
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050065 Frame(FrameTargeterTestBase* testPtr, VsyncId vsyncId, TimePoint& frameBeginTime,
Ady Abraham3db8a3c2023-11-20 17:53:47 -080066 Duration frameDuration, Fps refreshRate, Fps peakRefreshRate,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040067 FrameTargeter::IsFencePendingFuncPtr isFencePendingFuncPtr = Frame::fenceSignaled,
68 const ftl::Optional<VsyncSource>& vsyncSourceOpt = std::nullopt)
Ady Abraham3db8a3c2023-11-20 17:53:47 -080069 : testPtr(testPtr),
70 frameBeginTime(frameBeginTime),
71 period(refreshRate.getPeriod()),
72 minFramePeriod(peakRefreshRate.getPeriod()) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040073 const FrameTargeter::BeginFrameArgs args{.frameBeginTime = frameBeginTime,
74 .vsyncId = vsyncId,
75 .expectedVsyncTime =
76 frameBeginTime + frameDuration,
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050077 .sfWorkDuration = 10ms,
78 .hwcMinWorkDuration = kHwcMinWorkDuration};
Dominik Laskowskib418dd72023-06-13 17:31:04 -040079
80 testPtr->mTargeter.beginFrame(args,
81 vsyncSourceOpt
82 .or_else([&] {
83 return std::make_optional(
Ady Abraham3db8a3c2023-11-20 17:53:47 -080084 VsyncSource(period, period,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040085 args.expectedVsyncTime));
86 })
87 .value(),
88 isFencePendingFuncPtr);
89 }
90
91 FenceTimePtr end(CompositionCoverage coverage = CompositionCoverage::Hwc) {
92 if (ended) return nullptr;
93 ended = true;
94
95 auto [fence, fenceTime] = testPtr->mFenceMap.makePendingFenceForTest();
96 testPtr->mTargeter.setPresentFence(std::move(fence), fenceTime);
97
98 testPtr->mTargeter.endFrame({.compositionCoverage = coverage});
99 return fenceTime;
100 }
101
102 ~Frame() {
103 end();
104 frameBeginTime += period;
105 }
106
107 static bool fencePending(const FenceTimePtr&, int) { return true; }
108 static bool fenceSignaled(const FenceTimePtr&, int) { return false; }
109
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500110 FrameTargeterTestBase* const testPtr;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400111
112 TimePoint& frameBeginTime;
113 const Period period;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800114 const Period minFramePeriod;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400115
116 bool ended = false;
117 };
118
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500119 static constexpr Duration kHwcMinWorkDuration = std::chrono::nanoseconds(5ns);
120
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400121private:
122 FenceToFenceTimeMap mFenceMap;
123
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500124 FrameTargeter mTargeter;
125};
126
127class FrameTargeterTest : public FrameTargeterTestBase {
128public:
129 FrameTargeterTest() : FrameTargeterTestBase(Feature::kBackpressureGpuComposition) {}
130};
131
132class FrameTargeterWithExpectedPresentSupportTest : public FrameTargeterTestBase {
133public:
134 FrameTargeterWithExpectedPresentSupportTest()
135 : FrameTargeterTestBase(FeatureFlags(Feature::kBackpressureGpuComposition) |
136 Feature::kExpectedPresentTime) {}
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400137};
138
139TEST_F(FrameTargeterTest, targetsFrames) {
140 VsyncId vsyncId{42};
141 {
142 TimePoint frameBeginTime(989ms);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800143 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400144
145 EXPECT_EQ(target().vsyncId(), VsyncId{42});
146 EXPECT_EQ(target().frameBeginTime(), TimePoint(989ms));
147 EXPECT_EQ(target().expectedPresentTime(), TimePoint(999ms));
148 EXPECT_EQ(target().expectedFrameDuration(), 10ms);
149 }
150 {
151 TimePoint frameBeginTime(1100ms);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800152 const Frame frame(this, vsyncId++, frameBeginTime, 11ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400153
154 EXPECT_EQ(target().vsyncId(), VsyncId{43});
155 EXPECT_EQ(target().frameBeginTime(), TimePoint(1100ms));
156 EXPECT_EQ(target().expectedPresentTime(), TimePoint(1111ms));
157 EXPECT_EQ(target().expectedFrameDuration(), 11ms);
158 }
159}
160
161TEST_F(FrameTargeterTest, inflatesExpectedPresentTime) {
162 // Negative such that `expectedVsyncTime` is in the past.
163 constexpr Duration kFrameDuration = -3ms;
164 TimePoint frameBeginTime(777ms);
165
166 constexpr Fps kRefreshRate = 120_Hz;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800167 const VsyncSource vsyncSource(kRefreshRate.getPeriod(), kRefreshRate.getPeriod(),
168 frameBeginTime + 5ms);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400169 const Frame frame(this, VsyncId{123}, frameBeginTime, kFrameDuration, kRefreshRate,
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800170 kRefreshRate, Frame::fenceSignaled, vsyncSource);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400171
172 EXPECT_EQ(target().expectedPresentTime(), vsyncSource.vsyncDeadline + vsyncSource.vsyncPeriod);
173}
174
175TEST_F(FrameTargeterTest, recallsPastVsync) {
ramindani513e6502024-04-10 15:22:19 -0700176 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400177 VsyncId vsyncId{111};
178 TimePoint frameBeginTime(1000ms);
179 constexpr Fps kRefreshRate = 60_Hz;
180 constexpr Period kPeriod = kRefreshRate.getPeriod();
181 constexpr Duration kFrameDuration = 13ms;
182
183 for (int n = 5; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800184 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400185 const auto fence = frame.end();
186
187 EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - kPeriod);
ramindani7b32b3a2024-07-02 10:17:47 -0700188 EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, fence);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400189 }
190}
191
192TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
ramindani513e6502024-04-10 15:22:19 -0700193 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400194 VsyncId vsyncId{222};
195 TimePoint frameBeginTime(2000ms);
196 constexpr Fps kRefreshRate = 120_Hz;
197 constexpr Period kPeriod = kRefreshRate.getPeriod();
198 constexpr Duration kFrameDuration = 10ms;
199
200 FenceTimePtr previousFence = FenceTime::NO_FENCE;
201
202 for (int n = 5; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800203 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
204 const auto fence = frame.end();
205
206 EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
ramindani7b32b3a2024-07-02 10:17:47 -0700207 EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, previousFence);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800208
209 previousFence = fence;
210 }
211}
212
ramindani513e6502024-04-10 15:22:19 -0700213TEST_F(FrameTargeterTest, recallsPastNVsyncTwoVsyncsAhead) {
214 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
215 VsyncId vsyncId{222};
216 TimePoint frameBeginTime(2000ms);
217 constexpr Fps kRefreshRate = 120_Hz;
218 constexpr Period kPeriod = kRefreshRate.getPeriod();
219 constexpr Duration kFrameDuration = 10ms;
220
221 FenceTimePtr previousFence = FenceTime::NO_FENCE;
222
223 for (int n = 5; n-- > 0;) {
224 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
225 const auto fence = frame.end();
226
227 const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
228 EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
ramindani7b32b3a2024-07-02 10:17:47 -0700229 EXPECT_EQ(presentFenceForPastVsync(kFrameDuration).fenceTime, previousFence);
ramindani513e6502024-04-10 15:22:19 -0700230
231 frameBeginTime += kPeriod;
232 previousFence = fence;
233 }
234}
235
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800236TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) {
ramindani513e6502024-04-10 15:22:19 -0700237 SET_FLAG_FOR_TEST(flags::vrr_config, true);
238 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800239
240 VsyncId vsyncId{222};
241 TimePoint frameBeginTime(2000ms);
242 constexpr Fps kRefreshRate = 120_Hz;
243 constexpr Fps kPeakRefreshRate = 240_Hz;
244 constexpr Period kPeriod = kRefreshRate.getPeriod();
245 constexpr Duration kFrameDuration = 10ms;
246
247 FenceTimePtr previousFence = FenceTime::NO_FENCE;
248
249 for (int n = 5; n-- > 0;) {
250 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
251 kPeakRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400252 const auto fence = frame.end();
253
254 EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
ramindani7b32b3a2024-07-02 10:17:47 -0700255 EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, previousFence);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400256
257 previousFence = fence;
258 }
259}
260
ramindani513e6502024-04-10 15:22:19 -0700261TEST_F(FrameTargeterTest, recallsPastNVsyncTwoVsyncsAheadVrr) {
262 SET_FLAG_FOR_TEST(flags::vrr_config, true);
263 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
264
265 VsyncId vsyncId{222};
266 TimePoint frameBeginTime(2000ms);
267 constexpr Fps kRefreshRate = 120_Hz;
268 constexpr Fps kPeakRefreshRate = 240_Hz;
269 constexpr Period kPeriod = kRefreshRate.getPeriod();
270 constexpr Duration kFrameDuration = 10ms;
271
272 FenceTimePtr previousFence = FenceTime::NO_FENCE;
273
274 for (int n = 5; n-- > 0;) {
275 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
276 kPeakRefreshRate);
277 const auto fence = frame.end();
278
279 const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
280 EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
ramindani7b32b3a2024-07-02 10:17:47 -0700281 EXPECT_EQ(presentFenceForPastVsync(kFrameDuration).fenceTime, previousFence);
ramindani513e6502024-04-10 15:22:19 -0700282
283 frameBeginTime += kPeriod;
284 previousFence = fence;
285 }
286}
287
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400288TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
289 constexpr Period kPeriod = (60_Hz).getPeriod();
ramindani7b32b3a2024-07-02 10:17:47 -0700290 EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, FenceTime::NO_FENCE);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500291 EXPECT_FALSE(wouldPresentEarly(kPeriod));
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400292}
293
294TEST_F(FrameTargeterTest, detectsEarlyPresent) {
ramindani513e6502024-04-10 15:22:19 -0700295 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400296 VsyncId vsyncId{333};
297 TimePoint frameBeginTime(3000ms);
298 constexpr Fps kRefreshRate = 60_Hz;
299 constexpr Period kPeriod = kRefreshRate.getPeriod();
300
301 // The target is not early while past present fences are pending.
302 for (int n = 3; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800303 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500304 EXPECT_FALSE(wouldPresentEarly(kPeriod));
305 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400306 }
307
308 // The target is early if the past present fence was signaled.
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800309 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400310 const auto fence = frame.end();
311 fence->signalForTest(frameBeginTime.ns());
312
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500313 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
314
315 // `finalFrame` would present early, so it has an earliest present time.
316 EXPECT_TRUE(wouldPresentEarly(kPeriod));
317 ASSERT_NE(std::nullopt, target().earliestPresentTime());
318 EXPECT_EQ(*target().earliestPresentTime(),
319 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
320}
321
322// Same as `detectsEarlyPresent`, above, but verifies that we do not set an earliest present time
323// when there is expected present time support.
324TEST_F(FrameTargeterWithExpectedPresentSupportTest, detectsEarlyPresent) {
ramindani513e6502024-04-10 15:22:19 -0700325 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500326 VsyncId vsyncId{333};
327 TimePoint frameBeginTime(3000ms);
328 constexpr Fps kRefreshRate = 60_Hz;
329 constexpr Period kPeriod = kRefreshRate.getPeriod();
330
331 // The target is not early while past present fences are pending.
332 for (int n = 3; n-- > 0;) {
333 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
334 EXPECT_FALSE(wouldPresentEarly(kPeriod));
335 EXPECT_FALSE(target().earliestPresentTime());
336 }
337
338 // The target is early if the past present fence was signaled.
339 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
340 const auto fence = frame.end();
341 fence->signalForTest(frameBeginTime.ns());
342
343 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
344
345 // `finalFrame` would present early, but we have expected present time support, so it has no
346 // earliest present time.
347 EXPECT_TRUE(wouldPresentEarly(kPeriod));
348 ASSERT_EQ(std::nullopt, target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400349}
350
351TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
ramindani513e6502024-04-10 15:22:19 -0700352 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400353 VsyncId vsyncId{444};
354 TimePoint frameBeginTime(4000ms);
355 constexpr Fps kRefreshRate = 120_Hz;
356 constexpr Period kPeriod = kRefreshRate.getPeriod();
357
358 // The target is not early while past present fences are pending.
359 for (int n = 3; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800360 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500361 EXPECT_FALSE(wouldPresentEarly(kPeriod));
362 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400363 }
364
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800365 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400366 const auto fence = frame.end();
367 fence->signalForTest(frameBeginTime.ns());
368
369 // The target is two VSYNCs ahead, so the past present fence is still pending.
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500370 EXPECT_FALSE(wouldPresentEarly(kPeriod));
371 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400372
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800373 { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400374
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500375 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
376
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400377 // The target is early if the past present fence was signaled.
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500378 EXPECT_TRUE(wouldPresentEarly(kPeriod));
379 ASSERT_NE(std::nullopt, target().earliestPresentTime());
380 EXPECT_EQ(*target().earliestPresentTime(),
381 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400382}
383
ramindani513e6502024-04-10 15:22:19 -0700384TEST_F(FrameTargeterTest, detectsEarlyPresentNVsyncsAhead) {
385 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
386 VsyncId vsyncId{444};
387 TimePoint frameBeginTime(4000ms);
388 Fps refreshRate = 120_Hz;
389 Period period = refreshRate.getPeriod();
390
391 // The target is not early while past present fences are pending.
392 for (int n = 5; n-- > 0;) {
393 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
394 EXPECT_FALSE(wouldPresentEarly(period));
395 EXPECT_FALSE(target().earliestPresentTime());
396 }
397
398 Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
399 auto fence = frame.end();
400 frameBeginTime += period;
401 fence->signalForTest(frameBeginTime.ns());
402
403 // The target is two VSYNCs ahead, so the past present fence is still pending.
404 EXPECT_FALSE(wouldPresentEarly(period));
405 EXPECT_FALSE(target().earliestPresentTime());
406
407 { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate); }
408
409 Frame oneEarlyPresentFrame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
410 // The target is early if the past present fence was signaled.
411 EXPECT_TRUE(wouldPresentEarly(period));
412 ASSERT_NE(std::nullopt, target().earliestPresentTime());
413 EXPECT_EQ(*target().earliestPresentTime(),
414 target().expectedPresentTime() - period - kHwcMinWorkDuration);
415
416 fence = oneEarlyPresentFrame.end();
417 frameBeginTime += period;
418 fence->signalForTest(frameBeginTime.ns());
419
420 // Change rate to track frame more than 2 vsyncs ahead
421 refreshRate = 144_Hz;
422 period = refreshRate.getPeriod();
423 Frame onePresentEarlyFrame(this, vsyncId++, frameBeginTime, 16ms, refreshRate, refreshRate);
424 // The target is not early as last frame as the past frame is tracked for pending.
425 EXPECT_FALSE(wouldPresentEarly(period));
426}
427
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400428TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
ramindani513e6502024-04-10 15:22:19 -0700429 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400430 TimePoint frameBeginTime(5000ms);
431 constexpr Fps kRefreshRate = 144_Hz;
432 constexpr Period kPeriod = kRefreshRate.getPeriod();
433
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800434 const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400435
436 // 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 -0500437 EXPECT_TRUE(wouldPresentEarly(kPeriod));
438 EXPECT_TRUE(target().earliestPresentTime());
439 EXPECT_EQ(*target().earliestPresentTime(),
440 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400441}
442
443TEST_F(FrameTargeterTest, detectsMissedFrames) {
444 VsyncId vsyncId{555};
445 TimePoint frameBeginTime(5000ms);
446 constexpr Fps kRefreshRate = 60_Hz;
447 constexpr Period kPeriod = kRefreshRate.getPeriod();
448
449 EXPECT_FALSE(target().isFramePending());
450 EXPECT_FALSE(target().didMissFrame());
451 EXPECT_FALSE(target().didMissHwcFrame());
452
453 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800454 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400455 EXPECT_FALSE(target().isFramePending());
456
457 // The frame did not miss if the past present fence is invalid.
458 EXPECT_FALSE(target().didMissFrame());
459 EXPECT_FALSE(target().didMissHwcFrame());
460 }
461 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800462 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
463 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400464 EXPECT_TRUE(target().isFramePending());
465
466 // The frame missed if the past present fence is pending.
467 EXPECT_TRUE(target().didMissFrame());
468 EXPECT_TRUE(target().didMissHwcFrame());
469
470 frame.end(CompositionCoverage::Gpu);
471 }
472 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800473 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
474 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400475 EXPECT_TRUE(target().isFramePending());
476
477 // The GPU frame missed if the past present fence is pending.
478 EXPECT_TRUE(target().didMissFrame());
479 EXPECT_FALSE(target().didMissHwcFrame());
480 }
481 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800482 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400483 EXPECT_FALSE(target().isFramePending());
484
485 const auto fence = frame.end();
486 const auto expectedPresentTime = target().expectedPresentTime();
487 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2 + 1);
488 }
489 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800490 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400491 EXPECT_FALSE(target().isFramePending());
492
493 const auto fence = frame.end();
494 const auto expectedPresentTime = target().expectedPresentTime();
495 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2);
496
497 // The frame missed if the past present fence was signaled but not within slop.
498 EXPECT_TRUE(target().didMissFrame());
499 EXPECT_TRUE(target().didMissHwcFrame());
500 }
501 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800502 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400503 EXPECT_FALSE(target().isFramePending());
504
505 // The frame did not miss if the past present fence was signaled within slop.
506 EXPECT_FALSE(target().didMissFrame());
507 EXPECT_FALSE(target().didMissHwcFrame());
508 }
509}
510
511} // namespace android::scheduler