blob: 6f4e1f1dfe68d095ad840eca2ac088f1ecad0be2 [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
Ady Abrahamed1283a2024-07-24 15:49:16 -070056 bool wouldPresentEarly(Period vsyncPeriod, Period minFramePeriod) const {
57 return target().wouldPresentEarly(vsyncPeriod, minFramePeriod);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050058 }
59
Ady Abrahamed1283a2024-07-24 15:49:16 -070060 std::pair<bool /*wouldBackpressure*/, FrameTarget::PresentFence> expectedSignaledPresentFence(
61 Period vsyncPeriod, Period minFramePeriod) const {
62 return target().expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
ramindani7b32b3a2024-07-02 10:17:47 -070063 }
64
Dominik Laskowskib418dd72023-06-13 17:31:04 -040065 struct Frame {
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050066 Frame(FrameTargeterTestBase* testPtr, VsyncId vsyncId, TimePoint& frameBeginTime,
Ady Abraham3db8a3c2023-11-20 17:53:47 -080067 Duration frameDuration, Fps refreshRate, Fps peakRefreshRate,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040068 FrameTargeter::IsFencePendingFuncPtr isFencePendingFuncPtr = Frame::fenceSignaled,
69 const ftl::Optional<VsyncSource>& vsyncSourceOpt = std::nullopt)
Ady Abraham3db8a3c2023-11-20 17:53:47 -080070 : testPtr(testPtr),
71 frameBeginTime(frameBeginTime),
72 period(refreshRate.getPeriod()),
73 minFramePeriod(peakRefreshRate.getPeriod()) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040074 const FrameTargeter::BeginFrameArgs args{.frameBeginTime = frameBeginTime,
75 .vsyncId = vsyncId,
76 .expectedVsyncTime =
77 frameBeginTime + frameDuration,
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050078 .sfWorkDuration = 10ms,
79 .hwcMinWorkDuration = kHwcMinWorkDuration};
Dominik Laskowskib418dd72023-06-13 17:31:04 -040080
81 testPtr->mTargeter.beginFrame(args,
82 vsyncSourceOpt
83 .or_else([&] {
84 return std::make_optional(
Ady Abraham3db8a3c2023-11-20 17:53:47 -080085 VsyncSource(period, period,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040086 args.expectedVsyncTime));
87 })
88 .value(),
89 isFencePendingFuncPtr);
90 }
91
92 FenceTimePtr end(CompositionCoverage coverage = CompositionCoverage::Hwc) {
93 if (ended) return nullptr;
94 ended = true;
95
96 auto [fence, fenceTime] = testPtr->mFenceMap.makePendingFenceForTest();
97 testPtr->mTargeter.setPresentFence(std::move(fence), fenceTime);
98
99 testPtr->mTargeter.endFrame({.compositionCoverage = coverage});
100 return fenceTime;
101 }
102
103 ~Frame() {
104 end();
105 frameBeginTime += period;
106 }
107
108 static bool fencePending(const FenceTimePtr&, int) { return true; }
109 static bool fenceSignaled(const FenceTimePtr&, int) { return false; }
110
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500111 FrameTargeterTestBase* const testPtr;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400112
113 TimePoint& frameBeginTime;
114 const Period period;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800115 const Period minFramePeriod;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400116
117 bool ended = false;
118 };
119
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500120 static constexpr Duration kHwcMinWorkDuration = std::chrono::nanoseconds(5ns);
121
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400122private:
123 FenceToFenceTimeMap mFenceMap;
124
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500125 FrameTargeter mTargeter;
126};
127
128class FrameTargeterTest : public FrameTargeterTestBase {
129public:
130 FrameTargeterTest() : FrameTargeterTestBase(Feature::kBackpressureGpuComposition) {}
131};
132
133class FrameTargeterWithExpectedPresentSupportTest : public FrameTargeterTestBase {
134public:
135 FrameTargeterWithExpectedPresentSupportTest()
136 : FrameTargeterTestBase(FeatureFlags(Feature::kBackpressureGpuComposition) |
137 Feature::kExpectedPresentTime) {}
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400138};
139
140TEST_F(FrameTargeterTest, targetsFrames) {
141 VsyncId vsyncId{42};
142 {
143 TimePoint frameBeginTime(989ms);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800144 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400145
146 EXPECT_EQ(target().vsyncId(), VsyncId{42});
147 EXPECT_EQ(target().frameBeginTime(), TimePoint(989ms));
148 EXPECT_EQ(target().expectedPresentTime(), TimePoint(999ms));
149 EXPECT_EQ(target().expectedFrameDuration(), 10ms);
150 }
151 {
152 TimePoint frameBeginTime(1100ms);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800153 const Frame frame(this, vsyncId++, frameBeginTime, 11ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400154
155 EXPECT_EQ(target().vsyncId(), VsyncId{43});
156 EXPECT_EQ(target().frameBeginTime(), TimePoint(1100ms));
157 EXPECT_EQ(target().expectedPresentTime(), TimePoint(1111ms));
158 EXPECT_EQ(target().expectedFrameDuration(), 11ms);
159 }
160}
161
162TEST_F(FrameTargeterTest, inflatesExpectedPresentTime) {
163 // Negative such that `expectedVsyncTime` is in the past.
164 constexpr Duration kFrameDuration = -3ms;
165 TimePoint frameBeginTime(777ms);
166
167 constexpr Fps kRefreshRate = 120_Hz;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800168 const VsyncSource vsyncSource(kRefreshRate.getPeriod(), kRefreshRate.getPeriod(),
169 frameBeginTime + 5ms);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400170 const Frame frame(this, VsyncId{123}, frameBeginTime, kFrameDuration, kRefreshRate,
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800171 kRefreshRate, Frame::fenceSignaled, vsyncSource);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400172
173 EXPECT_EQ(target().expectedPresentTime(), vsyncSource.vsyncDeadline + vsyncSource.vsyncPeriod);
174}
175
176TEST_F(FrameTargeterTest, recallsPastVsync) {
177 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 Abrahamed1283a2024-07-24 15:49:16 -0700184 FenceTimePtr fence;
185 {
186 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
187 kRefreshRate);
188 fence = frame.end();
189 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400190
Ady Abrahamed1283a2024-07-24 15:49:16 -0700191 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
192 const auto [wouldBackpressure, presentFence] =
193 expectedSignaledPresentFence(kPeriod, kPeriod);
194 ASSERT_TRUE(wouldBackpressure);
195 EXPECT_EQ(presentFence.fenceTime, fence);
196 }
197}
198
199TEST_F(FrameTargeterTest, wouldBackpressureAfterTime) {
200 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
201 VsyncId vsyncId{111};
202 TimePoint frameBeginTime(1000ms);
203 constexpr Fps kRefreshRate = 60_Hz;
204 constexpr Period kPeriod = kRefreshRate.getPeriod();
205 constexpr Duration kFrameDuration = 13ms;
206
207 { Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate); }
208 {
209 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
210
211 const auto [wouldBackpressure, presentFence] =
212 expectedSignaledPresentFence(kPeriod, kPeriod);
213 EXPECT_TRUE(wouldBackpressure);
214 }
215 {
216 frameBeginTime += kPeriod;
217 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
218 const auto [wouldBackpressure, presentFence] =
219 expectedSignaledPresentFence(kPeriod, kPeriod);
220 EXPECT_FALSE(wouldBackpressure);
221 }
222}
223
224TEST_F(FrameTargeterTest, wouldBackpressureAfterTimeLegacy) {
225 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
226 VsyncId vsyncId{111};
227 TimePoint frameBeginTime(1000ms);
228 constexpr Fps kRefreshRate = 60_Hz;
229 constexpr Period kPeriod = kRefreshRate.getPeriod();
230 constexpr Duration kFrameDuration = 13ms;
231
232 { Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate); }
233 {
234 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
235
236 const auto [wouldBackpressure, presentFence] =
237 expectedSignaledPresentFence(kPeriod, kPeriod);
238 EXPECT_TRUE(wouldBackpressure);
239 }
240 {
241 frameBeginTime += kPeriod;
242 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
243 const auto [wouldBackpressure, presentFence] =
244 expectedSignaledPresentFence(kPeriod, kPeriod);
245 EXPECT_TRUE(wouldBackpressure);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400246 }
247}
248
249TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
250 VsyncId vsyncId{222};
251 TimePoint frameBeginTime(2000ms);
252 constexpr Fps kRefreshRate = 120_Hz;
253 constexpr Period kPeriod = kRefreshRate.getPeriod();
254 constexpr Duration kFrameDuration = 10ms;
255
256 FenceTimePtr previousFence = FenceTime::NO_FENCE;
Ady Abrahamed1283a2024-07-24 15:49:16 -0700257 FenceTimePtr currentFence = FenceTime::NO_FENCE;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400258 for (int n = 5; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800259 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
Ady Abrahamed1283a2024-07-24 15:49:16 -0700260 EXPECT_EQ(expectedSignaledPresentFence(kPeriod, kPeriod).second.fenceTime, previousFence);
261 previousFence = currentFence;
262 currentFence = frame.end();
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800263 }
264}
265
Ady Abrahamed1283a2024-07-24 15:49:16 -0700266TEST_F(FrameTargeterTest, recallsPastVsyncFiveVsyncsAhead) {
ramindani513e6502024-04-10 15:22:19 -0700267 SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
Ady Abrahamed1283a2024-07-24 15:49:16 -0700268
ramindani513e6502024-04-10 15:22:19 -0700269 VsyncId vsyncId{222};
270 TimePoint frameBeginTime(2000ms);
271 constexpr Fps kRefreshRate = 120_Hz;
272 constexpr Period kPeriod = kRefreshRate.getPeriod();
Ady Abrahamed1283a2024-07-24 15:49:16 -0700273 constexpr Duration kFrameDuration = 40ms;
ramindani513e6502024-04-10 15:22:19 -0700274
Ady Abrahamed1283a2024-07-24 15:49:16 -0700275 FenceTimePtr firstFence = FenceTime::NO_FENCE;
ramindani513e6502024-04-10 15:22:19 -0700276 for (int n = 5; n-- > 0;) {
277 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
278 const auto fence = frame.end();
Ady Abrahamed1283a2024-07-24 15:49:16 -0700279 if (firstFence == FenceTime::NO_FENCE) {
280 firstFence = fence;
281 }
ramindani513e6502024-04-10 15:22:19 -0700282 }
Ady Abrahamed1283a2024-07-24 15:49:16 -0700283
284 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
285 EXPECT_EQ(expectedSignaledPresentFence(kPeriod, kPeriod).second.fenceTime, firstFence);
ramindani513e6502024-04-10 15:22:19 -0700286}
287
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800288TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) {
ramindani513e6502024-04-10 15:22:19 -0700289 SET_FLAG_FOR_TEST(flags::vrr_config, true);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800290
291 VsyncId vsyncId{222};
292 TimePoint frameBeginTime(2000ms);
293 constexpr Fps kRefreshRate = 120_Hz;
Ady Abrahamed1283a2024-07-24 15:49:16 -0700294 constexpr Fps kVsyncRate = 240_Hz;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800295 constexpr Period kPeriod = kRefreshRate.getPeriod();
Ady Abrahamed1283a2024-07-24 15:49:16 -0700296 constexpr Period kVsyncPeriod = kVsyncRate.getPeriod();
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800297 constexpr Duration kFrameDuration = 10ms;
298
299 FenceTimePtr previousFence = FenceTime::NO_FENCE;
Ady Abrahamed1283a2024-07-24 15:49:16 -0700300 FenceTimePtr currentFence = FenceTime::NO_FENCE;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800301 for (int n = 5; n-- > 0;) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700302 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
303 EXPECT_EQ(expectedSignaledPresentFence(kVsyncPeriod, kPeriod).second.fenceTime,
304 previousFence);
305 previousFence = currentFence;
306 currentFence = frame.end();
ramindani513e6502024-04-10 15:22:19 -0700307 }
308}
309
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400310TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
311 constexpr Period kPeriod = (60_Hz).getPeriod();
Ady Abrahamed1283a2024-07-24 15:49:16 -0700312 EXPECT_EQ(expectedSignaledPresentFence(kPeriod, kPeriod).second.fenceTime, FenceTime::NO_FENCE);
313 EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400314}
315
316TEST_F(FrameTargeterTest, detectsEarlyPresent) {
317 VsyncId vsyncId{333};
318 TimePoint frameBeginTime(3000ms);
319 constexpr Fps kRefreshRate = 60_Hz;
320 constexpr Period kPeriod = kRefreshRate.getPeriod();
321
322 // The target is not early while past present fences are pending.
323 for (int n = 3; n-- > 0;) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700324 {
325 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
326 }
327 EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500328 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400329 }
330
331 // The target is early if the past present fence was signaled.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700332 {
333 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
334 const auto fence = frame.end();
335 fence->signalForTest(frameBeginTime.ns());
336 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400337
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500338 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
339
340 // `finalFrame` would present early, so it has an earliest present time.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700341 EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500342 ASSERT_NE(std::nullopt, target().earliestPresentTime());
343 EXPECT_EQ(*target().earliestPresentTime(),
344 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
345}
346
Ady Abraham74fe27e2024-07-26 10:56:54 -0700347TEST_F(FrameTargeterTest, detectsEarlyPresentAfterLongPeriod) {
348 VsyncId vsyncId{333};
349 TimePoint frameBeginTime(3000ms);
350 constexpr Fps kRefreshRate = 60_Hz;
351 constexpr Period kPeriod = kRefreshRate.getPeriod();
352
353 // The target is not early while past present fences are pending.
354 for (int n = 3; n-- > 0;) {
355 {
356 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
357 }
358 EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
359 EXPECT_FALSE(target().earliestPresentTime());
360 }
361
362 // The target is early if the past present fence was signaled.
363 {
364 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
365 const auto fence = frame.end();
366 fence->signalForTest(frameBeginTime.ns());
367 }
368
369 frameBeginTime += 10 * kPeriod;
370
371 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
372
373 // `finalFrame` would present early, so it has an earliest present time.
374 EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
375 ASSERT_NE(std::nullopt, target().earliestPresentTime());
376 EXPECT_EQ(*target().earliestPresentTime(),
377 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
378}
379
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500380// Same as `detectsEarlyPresent`, above, but verifies that we do not set an earliest present time
381// when there is expected present time support.
382TEST_F(FrameTargeterWithExpectedPresentSupportTest, detectsEarlyPresent) {
383 VsyncId vsyncId{333};
384 TimePoint frameBeginTime(3000ms);
385 constexpr Fps kRefreshRate = 60_Hz;
386 constexpr Period kPeriod = kRefreshRate.getPeriod();
387
388 // The target is not early while past present fences are pending.
389 for (int n = 3; n-- > 0;) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700390 {
391 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
392 }
393 EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500394 EXPECT_FALSE(target().earliestPresentTime());
395 }
396
397 // The target is early if the past present fence was signaled.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700398 {
399 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
400
401 const auto fence = frame.end();
402 fence->signalForTest(frameBeginTime.ns());
403 }
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500404
405 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
406
407 // `finalFrame` would present early, but we have expected present time support, so it has no
408 // earliest present time.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700409 EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500410 ASSERT_EQ(std::nullopt, target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400411}
412
413TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
414 VsyncId vsyncId{444};
415 TimePoint frameBeginTime(4000ms);
416 constexpr Fps kRefreshRate = 120_Hz;
417 constexpr Period kPeriod = kRefreshRate.getPeriod();
418
419 // The target is not early while past present fences are pending.
420 for (int n = 3; n-- > 0;) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700421 {
422 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
423 }
424 EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500425 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400426 }
Ady Abrahamed1283a2024-07-24 15:49:16 -0700427 {
428 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400429
Ady Abrahamed1283a2024-07-24 15:49:16 -0700430 const auto fence = frame.end();
431 fence->signalForTest(frameBeginTime.ns());
432 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400433
434 // The target is two VSYNCs ahead, so the past present fence is still pending.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700435 EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500436 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400437
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800438 { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400439
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500440 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
441
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400442 // The target is early if the past present fence was signaled.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700443 EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500444 ASSERT_NE(std::nullopt, target().earliestPresentTime());
445 EXPECT_EQ(*target().earliestPresentTime(),
446 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400447}
448
449TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
450 TimePoint frameBeginTime(5000ms);
451 constexpr Fps kRefreshRate = 144_Hz;
452 constexpr Period kPeriod = kRefreshRate.getPeriod();
453
Ady Abrahamed1283a2024-07-24 15:49:16 -0700454 { const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate); }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400455
456 // The target is more than two VSYNCs ahead, but present fences are not tracked that far back.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700457 EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500458 EXPECT_TRUE(target().earliestPresentTime());
459 EXPECT_EQ(*target().earliestPresentTime(),
460 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400461}
462
463TEST_F(FrameTargeterTest, detectsMissedFrames) {
464 VsyncId vsyncId{555};
465 TimePoint frameBeginTime(5000ms);
466 constexpr Fps kRefreshRate = 60_Hz;
467 constexpr Period kPeriod = kRefreshRate.getPeriod();
468
469 EXPECT_FALSE(target().isFramePending());
470 EXPECT_FALSE(target().didMissFrame());
471 EXPECT_FALSE(target().didMissHwcFrame());
472
473 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800474 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400475 EXPECT_FALSE(target().isFramePending());
476
477 // The frame did not miss if the past present fence is invalid.
478 EXPECT_FALSE(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,
483 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400484 EXPECT_TRUE(target().isFramePending());
485
486 // The frame missed if the past present fence is pending.
487 EXPECT_TRUE(target().didMissFrame());
488 EXPECT_TRUE(target().didMissHwcFrame());
489
490 frame.end(CompositionCoverage::Gpu);
491 }
492 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800493 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
494 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400495 EXPECT_TRUE(target().isFramePending());
496
497 // The GPU frame missed if the past present fence is pending.
498 EXPECT_TRUE(target().didMissFrame());
499 EXPECT_FALSE(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 const auto fence = frame.end();
506 const auto expectedPresentTime = target().expectedPresentTime();
507 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2 + 1);
508 }
509 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800510 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400511 EXPECT_FALSE(target().isFramePending());
512
513 const auto fence = frame.end();
514 const auto expectedPresentTime = target().expectedPresentTime();
515 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2);
516
517 // The frame missed if the past present fence was signaled but not within slop.
518 EXPECT_TRUE(target().didMissFrame());
519 EXPECT_TRUE(target().didMissHwcFrame());
520 }
521 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800522 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400523 EXPECT_FALSE(target().isFramePending());
524
525 // The frame did not miss if the past present fence was signaled within slop.
526 EXPECT_FALSE(target().didMissFrame());
527 EXPECT_FALSE(target().didMissHwcFrame());
528 }
529}
530
531} // namespace android::scheduler