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 #include "mock/MockDisplayModeSpecs.h"
23
24 #include <com_android_graphics_surfaceflinger_flags.h>
25 #include <common/test/FlagUtils.h>
26 #include <ftl/fake_guard.h>
27 #include <scheduler/Fps.h>
28
29 using namespace com::android::graphics::surfaceflinger;
30
31 #define EXPECT_SET_ACTIVE_CONFIG(displayId, modeId) \
32 EXPECT_CALL(*mComposer, \
33 setActiveConfigWithConstraints(displayId, \
34 static_cast<hal::HWConfigId>( \
35 ftl::to_underlying(modeId)), \
36 _, _)) \
37 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)))
38
39 namespace android {
40 namespace {
41
42 using android::hardware::graphics::composer::V2_4::Error;
43 using android::hardware::graphics::composer::V2_4::VsyncPeriodChangeTimeline;
44
45 class DisplayModeSwitchingTest : public DisplayTransactionTest {
46 public:
SetUp()47 void SetUp() override {
48 injectFakeBufferQueueFactory();
49 injectFakeNativeWindowSurfaceFactory();
50
51 PrimaryDisplayVariant::setupHwcHotplugCallExpectations(this);
52 PrimaryDisplayVariant::setupFramebufferConsumerBufferQueueCallExpectations(this);
53 PrimaryDisplayVariant::setupFramebufferProducerBufferQueueCallExpectations(this);
54 PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
55 PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this);
56
57 auto selectorPtr = std::make_shared<scheduler::RefreshRateSelector>(kModes, kModeId60);
58
59 setupScheduler(selectorPtr);
60
61 mFlinger.onComposerHalHotplugEvent(PrimaryDisplayVariant::HWC_DISPLAY_ID,
62 DisplayHotplugEvent::CONNECTED);
63 mFlinger.configureAndCommit();
64
65 auto vsyncController = std::make_unique<mock::VsyncController>();
66 auto vsyncTracker = std::make_shared<mock::VSyncTracker>();
67
68 EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0));
69 EXPECT_CALL(*vsyncTracker, currentPeriod())
70 .WillRepeatedly(Return(
71 TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
72 EXPECT_CALL(*vsyncTracker, minFramePeriod())
73 .WillRepeatedly(Return(Period::fromNs(
74 TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)));
75
76 mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
77 .setRefreshRateSelector(std::move(selectorPtr))
78 .inject(std::move(vsyncController), std::move(vsyncTracker));
79 mDisplayId = mDisplay->getPhysicalId();
80
81 // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy
82 // will call setActiveConfig instead of setActiveConfigWithConstraints.
83 ON_CALL(*mComposer, isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching))
84 .WillByDefault(Return(true));
85 }
86
87 static constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID;
88 static constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1;
89
injectOuterDisplay()90 auto injectOuterDisplay() {
91 constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u);
92
93 constexpr bool kIsPrimary = false;
94 TestableSurfaceFlinger::FakeHwcDisplayInjector(kOuterDisplayId, hal::DisplayType::PHYSICAL,
95 kIsPrimary)
96 .setHwcDisplayId(kOuterDisplayHwcId)
97 .setPowerMode(hal::PowerMode::OFF)
98 .inject(&mFlinger, mComposer);
99
100 mOuterDisplay = mFakeDisplayInjector.injectInternalDisplay(
101 [&](FakeDisplayDeviceInjector& injector) {
102 injector.setPowerMode(hal::PowerMode::OFF);
103 injector.setDisplayModes(mock::cloneForDisplay(kOuterDisplayId, kModes),
104 kModeId120);
105 },
106 {.displayId = kOuterDisplayId,
107 .hwcDisplayId = kOuterDisplayHwcId,
108 .isPrimary = kIsPrimary});
109
110 return std::forward_as_tuple(mDisplay, mOuterDisplay);
111 }
112
113 protected:
114 void setupScheduler(std::shared_ptr<scheduler::RefreshRateSelector>);
115
dmc()116 auto& dmc() { return mFlinger.mutableDisplayModeController(); }
117
118 sp<DisplayDevice> mDisplay, mOuterDisplay;
119 PhysicalDisplayId mDisplayId;
120
121 mock::EventThread* mAppEventThread;
122
123 static constexpr DisplayModeId kModeId60{0};
124 static constexpr DisplayModeId kModeId90{1};
125 static constexpr DisplayModeId kModeId120{2};
126 static constexpr DisplayModeId kModeId90_4K{3};
127
128 static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz, 0);
129 static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz, 1);
130 static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz, 2);
131
132 static constexpr ui::Size kResolution4K{3840, 2160};
133 static inline const DisplayModePtr kMode90_4K =
134 createDisplayMode(kModeId90_4K, 90_Hz, 3, kResolution4K);
135
136 static inline const DisplayModes kModes = makeModes(kMode60, kMode90, kMode120, kMode90_4K);
137 };
138
setupScheduler(std::shared_ptr<scheduler::RefreshRateSelector> selectorPtr)139 void DisplayModeSwitchingTest::setupScheduler(
140 std::shared_ptr<scheduler::RefreshRateSelector> selectorPtr) {
141 auto eventThread = std::make_unique<mock::EventThread>();
142 mAppEventThread = eventThread.get();
143 auto sfEventThread = std::make_unique<mock::EventThread>();
144
145 EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
146 EXPECT_CALL(*eventThread, createEventConnection(_, _))
147 .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
148 mock::EventThread::kCallingUid)));
149
150 EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
151 EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
152 .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
153 mock::EventThread::kCallingUid)));
154
155 auto vsyncController = std::make_unique<mock::VsyncController>();
156 auto vsyncTracker = std::make_shared<mock::VSyncTracker>();
157
158 EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0));
159 EXPECT_CALL(*vsyncTracker, currentPeriod())
160 .WillRepeatedly(
161 Return(TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
162 EXPECT_CALL(*vsyncTracker, minFramePeriod())
163 .WillRepeatedly(Return(Period::fromNs(
164 TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)));
165 EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0));
166 mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
167 std::move(eventThread), std::move(sfEventThread),
168 std::move(selectorPtr),
169 TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp);
170 }
171
TEST_F(DisplayModeSwitchingTest,changeRefreshRateOnActiveDisplayWithRefreshRequired)172 TEST_F(DisplayModeSwitchingTest, changeRefreshRateOnActiveDisplayWithRefreshRequired) {
173 ftl::FakeGuard guard(kMainThreadContext);
174
175 EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
176 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
177
178 mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
179
180 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
181 mock::createDisplayModeSpecs(kModeId90, false, 0, 120));
182
183 ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
184 EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId90);
185 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
186
187 // Verify that next commit will call setActiveConfigWithConstraints in HWC
188 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
189 EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId90);
190
191 mFlinger.commit();
192
193 Mock::VerifyAndClearExpectations(mComposer);
194
195 EXPECT_TRUE(dmc().getDesiredMode(mDisplayId));
196 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
197
198 // Verify that the next commit will complete the mode change and send
199 // a onModeChanged event to the framework.
200
201 EXPECT_CALL(*mAppEventThread,
202 onModeChanged(scheduler::FrameRateMode{90_Hz, ftl::as_non_null(kMode90)}));
203 mFlinger.commit();
204 Mock::VerifyAndClearExpectations(mAppEventThread);
205
206 EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
207 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId90);
208 }
209
TEST_F(DisplayModeSwitchingTest,changeRefreshRateOnActiveDisplayWithoutRefreshRequired)210 TEST_F(DisplayModeSwitchingTest, changeRefreshRateOnActiveDisplayWithoutRefreshRequired) {
211 ftl::FakeGuard guard(kMainThreadContext);
212
213 EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
214
215 mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
216
217 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
218 mock::createDisplayModeSpecs(kModeId90, true, 0, 120));
219
220 ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
221 EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId90);
222 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
223
224 // Verify that next commit will call setActiveConfigWithConstraints in HWC
225 // and complete the mode change.
226 const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
227 EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId90);
228
229 EXPECT_CALL(*mAppEventThread,
230 onModeChanged(scheduler::FrameRateMode{90_Hz, ftl::as_non_null(kMode90)}));
231
232 mFlinger.commit();
233
234 EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
235 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId90);
236 }
237
TEST_F(DisplayModeSwitchingTest,twoConsecutiveSetDesiredDisplayModeSpecs)238 TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) {
239 ftl::FakeGuard guard(kMainThreadContext);
240
241 // Test that if we call setDesiredDisplayModeSpecs while a previous mode change
242 // is still being processed the later call will be respected.
243
244 EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
245 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
246
247 mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
248
249 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
250 mock::createDisplayModeSpecs(kModeId90, false, 0, 120));
251
252 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
253 EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId90);
254
255 mFlinger.commit();
256
257 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
258 mock::createDisplayModeSpecs(kModeId120, false, 0, 180));
259
260 ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
261 EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId120);
262
263 EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId120);
264
265 mFlinger.commit();
266
267 ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
268 EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId120);
269
270 mFlinger.commit();
271
272 EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
273 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId120);
274 }
275
TEST_F(DisplayModeSwitchingTest,changeResolutionOnActiveDisplayWithoutRefreshRequired)276 TEST_F(DisplayModeSwitchingTest, changeResolutionOnActiveDisplayWithoutRefreshRequired) {
277 ftl::FakeGuard guard(kMainThreadContext);
278
279 EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
280 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
281
282 mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
283
284 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
285 mock::createDisplayModeSpecs(kModeId90_4K, false, 0, 120));
286
287 ASSERT_TRUE(dmc().getDesiredMode(mDisplayId));
288 EXPECT_EQ(dmc().getDesiredMode(mDisplayId)->mode.modePtr->getId(), kModeId90_4K);
289 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId60);
290
291 // Verify that next commit will call setActiveConfigWithConstraints in HWC
292 // and complete the mode change.
293 const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
294 EXPECT_SET_ACTIVE_CONFIG(PrimaryDisplayVariant::HWC_DISPLAY_ID, kModeId90_4K);
295
296 EXPECT_CALL(*mAppEventThread, onHotplugReceived(mDisplayId, true));
297
298 // Override expectations set up by PrimaryDisplayVariant.
299 EXPECT_CALL(*mConsumer,
300 setDefaultBufferSize(static_cast<uint32_t>(kResolution4K.getWidth()),
301 static_cast<uint32_t>(kResolution4K.getHeight())))
302 .WillOnce(Return(NO_ERROR));
303 EXPECT_CALL(*mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
304 EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(hal::Error::NONE));
305
306 // Create a new native surface to be used by the recreated display.
307 mNativeWindowSurface = nullptr;
308 injectFakeNativeWindowSurfaceFactory();
309 PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
310
311 mFlinger.commit();
312
313 EXPECT_FALSE(dmc().getDesiredMode(mDisplayId));
314 EXPECT_EQ(dmc().getActiveMode(mDisplayId).modePtr->getId(), kModeId90_4K);
315 }
316
317 MATCHER_P2(ModeSwitchingTo, flinger, modeId, "") {
318 const auto displayId = arg->getPhysicalId();
319 auto& dmc = flinger->mutableDisplayModeController();
320
321 if (!dmc.getDesiredMode(displayId)) {
322 *result_listener << "No desired mode";
323 return false;
324 }
325
326 if (dmc.getDesiredMode(displayId)->mode.modePtr->getId() != modeId) {
327 *result_listener << "Unexpected desired mode " << ftl::to_underlying(modeId);
328 return false;
329 }
330
331 // VsyncModulator should react to mode switches on the pacesetter display.
332 if (displayId == flinger->scheduler()->pacesetterDisplayId() &&
333 !flinger->scheduler()->vsyncModulator().isVsyncConfigEarly()) {
334 *result_listener << "VsyncModulator did not shift to early phase";
335 return false;
336 }
337
338 return true;
339 }
340
341 MATCHER_P2(ModeSettledTo, dmc, modeId, "") {
342 const auto displayId = arg->getPhysicalId();
343
344 if (const auto desiredOpt = dmc->getDesiredMode(displayId)) {
345 *result_listener << "Unsettled desired mode "
346 << ftl::to_underlying(desiredOpt->mode.modePtr->getId());
347 return false;
348 }
349
350 ftl::FakeGuard guard(kMainThreadContext);
351
352 if (dmc->getActiveMode(displayId).modePtr->getId() != modeId) {
353 *result_listener << "Settled to unexpected active mode " << ftl::to_underlying(modeId);
354 return false;
355 }
356
357 return true;
358 }
359
TEST_F(DisplayModeSwitchingTest,innerXorOuterDisplay)360 TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
361 SET_FLAG_FOR_TEST(flags::connected_display, true);
362
363 // For the inner display, this is handled by setupHwcHotplugCallExpectations.
364 EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
365 .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
366 Return(hal::V2_4::Error::NONE)));
367
368 const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
369
370 EXPECT_TRUE(innerDisplay->isPoweredOn());
371 EXPECT_FALSE(outerDisplay->isPoweredOn());
372
373 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
374 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
375
376 mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::OFF);
377 mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON);
378
379 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
380 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
381
382 EXPECT_EQ(NO_ERROR,
383 mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
384 mock::createDisplayModeSpecs(kModeId90, false,
385 0.f, 120.f)));
386
387 EXPECT_EQ(NO_ERROR,
388 mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
389 mock::createDisplayModeSpecs(kModeId60, false,
390 0.f, 120.f)));
391
392 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
393 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
394
395 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
396 EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);
397 EXPECT_SET_ACTIVE_CONFIG(kOuterDisplayHwcId, kModeId60);
398
399 mFlinger.commit();
400
401 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
402 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
403
404 mFlinger.commit();
405
406 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
407 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
408
409 mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::OFF);
410 mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
411
412 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
413 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
414
415 EXPECT_EQ(NO_ERROR,
416 mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
417 mock::createDisplayModeSpecs(kModeId60, false,
418 0.f, 120.f)));
419
420 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
421 EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId60);
422
423 mFlinger.commit();
424
425 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
426 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
427
428 mFlinger.commit();
429
430 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
431 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
432 }
433
TEST_F(DisplayModeSwitchingTest,innerAndOuterDisplay)434 TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) {
435 SET_FLAG_FOR_TEST(flags::connected_display, true);
436
437 // For the inner display, this is handled by setupHwcHotplugCallExpectations.
438 EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
439 .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
440 Return(hal::V2_4::Error::NONE)));
441 const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
442
443 EXPECT_TRUE(innerDisplay->isPoweredOn());
444 EXPECT_FALSE(outerDisplay->isPoweredOn());
445
446 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
447 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
448
449 mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON);
450 mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
451
452 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
453 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
454
455 EXPECT_EQ(NO_ERROR,
456 mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
457 mock::createDisplayModeSpecs(kModeId90, false,
458 0.f, 120.f)));
459
460 EXPECT_EQ(NO_ERROR,
461 mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
462 mock::createDisplayModeSpecs(kModeId60, false,
463 0.f, 120.f)));
464
465 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
466 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
467
468 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
469 EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);
470 EXPECT_SET_ACTIVE_CONFIG(kOuterDisplayHwcId, kModeId60);
471
472 mFlinger.commit();
473
474 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
475 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
476
477 mFlinger.commit();
478
479 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
480 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
481 }
482
TEST_F(DisplayModeSwitchingTest,powerOffDuringModeSet)483 TEST_F(DisplayModeSwitchingTest, powerOffDuringModeSet) {
484 EXPECT_TRUE(mDisplay->isPoweredOn());
485 EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60));
486
487 EXPECT_EQ(NO_ERROR,
488 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
489 mock::createDisplayModeSpecs(kModeId90, false,
490 0.f, 120.f)));
491
492 EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
493
494 // Power off the display before the mode has been set.
495 mFlinger.setPowerModeInternal(mDisplay, hal::PowerMode::OFF);
496
497 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
498 EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);
499
500 mFlinger.commit();
501
502 // Powering off should not abort the mode set.
503 EXPECT_FALSE(mDisplay->isPoweredOn());
504 EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
505
506 mFlinger.commit();
507
508 EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId90));
509 }
510
TEST_F(DisplayModeSwitchingTest,powerOffDuringConcurrentModeSet)511 TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) {
512 SET_FLAG_FOR_TEST(flags::connected_display, true);
513
514 // For the inner display, this is handled by setupHwcHotplugCallExpectations.
515 EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
516 .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
517 Return(hal::V2_4::Error::NONE)));
518
519 const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
520
521 EXPECT_TRUE(innerDisplay->isPoweredOn());
522 EXPECT_FALSE(outerDisplay->isPoweredOn());
523
524 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
525 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
526
527 mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON);
528 mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
529
530 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
531 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
532
533 EXPECT_EQ(NO_ERROR,
534 mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
535 mock::createDisplayModeSpecs(kModeId90, false,
536 0.f, 120.f)));
537
538 EXPECT_EQ(NO_ERROR,
539 mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
540 mock::createDisplayModeSpecs(kModeId60, false,
541 0.f, 120.f)));
542
543 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
544 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
545
546 // Power off the outer display before the mode has been set.
547 mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::OFF);
548
549 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
550 EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);
551 EXPECT_SET_ACTIVE_CONFIG(kOuterDisplayHwcId, kModeId60);
552
553 mFlinger.commit();
554
555 // Powering off the inactive display should not abort the mode set.
556 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
557 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
558
559 mFlinger.commit();
560
561 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
562 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
563
564 mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::OFF);
565 mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
566
567 EXPECT_EQ(NO_ERROR,
568 mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
569 mock::createDisplayModeSpecs(kModeId120, false,
570 0.f, 120.f)));
571
572 EXPECT_SET_ACTIVE_CONFIG(kOuterDisplayHwcId, kModeId120);
573
574 mFlinger.commit();
575
576 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
577 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId120));
578
579 mFlinger.commit();
580
581 EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
582 EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
583 }
584
585 } // namespace
586 } // namespace android
587