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.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
42 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
43 }
44
TEST_F(FoldableTest,promotesPacesetterOnFoldUnfold)45 TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) {
46 mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
47
48 // The outer display should become the pacesetter after folding.
49 mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
50 mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
51 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
52
53 // The inner display should become the pacesetter after unfolding.
54 mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF);
55 mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
56 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
57 }
58
TEST_F(FoldableTest,promotesPacesetterOnConcurrentPowerOn)59 TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) {
60 mFlinger.setPowerModeInternal(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.setPowerModeInternal(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.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
78 mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
79
80 // The outer display should become the pacesetter if the inner display powers off.
81 mFlinger.setPowerModeInternal(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.setPowerModeInternal(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.setPowerModeInternal(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 setPowerModeInternal.
118 mFlinger.setPowerModeInternal(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 setPowerModeInternal.
137 mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
138 mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
139 mFlinger.setPowerModeInternal(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 setPowerModeInternal.
158 mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
159 mFlinger.setPowerModeInternal(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 SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
171 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
172 .Times(1);
173 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
174 .Times(1);
175
176 mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
177 mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
178 }
179
TEST_F(FoldableTest,disableVsyncOnPowerOffPacesetter)180 TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) {
181 SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
182 // When the device boots, the inner display should be the pacesetter.
183 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
184
185 testing::InSequence seq;
186 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
187 .Times(1);
188 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
189 .Times(1);
190
191 // Turning off the pacesetter will result in disabling VSYNC.
192 EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, false))
193 .Times(1);
194
195 mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
196 mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
197
198 mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
199
200 // Other display is now the pacesetter.
201 ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
202 }
203
204 } // namespace
205 } // namespace android
206