/* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" #include #include #include "DualDisplayTransactionTest.h" #include #include using namespace com::android::graphics::surfaceflinger; namespace android { namespace { constexpr bool kExpectSetPowerModeOnce = false; struct FoldableTest : DualDisplayTransactionTest {}; TEST_F(FoldableTest, promotesPacesetterOnBoot) { // When the device boots, the inner display should be the pacesetter. ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); // ...and should still be after powering on. mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) { mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); // The outer display should become the pacesetter after folding. mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF); mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); // The inner display should become the pacesetter after unfolding. mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF); mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) { mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); // The inner display should stay the pacesetter if both are powered on. // TODO(b/255635821): The pacesetter should depend on the displays' refresh rates. mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); // The outer display should become the pacesetter if designated. mFlinger.scheduler()->setPacesetterDisplay(kOuterDisplayId); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); // The inner display should become the pacesetter if designated. mFlinger.scheduler()->setPacesetterDisplay(kInnerDisplayId); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOff) { mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); // The outer display should become the pacesetter if the inner display powers off. mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); // The outer display should stay the pacesetter if both are powered on. // TODO(b/255635821): The pacesetter should depend on the displays' refresh rates. mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); // The inner display should become the pacesetter if the outer display powers off. mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, doesNotRequestHardwareVsyncIfPoweredOff) { // Both displays are powered off. EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, _)) .Times(0); EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, _)) .Times(0); EXPECT_FALSE(mInnerDisplay->isPoweredOn()); EXPECT_FALSE(mOuterDisplay->isPoweredOn()); auto& scheduler = *mFlinger.scheduler(); scheduler.onHardwareVsyncRequest(kInnerDisplayId, true); scheduler.onHardwareVsyncRequest(kOuterDisplayId, true); } TEST_F(FoldableTest, requestsHardwareVsyncForInnerDisplay) { // Only inner display is powered on. EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, true)) .Times(1); EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, _)) .Times(0); // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode. mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); EXPECT_TRUE(mInnerDisplay->isPoweredOn()); EXPECT_FALSE(mOuterDisplay->isPoweredOn()); auto& scheduler = *mFlinger.scheduler(); scheduler.onHardwareVsyncRequest(kInnerDisplayId, true); scheduler.onHardwareVsyncRequest(kOuterDisplayId, true); } TEST_F(FoldableTest, requestsHardwareVsyncForOuterDisplay) { // Only outer display is powered on. EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, _)) .Times(0); EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, true)) .Times(1); // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode. mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF); mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); EXPECT_FALSE(mInnerDisplay->isPoweredOn()); EXPECT_TRUE(mOuterDisplay->isPoweredOn()); auto& scheduler = *mFlinger.scheduler(); scheduler.onHardwareVsyncRequest(kInnerDisplayId, true); scheduler.onHardwareVsyncRequest(kOuterDisplayId, true); } TEST_F(FoldableTest, requestsHardwareVsyncForBothDisplays) { // Both displays are powered on. EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, true)) .Times(1); EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, true)) .Times(1); // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode. mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); EXPECT_TRUE(mInnerDisplay->isPoweredOn()); EXPECT_TRUE(mOuterDisplay->isPoweredOn()); auto& scheduler = *mFlinger.scheduler(); scheduler.onHardwareVsyncRequest(mInnerDisplay->getPhysicalId(), true); scheduler.onHardwareVsyncRequest(mOuterDisplay->getPhysicalId(), true); } TEST_F(FoldableTest, requestVsyncOnPowerOn) { EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true)) .Times(1); EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true)) .Times(1); mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); } TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) { // When the device boots, the inner display should be the pacesetter. ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); testing::InSequence seq; EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true)) .Times(1); EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true)) .Times(1); // Turning off the pacesetter will result in disabling VSYNC. EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, false)) .Times(1); mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF); // Other display is now the pacesetter. ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); } } // namespace } // namespace android