1 /*
2 * Copyright 2023 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 <com_android_graphics_surfaceflinger_flags.h>
21 #include <common/test/FlagUtils.h>
22 #include "DualDisplayTransactionTest.h"
23
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26
27 using namespace com::android::graphics::surfaceflinger;
28
29 namespace android {
30 namespace {
31
32 constexpr bool kExpectSetPowerModeOnce = false;
33 struct FoldableTest : DualDisplayTransactionTest<hal::PowerMode::OFF, hal::PowerMode::OFF,
34 kExpectSetPowerModeOnce> {};
35
TEST_F(FoldableTest,promotesPacesetterOnBoot)36 TEST_F(FoldableTest, promotesPacesetterOnBoot) {
37 // When the device boots, the inner display should be the pacesetter.
38 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
39
40 // ...and should still be after powering on.
41 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
42 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
43 }
44
TEST_F(FoldableTest,promotesPacesetterOnFoldUnfold)45 TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) {
46 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
47
48 // The outer display should become the pacesetter after folding.
49 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
50 mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
51 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
52
53 // The inner display should become the pacesetter after unfolding.
54 mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF);
55 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
56 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
57 }
58
TEST_F(FoldableTest,promotesPacesetterOnConcurrentPowerOn)59 TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) {
60 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
61
62 // The inner display should stay the pacesetter if both are powered on.
63 // TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
64 mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
65 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
66
67 // The outer display should become the pacesetter if designated.
68 mFlinger.scheduler()->setPacesetterDisplay(kOuterDisplayId);
69 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
70
71 // The inner display should become the pacesetter if designated.
72 mFlinger.scheduler()->setPacesetterDisplay(kInnerDisplayId);
73 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
74 }
75
TEST_F(FoldableTest,promotesPacesetterOnConcurrentPowerOff)76 TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOff) {
77 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
78 mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
79
80 // The outer display should become the pacesetter if the inner display powers off.
81 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
82 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
83
84 // The outer display should stay the pacesetter if both are powered on.
85 // TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
86 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
87 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
88
89 // The inner display should become the pacesetter if the outer display powers off.
90 mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF);
91 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
92 }
93
TEST_F(FoldableTest,doesNotRequestHardwareVsyncIfPoweredOff)94 TEST_F(FoldableTest, doesNotRequestHardwareVsyncIfPoweredOff) {
95 // Both displays are powered off.
96 EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, _))
97 .Times(0);
98 EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, _))
99 .Times(0);
100
101 EXPECT_FALSE(mInnerDisplay->isPoweredOn());
102 EXPECT_FALSE(mOuterDisplay->isPoweredOn());
103
104 auto& scheduler = *mFlinger.scheduler();
105 scheduler.onHardwareVsyncRequest(kInnerDisplayId, true);
106 scheduler.onHardwareVsyncRequest(kOuterDisplayId, true);
107 }
108
TEST_F(FoldableTest,requestsHardwareVsyncForInnerDisplay)109 TEST_F(FoldableTest, requestsHardwareVsyncForInnerDisplay) {
110 // Only inner display is powered on.
111 EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, true))
112 .Times(1);
113 EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, _))
114 .Times(0);
115
116 // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
117 // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode.
118 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
119
120 EXPECT_TRUE(mInnerDisplay->isPoweredOn());
121 EXPECT_FALSE(mOuterDisplay->isPoweredOn());
122
123 auto& scheduler = *mFlinger.scheduler();
124 scheduler.onHardwareVsyncRequest(kInnerDisplayId, true);
125 scheduler.onHardwareVsyncRequest(kOuterDisplayId, true);
126 }
127
TEST_F(FoldableTest,requestsHardwareVsyncForOuterDisplay)128 TEST_F(FoldableTest, requestsHardwareVsyncForOuterDisplay) {
129 // Only outer display is powered on.
130 EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, _))
131 .Times(0);
132 EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, true))
133 .Times(1);
134
135 // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
136 // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode.
137 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
138 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
139 mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
140
141 EXPECT_FALSE(mInnerDisplay->isPoweredOn());
142 EXPECT_TRUE(mOuterDisplay->isPoweredOn());
143
144 auto& scheduler = *mFlinger.scheduler();
145 scheduler.onHardwareVsyncRequest(kInnerDisplayId, true);
146 scheduler.onHardwareVsyncRequest(kOuterDisplayId, true);
147 }
148
TEST_F(FoldableTest,requestsHardwareVsyncForBothDisplays)149 TEST_F(FoldableTest, requestsHardwareVsyncForBothDisplays) {
150 // Both displays are powered on.
151 EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, true))
152 .Times(1);
153 EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, true))
154 .Times(1);
155
156 // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
157 // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode.
158 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
159 mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
160
161 EXPECT_TRUE(mInnerDisplay->isPoweredOn());
162 EXPECT_TRUE(mOuterDisplay->isPoweredOn());
163
164 auto& scheduler = *mFlinger.scheduler();
165 scheduler.onHardwareVsyncRequest(mInnerDisplay->getPhysicalId(), true);
166 scheduler.onHardwareVsyncRequest(mOuterDisplay->getPhysicalId(), true);
167 }
168
TEST_F(FoldableTest,requestVsyncOnPowerOn)169 TEST_F(FoldableTest, requestVsyncOnPowerOn) {
170 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
171 .Times(1);
172 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
173 .Times(1);
174
175 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
176 mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
177 }
178
TEST_F(FoldableTest,disableVsyncOnPowerOffPacesetter)179 TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) {
180 // When the device boots, the inner display should be the pacesetter.
181 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
182
183 testing::InSequence seq;
184 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
185 .Times(1);
186 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
187 .Times(1);
188
189 // Turning off the pacesetter will result in disabling VSYNC.
190 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, false))
191 .Times(1);
192
193 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
194 mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
195
196 mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
197
198 // Other display is now the pacesetter.
199 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
200 }
201
202 } // namespace
203 } // namespace android
204