• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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