1 /*
2 * Copyright 2021 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 "LibSurfaceFlingerUnittests"
19
20 #include "DisplayTransactionTestHelpers.h"
21 #include "mock/DisplayHardware/MockDisplayMode.h"
22
23 #include <scheduler/Fps.h>
24
25 namespace android {
26 namespace {
27
28 using android::hardware::graphics::composer::V2_4::Error;
29 using android::hardware::graphics::composer::V2_4::VsyncPeriodChangeTimeline;
30
31 class DisplayModeSwitchingTest : public DisplayTransactionTest {
32 public:
SetUp()33 void SetUp() override {
34 injectFakeBufferQueueFactory();
35 injectFakeNativeWindowSurfaceFactory();
36
37 PrimaryDisplayVariant::setupHwcHotplugCallExpectations(this);
38 PrimaryDisplayVariant::setupFramebufferConsumerBufferQueueCallExpectations(this);
39 PrimaryDisplayVariant::setupFramebufferProducerBufferQueueCallExpectations(this);
40 PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
41 PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this);
42
43 mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
44
45 mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
46 .setDisplayModes(kModes, kModeId60)
47 .inject();
48
49 setupScheduler(mDisplay->holdRefreshRateConfigs());
50
51 // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy
52 // will call setActiveConfig instead of setActiveConfigWithConstraints.
53 ON_CALL(*mComposer, isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching))
54 .WillByDefault(Return(true));
55 }
56
57 protected:
58 void setupScheduler(std::shared_ptr<scheduler::RefreshRateConfigs>);
59
60 sp<DisplayDevice> mDisplay;
61 mock::EventThread* mAppEventThread;
62
63 static constexpr DisplayModeId kModeId60{0};
64 static constexpr DisplayModeId kModeId90{1};
65 static constexpr DisplayModeId kModeId120{2};
66 static constexpr DisplayModeId kModeId90_4K{3};
67
68 static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz, 0);
69 static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz, 1);
70 static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz, 2);
71
72 static constexpr ui::Size kResolution4K{3840, 2160};
73 static inline const DisplayModePtr kMode90_4K =
74 createDisplayMode(kModeId90_4K, 90_Hz, 3, kResolution4K);
75
76 static inline const DisplayModes kModes = makeModes(kMode60, kMode90, kMode120, kMode90_4K);
77 };
78
setupScheduler(std::shared_ptr<scheduler::RefreshRateConfigs> configs)79 void DisplayModeSwitchingTest::setupScheduler(
80 std::shared_ptr<scheduler::RefreshRateConfigs> configs) {
81 auto eventThread = std::make_unique<mock::EventThread>();
82 mAppEventThread = eventThread.get();
83 auto sfEventThread = std::make_unique<mock::EventThread>();
84
85 EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
86 EXPECT_CALL(*eventThread, createEventConnection(_, _))
87 .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
88 ResyncCallback())));
89
90 EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
91 EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
92 .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
93 ResyncCallback())));
94
95 auto vsyncController = std::make_unique<mock::VsyncController>();
96 auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
97
98 EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
99 EXPECT_CALL(*vsyncTracker, currentPeriod())
100 .WillRepeatedly(
101 Return(TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
102 EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
103 mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
104 std::move(eventThread), std::move(sfEventThread),
105 TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
106 std::move(configs));
107 }
108
TEST_F(DisplayModeSwitchingTest,changeRefreshRate_OnActiveDisplay_WithRefreshRequired)109 TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) {
110 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
111 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
112
113 mFlinger.onActiveDisplayChanged(mDisplay);
114
115 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90.value(),
116 false, 0.f, 120.f, 0.f, 120.f);
117
118 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
119 ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90);
120 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
121
122 // Verify that next commit will call setActiveConfigWithConstraints in HWC
123 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
124 EXPECT_CALL(*mComposer,
125 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
126 hal::HWConfigId(kModeId90.value()), _, _))
127 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
128
129 mFlinger.commit();
130
131 Mock::VerifyAndClearExpectations(mComposer);
132 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
133 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
134
135 // Verify that the next commit will complete the mode change and send
136 // a onModeChanged event to the framework.
137
138 EXPECT_CALL(*mAppEventThread, onModeChanged(kMode90));
139 mFlinger.commit();
140 Mock::VerifyAndClearExpectations(mAppEventThread);
141
142 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
143 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90);
144 }
145
TEST_F(DisplayModeSwitchingTest,changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired)146 TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired) {
147 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
148
149 mFlinger.onActiveDisplayChanged(mDisplay);
150
151 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90.value(),
152 true, 0.f, 120.f, 0.f, 120.f);
153
154 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
155 ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90);
156 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
157
158 // Verify that next commit will call setActiveConfigWithConstraints in HWC
159 // and complete the mode change.
160 const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
161 EXPECT_CALL(*mComposer,
162 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
163 hal::HWConfigId(kModeId90.value()), _, _))
164 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
165
166 EXPECT_CALL(*mAppEventThread, onModeChanged(kMode90));
167
168 mFlinger.commit();
169
170 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
171 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90);
172 }
173
TEST_F(DisplayModeSwitchingTest,twoConsecutiveSetDesiredDisplayModeSpecs)174 TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) {
175 // Test that if we call setDesiredDisplayModeSpecs while a previous mode change
176 // is still being processed the later call will be respected.
177
178 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
179 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
180
181 mFlinger.onActiveDisplayChanged(mDisplay);
182
183 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90.value(),
184 false, 0.f, 120.f, 0.f, 120.f);
185
186 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
187 EXPECT_CALL(*mComposer,
188 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
189 hal::HWConfigId(kModeId90.value()), _, _))
190 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
191
192 mFlinger.commit();
193
194 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId120.value(),
195 false, 0.f, 180.f, 0.f, 180.f);
196
197 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
198 ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId120);
199
200 EXPECT_CALL(*mComposer,
201 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
202 hal::HWConfigId(kModeId120.value()), _, _))
203 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
204
205 mFlinger.commit();
206
207 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
208 ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId120);
209
210 mFlinger.commit();
211
212 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
213 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId120);
214 }
215
TEST_F(DisplayModeSwitchingTest,changeResolution_OnActiveDisplay_WithoutRefreshRequired)216 TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefreshRequired) {
217 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
218 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
219
220 mFlinger.onActiveDisplayChanged(mDisplay);
221
222 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90_4K.value(),
223 false, 0.f, 120.f, 0.f, 120.f);
224
225 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
226 ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90_4K);
227 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60);
228
229 // Verify that next commit will call setActiveConfigWithConstraints in HWC
230 // and complete the mode change.
231 const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
232 EXPECT_CALL(*mComposer,
233 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
234 hal::HWConfigId(kModeId90_4K.value()), _, _))
235 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
236
237 EXPECT_CALL(*mAppEventThread, onHotplugReceived(mDisplay->getPhysicalId(), true));
238
239 // Misc expecations. We don't need to enforce these method calls, but since the helper methods
240 // already set expectations we should add new ones here, otherwise the test will fail.
241 EXPECT_CALL(*mConsumer,
242 setDefaultBufferSize(static_cast<uint32_t>(kResolution4K.getWidth()),
243 static_cast<uint32_t>(kResolution4K.getHeight())))
244 .WillOnce(Return(NO_ERROR));
245 EXPECT_CALL(*mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
246 EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(hal::Error::NONE));
247
248 // Create a new native surface to be used by the recreated display.
249 mNativeWindowSurface = nullptr;
250 injectFakeNativeWindowSurfaceFactory();
251 PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
252
253 const auto displayToken = mDisplay->getDisplayToken().promote();
254
255 mFlinger.commit();
256
257 // The DisplayDevice will be destroyed and recreated,
258 // so we need to update with the new instance.
259 mDisplay = mFlinger.getDisplay(displayToken);
260
261 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
262 ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90_4K);
263 }
264
TEST_F(DisplayModeSwitchingTest,multiDisplay)265 TEST_F(DisplayModeSwitchingTest, multiDisplay) {
266 constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID;
267 constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1;
268
269 constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u);
270
271 constexpr bool kIsPrimary = false;
272 TestableSurfaceFlinger::FakeHwcDisplayInjector(kOuterDisplayId, hal::DisplayType::PHYSICAL,
273 kIsPrimary)
274 .setHwcDisplayId(kOuterDisplayHwcId)
275 .inject(&mFlinger, mComposer);
276
277 const auto outerDisplay = mFakeDisplayInjector.injectInternalDisplay(
278 [&](FakeDisplayDeviceInjector& injector) {
279 injector.setDisplayModes(mock::cloneForDisplay(kOuterDisplayId, kModes),
280 kModeId120);
281 },
282 {.displayId = kOuterDisplayId,
283 .hwcDisplayId = kOuterDisplayHwcId,
284 .isPrimary = kIsPrimary});
285
286 const auto& innerDisplay = mDisplay;
287
288 EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
289 EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
290
291 EXPECT_EQ(innerDisplay->getActiveMode()->getId(), kModeId60);
292 EXPECT_EQ(outerDisplay->getActiveMode()->getId(), kModeId120);
293
294 mFlinger.onActiveDisplayChanged(innerDisplay);
295
296 EXPECT_EQ(NO_ERROR,
297 mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
298 kModeId90.value(), false, 0.f, 120.f, 0.f,
299 120.f));
300
301 EXPECT_EQ(NO_ERROR,
302 mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
303 kModeId60.value(), false, 0.f, 120.f, 0.f,
304 120.f));
305
306 // Transition on the inner display.
307 ASSERT_TRUE(innerDisplay->getDesiredActiveMode());
308 EXPECT_EQ(innerDisplay->getDesiredActiveMode()->mode->getId(), kModeId90);
309
310 // No transition on the outer display.
311 EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
312
313 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
314 EXPECT_CALL(*mComposer,
315 setActiveConfigWithConstraints(kInnerDisplayHwcId,
316 hal::HWConfigId(kModeId90.value()), _, _))
317 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
318
319 mFlinger.commit();
320
321 // Transition on the inner display.
322 ASSERT_TRUE(innerDisplay->getDesiredActiveMode());
323 EXPECT_EQ(innerDisplay->getDesiredActiveMode()->mode->getId(), kModeId90);
324
325 // No transition on the outer display.
326 EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
327
328 mFlinger.commit();
329
330 // Transition on the inner display.
331 EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
332 EXPECT_EQ(innerDisplay->getActiveMode()->getId(), kModeId90);
333
334 // No transition on the outer display.
335 EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
336 EXPECT_EQ(outerDisplay->getActiveMode()->getId(), kModeId120);
337
338 mFlinger.onActiveDisplayChanged(outerDisplay);
339
340 // No transition on the inner display.
341 EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
342
343 // Transition on the outer display.
344 ASSERT_TRUE(outerDisplay->getDesiredActiveMode());
345 EXPECT_EQ(outerDisplay->getDesiredActiveMode()->mode->getId(), kModeId60);
346
347 EXPECT_CALL(*mComposer,
348 setActiveConfigWithConstraints(kOuterDisplayHwcId,
349 hal::HWConfigId(kModeId60.value()), _, _))
350 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
351
352 mFlinger.commit();
353
354 // No transition on the inner display.
355 EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
356
357 // Transition on the outer display.
358 ASSERT_TRUE(outerDisplay->getDesiredActiveMode());
359 EXPECT_EQ(outerDisplay->getDesiredActiveMode()->mode->getId(), kModeId60);
360
361 mFlinger.commit();
362
363 // No transition on the inner display.
364 EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
365 EXPECT_EQ(innerDisplay->getActiveMode()->getId(), kModeId90);
366
367 // Transition on the outer display.
368 EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
369 EXPECT_EQ(outerDisplay->getActiveMode()->getId(), kModeId60);
370 }
371
372 } // namespace
373 } // namespace android
374