diff options
author | 2024-10-31 15:52:31 -0700 | |
---|---|---|
committer | 2024-11-01 04:48:18 +0000 | |
commit | 8e3e2ea8a946c616140c1df06e395a62c724bacb (patch) | |
tree | c6435c1d10367c1171a3fb5fc3474516cce0f804 | |
parent | a8217b5de82897fdfb4a427643a1d1c851845e3a (diff) |
SF: omit vsync callbacks when screen is OFF
This CL is submitted behind a flag and in still in development.
The flag should not be enabled just yet.
Test: manual
Bug: 331636736
Flag: com.android.graphics.surfaceflinger.flags.no_vsyncs_on_screen_off
Change-Id: Iec9cde3bafb9c112c9ce9beebe6dded4727fc99c
-rw-r--r-- | services/surfaceflinger/DisplayDevice.cpp | 4 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/EventThread.cpp | 22 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/EventThread.h | 7 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.cpp | 8 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 40 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 5 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/mock/MockEventThread.h | 1 |
9 files changed, 88 insertions, 1 deletions
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 402a3d2e2f..c743ea2ff4 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -201,6 +201,10 @@ bool DisplayDevice::isPoweredOn() const { return mPowerMode != hal::PowerMode::OFF; } +bool DisplayDevice::isRefreshable() const { + return mPowerMode == hal::PowerMode::DOZE || mPowerMode == hal::PowerMode::ON; +} + ui::Dataspace DisplayDevice::getCompositionDataSpace() const { return mCompositionDisplay->getState().dataspace; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 3e3f558cee..d09a6b369b 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -173,6 +173,7 @@ public: hardware::graphics::composer::hal::PowerMode getPowerMode() const; void setPowerMode(hardware::graphics::composer::hal::PowerMode); bool isPoweredOn() const; + bool isRefreshable() const; void tracePowerMode(); // Enables layer caching on this DisplayDevice diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index e385f18243..7729671401 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -420,6 +420,16 @@ void EventThread::enableSyntheticVsync(bool enable) { mCondition.notify_all(); } +void EventThread::omitVsyncDispatching(bool omitted) { + std::lock_guard<std::mutex> lock(mMutex); + if (!mVSyncState || mVSyncState->omitted == omitted) { + return; + } + + mVSyncState->omitted = omitted; + mCondition.notify_all(); +} + void EventThread::onVsync(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) { std::lock_guard<std::mutex> lock(mMutex); mLastVsyncCallbackTime = TimePoint::fromNs(vsyncTime); @@ -521,7 +531,17 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { } if (mVSyncState && vsyncRequested) { - mState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync; + const bool vsyncOmitted = + FlagManager::getInstance().no_vsyncs_on_screen_off() && mVSyncState->omitted; + if (vsyncOmitted) { + mState = State::Idle; + SFTRACE_INT("VsyncPendingScreenOn", 1); + } else { + mState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync; + if (FlagManager::getInstance().no_vsyncs_on_screen_off()) { + SFTRACE_INT("VsyncPendingScreenOn", 0); + } + } } else { ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected"); mState = State::Idle; diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index c3c7eb0ee1..2daf126d77 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -106,6 +106,8 @@ public: // Feed clients with fake VSYNC, e.g. while the display is off. virtual void enableSyntheticVsync(bool) = 0; + virtual void omitVsyncDispatching(bool) = 0; + virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0; virtual void onHotplugConnectionError(int32_t connectionError) = 0; @@ -165,6 +167,8 @@ public: void enableSyntheticVsync(bool) override; + void omitVsyncDispatching(bool) override; + void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override; void onHotplugConnectionError(int32_t connectionError) override; @@ -240,6 +244,9 @@ private: // True if VSYNC should be faked, e.g. when display is off. bool synthetic = false; + + // True if VSYNC should not be delivered to apps. Used when the display is off. + bool omitted = false; }; // TODO(b/74619554): Create per-display threads waiting on respective VSYNC signals, diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index b83ff19fe7..b8b1f59223 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -405,6 +405,14 @@ void Scheduler::enableSyntheticVsync(bool enable) { eventThreadFor(Cycle::Render).enableSyntheticVsync(enable); } +void Scheduler::omitVsyncDispatching(bool omitted) { + eventThreadFor(Cycle::Render).omitVsyncDispatching(omitted); + // Note: If we don't couple Cycle::LastComposite event thread, there is a black screen + // after boot. This is most likely sysui or system_server dependency on sf instance + // Choreographer + eventThreadFor(Cycle::LastComposite).omitVsyncDispatching(omitted); +} + void Scheduler::onFrameRateOverridesChanged() { const auto [pacesetterId, supportsFrameRateOverrideByContent] = [this] { std::scoped_lock lock(mDisplayLock); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index c88b563805..d029488541 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -154,6 +154,7 @@ public: bool onDisplayModeChanged(PhysicalDisplayId, const FrameRateMode&) EXCLUDES(mPolicyLock); void enableSyntheticVsync(bool = true) REQUIRES(kMainThreadContext); + void omitVsyncDispatching(bool) REQUIRES(kMainThreadContext); void onHdcpLevelsChanged(Cycle, PhysicalDisplayId, int32_t, int32_t); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d35a76ad4b..0ba29f98ae 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3660,6 +3660,26 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( return display; } +void SurfaceFlinger::incRefreshableDisplays() { + if (FlagManager::getInstance().no_vsyncs_on_screen_off()) { + mRefreshableDisplays++; + if (mRefreshableDisplays == 1) { + ftl::FakeGuard guard(kMainThreadContext); + mScheduler->omitVsyncDispatching(false); + } + } +} + +void SurfaceFlinger::decRefreshableDisplays() { + if (FlagManager::getInstance().no_vsyncs_on_screen_off()) { + mRefreshableDisplays--; + if (mRefreshableDisplays == 0) { + ftl::FakeGuard guard(kMainThreadContext); + mScheduler->omitVsyncDispatching(true); + } + } +} + void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState& state) { ui::Size resolution(0, 0); @@ -3751,6 +3771,10 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, display->adjustRefreshRate(mScheduler->getPacesetterRefreshRate()); } + if (display->isRefreshable()) { + incRefreshableDisplays(); + } + mDisplays.try_emplace(displayToken, std::move(display)); // For an external display, loadDisplayModes already attempted to select the same mode @@ -3785,6 +3809,10 @@ void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { } else { mScheduler->unregisterDisplay(display->getPhysicalId(), mActiveDisplayId); } + + if (display->isRefreshable()) { + decRefreshableDisplays(); + } } mDisplays.erase(displayToken); @@ -3819,6 +3847,10 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (display->isVirtual()) { releaseVirtualDisplay(display->getVirtualId()); } + + if (display->isRefreshable()) { + decRefreshableDisplays(); + } } mDisplays.erase(displayToken); @@ -5317,7 +5349,15 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: activeDisplay->isPoweredOn(), "Trying to change power mode on inactive display without powering off active display"); + const bool couldRefresh = display->isRefreshable(); display->setPowerMode(mode); + const bool canRefresh = display->isRefreshable(); + + if (couldRefresh && !canRefresh) { + decRefreshableDisplays(); + } else if (!couldRefresh && canRefresh) { + incRefreshableDisplays(); + } const auto activeMode = display->refreshRateSelector().getActiveMode().modePtr; if (currentMode == hal::PowerMode::OFF) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 31218edbe7..b9c4368801 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1423,6 +1423,11 @@ private: // Whether a display should be turned on when initialized bool mSkipPowerOnForQuiescent; + // used for omitting vsync callbacks to apps when the display is not updatable + int mRefreshableDisplays GUARDED_BY(mStateLock) = 0; + void incRefreshableDisplays() REQUIRES(mStateLock); + void decRefreshableDisplays() REQUIRES(mStateLock); + frontend::LayerLifecycleManager mLayerLifecycleManager GUARDED_BY(kMainThreadContext); frontend::LayerHierarchyBuilder mLayerHierarchyBuilder GUARDED_BY(kMainThreadContext); frontend::LayerSnapshotBuilder mLayerSnapshotBuilder GUARDED_BY(kMainThreadContext); diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 7398cbebe3..82500fef10 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -30,6 +30,7 @@ public: MOCK_METHOD(sp<EventThreadConnection>, createEventConnection, (EventRegistrationFlags), (const, override)); MOCK_METHOD(void, enableSyntheticVsync, (bool), (override)); + MOCK_METHOD(void, omitVsyncDispatching, (bool), (override)); MOCK_METHOD(void, onHotplugReceived, (PhysicalDisplayId, bool), (override)); MOCK_METHOD(void, onHotplugConnectionError, (int32_t), (override)); MOCK_METHOD(void, onModeChanged, (const scheduler::FrameRateMode&), (override)); |