blob: c88338575532eca83a8e6a326be7d132927bbedc [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
47class FrameTargeterTest : public testing::Test {
48public:
49 const auto& target() const { return mTargeter.target(); }
50
51 struct Frame {
52 Frame(FrameTargeterTest* testPtr, VsyncId vsyncId, TimePoint& frameBeginTime,
Ady Abraham3db8a3c2023-11-20 17:53:47 -080053 Duration frameDuration, Fps refreshRate, Fps peakRefreshRate,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040054 FrameTargeter::IsFencePendingFuncPtr isFencePendingFuncPtr = Frame::fenceSignaled,
55 const ftl::Optional<VsyncSource>& vsyncSourceOpt = std::nullopt)
Ady Abraham3db8a3c2023-11-20 17:53:47 -080056 : testPtr(testPtr),
57 frameBeginTime(frameBeginTime),
58 period(refreshRate.getPeriod()),
59 minFramePeriod(peakRefreshRate.getPeriod()) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040060 const FrameTargeter::BeginFrameArgs args{.frameBeginTime = frameBeginTime,
61 .vsyncId = vsyncId,
62 .expectedVsyncTime =
63 frameBeginTime + frameDuration,
64 .sfWorkDuration = 10ms};
65
66 testPtr->mTargeter.beginFrame(args,
67 vsyncSourceOpt
68 .or_else([&] {
69 return std::make_optional(
Ady Abraham3db8a3c2023-11-20 17:53:47 -080070 VsyncSource(period, period,
Dominik Laskowskib418dd72023-06-13 17:31:04 -040071 args.expectedVsyncTime));
72 })
73 .value(),
74 isFencePendingFuncPtr);
75 }
76
77 FenceTimePtr end(CompositionCoverage coverage = CompositionCoverage::Hwc) {
78 if (ended) return nullptr;
79 ended = true;
80
81 auto [fence, fenceTime] = testPtr->mFenceMap.makePendingFenceForTest();
82 testPtr->mTargeter.setPresentFence(std::move(fence), fenceTime);
83
84 testPtr->mTargeter.endFrame({.compositionCoverage = coverage});
85 return fenceTime;
86 }
87
88 ~Frame() {
89 end();
90 frameBeginTime += period;
91 }
92
93 static bool fencePending(const FenceTimePtr&, int) { return true; }
94 static bool fenceSignaled(const FenceTimePtr&, int) { return false; }
95
96 FrameTargeterTest* const testPtr;
97
98 TimePoint& frameBeginTime;
99 const Period period;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800100 const Period minFramePeriod;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400101
102 bool ended = false;
103 };
104
105private:
106 FenceToFenceTimeMap mFenceMap;
107
108 static constexpr bool kBackpressureGpuComposition = true;
Dominik Laskowskiec0eac22023-01-28 16:16:19 -0500109 FrameTargeter mTargeter{PhysicalDisplayId::fromPort(13), kBackpressureGpuComposition};
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400110};
111
112TEST_F(FrameTargeterTest, targetsFrames) {
113 VsyncId vsyncId{42};
114 {
115 TimePoint frameBeginTime(989ms);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800116 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400117
118 EXPECT_EQ(target().vsyncId(), VsyncId{42});
119 EXPECT_EQ(target().frameBeginTime(), TimePoint(989ms));
120 EXPECT_EQ(target().expectedPresentTime(), TimePoint(999ms));
121 EXPECT_EQ(target().expectedFrameDuration(), 10ms);
122 }
123 {
124 TimePoint frameBeginTime(1100ms);
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800125 const Frame frame(this, vsyncId++, frameBeginTime, 11ms, 60_Hz, 60_Hz);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400126
127 EXPECT_EQ(target().vsyncId(), VsyncId{43});
128 EXPECT_EQ(target().frameBeginTime(), TimePoint(1100ms));
129 EXPECT_EQ(target().expectedPresentTime(), TimePoint(1111ms));
130 EXPECT_EQ(target().expectedFrameDuration(), 11ms);
131 }
132}
133
134TEST_F(FrameTargeterTest, inflatesExpectedPresentTime) {
135 // Negative such that `expectedVsyncTime` is in the past.
136 constexpr Duration kFrameDuration = -3ms;
137 TimePoint frameBeginTime(777ms);
138
139 constexpr Fps kRefreshRate = 120_Hz;
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800140 const VsyncSource vsyncSource(kRefreshRate.getPeriod(), kRefreshRate.getPeriod(),
141 frameBeginTime + 5ms);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400142 const Frame frame(this, VsyncId{123}, frameBeginTime, kFrameDuration, kRefreshRate,
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800143 kRefreshRate, Frame::fenceSignaled, vsyncSource);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400144
145 EXPECT_EQ(target().expectedPresentTime(), vsyncSource.vsyncDeadline + vsyncSource.vsyncPeriod);
146}
147
148TEST_F(FrameTargeterTest, recallsPastVsync) {
149 VsyncId vsyncId{111};
150 TimePoint frameBeginTime(1000ms);
151 constexpr Fps kRefreshRate = 60_Hz;
152 constexpr Period kPeriod = kRefreshRate.getPeriod();
153 constexpr Duration kFrameDuration = 13ms;
154
155 for (int n = 5; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800156 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400157 const auto fence = frame.end();
158
159 EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - kPeriod);
160 EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), fence);
161 }
162}
163
164TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
165 VsyncId vsyncId{222};
166 TimePoint frameBeginTime(2000ms);
167 constexpr Fps kRefreshRate = 120_Hz;
168 constexpr Period kPeriod = kRefreshRate.getPeriod();
169 constexpr Duration kFrameDuration = 10ms;
170
171 FenceTimePtr previousFence = FenceTime::NO_FENCE;
172
173 for (int n = 5; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800174 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
175 const auto fence = frame.end();
176
177 EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
178 EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence);
179
180 previousFence = fence;
181 }
182}
183
184TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) {
185 SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::vrr_config, true);
186
187 VsyncId vsyncId{222};
188 TimePoint frameBeginTime(2000ms);
189 constexpr Fps kRefreshRate = 120_Hz;
190 constexpr Fps kPeakRefreshRate = 240_Hz;
191 constexpr Period kPeriod = kRefreshRate.getPeriod();
192 constexpr Duration kFrameDuration = 10ms;
193
194 FenceTimePtr previousFence = FenceTime::NO_FENCE;
195
196 for (int n = 5; n-- > 0;) {
197 Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
198 kPeakRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400199 const auto fence = frame.end();
200
201 EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
202 EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence);
203
204 previousFence = fence;
205 }
206}
207
208TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
209 constexpr Period kPeriod = (60_Hz).getPeriod();
210 EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), FenceTime::NO_FENCE);
211 EXPECT_FALSE(target().wouldPresentEarly(kPeriod));
212}
213
214TEST_F(FrameTargeterTest, detectsEarlyPresent) {
215 VsyncId vsyncId{333};
216 TimePoint frameBeginTime(3000ms);
217 constexpr Fps kRefreshRate = 60_Hz;
218 constexpr Period kPeriod = kRefreshRate.getPeriod();
219
220 // The target is not early while past present fences are pending.
221 for (int n = 3; n-- > 0;) {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800222 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400223 EXPECT_FALSE(target().wouldPresentEarly(kPeriod));
224 }
225
226 // The target is early if the past present fence was signaled.
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800227 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400228 const auto fence = frame.end();
229 fence->signalForTest(frameBeginTime.ns());
230
231 EXPECT_TRUE(target().wouldPresentEarly(kPeriod));
232}
233
234TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
235 VsyncId vsyncId{444};
236 TimePoint frameBeginTime(4000ms);
237 constexpr Fps kRefreshRate = 120_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);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400243 EXPECT_FALSE(target().wouldPresentEarly(kPeriod));
244 }
245
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800246 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400247 const auto fence = frame.end();
248 fence->signalForTest(frameBeginTime.ns());
249
250 // The target is two VSYNCs ahead, so the past present fence is still pending.
251 EXPECT_FALSE(target().wouldPresentEarly(kPeriod));
252
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800253 { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400254
255 // The target is early if the past present fence was signaled.
256 EXPECT_TRUE(target().wouldPresentEarly(kPeriod));
257}
258
259TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
260 TimePoint frameBeginTime(5000ms);
261 constexpr Fps kRefreshRate = 144_Hz;
262 constexpr Period kPeriod = kRefreshRate.getPeriod();
263
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800264 const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400265
266 // The target is more than two VSYNCs ahead, but present fences are not tracked that far back.
267 EXPECT_TRUE(target().wouldPresentEarly(kPeriod));
268}
269
270TEST_F(FrameTargeterTest, detectsMissedFrames) {
271 VsyncId vsyncId{555};
272 TimePoint frameBeginTime(5000ms);
273 constexpr Fps kRefreshRate = 60_Hz;
274 constexpr Period kPeriod = kRefreshRate.getPeriod();
275
276 EXPECT_FALSE(target().isFramePending());
277 EXPECT_FALSE(target().didMissFrame());
278 EXPECT_FALSE(target().didMissHwcFrame());
279
280 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800281 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400282 EXPECT_FALSE(target().isFramePending());
283
284 // The frame did not miss if the past present fence is invalid.
285 EXPECT_FALSE(target().didMissFrame());
286 EXPECT_FALSE(target().didMissHwcFrame());
287 }
288 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800289 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
290 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400291 EXPECT_TRUE(target().isFramePending());
292
293 // The frame missed if the past present fence is pending.
294 EXPECT_TRUE(target().didMissFrame());
295 EXPECT_TRUE(target().didMissHwcFrame());
296
297 frame.end(CompositionCoverage::Gpu);
298 }
299 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800300 const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate,
301 Frame::fencePending);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400302 EXPECT_TRUE(target().isFramePending());
303
304 // The GPU frame missed if the past present fence is pending.
305 EXPECT_TRUE(target().didMissFrame());
306 EXPECT_FALSE(target().didMissHwcFrame());
307 }
308 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800309 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400310 EXPECT_FALSE(target().isFramePending());
311
312 const auto fence = frame.end();
313 const auto expectedPresentTime = target().expectedPresentTime();
314 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2 + 1);
315 }
316 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800317 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400318 EXPECT_FALSE(target().isFramePending());
319
320 const auto fence = frame.end();
321 const auto expectedPresentTime = target().expectedPresentTime();
322 fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2);
323
324 // The frame missed if the past present fence was signaled but not within slop.
325 EXPECT_TRUE(target().didMissFrame());
326 EXPECT_TRUE(target().didMissHwcFrame());
327 }
328 {
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800329 Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400330 EXPECT_FALSE(target().isFramePending());
331
332 // The frame did not miss if the past present fence was signaled within slop.
333 EXPECT_FALSE(target().didMissFrame());
334 EXPECT_FALSE(target().didMissHwcFrame());
335 }
336}
337
338} // namespace android::scheduler