diff options
| author | 2025-02-06 02:34:05 -0800 | |
|---|---|---|
| committer | 2025-03-11 11:26:47 -0700 | |
| commit | 00a764ee8a3d2b59991f0e08557ac7a876862b81 (patch) | |
| tree | 44e96e569d948cfceb37aa30ffe507da70ec3502 | |
| parent | d0503fa4db892711445b44302d36968a88a469a8 (diff) | |
Use power mode of all independent displays to control power optimisations.
In the following cases, if there is any performance-optimised/independent active display (powered on) then power optimisations are disabled. If there is no performance-optimised/independent active display then power optimisations are enabled, even if there are power-optimised displays that are powered on.
* Physical or virtual display power mode change
* Physical or virtual display added or removed
Power optimisations include:
* Lowering thread priority
Bug: 342681202
Bug: 241285876
Flag: android.companion.virtualdevice.flags.correct_virtual_display_power_state
Test: manually tested with flag on/off using Android Auto Projected
Change-Id: I96068c8779dbfe2b51b4d9acd522b6cb3995681f
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 95 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 16 |
2 files changed, 98 insertions, 13 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 099aa7a865..217581c1a9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4075,6 +4075,10 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, incRefreshableDisplays(); } + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy(__func__); + } + mDisplays.try_emplace(displayToken, std::move(display)); // For an external display, loadDisplayModes already attempted to select the same mode @@ -4131,6 +4135,10 @@ void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { // not be accessible. })); } + + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy(__func__); + } } void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, @@ -5679,7 +5687,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } const auto displayId = display->getPhysicalId(); - ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str()); + ALOGD("Setting power mode %d on physical display %s", mode, to_string(displayId).c_str()); const auto currentMode = display->getPowerMode(); if (currentMode == mode) { @@ -5722,11 +5730,11 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } if (displayId == mActiveDisplayId) { - // TODO: b/281692563 - Merge the syscalls. For now, keep uclamp in a separate syscall - // and set it before SCHED_FIFO due to b/190237315. - constexpr const char* kWhence = "setPowerMode(ON)"; - setSchedAttr(true, kWhence); - setSchedFifo(true, kWhence); + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy("setPhysicalDisplayPowerMode(ON)"); + } else { + disablePowerOptimizations("setPhysicalDisplayPowerMode(ON)"); + } } getHwComposer().setPowerMode(displayId, mode); @@ -5753,9 +5761,11 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: if (const auto display = getActivatableDisplay()) { onActiveDisplayChangedLocked(activeDisplay.get(), *display); } else { - constexpr const char* kWhence = "setPowerMode(OFF)"; - setSchedFifo(false, kWhence); - setSchedAttr(false, kWhence); + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy("setPhysicalDisplayPowerMode(OFF)"); + } else { + enablePowerOptimizations("setPhysicalDisplayPowerMode(OFF)"); + } if (currentModeNotDozeSuspend) { if (!FlagManager::getInstance().multithreaded_present()) { @@ -5816,7 +5826,67 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mScheduler->setDisplayPowerMode(displayId, mode); - ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str()); + ALOGD("Finished setting power mode %d on physical display %s", mode, + to_string(displayId).c_str()); +} + +void SurfaceFlinger::setVirtualDisplayPowerMode(const sp<DisplayDevice>& display, + hal::PowerMode mode) { + if (!display->isVirtual()) { + ALOGE("%s: Invalid operation on physical display", __func__); + return; + } + + const auto displayId = display->getVirtualId(); + ALOGD("Setting power mode %d on virtual display %s %s", mode, to_string(displayId).c_str(), + display->getDisplayName().c_str()); + + display->setPowerMode(static_cast<hal::PowerMode>(mode)); + + applyOptimizationPolicy(__func__); + + ALOGD("Finished setting power mode %d on virtual display %s", mode, + to_string(displayId).c_str()); +} + +bool SurfaceFlinger::shouldOptimizeForPerformance() { + for (const auto& [_, display] : mDisplays) { + // Displays that are optimized for power are always powered on and should not influence + // whether there is an active display for the purpose of power optimization, etc. If these + // displays are being shown somewhere, a different (physical or virtual) display that is + // optimized for performance will be powered on in addition. Displays optimized for + // performance will change power mode, so if they are off then they are not active. + if (display->isPoweredOn() && + display->getOptimizationPolicy() == + gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance) { + return true; + } + } + return false; +} + +void SurfaceFlinger::enablePowerOptimizations(const char* whence) { + ALOGD("%s: Enabling power optimizations", whence); + + setSchedAttr(false, whence); + setSchedFifo(false, whence); +} + +void SurfaceFlinger::disablePowerOptimizations(const char* whence) { + ALOGD("%s: Disabling power optimizations", whence); + + // TODO: b/281692563 - Merge the syscalls. For now, keep uclamp in a separate syscall + // and set it before SCHED_FIFO due to b/190237315. + setSchedAttr(true, whence); + setSchedFifo(true, whence); +} + +void SurfaceFlinger::applyOptimizationPolicy(const char* whence) { + if (shouldOptimizeForPerformance()) { + disablePowerOptimizations(whence); + } else { + enablePowerOptimizations(whence); + } } void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) { @@ -5838,9 +5908,8 @@ void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) { ALOGE("Failed to set power mode %d for display token %p", mode, displayToken.get()); } else if (display->isVirtual()) { if (FlagManager::getInstance().correct_virtual_display_power_state()) { - ALOGD("Setting power mode %d on virtual display %s", mode, - display->getDisplayName().c_str()); - display->setPowerMode(static_cast<hal::PowerMode>(mode)); + ftl::FakeGuard guard(mStateLock); + setVirtualDisplayPowerMode(display, static_cast<hal::PowerMode>(mode)); } else { ALOGW("Attempt to set power mode %d for virtual display", mode); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 39e237b1f9..8a0489fcb4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -735,6 +735,22 @@ private: // Called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) REQUIRES(mStateLock, kMainThreadContext); + void setVirtualDisplayPowerMode(const sp<DisplayDevice>& display, hal::PowerMode mode) + REQUIRES(mStateLock, kMainThreadContext); + + // Returns whether to optimize globally for performance instead of power. + bool shouldOptimizeForPerformance() REQUIRES(mStateLock); + + // Turns on power optimizations, for example when there are no displays to be optimized for + // performance. + static void enablePowerOptimizations(const char* whence); + + // Turns off power optimizations. + static void disablePowerOptimizations(const char* whence); + + // Enables or disables power optimizations depending on whether there are displays that should + // be optimized for performance. + void applyOptimizationPolicy(const char* whence) REQUIRES(mStateLock); // Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that // display. Falls back to the display's defaultModeId otherwise. |