summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dennis Kiilerich <dki@google.com> 2025-03-07 14:58:25 -0800
committer Dennis Kiilerich <dki@google.com> 2025-03-14 13:16:28 -0700
commitbac7071aa3b1ae72f90b904b9af61b5c74ba9265 (patch)
treeb350f3ed5472a4d2e9d511ee085aa997f64075ed
parent913c8f38edd7d5423a65f1b78b7c78a3cc7d8ef6 (diff)
Turn off synthetic VSYNC when adjusting thread scheduling for performance
* This CL explicitly sets synthetic VSYNC state based on the new power state. Before, the synthetic VSYNC state was assumed based on the previous power state and in some cases was not set explicitly. * The previous behaviour of enabling synthetic VSYNC if the only display is DOZE_SUSPEND is preserved. * This also fixes a hypothetical gap where it would not optimise for performance if there were a display that needed it, while the primary display was DOZE_SUSPEND. 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: I181aefad586ad7b1732c837b67a01d61939d1d3e
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp11
-rw-r--r--services/surfaceflinger/DisplayDevice.h11
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp99
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h15
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp30
5 files changed, 95 insertions, 71 deletions
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index bad5e2e3b5..de7d455fa4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -50,17 +50,6 @@ namespace android {
namespace hal = hardware::graphics::composer::hal;
-namespace gui {
-inline std::string_view to_string(ISurfaceComposer::OptimizationPolicy optimizationPolicy) {
- switch (optimizationPolicy) {
- case ISurfaceComposer::OptimizationPolicy::optimizeForPower:
- return "optimizeForPower";
- case ISurfaceComposer::OptimizationPolicy::optimizeForPerformance:
- return "optimizeForPerformance";
- }
-}
-} // namespace gui
-
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(
const sp<SurfaceFlinger>& flinger, HWComposer& hwComposer, const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay)
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 7d7c8adb7b..1b14145147 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -67,6 +67,17 @@ namespace display {
class DisplaySnapshot;
} // namespace display
+namespace gui {
+inline const char* to_string(ISurfaceComposer::OptimizationPolicy optimizationPolicy) {
+ switch (optimizationPolicy) {
+ case ISurfaceComposer::OptimizationPolicy::optimizeForPower:
+ return "optimizeForPower";
+ case ISurfaceComposer::OptimizationPolicy::optimizeForPerformance:
+ return "optimizeForPerformance";
+ }
+}
+} // namespace gui
+
class DisplayDevice : public RefBase {
public:
constexpr static float sDefaultMinLumiance = 0.0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 940374b256..aa933ee8a7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5719,7 +5719,13 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
incRefreshableDisplays();
}
+ if (displayId == mActiveDisplayId &&
+ FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy(__func__);
+ }
+
const auto activeMode = display->refreshRateSelector().getActiveMode().modePtr;
+ using OptimizationPolicy = gui::ISurfaceComposer::OptimizationPolicy;
if (currentMode == hal::PowerMode::OFF) {
// Turn on the display
@@ -5734,12 +5740,10 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
onActiveDisplayChangedLocked(activeDisplay.get(), *display);
}
- if (displayId == mActiveDisplayId) {
- if (FlagManager::getInstance().correct_virtual_display_power_state()) {
- applyOptimizationPolicy("setPhysicalDisplayPowerMode(ON)");
- } else {
- disablePowerOptimizations("setPhysicalDisplayPowerMode(ON)");
- }
+ if (displayId == mActiveDisplayId &&
+ !FlagManager::getInstance().correct_virtual_display_power_state()) {
+ optimizeThreadScheduling("setPhysicalDisplayPowerMode(ON/DOZE)",
+ OptimizationPolicy::optimizeForPerformance);
}
getHwComposer().setPowerMode(displayId, mode);
@@ -5748,7 +5752,8 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
mScheduler->getVsyncSchedule(displayId)->getPendingHardwareVsyncState();
requestHardwareVsync(displayId, enable);
- if (displayId == mActiveDisplayId) {
+ if (displayId == mActiveDisplayId &&
+ !FlagManager::getInstance().correct_virtual_display_power_state()) {
mScheduler->enableSyntheticVsync(false);
}
@@ -5765,13 +5770,13 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
if (const auto display = getActivatableDisplay()) {
onActiveDisplayChangedLocked(activeDisplay.get(), *display);
} else {
- if (FlagManager::getInstance().correct_virtual_display_power_state()) {
- applyOptimizationPolicy("setPhysicalDisplayPowerMode(OFF)");
- } else {
- enablePowerOptimizations("setPhysicalDisplayPowerMode(OFF)");
+ if (!FlagManager::getInstance().correct_virtual_display_power_state()) {
+ optimizeThreadScheduling("setPhysicalDisplayPowerMode(OFF)",
+ OptimizationPolicy::optimizeForPower);
}
- if (currentModeNotDozeSuspend) {
+ if (currentModeNotDozeSuspend &&
+ !FlagManager::getInstance().correct_virtual_display_power_state()) {
mScheduler->enableSyntheticVsync();
}
}
@@ -5799,7 +5804,9 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
mVisibleRegionsDirty = true;
scheduleRepaint();
- mScheduler->enableSyntheticVsync(false);
+ if (!FlagManager::getInstance().correct_virtual_display_power_state()) {
+ mScheduler->enableSyntheticVsync(false);
+ }
}
constexpr bool kAllowToEnable = true;
mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, activeMode.get());
@@ -5809,7 +5816,8 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
constexpr bool kDisallow = true;
mScheduler->disableHardwareVsync(displayId, kDisallow);
- if (displayId == mActiveDisplayId) {
+ if (displayId == mActiveDisplayId &&
+ !FlagManager::getInstance().correct_virtual_display_power_state()) {
mScheduler->enableSyntheticVsync();
}
getHwComposer().setPowerMode(displayId, mode);
@@ -5848,43 +5856,44 @@ void SurfaceFlinger::setVirtualDisplayPowerMode(const sp<DisplayDevice>& display
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);
+void SurfaceFlinger::optimizeThreadScheduling(
+ const char* whence, gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy) {
+ ALOGD("%s: Optimizing thread scheduling: %s", whence, to_string(optimizationPolicy));
+ const bool optimizeForPerformance =
+ optimizationPolicy == gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance;
// 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);
+ setSchedAttr(optimizeForPerformance, whence);
+ setSchedFifo(optimizeForPerformance, whence);
}
void SurfaceFlinger::applyOptimizationPolicy(const char* whence) {
- if (shouldOptimizeForPerformance()) {
- disablePowerOptimizations(whence);
- } else {
- enablePowerOptimizations(whence);
+ using OptimizationPolicy = gui::ISurfaceComposer::OptimizationPolicy;
+
+ const bool optimizeForPerformance =
+ std::any_of(mDisplays.begin(), mDisplays.end(), [](const auto& pair) {
+ const auto& display = pair.second;
+ return display->isPoweredOn() &&
+ display->getOptimizationPolicy() ==
+ OptimizationPolicy::optimizeForPerformance;
+ });
+
+ optimizeThreadScheduling(whence,
+ optimizeForPerformance ? OptimizationPolicy::optimizeForPerformance
+ : OptimizationPolicy::optimizeForPower);
+
+ if (mScheduler) {
+ const bool disableSyntheticVsync =
+ std::any_of(mDisplays.begin(), mDisplays.end(), [](const auto& pair) {
+ const auto& display = pair.second;
+ const hal::PowerMode powerMode = display->getPowerMode();
+ return powerMode != hal::PowerMode::OFF &&
+ powerMode != hal::PowerMode::DOZE_SUSPEND &&
+ display->getOptimizationPolicy() ==
+ OptimizationPolicy::optimizeForPerformance;
+ });
+ mScheduler->enableSyntheticVsync(!disableSyntheticVsync);
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9cf0c6aaa0..f61214cc65 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -733,19 +733,14 @@ private:
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);
+ // Adjusts thread scheduling according to the optimization policy
+ static void optimizeThreadScheduling(
+ const char* whence, gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy);
// Enables or disables power optimizations depending on whether there are displays that should
// be optimized for performance.
- void applyOptimizationPolicy(const char* whence) REQUIRES(mStateLock);
+ void applyOptimizationPolicy(const char* whence) REQUIRES(kMainThreadContext)
+ 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.
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
index d5c22a9601..2332bf62da 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <android_companion_virtualdevice_flags.h>
#include <com_android_graphics_surfaceflinger_flags.h>
#include <common/test/FlagUtils.h>
#include "DisplayTransactionTestHelpers.h"
@@ -78,11 +79,19 @@ struct EventThreadBaseSupportedVariant {
struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant {
static void setupEnableVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, true)).Times(1);
+ setupDisableSyntheticVsyncCallExpectations(test);
+ }
+
+ static void setupDisableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(_)).Times(0);
}
static void setupDisableVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, false)).Times(1);
+ setupEnableSyntheticVsyncCallExpectations(test);
+ }
+
+ static void setupEnableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(_)).Times(0);
}
};
@@ -91,12 +100,20 @@ struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant {
static void setupEnableVsyncCallExpectations(DisplayTransactionTest* test) {
// Expect to enable hardware VSYNC and disable synthetic VSYNC.
EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, true)).Times(1);
+ setupDisableSyntheticVsyncCallExpectations(test);
+ }
+
+ static void setupDisableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(false)).Times(1);
}
static void setupDisableVsyncCallExpectations(DisplayTransactionTest* test) {
// Expect to disable hardware VSYNC and enable synthetic VSYNC.
EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, false)).Times(1);
+ setupEnableSyntheticVsyncCallExpectations(test);
+ }
+
+ static void setupEnableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(true)).Times(1);
}
};
@@ -151,7 +168,7 @@ struct TransitionOffToDozeSuspendVariant
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupEnableSyntheticVsyncCallExpectations(test);
Case::setupRepaintEverythingCallExpectations(test);
}
@@ -176,7 +193,7 @@ struct TransitionDozeSuspendToOffVariant
: public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupEnableSyntheticVsyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
}
@@ -188,7 +205,7 @@ struct TransitionDozeSuspendToOffVariant
struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupDisableSyntheticVsyncCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
}
};
@@ -206,7 +223,7 @@ struct TransitionDozeSuspendToDozeVariant
struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupDisableSyntheticVsyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
}
};
@@ -234,7 +251,7 @@ struct TransitionOnToUnknownVariant
: public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupDisableSyntheticVsyncCallExpectations(test);
Case::setupNoComposerPowerModeCallExpectations(test);
}
};
@@ -335,6 +352,9 @@ void SetPhysicalDisplayPowerModeTest::transitionDisplayCommon() {
// --------------------------------------------------------------------
// Preconditions
+ SET_FLAG_FOR_TEST(android::companion::virtualdevice::flags::correct_virtual_display_power_state,
+ true);
+
Case::Doze::setupComposerCallExpectations(this);
auto display =
Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE);