blob: c1fa6ac6f2e15542f1886710d7c6a1722bb95cdb [file] [log] [blame]
Marin Shalamanov2045d5b2020-12-28 18:11:41 +01001/*
2 * Copyright 2020 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#undef LOG_TAG
18#define LOG_TAG "LayerInfoTest"
19
20#include <gtest/gtest.h>
21
Dominik Laskowskif6b4ba62021-11-09 12:46:10 -080022#include <scheduler/Fps.h>
23
Ady Abraham3db8a3c2023-11-20 17:53:47 -080024#include <common/test/FlagUtils.h>
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070025#include "FpsOps.h"
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010026#include "Scheduler/LayerHistory.h"
27#include "Scheduler/LayerInfo.h"
Rachel Leece6e0042023-06-27 11:22:54 -070028#include "TestableScheduler.h"
29#include "TestableSurfaceFlinger.h"
30#include "mock/MockSchedulerCallback.h"
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010031
Alec Mouri89f5d4e2023-10-20 17:12:49 +000032#include <com_android_graphics_surfaceflinger_flags.h>
33
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010034namespace android::scheduler {
35
Rachel Leece6e0042023-06-27 11:22:54 -070036using android::mock::createDisplayMode;
37
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010038class LayerInfoTest : public testing::Test {
39protected:
40 using FrameTimeData = LayerInfo::FrameTimeData;
41
Rachel Leece6e0042023-06-27 11:22:54 -070042 static constexpr Fps LO_FPS = 30_Hz;
43 static constexpr Fps HI_FPS = 90_Hz;
44
45 LayerInfoTest() { mFlinger.resetScheduler(mScheduler); }
46
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010047 void setFrameTimes(const std::deque<FrameTimeData>& frameTimes) {
48 layerInfo.mFrameTimes = frameTimes;
49 }
50
51 void setLastRefreshRate(Fps fps) {
52 layerInfo.mLastRefreshRate.reported = fps;
53 layerInfo.mLastRefreshRate.calculated = fps;
54 }
55
56 auto calculateAverageFrameTime() { return layerInfo.calculateAverageFrameTime(); }
57
Ady Abrahambdda8f02021-04-01 16:06:11 -070058 LayerInfo layerInfo{"TestLayerInfo", 0, LayerHistory::LayerVoteType::Heuristic};
Rachel Leece6e0042023-06-27 11:22:54 -070059
60 std::shared_ptr<RefreshRateSelector> mSelector =
61 std::make_shared<RefreshRateSelector>(makeModes(createDisplayMode(DisplayModeId(0),
62 LO_FPS),
63 createDisplayMode(DisplayModeId(1),
64 HI_FPS)),
65 DisplayModeId(0));
66 mock::SchedulerCallback mSchedulerCallback;
Rachel Leece6e0042023-06-27 11:22:54 -070067 TestableSurfaceFlinger mFlinger;
ramindaniae645822024-01-11 10:57:29 -080068 TestableScheduler* mScheduler = new TestableScheduler(mSelector, mFlinger, mSchedulerCallback);
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010069};
70
71namespace {
72
Alec Mouri89f5d4e2023-10-20 17:12:49 +000073using namespace com::android::graphics::surfaceflinger;
74
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010075TEST_F(LayerInfoTest, prefersPresentTime) {
76 std::deque<FrameTimeData> frameTimes;
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070077 constexpr auto kExpectedFps = 50_Hz;
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010078 constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
79 constexpr int kNumFrames = 10;
80 for (int i = 1; i <= kNumFrames; i++) {
81 frameTimes.push_back(FrameTimeData{.presentTime = kPeriod * i,
82 .queueTime = 0,
Marin Shalamanova7fe3042021-01-29 21:02:08 +010083 .pendingModeChange = false});
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010084 }
85 setFrameTimes(frameTimes);
86 const auto averageFrameTime = calculateAverageFrameTime();
87 ASSERT_TRUE(averageFrameTime.has_value());
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070088 ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010089}
90
91TEST_F(LayerInfoTest, fallbacksToQueueTimeIfNoPresentTime) {
92 std::deque<FrameTimeData> frameTimes;
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070093 constexpr auto kExpectedFps = 50_Hz;
Marin Shalamanov2045d5b2020-12-28 18:11:41 +010094 constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
95 constexpr int kNumFrames = 10;
96 for (int i = 1; i <= kNumFrames; i++) {
97 frameTimes.push_back(FrameTimeData{.presentTime = 0,
98 .queueTime = kPeriod * i,
Marin Shalamanova7fe3042021-01-29 21:02:08 +010099 .pendingModeChange = false});
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100100 }
101 setFrameTimes(frameTimes);
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700102 setLastRefreshRate(20_Hz); // Set to some valid value.
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100103 const auto averageFrameTime = calculateAverageFrameTime();
104 ASSERT_TRUE(averageFrameTime.has_value());
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700105 ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100106}
107
108TEST_F(LayerInfoTest, returnsNulloptIfThereWasConfigChange) {
109 std::deque<FrameTimeData> frameTimesWithoutConfigChange;
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700110 const auto period = (50_Hz).getPeriodNsecs();
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100111 constexpr int kNumFrames = 10;
112 for (int i = 1; i <= kNumFrames; i++) {
113 frameTimesWithoutConfigChange.push_back(FrameTimeData{.presentTime = period * i,
114 .queueTime = period * i,
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100115 .pendingModeChange = false});
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100116 }
117
118 setFrameTimes(frameTimesWithoutConfigChange);
119 ASSERT_TRUE(calculateAverageFrameTime().has_value());
120
121 {
122 // Config change in the first record
123 auto frameTimes = frameTimesWithoutConfigChange;
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100124 frameTimes[0].pendingModeChange = true;
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100125 setFrameTimes(frameTimes);
126 ASSERT_FALSE(calculateAverageFrameTime().has_value());
127 }
128
129 {
130 // Config change in the last record
131 auto frameTimes = frameTimesWithoutConfigChange;
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100132 frameTimes[frameTimes.size() - 1].pendingModeChange = true;
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100133 setFrameTimes(frameTimes);
134 ASSERT_FALSE(calculateAverageFrameTime().has_value());
135 }
136
137 {
138 // Config change in the middle
139 auto frameTimes = frameTimesWithoutConfigChange;
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100140 frameTimes[frameTimes.size() / 2].pendingModeChange = true;
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100141 setFrameTimes(frameTimes);
142 ASSERT_FALSE(calculateAverageFrameTime().has_value());
143 }
144}
145
146// A frame can be recorded twice with very close presentation or queue times.
147// Make sure that this doesn't influence the calculated average FPS.
148TEST_F(LayerInfoTest, ignoresSmallPeriods) {
149 std::deque<FrameTimeData> frameTimes;
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700150 constexpr auto kExpectedFps = 50_Hz;
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100151 constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700152 constexpr auto kSmallPeriod = (250_Hz).getPeriodNsecs();
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100153 constexpr int kNumIterations = 10;
154 for (int i = 1; i <= kNumIterations; i++) {
155 frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i,
156 .queueTime = 0,
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100157 .pendingModeChange = false});
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100158
159 // A duplicate frame
160 frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i + kSmallPeriod,
161 .queueTime = 0,
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100162 .pendingModeChange = false});
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100163 }
164 setFrameTimes(frameTimes);
165 const auto averageFrameTime = calculateAverageFrameTime();
166 ASSERT_TRUE(averageFrameTime.has_value());
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700167 ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100168}
169
170// There may be a big period of time between two frames. Make sure that
171// this doesn't influence the calculated average FPS.
172TEST_F(LayerInfoTest, ignoresLargePeriods) {
173 std::deque<FrameTimeData> frameTimes;
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700174 constexpr auto kExpectedFps = 50_Hz;
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100175 constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700176 constexpr auto kLargePeriod = (9_Hz).getPeriodNsecs();
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100177
178 auto record = [&](nsecs_t time) {
179 frameTimes.push_back(
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100180 FrameTimeData{.presentTime = time, .queueTime = 0, .pendingModeChange = false});
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100181 };
182
183 auto time = kExpectedPeriod; // Start with non-zero time.
184 record(time);
185 time += kLargePeriod;
186 record(time);
187 constexpr int kNumIterations = 10;
188 for (int i = 1; i <= kNumIterations; i++) {
189 time += kExpectedPeriod;
190 record(time);
191 }
192
193 setFrameTimes(frameTimes);
194 const auto averageFrameTime = calculateAverageFrameTime();
195 ASSERT_TRUE(averageFrameTime.has_value());
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700196 ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100197}
198
Rachel Leece6e0042023-06-27 11:22:54 -0700199TEST_F(LayerInfoTest, getRefreshRateVote_explicitVote) {
200 LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault,
201 .fps = 20_Hz};
202 layerInfo.setLayerVote(vote);
203
204 auto actualVotes =
205 layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime());
206 ASSERT_EQ(actualVotes.size(), 1u);
207 ASSERT_EQ(actualVotes[0].type, vote.type);
208 ASSERT_EQ(actualVotes[0].fps, vote.fps);
209 ASSERT_EQ(actualVotes[0].seamlessness, vote.seamlessness);
210 ASSERT_EQ(actualVotes[0].category, vote.category);
211}
212
213TEST_F(LayerInfoTest, getRefreshRateVote_explicitVoteWithCategory) {
214 LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault,
215 .fps = 20_Hz,
Ady Abraham0dd4bd42024-02-06 18:36:49 -0800216 .category = FrameRateCategory::High,
217 .categorySmoothSwitchOnly = true};
Rachel Leece6e0042023-06-27 11:22:54 -0700218 layerInfo.setLayerVote(vote);
219
220 auto actualVotes =
221 layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime());
222 ASSERT_EQ(actualVotes.size(), 2u);
223 ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory);
224 ASSERT_EQ(actualVotes[0].category, vote.category);
Ady Abraham0dd4bd42024-02-06 18:36:49 -0800225 ASSERT_TRUE(actualVotes[0].categorySmoothSwitchOnly);
Rachel Leece6e0042023-06-27 11:22:54 -0700226 ASSERT_EQ(actualVotes[1].type, vote.type);
227 ASSERT_EQ(actualVotes[1].fps, vote.fps);
228 ASSERT_EQ(actualVotes[1].seamlessness, vote.seamlessness);
Ady Abraham0dd4bd42024-02-06 18:36:49 -0800229 ASSERT_EQ(actualVotes[1].category, FrameRateCategory::Default);
230 ASSERT_TRUE(actualVotes[1].categorySmoothSwitchOnly);
Rachel Leece6e0042023-06-27 11:22:54 -0700231}
232
233TEST_F(LayerInfoTest, getRefreshRateVote_explicitCategory) {
Rachel Leece6e0042023-06-27 11:22:54 -0700234 LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault,
235 .category = FrameRateCategory::High};
236 layerInfo.setLayerVote(vote);
237
238 auto actualVotes =
239 layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime());
240 ASSERT_EQ(actualVotes.size(), 1u);
241 ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory);
242 ASSERT_EQ(actualVotes[0].category, vote.category);
Rachel Leef377b362023-09-06 15:01:06 -0700243 ASSERT_EQ(actualVotes[0].fps, 0_Hz);
244}
245
246TEST_F(LayerInfoTest, getRefreshRateVote_categoryNoPreference) {
247 LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault,
248 .category = FrameRateCategory::NoPreference};
249 layerInfo.setLayerVote(vote);
250
251 auto actualVotes =
252 layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime());
253 ASSERT_EQ(actualVotes.size(), 1u);
254 ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory);
255 ASSERT_EQ(actualVotes[0].category, vote.category);
256 ASSERT_EQ(actualVotes[0].fps, 0_Hz);
Rachel Leece6e0042023-06-27 11:22:54 -0700257}
258
259TEST_F(LayerInfoTest, getRefreshRateVote_noData) {
260 LayerInfo::LayerVote vote = {
261 .type = LayerHistory::LayerVoteType::Heuristic,
262 };
263 layerInfo.setLayerVote(vote);
264
265 auto actualVotes =
266 layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime());
267 ASSERT_EQ(actualVotes.size(), 1u);
268 ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::Max);
269 ASSERT_EQ(actualVotes[0].fps, vote.fps);
270}
271
Alec Mouri89f5d4e2023-10-20 17:12:49 +0000272TEST_F(LayerInfoTest, isFrontBuffered) {
273 SET_FLAG_FOR_TEST(flags::vrr_config, true);
274 ASSERT_FALSE(layerInfo.isFrontBuffered());
275
276 LayerProps prop = {.isFrontBuffered = true};
277 layerInfo.setLastPresentTime(0, 0, LayerHistory::LayerUpdateType::Buffer, true, prop);
278 ASSERT_TRUE(layerInfo.isFrontBuffered());
279
280 prop.isFrontBuffered = false;
281 layerInfo.setLastPresentTime(0, 0, LayerHistory::LayerUpdateType::Buffer, true, prop);
282 ASSERT_FALSE(layerInfo.isFrontBuffered());
283}
284
Marin Shalamanov2045d5b2020-12-28 18:11:41 +0100285} // namespace
286} // namespace android::scheduler