1 /*
2  * Copyright 2024 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 "Display/DisplayModeController.h"
21 #include "Display/DisplaySnapshot.h"
22 #include "DisplayHardware/HWComposer.h"
23 #include "DisplayIdentificationTestHelpers.h"
24 #include "FpsOps.h"
25 #include "mock/DisplayHardware/MockComposer.h"
26 #include "mock/DisplayHardware/MockDisplayMode.h"
27 #include "mock/MockFrameRateMode.h"
28 
29 #include <ftl/fake_guard.h>
30 #include <gmock/gmock.h>
31 #include <gtest/gtest.h>
32 
33 #define EXPECT_DISPLAY_MODE_REQUEST(expected, requestOpt)                               \
34     ASSERT_TRUE(requestOpt);                                                            \
35     EXPECT_FRAME_RATE_MODE(expected.mode.modePtr, expected.mode.fps, requestOpt->mode); \
36     EXPECT_EQ(expected.emitEvent, requestOpt->emitEvent)
37 
38 namespace android::display {
39 namespace {
40 
41 namespace hal = android::hardware::graphics::composer::hal;
42 
43 using testing::_;
44 using testing::DoAll;
45 using testing::Return;
46 using testing::SetArgPointee;
47 
48 class DisplayModeControllerTest : public testing::Test {
49 public:
50     using Action = DisplayModeController::DesiredModeAction;
51 
SetUp()52     void SetUp() override {
53         mDmc.setHwComposer(mComposer.get());
54         mDmc.setActiveModeListener(
55                 [this](PhysicalDisplayId displayId, Fps vsyncRate, Fps renderFps) {
56                     mActiveModeListener.Call(displayId, vsyncRate, renderFps);
57                 });
58 
59         constexpr uint8_t kPort = 111;
60         EXPECT_CALL(*mComposerHal, getDisplayIdentificationData(kHwcDisplayId, _, _))
61                 .WillOnce(DoAll(SetArgPointee<1>(kPort), SetArgPointee<2>(getInternalEdid()),
62                                 Return(hal::Error::NONE)));
63 
64         EXPECT_CALL(*mComposerHal, setClientTargetSlotCount(kHwcDisplayId));
65         EXPECT_CALL(*mComposerHal,
66                     setVsyncEnabled(kHwcDisplayId, hal::IComposerClient::Vsync::DISABLE));
67         EXPECT_CALL(*mComposerHal, onHotplugConnect(kHwcDisplayId));
68 
69         const auto infoOpt = mComposer->onHotplug(kHwcDisplayId, hal::Connection::CONNECTED);
70         ASSERT_TRUE(infoOpt);
71 
72         mDisplayId = infoOpt->id;
73         mDisplaySnapshotOpt.emplace(mDisplayId, ui::DisplayConnectionType::Internal,
74                                     makeModes(kMode60, kMode90, kMode120), ui::ColorModes{},
75                                     std::nullopt);
76 
77         ftl::FakeGuard guard(kMainThreadContext);
78         mDmc.registerDisplay(*mDisplaySnapshotOpt, kModeId60,
79                              scheduler::RefreshRateSelector::Config{});
80     }
81 
82 protected:
expectModeSet(const DisplayModeRequest & request,hal::VsyncPeriodChangeTimeline & timeline,bool subsequent=false)83     hal::VsyncPeriodChangeConstraints expectModeSet(const DisplayModeRequest& request,
84                                                     hal::VsyncPeriodChangeTimeline& timeline,
85                                                     bool subsequent = false) {
86         EXPECT_CALL(*mComposerHal,
87                     isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching))
88                 .WillOnce(Return(true));
89 
90         if (!subsequent) {
91             EXPECT_CALL(*mComposerHal, getDisplayConnectionType(kHwcDisplayId, _))
92                     .WillOnce(DoAll(SetArgPointee<1>(
93                                             hal::IComposerClient::DisplayConnectionType::INTERNAL),
94                                     Return(hal::V2_4::Error::NONE)));
95         }
96 
97         const hal::VsyncPeriodChangeConstraints constraints{
98                 .desiredTimeNanos = systemTime(),
99                 .seamlessRequired = false,
100         };
101 
102         const hal::HWConfigId hwcModeId = request.mode.modePtr->getHwcId();
103 
104         EXPECT_CALL(*mComposerHal,
105                     setActiveConfigWithConstraints(kHwcDisplayId, hwcModeId, constraints, _))
106                 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(hal::V2_4::Error::NONE)));
107 
108         return constraints;
109     }
110 
111     static constexpr hal::HWDisplayId kHwcDisplayId = 1234;
112 
113     Hwc2::mock::Composer* mComposerHal = new testing::StrictMock<Hwc2::mock::Composer>();
114     const std::unique_ptr<HWComposer> mComposer{
115             std::make_unique<impl::HWComposer>(std::unique_ptr<Hwc2::Composer>(mComposerHal))};
116 
117     testing::MockFunction<void(PhysicalDisplayId, Fps, Fps)> mActiveModeListener;
118 
119     DisplayModeController mDmc;
120 
121     PhysicalDisplayId mDisplayId;
122     std::optional<DisplaySnapshot> mDisplaySnapshotOpt;
123 
124     static constexpr DisplayModeId kModeId60{0};
125     static constexpr DisplayModeId kModeId90{1};
126     static constexpr DisplayModeId kModeId120{2};
127 
128     static inline const ftl::NonNull<DisplayModePtr> kMode60 =
129             ftl::as_non_null(mock::createDisplayMode(kModeId60, 60_Hz));
130     static inline const ftl::NonNull<DisplayModePtr> kMode90 =
131             ftl::as_non_null(mock::createDisplayMode(kModeId90, 90_Hz));
132     static inline const ftl::NonNull<DisplayModePtr> kMode120 =
133             ftl::as_non_null(mock::createDisplayMode(kModeId120, 120_Hz));
134 
135     static inline const DisplayModeRequest kDesiredMode30{{30_Hz, kMode60}, .emitEvent = false};
136     static inline const DisplayModeRequest kDesiredMode60{{60_Hz, kMode60}, .emitEvent = true};
137     static inline const DisplayModeRequest kDesiredMode90{{90_Hz, kMode90}, .emitEvent = false};
138     static inline const DisplayModeRequest kDesiredMode120{{120_Hz, kMode120}, .emitEvent = true};
139 };
140 
TEST_F(DisplayModeControllerTest,setDesiredModeToActiveMode)141 TEST_F(DisplayModeControllerTest, setDesiredModeToActiveMode) {
142     EXPECT_CALL(mActiveModeListener, Call(_, _, _)).Times(0);
143 
144     EXPECT_EQ(Action::None, mDmc.setDesiredMode(mDisplayId, DisplayModeRequest(kDesiredMode60)));
145     EXPECT_FALSE(mDmc.getDesiredMode(mDisplayId));
146 }
147 
TEST_F(DisplayModeControllerTest,setDesiredMode)148 TEST_F(DisplayModeControllerTest, setDesiredMode) {
149     // Called because setDesiredMode resets the render rate to the active refresh rate.
150     EXPECT_CALL(mActiveModeListener, Call(mDisplayId, 60_Hz, 60_Hz)).Times(1);
151 
152     EXPECT_EQ(Action::InitiateDisplayModeSwitch,
153               mDmc.setDesiredMode(mDisplayId, DisplayModeRequest(kDesiredMode90)));
154     EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDmc.getDesiredMode(mDisplayId));
155 
156     // No action since a mode switch has already been initiated.
157     EXPECT_EQ(Action::None, mDmc.setDesiredMode(mDisplayId, DisplayModeRequest(kDesiredMode120)));
158     EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDmc.getDesiredMode(mDisplayId));
159 }
160 
TEST_F(DisplayModeControllerTest,clearDesiredMode)161 TEST_F(DisplayModeControllerTest, clearDesiredMode) {
162     // Called because setDesiredMode resets the render rate to the active refresh rate.
163     EXPECT_CALL(mActiveModeListener, Call(mDisplayId, 60_Hz, 60_Hz)).Times(1);
164 
165     EXPECT_EQ(Action::InitiateDisplayModeSwitch,
166               mDmc.setDesiredMode(mDisplayId, DisplayModeRequest(kDesiredMode90)));
167     EXPECT_TRUE(mDmc.getDesiredMode(mDisplayId));
168 
169     mDmc.clearDesiredMode(mDisplayId);
170     EXPECT_FALSE(mDmc.getDesiredMode(mDisplayId));
171 }
172 
TEST_F(DisplayModeControllerTest,initiateModeChange)173 TEST_F(DisplayModeControllerTest, initiateModeChange) REQUIRES(kMainThreadContext) {
174     // Called because setDesiredMode resets the render rate to the active refresh rate.
175     EXPECT_CALL(mActiveModeListener, Call(mDisplayId, 60_Hz, 60_Hz)).Times(1);
176 
177     EXPECT_EQ(Action::InitiateDisplayModeSwitch,
178               mDmc.setDesiredMode(mDisplayId, DisplayModeRequest(kDesiredMode90)));
179 
180     EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDmc.getDesiredMode(mDisplayId));
181     auto modeRequest = kDesiredMode90;
182 
183     hal::VsyncPeriodChangeTimeline timeline;
184     const auto constraints = expectModeSet(modeRequest, timeline);
185 
186     EXPECT_TRUE(mDmc.initiateModeChange(mDisplayId, std::move(modeRequest), constraints, timeline));
187     EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDmc.getPendingMode(mDisplayId));
188 
189     mDmc.clearDesiredMode(mDisplayId);
190     EXPECT_FALSE(mDmc.getDesiredMode(mDisplayId));
191 }
192 
TEST_F(DisplayModeControllerTest,initiateRenderRateSwitch)193 TEST_F(DisplayModeControllerTest, initiateRenderRateSwitch) {
194     EXPECT_CALL(mActiveModeListener, Call(mDisplayId, 60_Hz, 30_Hz)).Times(1);
195 
196     EXPECT_EQ(Action::InitiateRenderRateSwitch,
197               mDmc.setDesiredMode(mDisplayId, DisplayModeRequest(kDesiredMode30)));
198     EXPECT_FALSE(mDmc.getDesiredMode(mDisplayId));
199 }
200 
TEST_F(DisplayModeControllerTest,initiateDisplayModeSwitch)201 TEST_F(DisplayModeControllerTest, initiateDisplayModeSwitch) FTL_FAKE_GUARD(kMainThreadContext) {
202     // Called because setDesiredMode resets the render rate to the active refresh rate.
203     EXPECT_CALL(mActiveModeListener, Call(mDisplayId, 60_Hz, 60_Hz)).Times(1);
204 
205     EXPECT_EQ(Action::InitiateDisplayModeSwitch,
206               mDmc.setDesiredMode(mDisplayId, DisplayModeRequest(kDesiredMode90)));
207     EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDmc.getDesiredMode(mDisplayId));
208     auto modeRequest = kDesiredMode90;
209 
210     hal::VsyncPeriodChangeTimeline timeline;
211     auto constraints = expectModeSet(modeRequest, timeline);
212 
213     EXPECT_TRUE(mDmc.initiateModeChange(mDisplayId, std::move(modeRequest), constraints, timeline));
214     EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDmc.getPendingMode(mDisplayId));
215 
216     // No action since a mode switch has already been initiated.
217     EXPECT_EQ(Action::None, mDmc.setDesiredMode(mDisplayId, DisplayModeRequest(kDesiredMode120)));
218 
219     EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDmc.getPendingMode(mDisplayId));
220     EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDmc.getDesiredMode(mDisplayId));
221     modeRequest = kDesiredMode120;
222 
223     constexpr bool kSubsequent = true;
224     constraints = expectModeSet(modeRequest, timeline, kSubsequent);
225 
226     EXPECT_TRUE(mDmc.initiateModeChange(mDisplayId, std::move(modeRequest), constraints, timeline));
227     EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDmc.getPendingMode(mDisplayId));
228 
229     mDmc.clearDesiredMode(mDisplayId);
230     EXPECT_FALSE(mDmc.getDesiredMode(mDisplayId));
231 }
232 
233 } // namespace
234 } // namespace android::display
235