blob: bc73cbbfd5e726552db398f5e71a8e71af3ac369 [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
347// Same as `detectsEarlyPresent`, above, but verifies that we do not set an earliest present time
348// when there is expected present time support.
349TEST_F(FrameTargeterWithExpectedPresentSupportTest, detectsEarlyPresent) {
350 VsyncId vsyncId{333};
351 TimePoint frameBeginTime(3000ms);
352 constexpr Fps kRefreshRate = 60_Hz;
353 constexpr Period kPeriod = kRefreshRate.getPeriod();
354
355 // The target is not early while past present fences are pending.
356 for (int n = 3; n-- > 0;) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700357 {
358 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
359 }
360 EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500361 EXPECT_FALSE(target().earliestPresentTime());
362 }
363
364 // The target is early if the past present fence was signaled.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700365 {
366 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
367
368 const auto fence = frame.end();
369 fence->signalForTest(frameBeginTime.ns());
370 }
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500371
372 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
373
374 // `finalFrame` would present early, but we have expected present time support, so it has no
375 // earliest present time.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700376 EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500377 ASSERT_EQ(std::nullopt, target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400378}
379
380TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
381 VsyncId vsyncId{444};
382 TimePoint frameBeginTime(4000ms);
383 constexpr Fps kRefreshRate = 120_Hz;
384 constexpr Period kPeriod = kRefreshRate.getPeriod();
385
386 // The target is not early while past present fences are pending.
387 for (int n = 3; n-- > 0;) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700388 {
389 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
390 }
391 EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500392 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400393 }
Ady Abrahamed1283a2024-07-24 15:49:16 -0700394 {
395 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400396
Ady Abrahamed1283a2024-07-24 15:49:16 -0700397 const auto fence = frame.end();
398 fence->signalForTest(frameBeginTime.ns());
399 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400400
401 // The target is two VSYNCs ahead, so the past present fence is still pending.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700402 EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500403 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400404
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800405 { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400406
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500407 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
408
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400409 // The target is early if the past present fence was signaled.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700410 EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500411 ASSERT_NE(std::nullopt, target().earliestPresentTime());
412 EXPECT_EQ(*target().earliestPresentTime(),
413 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400414}
415
416TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
417 TimePoint frameBeginTime(5000ms);
418 constexpr Fps kRefreshRate = 144_Hz;
419 constexpr Period kPeriod = kRefreshRate.getPeriod();
420
Ady Abrahamed1283a2024-07-24 15:49:16 -0700421 { const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate); }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400422
423 // The target is more than two VSYNCs ahead, but present fences are not tracked that far back.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700424 EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500425 EXPECT_TRUE(target().earliestPresentTime());
426 EXPECT_EQ(*target().earliestPresentTime(),
427 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400428}
429
430TEST_F(FrameTargeterTest, detectsMissedFrames) {
431 VsyncId vsyncId{555};
432 TimePoint frameBeginTime(5000ms);
433 constexpr Fps kRefreshRate = 60_Hz;
434 constexpr Period kPeriod = kRefreshRate.getPeriod();
435
436 EXPECT_FALSE(target().isFramePending());
437 EXPECT_FALSE(target().didMissFrame());
438 EXPECT_FALSE(target().didMissHwcFrame());
439
440 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800441 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400442 EXPECT_FALSE(target().isFramePending());
443
444 // The frame did not miss if the past present fence is invalid.
445 EXPECT_FALSE(target().didMissFrame());
446 EXPECT_FALSE(target().didMissHwcFrame());
447 }
448 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800449 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
450 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400451 EXPECT_TRUE(target().isFramePending());
452
453 // The frame missed if the past present fence is pending.
454 EXPECT_TRUE(target().didMissFrame());
455 EXPECT_TRUE(target().didMissHwcFrame());
456
457 frame.end(CompositionCoverage::Gpu);
458 }
459 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800460 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
461 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400462 EXPECT_TRUE(target().isFramePending());
463
464 // The GPU frame missed if the past present fence is pending.
465 EXPECT_TRUE(target().didMissFrame());
466 EXPECT_FALSE(target().didMissHwcFrame());
467 }
468 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800469 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400470 EXPECT_FALSE(target().isFramePending());
471
472 const auto fence = frame.end();
473 const auto expectedPresentTime = target().expectedPresentTime();
474 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2 + 1);
475 }
476 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800477 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400478 EXPECT_FALSE(target().isFramePending());
479
480 const auto fence = frame.end();
481 const auto expectedPresentTime = target().expectedPresentTime();
482 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2);
483
484 // The frame missed if the past present fence was signaled but not within slop.
485 EXPECT_TRUE(target().didMissFrame());
486 EXPECT_TRUE(target().didMissHwcFrame());
487 }
488 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800489 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400490 EXPECT_FALSE(target().isFramePending());
491
492 // The frame did not miss if the past present fence was signaled within slop.
493 EXPECT_FALSE(target().didMissFrame());
494 EXPECT_FALSE(target().didMissHwcFrame());
495 }
496}
497
498} // namespace android::scheduler