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