Loading services/surfaceflinger/SurfaceFlinger.cpp +29 −11 Original line number Diff line number Diff line Loading @@ -5522,6 +5522,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: // Turn off the display if (displayId == mActiveDisplayId) { if (const auto display = getActivatableDisplay()) { onActiveDisplayChangedLocked(activeDisplay.get(), *display); } else { if (setSchedFifo(false) != NO_ERROR) { ALOGW("Failed to set SCHED_OTHER after powering off active display: %s", strerror(errno)); Loading @@ -5536,6 +5539,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mScheduler->enableSyntheticVsync(); } } } // Disable VSYNC before turning off the display. requestHardwareVsync(displayId, false); Loading Loading @@ -7951,6 +7955,20 @@ void SurfaceFlinger::onActiveDisplaySizeChanged(const DisplayDevice& activeDispl getRenderEngine().onActiveDisplaySizeChanged(activeDisplay.getSize()); } sp<DisplayDevice> SurfaceFlinger::getActivatableDisplay() const { if (mPhysicalDisplays.size() == 1) return nullptr; // TODO(b/255635821): Choose the pacesetter display, considering both internal and external // displays. For now, pick the other internal display, assuming a dual-display foldable. return findDisplay([this](const DisplayDevice& display) REQUIRES(mStateLock) { const auto idOpt = PhysicalDisplayId::tryCast(display.getId()); return idOpt && *idOpt != mActiveDisplayId && display.isPoweredOn() && mPhysicalDisplays.get(*idOpt) .transform(&PhysicalDisplay::isInternal) .value_or(false); }); } void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveDisplayPtr, const DisplayDevice& activeDisplay) { ATRACE_CALL(); Loading services/surfaceflinger/SurfaceFlinger.h +5 −1 Original line number Diff line number Diff line Loading @@ -934,7 +934,8 @@ private: template <typename Predicate> sp<DisplayDevice> findDisplay(Predicate p) const REQUIRES(mStateLock) { const auto it = std::find_if(mDisplays.begin(), mDisplays.end(), [&](const auto& pair) { return p(*pair.second); }); [&](const auto& pair) REQUIRES(mStateLock) { return p(*pair.second); }); return it == mDisplays.end() ? nullptr : it->second; } Loading Loading @@ -1047,6 +1048,9 @@ private: VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock); void releaseVirtualDisplay(VirtualDisplayId); // Returns a display other than `mActiveDisplayId` that can be activated, if any. sp<DisplayDevice> getActivatableDisplay() const REQUIRES(mStateLock, kMainThreadContext); void onActiveDisplayChangedLocked(const DisplayDevice* inactiveDisplayPtr, const DisplayDevice& activeDisplay) REQUIRES(mStateLock, kMainThreadContext); Loading services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp +31 −1 Original line number Diff line number Diff line Loading @@ -55,13 +55,17 @@ struct FoldableTest : DisplayTransactionTest { sp<DisplayDevice> mInnerDisplay, mOuterDisplay; }; TEST_F(FoldableTest, foldUnfold) { 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.setPowerModeInternal(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) { mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); // The outer display should become the pacesetter after folding. mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF); Loading @@ -72,6 +76,10 @@ TEST_F(FoldableTest, foldUnfold) { mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF); mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) { mFlinger.setPowerModeInternal(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. Loading @@ -81,6 +89,28 @@ TEST_F(FoldableTest, foldUnfold) { // 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.setPowerModeInternal(mInnerDisplay, PowerMode::ON); mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON); // The outer display should become the pacesetter if the inner display powers off. mFlinger.setPowerModeInternal(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.setPowerModeInternal(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); // The inner display should become the pacesetter if the outer display powers off. mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, doesNotRequestHardwareVsyncIfPoweredOff) { Loading Loading
services/surfaceflinger/SurfaceFlinger.cpp +29 −11 Original line number Diff line number Diff line Loading @@ -5522,6 +5522,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: // Turn off the display if (displayId == mActiveDisplayId) { if (const auto display = getActivatableDisplay()) { onActiveDisplayChangedLocked(activeDisplay.get(), *display); } else { if (setSchedFifo(false) != NO_ERROR) { ALOGW("Failed to set SCHED_OTHER after powering off active display: %s", strerror(errno)); Loading @@ -5536,6 +5539,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mScheduler->enableSyntheticVsync(); } } } // Disable VSYNC before turning off the display. requestHardwareVsync(displayId, false); Loading Loading @@ -7951,6 +7955,20 @@ void SurfaceFlinger::onActiveDisplaySizeChanged(const DisplayDevice& activeDispl getRenderEngine().onActiveDisplaySizeChanged(activeDisplay.getSize()); } sp<DisplayDevice> SurfaceFlinger::getActivatableDisplay() const { if (mPhysicalDisplays.size() == 1) return nullptr; // TODO(b/255635821): Choose the pacesetter display, considering both internal and external // displays. For now, pick the other internal display, assuming a dual-display foldable. return findDisplay([this](const DisplayDevice& display) REQUIRES(mStateLock) { const auto idOpt = PhysicalDisplayId::tryCast(display.getId()); return idOpt && *idOpt != mActiveDisplayId && display.isPoweredOn() && mPhysicalDisplays.get(*idOpt) .transform(&PhysicalDisplay::isInternal) .value_or(false); }); } void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveDisplayPtr, const DisplayDevice& activeDisplay) { ATRACE_CALL(); Loading
services/surfaceflinger/SurfaceFlinger.h +5 −1 Original line number Diff line number Diff line Loading @@ -934,7 +934,8 @@ private: template <typename Predicate> sp<DisplayDevice> findDisplay(Predicate p) const REQUIRES(mStateLock) { const auto it = std::find_if(mDisplays.begin(), mDisplays.end(), [&](const auto& pair) { return p(*pair.second); }); [&](const auto& pair) REQUIRES(mStateLock) { return p(*pair.second); }); return it == mDisplays.end() ? nullptr : it->second; } Loading Loading @@ -1047,6 +1048,9 @@ private: VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock); void releaseVirtualDisplay(VirtualDisplayId); // Returns a display other than `mActiveDisplayId` that can be activated, if any. sp<DisplayDevice> getActivatableDisplay() const REQUIRES(mStateLock, kMainThreadContext); void onActiveDisplayChangedLocked(const DisplayDevice* inactiveDisplayPtr, const DisplayDevice& activeDisplay) REQUIRES(mStateLock, kMainThreadContext); Loading
services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp +31 −1 Original line number Diff line number Diff line Loading @@ -55,13 +55,17 @@ struct FoldableTest : DisplayTransactionTest { sp<DisplayDevice> mInnerDisplay, mOuterDisplay; }; TEST_F(FoldableTest, foldUnfold) { 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.setPowerModeInternal(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) { mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); // The outer display should become the pacesetter after folding. mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF); Loading @@ -72,6 +76,10 @@ TEST_F(FoldableTest, foldUnfold) { mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF); mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) { mFlinger.setPowerModeInternal(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. Loading @@ -81,6 +89,28 @@ TEST_F(FoldableTest, foldUnfold) { // 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.setPowerModeInternal(mInnerDisplay, PowerMode::ON); mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON); // The outer display should become the pacesetter if the inner display powers off. mFlinger.setPowerModeInternal(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.setPowerModeInternal(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); // The inner display should become the pacesetter if the outer display powers off. mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, doesNotRequestHardwareVsyncIfPoweredOff) { Loading