blob: a9abcaf14c0a5837669ddf1be85130c42e68f22e [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
Dominik Laskowskib418dd72023-06-13 17:31:04 -040027using namespace std::chrono_literals;
28
29namespace android::scheduler {
30namespace {
31
32struct VsyncSource final : IVsyncSource {
Ady Abraham3db8a3c2023-11-20 17:53:47 -080033 VsyncSource(Period period, Period minFramePeriod, TimePoint deadline)
34 : vsyncPeriod(period), framePeriod(minFramePeriod), vsyncDeadline(deadline) {}
Dominik Laskowskib418dd72023-06-13 17:31:04 -040035
36 const Period vsyncPeriod;
Ady Abraham3db8a3c2023-11-20 17:53:47 -080037 const Period framePeriod;
Dominik Laskowskib418dd72023-06-13 17:31:04 -040038 const TimePoint vsyncDeadline;
39
40 Period period() const override { return vsyncPeriod; }
41 TimePoint vsyncDeadlineAfter(TimePoint) const override { return vsyncDeadline; }
Ady Abraham3db8a3c2023-11-20 17:53:47 -080042 Period minFramePeriod() const override { return framePeriod; }
Dominik Laskowskib418dd72023-06-13 17:31:04 -040043};
44
45} // namespace
46
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050047class FrameTargeterTestBase : public testing::Test {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040048public:
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050049 FrameTargeterTestBase(FeatureFlags flags) : mTargeter(PhysicalDisplayId::fromPort(13), flags) {}
50
Dominik Laskowskib418dd72023-06-13 17:31:04 -040051 const auto& target() const { return mTargeter.target(); }
52
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050053 bool wouldPresentEarly(Period minFramePeriod) const {
54 return target().wouldPresentEarly(minFramePeriod);
55 }
56
Dominik Laskowskib418dd72023-06-13 17:31:04 -040057 struct Frame {
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050058 Frame(FrameTargeterTestBase* testPtr, VsyncId vsyncId, TimePoint& frameBeginTime,
Ady Abraham3db8a3c2023-11-20 17:53:47 -080059 Duration frameDuration, Fps refreshRate, Fps peakRefreshRate,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040060 FrameTargeter::IsFencePendingFuncPtr isFencePendingFuncPtr = Frame::fenceSignaled,
61 const ftl::Optional<VsyncSource>& vsyncSourceOpt = std::nullopt)
Ady Abraham3db8a3c2023-11-20 17:53:47 -080062 : testPtr(testPtr),
63 frameBeginTime(frameBeginTime),
64 period(refreshRate.getPeriod()),
65 minFramePeriod(peakRefreshRate.getPeriod()) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040066 const FrameTargeter::BeginFrameArgs args{.frameBeginTime = frameBeginTime,
67 .vsyncId = vsyncId,
68 .expectedVsyncTime =
69 frameBeginTime + frameDuration,
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050070 .sfWorkDuration = 10ms,
71 .hwcMinWorkDuration = kHwcMinWorkDuration};
Dominik Laskowskib418dd72023-06-13 17:31:04 -040072
73 testPtr->mTargeter.beginFrame(args,
74 vsyncSourceOpt
75 .or_else([&] {
76 return std::make_optional(
Ady Abraham3db8a3c2023-11-20 17:53:47 -080077 VsyncSource(period, period,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040078 args.expectedVsyncTime));
79 })
80 .value(),
81 isFencePendingFuncPtr);
82 }
83
84 FenceTimePtr end(CompositionCoverage coverage = CompositionCoverage::Hwc) {
85 if (ended) return nullptr;
86 ended = true;
87
88 auto [fence, fenceTime] = testPtr->mFenceMap.makePendingFenceForTest();
89 testPtr->mTargeter.setPresentFence(std::move(fence), fenceTime);
90
91 testPtr->mTargeter.endFrame({.compositionCoverage = coverage});
92 return fenceTime;
93 }
94
95 ~Frame() {
96 end();
97 frameBeginTime += period;
98 }
99
100 static bool fencePending(const FenceTimePtr&, int) { return true; }
101 static bool fenceSignaled(const FenceTimePtr&, int) { return false; }
102
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500103 FrameTargeterTestBase* const testPtr;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400104
105 TimePoint& frameBeginTime;
106 const Period period;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800107 const Period minFramePeriod;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400108
109 bool ended = false;
110 };
111
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500112 static constexpr Duration kHwcMinWorkDuration = std::chrono::nanoseconds(5ns);
113
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400114private:
115 FenceToFenceTimeMap mFenceMap;
116
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500117 FrameTargeter mTargeter;
118};
119
120class FrameTargeterTest : public FrameTargeterTestBase {
121public:
122 FrameTargeterTest() : FrameTargeterTestBase(Feature::kBackpressureGpuComposition) {}
123};
124
125class FrameTargeterWithExpectedPresentSupportTest : public FrameTargeterTestBase {
126public:
127 FrameTargeterWithExpectedPresentSupportTest()
128 : FrameTargeterTestBase(FeatureFlags(Feature::kBackpressureGpuComposition) |
129 Feature::kExpectedPresentTime) {}
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400130};
131
132TEST_F(FrameTargeterTest, targetsFrames) {
133 VsyncId vsyncId{42};
134 {
135 TimePoint frameBeginTime(989ms);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800136 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400137
138 EXPECT_EQ(target().vsyncId(), VsyncId{42});
139 EXPECT_EQ(target().frameBeginTime(), TimePoint(989ms));
140 EXPECT_EQ(target().expectedPresentTime(), TimePoint(999ms));
141 EXPECT_EQ(target().expectedFrameDuration(), 10ms);
142 }
143 {
144 TimePoint frameBeginTime(1100ms);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800145 const Frame frame(this, vsyncId++, frameBeginTime, 11ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400146
147 EXPECT_EQ(target().vsyncId(), VsyncId{43});
148 EXPECT_EQ(target().frameBeginTime(), TimePoint(1100ms));
149 EXPECT_EQ(target().expectedPresentTime(), TimePoint(1111ms));
150 EXPECT_EQ(target().expectedFrameDuration(), 11ms);
151 }
152}
153
154TEST_F(FrameTargeterTest, inflatesExpectedPresentTime) {
155 // Negative such that `expectedVsyncTime` is in the past.
156 constexpr Duration kFrameDuration = -3ms;
157 TimePoint frameBeginTime(777ms);
158
159 constexpr Fps kRefreshRate = 120_Hz;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800160 const VsyncSource vsyncSource(kRefreshRate.getPeriod(), kRefreshRate.getPeriod(),
161 frameBeginTime + 5ms);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400162 const Frame frame(this, VsyncId{123}, frameBeginTime, kFrameDuration, kRefreshRate,
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800163 kRefreshRate, Frame::fenceSignaled, vsyncSource);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400164
165 EXPECT_EQ(target().expectedPresentTime(), vsyncSource.vsyncDeadline + vsyncSource.vsyncPeriod);
166}
167
168TEST_F(FrameTargeterTest, recallsPastVsync) {
169 VsyncId vsyncId{111};
170 TimePoint frameBeginTime(1000ms);
171 constexpr Fps kRefreshRate = 60_Hz;
172 constexpr Period kPeriod = kRefreshRate.getPeriod();
173 constexpr Duration kFrameDuration = 13ms;
174
175 for (int n = 5; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800176 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400177 const auto fence = frame.end();
178
179 EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - kPeriod);
180 EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), fence);
181 }
182}
183
184TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
185 VsyncId vsyncId{222};
186 TimePoint frameBeginTime(2000ms);
187 constexpr Fps kRefreshRate = 120_Hz;
188 constexpr Period kPeriod = kRefreshRate.getPeriod();
189 constexpr Duration kFrameDuration = 10ms;
190
191 FenceTimePtr previousFence = FenceTime::NO_FENCE;
192
193 for (int n = 5; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800194 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
195 const auto fence = frame.end();
196
197 EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
198 EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence);
199
200 previousFence = fence;
201 }
202}
203
204TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) {
205 SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::vrr_config, true);
206
207 VsyncId vsyncId{222};
208 TimePoint frameBeginTime(2000ms);
209 constexpr Fps kRefreshRate = 120_Hz;
210 constexpr Fps kPeakRefreshRate = 240_Hz;
211 constexpr Period kPeriod = kRefreshRate.getPeriod();
212 constexpr Duration kFrameDuration = 10ms;
213
214 FenceTimePtr previousFence = FenceTime::NO_FENCE;
215
216 for (int n = 5; n-- > 0;) {
217 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
218 kPeakRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400219 const auto fence = frame.end();
220
221 EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
222 EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence);
223
224 previousFence = fence;
225 }
226}
227
228TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
229 constexpr Period kPeriod = (60_Hz).getPeriod();
230 EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), FenceTime::NO_FENCE);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500231 EXPECT_FALSE(wouldPresentEarly(kPeriod));
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400232}
233
234TEST_F(FrameTargeterTest, detectsEarlyPresent) {
235 VsyncId vsyncId{333};
236 TimePoint frameBeginTime(3000ms);
237 constexpr Fps kRefreshRate = 60_Hz;
238 constexpr Period kPeriod = kRefreshRate.getPeriod();
239
240 // The target is not early while past present fences are pending.
241 for (int n = 3; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800242 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500243 EXPECT_FALSE(wouldPresentEarly(kPeriod));
244 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400245 }
246
247 // The target is early if the past present fence was signaled.
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800248 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400249 const auto fence = frame.end();
250 fence->signalForTest(frameBeginTime.ns());
251
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500252 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
253
254 // `finalFrame` would present early, so it has an earliest present time.
255 EXPECT_TRUE(wouldPresentEarly(kPeriod));
256 ASSERT_NE(std::nullopt, target().earliestPresentTime());
257 EXPECT_EQ(*target().earliestPresentTime(),
258 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
259}
260
261// Same as `detectsEarlyPresent`, above, but verifies that we do not set an earliest present time
262// when there is expected present time support.
263TEST_F(FrameTargeterWithExpectedPresentSupportTest, detectsEarlyPresent) {
264 VsyncId vsyncId{333};
265 TimePoint frameBeginTime(3000ms);
266 constexpr Fps kRefreshRate = 60_Hz;
267 constexpr Period kPeriod = kRefreshRate.getPeriod();
268
269 // The target is not early while past present fences are pending.
270 for (int n = 3; n-- > 0;) {
271 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
272 EXPECT_FALSE(wouldPresentEarly(kPeriod));
273 EXPECT_FALSE(target().earliestPresentTime());
274 }
275
276 // The target is early if the past present fence was signaled.
277 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
278 const auto fence = frame.end();
279 fence->signalForTest(frameBeginTime.ns());
280
281 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
282
283 // `finalFrame` would present early, but we have expected present time support, so it has no
284 // earliest present time.
285 EXPECT_TRUE(wouldPresentEarly(kPeriod));
286 ASSERT_EQ(std::nullopt, target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400287}
288
289TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
290 VsyncId vsyncId{444};
291 TimePoint frameBeginTime(4000ms);
292 constexpr Fps kRefreshRate = 120_Hz;
293 constexpr Period kPeriod = kRefreshRate.getPeriod();
294
295 // The target is not early while past present fences are pending.
296 for (int n = 3; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800297 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500298 EXPECT_FALSE(wouldPresentEarly(kPeriod));
299 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400300 }
301
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800302 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400303 const auto fence = frame.end();
304 fence->signalForTest(frameBeginTime.ns());
305
306 // The target is two VSYNCs ahead, so the past present fence is still pending.
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500307 EXPECT_FALSE(wouldPresentEarly(kPeriod));
308 EXPECT_FALSE(target().earliestPresentTime());
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400309
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800310 { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400311
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500312 Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
313
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400314 // The target is early if the past present fence was signaled.
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500315 EXPECT_TRUE(wouldPresentEarly(kPeriod));
316 ASSERT_NE(std::nullopt, target().earliestPresentTime());
317 EXPECT_EQ(*target().earliestPresentTime(),
318 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400319}
320
321TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
322 TimePoint frameBeginTime(5000ms);
323 constexpr Fps kRefreshRate = 144_Hz;
324 constexpr Period kPeriod = kRefreshRate.getPeriod();
325
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800326 const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400327
328 // 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 -0500329 EXPECT_TRUE(wouldPresentEarly(kPeriod));
330 EXPECT_TRUE(target().earliestPresentTime());
331 EXPECT_EQ(*target().earliestPresentTime(),
332 target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400333}
334
335TEST_F(FrameTargeterTest, detectsMissedFrames) {
336 VsyncId vsyncId{555};
337 TimePoint frameBeginTime(5000ms);
338 constexpr Fps kRefreshRate = 60_Hz;
339 constexpr Period kPeriod = kRefreshRate.getPeriod();
340
341 EXPECT_FALSE(target().isFramePending());
342 EXPECT_FALSE(target().didMissFrame());
343 EXPECT_FALSE(target().didMissHwcFrame());
344
345 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800346 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400347 EXPECT_FALSE(target().isFramePending());
348
349 // The frame did not miss if the past present fence is invalid.
350 EXPECT_FALSE(target().didMissFrame());
351 EXPECT_FALSE(target().didMissHwcFrame());
352 }
353 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800354 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
355 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400356 EXPECT_TRUE(target().isFramePending());
357
358 // The frame missed if the past present fence is pending.
359 EXPECT_TRUE(target().didMissFrame());
360 EXPECT_TRUE(target().didMissHwcFrame());
361
362 frame.end(CompositionCoverage::Gpu);
363 }
364 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800365 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
366 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400367 EXPECT_TRUE(target().isFramePending());
368
369 // The GPU frame missed if the past present fence is pending.
370 EXPECT_TRUE(target().didMissFrame());
371 EXPECT_FALSE(target().didMissHwcFrame());
372 }
373 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800374 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400375 EXPECT_FALSE(target().isFramePending());
376
377 const auto fence = frame.end();
378 const auto expectedPresentTime = target().expectedPresentTime();
379 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2 + 1);
380 }
381 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800382 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400383 EXPECT_FALSE(target().isFramePending());
384
385 const auto fence = frame.end();
386 const auto expectedPresentTime = target().expectedPresentTime();
387 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2);
388
389 // The frame missed if the past present fence was signaled but not within slop.
390 EXPECT_TRUE(target().didMissFrame());
391 EXPECT_TRUE(target().didMissHwcFrame());
392 }
393 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800394 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400395 EXPECT_FALSE(target().isFramePending());
396
397 // The frame did not miss if the past present fence was signaled within slop.
398 EXPECT_FALSE(target().didMissFrame());
399 EXPECT_FALSE(target().didMissHwcFrame());
400 }
401}
402
403} // namespace android::scheduler