Merge "Skia HLG should scale to [0, 1] instead of [0, 12]" into tm-dev
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 1c3a4f2..32ffe14 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -63,6 +63,8 @@
chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_pause/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_work_period/enable
+ chmod 0666 /sys/kernel/tracing/events/power/gpu_work_period/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/suspend_resume/enable
chmod 0666 /sys/kernel/tracing/events/power/suspend_resume/enable
chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 4e12579..397d432 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -473,7 +473,8 @@
StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
sUsingProjectIdsFlag = access(using_project_ids.c_str(), F_OK) == 0;
});
- return sUsingProjectIdsFlag;
+ // return sUsingProjectIdsFlag;
+ return false;
}
static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
@@ -632,8 +633,9 @@
}
static binder::Status createAppDataDirs(const std::string& path, int32_t uid, int32_t gid,
- int32_t* previousUid, int32_t cacheGid,
- const std::string& seInfo, mode_t targetMode) {
+ int32_t previousUid, int32_t cacheGid,
+ const std::string& seInfo, mode_t targetMode,
+ long projectIdApp, long projectIdCache) {
struct stat st{};
bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
@@ -643,25 +645,17 @@
bool code_cache_exists = (access(code_cache_path.c_str(), F_OK) == 0);
if (parent_dir_exists) {
- if (*previousUid < 0) {
- // If previousAppId is -1 in CreateAppDataArgs, we will assume the current owner
- // of the directory as previousUid. This is required because it is not always possible
- // to chown app data during app upgrade (e.g. secondary users' CE storage not unlocked)
- *previousUid = st.st_uid;
- }
- if (*previousUid != uid) {
- if (!chown_app_dir(path, uid, *previousUid, cacheGid)) {
+ if (previousUid > 0 && previousUid != uid) {
+ if (!chown_app_dir(path, uid, previousUid, cacheGid)) {
return error("Failed to chown " + path);
}
}
}
// Prepare only the parent app directory
- long project_id_app = get_project_id(uid, PROJECT_ID_APP_START);
- long project_id_cache_app = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
- if (prepare_app_dir(path, targetMode, uid, gid, project_id_app) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, project_id_cache_app) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, project_id_cache_app)) {
+ if (prepare_app_dir(path, targetMode, uid, gid, projectIdApp) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, projectIdCache) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, projectIdCache)) {
return error("Failed to prepare " + path);
}
@@ -702,12 +696,9 @@
int32_t uid = multiuser_get_uid(userId, appId);
- // If previousAppId < 0, we will use the existing app data owner as previousAppUid
- // If previousAppId == 0, we use uid as previousUid (no data migration will happen)
- // if previousAppId > 0, an app is upgrading and changing its app ID
- int32_t previousUid = previousAppId > 0
- ? (int32_t) multiuser_get_uid(userId, previousAppId)
- : (previousAppId == 0 ? uid : -1);
+ // If previousAppId > 0, an app is changing its app ID
+ int32_t previousUid =
+ previousAppId > 0 ? (int32_t)multiuser_get_uid(userId, previousAppId) : -1;
int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
@@ -717,10 +708,14 @@
cacheGid = uid;
}
+ long projectIdApp = get_project_id(uid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
if (!status.isOk()) {
return status;
}
@@ -745,11 +740,12 @@
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
if (!status.isOk()) {
return status;
}
- if (previousUid != uid) {
+ if (previousUid > 0 && previousUid != uid) {
chown_app_profile_dir(packageName, appId, userId);
}
@@ -945,8 +941,12 @@
}
const int32_t sandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
int32_t previousSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
- auto status = createAppDataDirs(path, sandboxUid, AID_NOBODY, &previousSandboxUid,
- cacheGid, seInfo, 0700 | S_ISGID);
+ int32_t appUid = multiuser_get_uid(userId, appId);
+ long projectIdApp = get_project_id(appUid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(appUid, PROJECT_ID_APP_CACHE_START);
+ auto status =
+ createAppDataDirs(path, sandboxUid, AID_NOBODY, previousSandboxUid, cacheGid,
+ seInfo, 0700 | S_ISGID, projectIdApp, projectIdCache);
if (!status.isOk()) {
res = status;
continue;
@@ -3429,7 +3429,7 @@
auto temp_path = StringPrintf("%smisc/installd/ioctl_check", android_data_dir.c_str());
if (access(temp_path.c_str(), F_OK) != 0) {
int fd = open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
- result = set_quota_project_id(temp_path, 0, true) == 0;
+ result = set_quota_project_id(temp_path, 0, false) == 0;
close(fd);
// delete the temp file
remove(temp_path.c_str());
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 38cb370..f86f1d5 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -465,7 +465,7 @@
EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}
-TEST_F(ServiceTest, GetAppSize) {
+TEST_F(ServiceTest, GetAppSizeManualForMedia) {
struct stat s;
std::string externalPicDir =
@@ -509,6 +509,7 @@
system(removeCommand.c_str());
}
}
+
TEST_F(ServiceTest, GetAppSizeWrongSizes) {
int32_t externalStorageAppId = -1;
std::vector<int64_t> externalStorageSize;
diff --git a/include/android/sensor.h b/include/android/sensor.h
index c714b05..6112d5f 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -213,6 +213,13 @@
*/
ASENSOR_TYPE_HEART_BEAT = 31,
/**
+ * A constant describing a dynamic sensor meta event sensor.
+ *
+ * A sensor event of this type is received when a dynamic sensor is added to or removed from
+ * the system. This sensor type should always use special trigger report mode.
+ */
+ ASENSOR_TYPE_DYNAMIC_SENSOR_META = 32,
+ /**
* This sensor type is for delivering additional sensor information aside
* from sensor event data.
*
@@ -761,6 +768,10 @@
* Each time this is called, the previously returned list is deallocated and
* must no longer be used.
*
+ * Clients should call this if they receive a sensor update from
+ * {@link ASENSOR_TYPE_DYNAMIC_SENSOR_META} indicating the sensors have changed.
+ * If this happens, previously received lists from this method will be stale.
+ *
* Available since API level 33.
*
* \param manager the {@link ASensorManager} instance obtained from
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index f113ba8..d0cd11f 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -97,6 +97,10 @@
*
* This interface has system<->vendor stability
*/
+// b/227835797 - can't use __INTRODUCED_IN(30) because old targets load this code
+#if __ANDROID_MIN_SDK_VERSION__ < 30
+__attribute__((weak))
+#endif // __ANDROID_MIN_SDK_VERSION__ < 30
void AIBinder_markVintfStability(AIBinder* binder);
__END_DECLS
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index e3e4730..4df557b 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -575,6 +575,20 @@
cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
}
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Send for DeathRecipient {}
+
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Sync for DeathRecipient {}
+
impl DeathRecipient {
/// Create a new death recipient that will call the given callback when its
/// associated object dies.
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 5532c6e..24d39fe 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -226,101 +226,6 @@
return result;
}
- sp<IBinder> createDisplay(const String8& displayName, bool secure) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- status_t status = data.writeString8(displayName);
- if (status) {
- return nullptr;
- }
- status = data.writeBool(secure);
- if (status) {
- return nullptr;
- }
-
- status = remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
- if (status) {
- return nullptr;
- }
- sp<IBinder> display;
- status = reply.readNullableStrongBinder(&display);
- if (status) {
- return nullptr;
- }
- return display;
- }
-
- void destroyDisplay(const sp<IBinder>& display) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
- }
-
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
- NO_ERROR) {
- std::vector<uint64_t> rawIds;
- if (reply.readUint64Vector(&rawIds) == NO_ERROR) {
- std::vector<PhysicalDisplayId> displayIds;
- displayIds.reserve(rawIds.size());
-
- for (const uint64_t rawId : rawIds) {
- if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
- displayIds.push_back(*id);
- }
- }
- return displayIds;
- }
- }
-
- return {};
- }
-
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId* displayId) const override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(remote()->transact, BnSurfaceComposer::GET_PRIMARY_PHYSICAL_DISPLAY_ID, data,
- &reply);
- uint64_t rawId;
- SAFE_PARCEL(reply.readUint64, &rawId);
- if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
- *displayId = *id;
- return NO_ERROR;
- }
- return NAME_NOT_FOUND;
- }
-
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeUint64(displayId.value);
- remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply);
- return reply.readStrongBinder();
- }
-
- void setPowerMode(const sp<IBinder>& display, int mode) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- data.writeInt32(mode);
- remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply);
- }
-
- status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATE, data, &reply);
- const status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- memcpy(state, reply.readInplace(sizeof(ui::DisplayState)), sizeof(ui::DisplayState));
- }
- return result;
- }
-
status_t getStaticDisplayInfo(const sp<IBinder>& display,
ui::StaticDisplayInfo* info) override {
Parcel data, reply;
@@ -343,20 +248,6 @@
return reply.read(*info);
}
- status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATS, data, &reply);
- status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- memcpy(stats,
- reply.readInplace(sizeof(DisplayStatInfo)),
- sizeof(DisplayStatInfo));
- }
- return result;
- }
-
status_t getDisplayNativePrimaries(const sp<IBinder>& display,
ui::DisplayPrimaries& primaries) override {
Parcel data, reply;
@@ -408,29 +299,6 @@
return static_cast<status_t>(reply.readInt32());
}
- // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
- status_t getBootDisplayModeSupport(bool* outSupport) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to write interface token: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::GET_BOOT_DISPLAY_MODE_SUPPORT, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to transact: %d", error);
- return error;
- }
- bool support;
- error = reply.readBool(&support);
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to read support: %d", error);
- return error;
- }
- *outSupport = support;
- return NO_ERROR;
- }
-
status_t setBootDisplayMode(const sp<IBinder>& display,
ui::DisplayModeId displayModeId) override {
Parcel data, reply;
@@ -456,73 +324,6 @@
return result;
}
- status_t clearBootDisplayMode(const sp<IBinder>& display) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::CLEAR_BOOT_DISPLAY_MODE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to transact: %d", result);
- }
- return result;
- }
-
- void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeInterfaceToken: %d", result);
- return;
- }
-
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeStrongBinder: %d", result);
- return;
- }
- result = data.writeBool(on);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeBool: %d", result);
- return;
- }
- result = remote()->transact(BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to transact: %d", result);
- return;
- }
- }
-
- void setGameContentType(const sp<IBinder>& display, bool on) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeInterfaceToken: %d", result);
- return;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeStrongBinder: %d", result);
- return;
- }
- result = data.writeBool(on);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeBool: %d", result);
- return;
- }
- result = remote()->transact(BnSurfaceComposer::SET_GAME_CONTENT_TYPE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to transact: %d", result);
- }
- }
-
status_t clearAnimationFrameStats() override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -797,26 +598,6 @@
return error;
}
- status_t isWideColorDisplay(const sp<IBinder>& token,
- bool* outIsWideColorDisplay) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- return error;
- }
- error = data.writeStrongBinder(token);
- if (error != NO_ERROR) {
- return error;
- }
-
- error = remote()->transact(BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY, data, &reply);
- if (error != NO_ERROR) {
- return error;
- }
- error = reply.readBool(outIsWideColorDisplay);
- return error;
- }
-
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override {
Parcel data, reply;
@@ -1049,109 +830,6 @@
return reply.readInt32();
}
- status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeStrongBinder(displayToken);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to write display token: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to transact: %d", error);
- return error;
- }
- bool support;
- error = reply.readBool(&support);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to read support: %d", error);
- return error;
- }
- *outSupport = support;
- return NO_ERROR;
- }
-
- status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeStrongBinder(displayToken);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write display token: %d", error);
- return error;
- }
- error = data.writeParcelable(brightness);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write brightness: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to transact: %d", error);
- return error;
- }
- return NO_ERROR;
- }
-
- status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeStrongBinder, displayToken);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
- const status_t error =
- remote()->transact(BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER, data, &reply);
- if (error != OK) {
- ALOGE("addHdrLayerInfoListener: Failed to transact; error = %d", error);
- }
- return error;
- }
-
- status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeStrongBinder, displayToken);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
- const status_t error =
- remote()->transact(BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER, data, &reply);
- if (error != OK) {
- ALOGE("removeHdrLayerInfoListener: Failed to transact; error = %d", error);
- }
- return error;
- }
-
- status_t notifyPowerBoost(int32_t boostId) override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeInt32(boostId);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to write boostId: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::NOTIFY_POWER_BOOST, data, &reply,
- IBinder::FLAG_ONEWAY);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to transact: %d", error);
- return error;
- }
- return NO_ERROR;
- }
-
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override {
Parcel data, reply;
@@ -1467,41 +1145,6 @@
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
- case CREATE_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- String8 displayName;
- SAFE_PARCEL(data.readString8, &displayName);
- bool secure = false;
- SAFE_PARCEL(data.readBool, &secure);
- sp<IBinder> display = createDisplay(displayName, secure);
- SAFE_PARCEL(reply->writeStrongBinder, display);
- return NO_ERROR;
- }
- case DESTROY_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- destroyDisplay(display);
- return NO_ERROR;
- }
- case GET_PHYSICAL_DISPLAY_TOKEN: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- const auto id = DisplayId::fromValue<PhysicalDisplayId>(data.readUint64());
- if (!id) return BAD_VALUE;
- reply->writeStrongBinder(getPhysicalDisplayToken(*id));
- return NO_ERROR;
- }
- case GET_DISPLAY_STATE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- ui::DisplayState state;
- const sp<IBinder> display = data.readStrongBinder();
- const status_t result = getDisplayState(display, &state);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- memcpy(reply->writeInplace(sizeof(ui::DisplayState)), &state,
- sizeof(ui::DisplayState));
- }
- return NO_ERROR;
- }
case GET_STATIC_DISPLAY_INFO: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
ui::StaticDisplayInfo info;
@@ -1522,18 +1165,6 @@
SAFE_PARCEL(reply->write, info);
return NO_ERROR;
}
- case GET_DISPLAY_STATS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- DisplayStatInfo stats;
- sp<IBinder> display = data.readStrongBinder();
- status_t result = getDisplayStats(display, &stats);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- memcpy(reply->writeInplace(sizeof(DisplayStatInfo)),
- &stats, sizeof(DisplayStatInfo));
- }
- return NO_ERROR;
- }
case GET_DISPLAY_NATIVE_PRIMARIES: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
ui::DisplayPrimaries primaries;
@@ -1573,15 +1204,6 @@
result = reply->writeInt32(result);
return result;
}
- case GET_BOOT_DISPLAY_MODE_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- bool support = false;
- status_t result = getBootDisplayModeSupport(&support);
- if (result == NO_ERROR) {
- reply->writeBool(support);
- }
- return result;
- }
case SET_BOOT_DISPLAY_MODE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -1598,50 +1220,6 @@
}
return setBootDisplayMode(display, displayModeId);
}
- case CLEAR_BOOT_DISPLAY_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to readStrongBinder: %d", result);
- return result;
- }
- return clearBootDisplayMode(display);
- }
- case SET_AUTO_LOW_LATENCY_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to readStrongBinder: %d", result);
- return result;
- }
- bool setAllm = false;
- result = data.readBool(&setAllm);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to readBool: %d", result);
- return result;
- }
- setAutoLowLatencyMode(display, setAllm);
- return result;
- }
- case SET_GAME_CONTENT_TYPE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to readStrongBinder: %d", result);
- return result;
- }
- bool setGameContentTypeOn = false;
- result = data.readBool(&setGameContentTypeOn);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to readBool: %d", result);
- return result;
- }
- setGameContentType(display, setGameContentTypeOn);
- return result;
- }
case CLEAR_ANIMATION_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
status_t result = clearAnimationFrameStats();
@@ -1656,13 +1234,6 @@
reply->writeInt32(result);
return NO_ERROR;
}
- case SET_POWER_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- int32_t mode = data.readInt32();
- setPowerMode(display, mode);
- return NO_ERROR;
- }
case ENABLE_VSYNC_INJECTIONS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bool enable = false;
@@ -1812,38 +1383,6 @@
}
return error;
}
- case IS_WIDE_COLOR_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t error = data.readStrongBinder(&display);
- if (error != NO_ERROR) {
- return error;
- }
- bool result;
- error = isWideColorDisplay(display, &result);
- if (error == NO_ERROR) {
- reply->writeBool(result);
- }
- return error;
- }
- case GET_PHYSICAL_DISPLAY_IDS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- std::vector<PhysicalDisplayId> ids = getPhysicalDisplayIds();
- std::vector<uint64_t> rawIds(ids.size());
- std::transform(ids.begin(), ids.end(), rawIds.begin(),
- [](PhysicalDisplayId id) { return id.value; });
- return reply->writeUint64Vector(rawIds);
- }
- case GET_PRIMARY_PHYSICAL_DISPLAY_ID: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- PhysicalDisplayId id;
- status_t result = getPrimaryPhysicalDisplayId(&id);
- if (result != NO_ERROR) {
- ALOGE("getPrimaryPhysicalDisplayId: Failed to get id");
- return result;
- }
- return reply->writeUint64(id.value);
- }
case ADD_REGION_SAMPLING_LISTENER: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
Rect samplingArea;
@@ -2041,77 +1580,6 @@
reply->writeInt32(result);
return result;
}
- case GET_DISPLAY_BRIGHTNESS_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to read display token: %d", error);
- return error;
- }
- bool support = false;
- error = getDisplayBrightnessSupport(displayToken, &support);
- reply->writeBool(support);
- return error;
- }
- case SET_DISPLAY_BRIGHTNESS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to read display token: %d", error);
- return error;
- }
- gui::DisplayBrightness brightness;
- error = data.readParcelable(&brightness);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to read brightness: %d", error);
- return error;
- }
- return setDisplayBrightness(displayToken, brightness);
- }
- case ADD_HDR_LAYER_INFO_LISTENER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("addHdrLayerInfoListener: Failed to read display token");
- return error;
- }
- sp<gui::IHdrLayerInfoListener> listener;
- error = data.readNullableStrongBinder(&listener);
- if (error != NO_ERROR) {
- ALOGE("addHdrLayerInfoListener: Failed to read listener");
- return error;
- }
- return addHdrLayerInfoListener(displayToken, listener);
- }
- case REMOVE_HDR_LAYER_INFO_LISTENER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("removeHdrLayerInfoListener: Failed to read display token");
- return error;
- }
- sp<gui::IHdrLayerInfoListener> listener;
- error = data.readNullableStrongBinder(&listener);
- if (error != NO_ERROR) {
- ALOGE("removeHdrLayerInfoListener: Failed to read listener");
- return error;
- }
- return removeHdrLayerInfoListener(displayToken, listener);
- }
- case NOTIFY_POWER_BOOST: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int32_t boostId;
- status_t error = data.readInt32(&boostId);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to read boostId: %d", error);
- return error;
- }
- return notifyPowerBoost(boostId);
- }
case SET_GLOBAL_SHADOW_SETTINGS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index f7cd5c4..502031c 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -16,8 +16,8 @@
#define LOG_TAG "LayerState"
-#include <apex/window.h>
-#include <inttypes.h>
+#include <cinttypes>
+#include <cmath>
#include <android/native_window.h>
#include <binder/Parcel.h>
@@ -25,10 +25,9 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
#include <private/gui/ParcelUtils.h>
+#include <system/window.h>
#include <utils/Errors.h>
-#include <cmath>
-
namespace android {
using gui::FocusRequest;
@@ -679,7 +678,9 @@
if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
- (!privileged || compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT)) {
+ (!privileged ||
+ (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT &&
+ compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) {
ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName,
compatibility, privileged ? "yes" : "no");
return false;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1fb11e0..54b6d6a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -27,13 +27,13 @@
#include <inttypes.h>
+#include <android/gui/DisplayStatInfo.h>
#include <android/native_window.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <utils/NativeHandle.h>
-#include <ui/DisplayStatInfo.h>
#include <ui/DynamicDisplayInfo.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
@@ -45,6 +45,7 @@
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
namespace android {
@@ -125,6 +126,10 @@
return ComposerService::getComposerService();
}
+sp<gui::ISurfaceComposer> Surface::composerServiceAIDL() const {
+ return ComposerServiceAIDL::getComposerService();
+}
+
nsecs_t Surface::now() const {
return systemTime();
}
@@ -174,10 +179,10 @@
status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
ATRACE_CALL();
- DisplayStatInfo stats;
- status_t result = composerService()->getDisplayStats(nullptr, &stats);
- if (result != NO_ERROR) {
- return result;
+ gui::DisplayStatInfo stats;
+ binder::Status status = composerServiceAIDL()->getDisplayStats(nullptr, &stats);
+ if (!status.isOk()) {
+ return status.transactionError();
}
*outRefreshDuration = stats.vsyncPeriod;
@@ -343,20 +348,20 @@
status_t Surface::getWideColorSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
if (display == nullptr) {
return NAME_NOT_FOUND;
}
*supported = false;
- status_t error = composerService()->isWideColorDisplay(display, supported);
- return error;
+ binder::Status status = composerServiceAIDL()->isWideColorDisplay(display, supported);
+ return status.transactionError();
}
status_t Surface::getHdrSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
if (display == nullptr) {
return NAME_NOT_FOUND;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6c197c4..7a63af0 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/gui/DisplayState.h>
#include <android/gui/IWindowInfosListener.h>
#include <utils/Errors.h>
#include <utils/Log.h>
@@ -43,6 +44,7 @@
#include <gui/WindowInfo.h>
#include <private/gui/ParcelUtils.h>
#include <ui/DisplayMode.h>
+#include <ui/DisplayState.h>
#include <ui/DynamicDisplayInfo.h>
#include <private/gui/ComposerService.h>
@@ -206,12 +208,14 @@
}
sp<TransactionCompletedListener> TransactionCompletedListener::sInstance = nullptr;
+static std::mutex sListenerInstanceMutex;
void TransactionCompletedListener::setInstance(const sp<TransactionCompletedListener>& listener) {
sInstance = listener;
}
sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
+ std::lock_guard<std::mutex> lock(sListenerInstanceMutex);
if (sInstance == nullptr) {
sInstance = new TransactionCompletedListener;
}
@@ -1022,32 +1026,59 @@
// ---------------------------------------------------------------------------
sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
- return ComposerService::getComposerService()->createDisplay(displayName,
- secure);
+ sp<IBinder> display = nullptr;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->createDisplay(std::string(
+ displayName.string()),
+ secure, &display);
+ return status.isOk() ? display : nullptr;
}
void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->destroyDisplay(display);
+ ComposerServiceAIDL::getComposerService()->destroyDisplay(display);
}
std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() {
- return ComposerService::getComposerService()->getPhysicalDisplayIds();
+ std::vector<int64_t> displayIds;
+ std::vector<PhysicalDisplayId> physicalDisplayIds;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPhysicalDisplayIds(&displayIds);
+ if (status.isOk()) {
+ physicalDisplayIds.reserve(displayIds.size());
+ for (auto item : displayIds) {
+ auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(item));
+ physicalDisplayIds.push_back(*id);
+ }
+ }
+ return physicalDisplayIds;
}
status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) {
- return ComposerService::getComposerService()->getPrimaryPhysicalDisplayId(id);
+ int64_t displayId;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPrimaryPhysicalDisplayId(&displayId);
+ if (status.isOk()) {
+ *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+ }
+ return status.transactionError();
}
std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
- return ComposerService::getComposerService()->getInternalDisplayId();
+ ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+ return instance.getInternalDisplayId();
}
sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
- return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId);
+ sp<IBinder> display = nullptr;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPhysicalDisplayToken(displayId.value,
+ &display);
+ return status.isOk() ? display : nullptr;
}
sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
- return ComposerService::getComposerService()->getInternalDisplayToken();
+ ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+ return instance.getInternalDisplayToken();
}
void SurfaceComposerClient::Transaction::setAnimationTransaction() {
@@ -2100,7 +2131,16 @@
status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
ui::DisplayState* state) {
- return ComposerService::getComposerService()->getDisplayState(display, state);
+ gui::DisplayState ds;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getDisplayState(display, &ds);
+ if (status.isOk()) {
+ state->layerStack = ui::LayerStack::fromValue(ds.layerStack);
+ state->orientation = static_cast<ui::Rotation>(ds.orientation);
+ state->layerStackSpaceRect =
+ ui::Size(ds.layerStackSpaceRect.width, ds.layerStackSpaceRect.height);
+ }
+ return status.transactionError();
}
status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display,
@@ -2164,7 +2204,9 @@
}
status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) {
- return ComposerService::getComposerService()->getBootDisplayModeSupport(support);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getBootDisplayModeSupport(support);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display,
@@ -2173,7 +2215,9 @@
}
status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->clearBootDisplayMode(display);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->clearBootDisplayMode(display);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) {
@@ -2181,16 +2225,16 @@
}
void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
- ComposerService::getComposerService()->setAutoLowLatencyMode(display, on);
+ ComposerServiceAIDL::getComposerService()->setAutoLowLatencyMode(display, on);
}
void SurfaceComposerClient::setGameContentType(const sp<IBinder>& display, bool on) {
- ComposerService::getComposerService()->setGameContentType(display, on);
+ ComposerServiceAIDL::getComposerService()->setGameContentType(display, on);
}
void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token,
int mode) {
- ComposerService::getComposerService()->setPowerMode(token, mode);
+ ComposerServiceAIDL::getComposerService()->setPowerMode(token, mode);
}
status_t SurfaceComposerClient::getCompositionPreference(
@@ -2251,8 +2295,10 @@
status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display,
bool* outIsWideColorDisplay) {
- return ComposerService::getComposerService()->isWideColorDisplay(display,
- outIsWideColorDisplay);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->isWideColorDisplay(display,
+ outIsWideColorDisplay);
+ return status.transactionError();
}
status_t SurfaceComposerClient::addRegionSamplingListener(
@@ -2289,28 +2335,39 @@
bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) {
bool support = false;
- ComposerService::getComposerService()->getDisplayBrightnessSupport(displayToken, &support);
- return support;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getDisplayBrightnessSupport(displayToken,
+ &support);
+ return status.isOk() ? support : false;
}
status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness) {
- return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->setDisplayBrightness(displayToken,
+ brightness);
+ return status.transactionError();
}
status_t SurfaceComposerClient::addHdrLayerInfoListener(
const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
- return ComposerService::getComposerService()->addHdrLayerInfoListener(displayToken, listener);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->addHdrLayerInfoListener(displayToken,
+ listener);
+ return status.transactionError();
}
status_t SurfaceComposerClient::removeHdrLayerInfoListener(
const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
- return ComposerService::getComposerService()->removeHdrLayerInfoListener(displayToken,
- listener);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->removeHdrLayerInfoListener(displayToken,
+ listener);
+ return status.transactionError();
}
status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) {
- return ComposerService::getComposerService()->notifyPowerBoost(boostId);
+ binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor,
diff --git a/libs/gui/aidl/android/gui/DisplayStatInfo.aidl b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
new file mode 100644
index 0000000..68f3942
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package android.gui;
+
+/** @hide */
+parcelable DisplayStatInfo {
+ long vsyncTime;
+ long vsyncPeriod;
+}
diff --git a/libs/gui/aidl/android/gui/DisplayState.aidl b/libs/gui/aidl/android/gui/DisplayState.aidl
new file mode 100644
index 0000000..9589ab6
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DisplayState.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package android.gui;
+
+import android.gui.Rotation;
+import android.gui.Size;
+
+/** @hide */
+parcelable DisplayState {
+ int layerStack;
+ Rotation orientation = Rotation.Rotation0;
+ Size layerStackSpaceRect;
+}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 07921a5..a9977b0 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -17,11 +17,88 @@
package android.gui;
import android.gui.DisplayCaptureArgs;
+import android.gui.DisplayBrightness;
+import android.gui.DisplayState;
+import android.gui.DisplayStatInfo;
+import android.gui.IHdrLayerInfoListener;
import android.gui.LayerCaptureArgs;
import android.gui.IScreenCaptureListener;
/** @hide */
interface ISurfaceComposer {
+
+ /* create a virtual display
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ @nullable IBinder createDisplay(@utf8InCpp String displayName, boolean secure);
+
+ /* destroy a virtual display
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ void destroyDisplay(IBinder display);
+
+ /* get stable IDs for connected physical displays.
+ */
+ long[] getPhysicalDisplayIds();
+
+ long getPrimaryPhysicalDisplayId();
+
+ /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
+ * DisplayEventReceiver hotplug event.
+ */
+ @nullable IBinder getPhysicalDisplayToken(long displayId);
+
+ /* set display power mode. depending on the mode, it can either trigger
+ * screen on, off or low power mode and wait for it to complete.
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ void setPowerMode(IBinder display, int mode);
+
+ /* returns display statistics for a given display
+ * intended to be used by the media framework to properly schedule
+ * video frames */
+ DisplayStatInfo getDisplayStats(IBinder display);
+
+ /**
+ * Get transactional state of given display.
+ */
+ DisplayState getDisplayState(IBinder display);
+
+ /**
+ * Clears the user-preferred display mode. The device should now boot in system preferred
+ * display mode.
+ */
+ void clearBootDisplayMode(IBinder display);
+
+ /**
+ * Gets whether boot time display mode operations are supported on the device.
+ *
+ * outSupport
+ * An output parameter for whether boot time display mode operations are supported.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
+ boolean getBootDisplayModeSupport();
+
+ /**
+ * Switches Auto Low Latency Mode on/off on the connected display, if it is
+ * available. This should only be called if the display supports Auto Low
+ * Latency Mode as reported in #getDynamicDisplayInfo.
+ * For more information, see the HDMI 2.1 specification.
+ */
+ void setAutoLowLatencyMode(IBinder display, boolean on);
+
+ /**
+ * This will start sending infoframes to the connected display with
+ * ContentType=Game (if on=true). This should only be called if the display
+ * Game Content Type as reported in #getDynamicDisplayInfo.
+ * For more information, see the HDMI 1.4 specification.
+ */
+ void setGameContentType(IBinder display, boolean on);
+
/**
* Capture the specified screen. This requires READ_FRAME_BUFFER
* permission. This function will fail if there is a secure window on
@@ -39,4 +116,67 @@
* is a secure window on screen
*/
void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
+
+ /*
+ * Queries whether the given display is a wide color display.
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ boolean isWideColorDisplay(IBinder token);
+
+ /*
+ * Gets whether brightness operations are supported on a display.
+ *
+ * displayToken
+ * The token of the display.
+ * outSupport
+ * An output parameter for whether brightness operations are supported.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ boolean getDisplayBrightnessSupport(IBinder displayToken);
+
+ /*
+ * Sets the brightness of a display.
+ *
+ * displayToken
+ * The token of the display whose brightness is set.
+ * brightness
+ * The DisplayBrightness info to set on the desired display.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the brightness is invalid, or
+ * INVALID_OPERATION if brightness operations are not supported.
+ */
+ void setDisplayBrightness(IBinder displayToken, in DisplayBrightness brightness);
+
+ /*
+ * Adds a listener that receives HDR layer information. This is used in combination
+ * with setDisplayBrightness to adjust the display brightness depending on factors such
+ * as whether or not HDR is in use.
+ *
+ * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
+ */
+ void addHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+ /*
+ * Removes a listener that was added with addHdrLayerInfoListener.
+ *
+ * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
+ * the listener wasn't registered.
+ *
+ */
+ void removeHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+ /*
+ * Sends a power boost to the composer. This function is asynchronous.
+ *
+ * boostId
+ * boost id according to android::hardware::power::Boost
+ *
+ * Returns NO_ERROR upon success.
+ */
+ void notifyPowerBoost(int boostId);
}
diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/Rect.aidl
new file mode 100644
index 0000000..1b13761
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Rect.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package android.gui;
+
+// copied from libs/arect/include/android/rect.h
+// TODO(b/221473398):
+// use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
+/** @hide */
+parcelable Rect {
+ /// Minimum X coordinate of the rectangle.
+ int left;
+
+ /// Minimum Y coordinate of the rectangle.
+ int top;
+
+ /// Maximum X coordinate of the rectangle.
+ int right;
+
+ /// Maximum Y coordinate of the rectangle.
+ int bottom;
+}
diff --git a/libs/gui/aidl/android/gui/Rotation.aidl b/libs/gui/aidl/android/gui/Rotation.aidl
new file mode 100644
index 0000000..451ff45
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Rotation.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package android.gui;
+
+/** @hide */
+@Backing(type="int")
+enum Rotation {
+ Rotation0 = 0,
+ Rotation90 = 1,
+ Rotation180 = 2,
+ Rotation270 = 3
+}
diff --git a/libs/gui/aidl/android/gui/Size.aidl b/libs/gui/aidl/android/gui/Size.aidl
new file mode 100644
index 0000000..415fa36
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Size.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package android.gui;
+
+/** @hide */
+parcelable Size {
+ int width = -1;
+ int height = -1;
+}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index b11e674..a610e94 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -138,40 +138,6 @@
VsyncSource vsyncSource = eVsyncSourceApp,
EventRegistrationFlags eventRegistration = {}) = 0;
- /* create a virtual display
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual sp<IBinder> createDisplay(const String8& displayName,
- bool secure) = 0;
-
- /* destroy a virtual display
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual void destroyDisplay(const sp<IBinder>& display) = 0;
-
- /* get stable IDs for connected physical displays.
- */
- virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
-
- virtual status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const = 0;
-
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- std::optional<PhysicalDisplayId> getInternalDisplayId() const {
- const auto displayIds = getPhysicalDisplayIds();
- return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
- }
-
- /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
- * DisplayEventReceiver hotplug event.
- */
- virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const = 0;
-
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- sp<IBinder> getInternalDisplayToken() const {
- const auto displayId = getInternalDisplayId();
- return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
- }
-
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual status_t setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state,
@@ -195,24 +161,6 @@
virtual status_t getSupportedFrameTimestamps(
std::vector<FrameEvent>* outSupported) const = 0;
- /* set display power mode. depending on the mode, it can either trigger
- * screen on, off or low power mode and wait for it to complete.
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual void setPowerMode(const sp<IBinder>& display, int mode) = 0;
-
-
- /* returns display statistics for a given display
- * intended to be used by the media framework to properly schedule
- * video frames */
- virtual status_t getDisplayStats(const sp<IBinder>& display,
- DisplayStatInfo* stats) = 0;
-
- /**
- * Get transactional state of given display.
- */
- virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0;
-
/**
* Gets immutable information about given physical display.
*/
@@ -233,40 +181,6 @@
*/
virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0;
- /**
- * Clears the user-preferred display mode. The device should now boot in system preferred
- * display mode.
- */
- virtual status_t clearBootDisplayMode(const sp<IBinder>& display) = 0;
-
- /**
- * Gets whether boot time display mode operations are supported on the device.
- *
- * outSupport
- * An output parameter for whether boot time display mode operations are supported.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the output parameter is invalid.
- */
- virtual status_t getBootDisplayModeSupport(bool* outSupport) const = 0;
-
- /**
- * Switches Auto Low Latency Mode on/off on the connected display, if it is
- * available. This should only be called if the display supports Auto Low
- * Latency Mode as reported in #getDynamicDisplayInfo.
- * For more information, see the HDMI 2.1 specification.
- */
- virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) = 0;
-
- /**
- * This will start sending infoframes to the connected display with
- * ContentType=Game (if on=true). This should only be called if the display
- * Game Content Type as reported in #getDynamicDisplayInfo.
- * For more information, see the HDMI 1.4 specification.
- */
- virtual void setGameContentType(const sp<IBinder>& display, bool on) = 0;
-
/* Clears the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.
@@ -345,13 +259,6 @@
*/
virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
- /*
- * Queries whether the given display is a wide color display.
- * Requires the ACCESS_SURFACE_FLINGER permission.
- */
- virtual status_t isWideColorDisplay(const sp<IBinder>& token,
- bool* outIsWideColorDisplay) const = 0;
-
/* Registers a listener to stream median luma updates from SurfaceFlinger.
*
* The sampling area is bounded by both samplingArea and the given stopLayerHandle
@@ -432,65 +339,6 @@
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) = 0;
- /*
- * Gets whether brightness operations are supported on a display.
- *
- * displayToken
- * The token of the display.
- * outSupport
- * An output parameter for whether brightness operations are supported.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the output parameter is invalid.
- */
- virtual status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const = 0;
-
- /*
- * Sets the brightness of a display.
- *
- * displayToken
- * The token of the display whose brightness is set.
- * brightness
- * The DisplayBrightness info to set on the desired display.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the brightness is invalid, or
- * INVALID_OPERATION if brightness operations are not supported.
- */
- virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) = 0;
-
- /*
- * Adds a listener that receives HDR layer information. This is used in combination
- * with setDisplayBrightness to adjust the display brightness depending on factors such
- * as whether or not HDR is in use.
- *
- * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
- */
- virtual status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) = 0;
- /*
- * Removes a listener that was added with addHdrLayerInfoListener.
- *
- * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
- * the listener wasn't registered.
- *
- */
- virtual status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) = 0;
-
- /*
- * Sends a power boost to the composer. This function is asynchronous.
- *
- * boostId
- * boost id according to android::hardware::power::Boost
- *
- * Returns NO_ERROR upon success.
- */
- virtual status_t notifyPowerBoost(int32_t boostId) = 0;
/*
* Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
@@ -597,9 +445,9 @@
CREATE_CONNECTION,
GET_STATIC_DISPLAY_INFO,
CREATE_DISPLAY_EVENT_CONNECTION,
- CREATE_DISPLAY,
- DESTROY_DISPLAY,
- GET_PHYSICAL_DISPLAY_TOKEN,
+ CREATE_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+ DESTROY_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+ GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now.
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
GET_SUPPORTED_FRAME_TIMESTAMPS,
@@ -610,7 +458,7 @@
CAPTURE_LAYERS, // Deprecated. Autogenerated by .aidl now.
CLEAR_ANIMATION_FRAME_STATS,
GET_ANIMATION_FRAME_STATS,
- SET_POWER_MODE,
+ SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_STATS,
GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
@@ -625,22 +473,22 @@
SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
GET_DISPLAYED_CONTENT_SAMPLE,
GET_PROTECTED_CONTENT_SUPPORT,
- IS_WIDE_COLOR_DISPLAY,
+ IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_NATIVE_PRIMARIES,
- GET_PHYSICAL_DISPLAY_IDS,
+ GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now.
ADD_REGION_SAMPLING_LISTENER,
REMOVE_REGION_SAMPLING_LISTENER,
SET_DESIRED_DISPLAY_MODE_SPECS,
GET_DESIRED_DISPLAY_MODE_SPECS,
- GET_DISPLAY_BRIGHTNESS_SUPPORT,
- SET_DISPLAY_BRIGHTNESS,
- CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now.
- NOTIFY_POWER_BOOST,
+ GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now.
+ SET_DISPLAY_BRIGHTNESS, // Deprecated. Autogenerated by .aidl now.
+ CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now.
+ NOTIFY_POWER_BOOST, // Deprecated. Autogenerated by .aidl now.
SET_GLOBAL_SHADOW_SETTINGS,
GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
- SET_AUTO_LOW_LATENCY_MODE,
- GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
- SET_GAME_CONTENT_TYPE,
+ SET_AUTO_LOW_LATENCY_MODE, // Deprecated. Autogenerated by .aidl now.
+ GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+ SET_GAME_CONTENT_TYPE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
SET_FRAME_RATE,
// Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
@@ -652,18 +500,18 @@
ADD_FPS_LISTENER,
REMOVE_FPS_LISTENER,
OVERRIDE_HDR_TYPES,
- ADD_HDR_LAYER_INFO_LISTENER,
- REMOVE_HDR_LAYER_INFO_LISTENER,
+ ADD_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
+ REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
ON_PULL_ATOM,
ADD_TUNNEL_MODE_ENABLED_LISTENER,
REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
ADD_WINDOW_INFOS_LISTENER,
REMOVE_WINDOW_INFOS_LISTENER,
- GET_PRIMARY_PHYSICAL_DISPLAY_ID,
+ GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_DECORATION_SUPPORT,
- GET_BOOT_DISPLAY_MODE_SUPPORT,
+ GET_BOOT_DISPLAY_MODE_SUPPORT, // Deprecated. Autogenerated by .aidl now.
SET_BOOT_DISPLAY_MODE,
- CLEAR_BOOT_DISPLAY_MODE,
+ CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now.
SET_OVERRIDE_FRAME_RATE,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 5fe308c..ab9ebaa 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -35,6 +35,10 @@
namespace android {
+namespace gui {
+class ISurfaceComposer;
+} // namespace gui
+
class ISurfaceComposer;
/* This is the same as ProducerListener except that onBuffersDiscarded is
@@ -196,6 +200,7 @@
// Virtual for testing.
virtual sp<ISurfaceComposer> composerService() const;
+ virtual sp<gui::ISurfaceComposer> composerServiceAIDL() const;
virtual nsecs_t now() const;
private:
diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h
index fee37ee..9a96976 100644
--- a/libs/gui/include/private/gui/ComposerServiceAIDL.h
+++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h
@@ -50,6 +50,28 @@
// Get a connection to the Composer Service. This will block until
// a connection is established. Returns null if permission is denied.
static sp<gui::ISurfaceComposer> getComposerService();
+
+ // the following two methods are moved from ISurfaceComposer.h
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+ std::vector<int64_t> displayIds;
+ binder::Status status = mComposerService->getPhysicalDisplayIds(&displayIds);
+ return (!status.isOk() || displayIds.empty())
+ ? std::nullopt
+ : DisplayId::fromValue<PhysicalDisplayId>(
+ static_cast<uint64_t>(displayIds.front()));
+ }
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId) return nullptr;
+ sp<IBinder> display;
+ binder::Status status =
+ mComposerService->getPhysicalDisplayToken(static_cast<int64_t>(displayId->value),
+ &display);
+ return status.isOk() ? display : nullptr;
+ }
};
// ---------------------------------------------------------------------------
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index a885e92..065cd7a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -20,6 +20,7 @@
#include <SurfaceFlingerProperties.h>
#include <android/gui/IDisplayEventConnection.h>
+#include <android/gui/ISurfaceComposer.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <binder/ProcessState.h>
#include <configstore/Utils.h>
@@ -260,9 +261,7 @@
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
- const sp<IBinder> display = sf->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
DisplayCaptureArgs captureArgs;
@@ -696,12 +695,6 @@
ISurfaceComposer::VsyncSource, ISurfaceComposer::EventRegistrationFlags) override {
return nullptr;
}
- sp<IBinder> createDisplay(const String8& /*displayName*/,
- bool /*secure*/) override { return nullptr; }
- void destroyDisplay(const sp<IBinder>& /*display */) override {}
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override { return NO_ERROR; }
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
const Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
@@ -740,7 +733,6 @@
return NO_ERROR;
}
- void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override {
return NO_ERROR;
}
@@ -748,24 +740,16 @@
ui::DynamicDisplayInfo*) override {
return NO_ERROR;
}
- status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
- return NO_ERROR;
- }
- status_t getDisplayStats(const sp<IBinder>& /*display*/,
- DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
ui::DisplayPrimaries& /*primaries*/) override {
return NO_ERROR;
}
- status_t setActiveColorMode(const sp<IBinder>& /*display*/,
- ColorMode /*colorMode*/) override { return NO_ERROR; }
- status_t getBootDisplayModeSupport(bool* /*outSupport*/) const override { return NO_ERROR; }
+ status_t setActiveColorMode(const sp<IBinder>& /*display*/, ColorMode /*colorMode*/) override {
+ return NO_ERROR;
+ }
status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override {
return NO_ERROR;
}
- status_t clearBootDisplayMode(const sp<IBinder>& /*display*/) override { return NO_ERROR; }
- void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
- void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
status_t clearAnimationFrameStats() override { return NO_ERROR; }
status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
@@ -812,26 +796,6 @@
status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
- status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
- status_t getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
- bool* /*outSupport*/) const override {
- return NO_ERROR;
- }
- status_t setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
- const gui::DisplayBrightness& /*brightness*/) override {
- return NO_ERROR;
- }
-
- status_t addHdrLayerInfoListener(const sp<IBinder>&,
- const sp<gui::IHdrLayerInfoListener>&) override {
- return NO_ERROR;
- }
-
- status_t removeHdrLayerInfoListener(const sp<IBinder>&,
- const sp<gui::IHdrLayerInfoListener>&) override {
- return NO_ERROR;
- }
-
status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
const sp<IBinder>& /*stopLayerHandle*/,
const sp<IRegionSamplingListener>& /*listener*/) override {
@@ -873,7 +837,6 @@
float* /*outAppRequestRefreshRateMax*/) override {
return NO_ERROR;
};
- status_t notifyPowerBoost(int32_t /*boostId*/) override { return NO_ERROR; }
status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/,
float /*lightPosY*/, float /*lightPosZ*/,
@@ -925,6 +888,114 @@
bool mSupportsPresent{true};
};
+class FakeSurfaceComposerAIDL : public gui::ISurfaceComposer {
+public:
+ ~FakeSurfaceComposerAIDL() override {}
+
+ void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; }
+
+ binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/,
+ sp<IBinder>* /*outDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status destroyDisplay(const sp<IBinder>& /*display*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPhysicalDisplayIds(std::vector<int64_t>* /*outDisplayIds*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPhysicalDisplayToken(int64_t /*displayId*/,
+ sp<IBinder>* /*outDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayStats(const sp<IBinder>& /*display*/,
+ gui::DisplayStatInfo* /*outStatInfo*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayState(const sp<IBinder>& /*display*/,
+ gui::DisplayState* /*outState*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getBootDisplayModeSupport(bool* /*outMode*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureDisplay(const DisplayCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureLayers(const LayerCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/,
+ bool* /*outIsWideColorDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
+ bool* /*outSupport*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
+ const gui::DisplayBrightness& /*brightness*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status addHdrLayerInfoListener(
+ const sp<IBinder>& /*displayToken*/,
+ const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status removeHdrLayerInfoListener(
+ const sp<IBinder>& /*displayToken*/,
+ const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status notifyPowerBoost(int /*boostId*/) override { return binder::Status::ok(); }
+
+protected:
+ IBinder* onAsBinder() override { return nullptr; }
+
+private:
+ bool mSupportsPresent{true};
+};
+
class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
public:
explicit FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap) : mFenceMap(fenceMap) {}
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 0923438..2d1354c 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -39,19 +39,6 @@
// clang-format on
};
-/*
- * Internal extension of compatibility value for ANativeWindow_setFrameRate. */
-enum ANativeWindow_FrameRateCompatibilityInternal {
- /**
- * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
- * to operate at the exact frame rate.
- *
- * This is used internally by the platform and should not be used by apps.
- * @hide
- */
- ANATIVEWINDOW_FRAME_RATE_EXACT = 100,
-};
-
/**
* Prototype of the function that an ANativeWindow implementation would call
* when ANativeWindow_cancelBuffer is called.
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index a319769..a54af1f 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1018,6 +1018,24 @@
return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
}
+/*
+ * Internal extension of ANativeWindow_FrameRateCompatibility.
+ */
+enum {
+ /**
+ * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
+ * to operate at the exact frame rate.
+ *
+ * Keep in sync with Surface.java constant.
+ */
+ ANATIVEWINDOW_FRAME_RATE_EXACT = 100,
+
+ /**
+ * This surface is ignored while choosing the refresh rate.
+ */
+ ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+};
+
static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
int8_t compatibility, int8_t changeFrameRateStrategy) {
return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate,
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 84e84dd..cb92df3 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -27,6 +27,7 @@
"-DEGL_EGLEXT_PROTOTYPES",
],
shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libEGL",
diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp
index 471159f..249fec5 100644
--- a/libs/renderengine/benchmark/Android.bp
+++ b/libs/renderengine/benchmark/Android.bp
@@ -43,6 +43,7 @@
],
shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libjnigraphics",
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 40ba5ad..bf50644 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -16,6 +16,7 @@
#pragma once
+#include <aidl/android/hardware/graphics/composer3/DimmingStage.h>
#include <iosfwd>
#include <math/mat4.h>
@@ -68,6 +69,10 @@
// All layers will be dimmed by (max(layer white points) / targetLuminanceNits).
// If the target luminance is unknown, then no display-level dimming occurs.
float targetLuminanceNits = -1.f;
+
+ // Configures when dimming should be applied for each layer.
+ aidl::android::hardware::graphics::composer3::DimmingStage dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::NONE;
};
static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index df9f8ab..a77a798 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -737,7 +737,9 @@
return roundedRect;
}
-static bool equalsWithinMargin(float expected, float value, float margin) {
+// Arbitrary default margin which should be close enough to zero.
+constexpr float kDefaultMargin = 0.0001f;
+static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) {
LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
return std::abs(expected - value) < margin;
}
@@ -995,10 +997,13 @@
? displayDimmingRatio
: (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
+ const bool dimInLinearSpace = display.dimmingStage !=
+ aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
+
const bool requiresLinearEffect = layer.colorTransform != mat4() ||
(mUseColorManagement &&
needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
- !equalsWithinMargin(1.f, layerDimmingRatio, 0.001f);
+ (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio));
// quick abort from drawing the remaining portion of the layer
if (layer.skipContentDraw ||
@@ -1104,7 +1109,9 @@
.undoPremultipliedAlpha = !item.isOpaque &&
item.usePremultipliedAlpha,
.requiresLinearEffect = requiresLinearEffect,
- .layerDimmingRatio = layerDimmingRatio}));
+ .layerDimmingRatio = dimInLinearSpace
+ ? layerDimmingRatio
+ : 1.f}));
// Turn on dithering when dimming beyond this (arbitrary) threshold...
static constexpr float kDimmingThreshold = 0.2f;
@@ -1177,7 +1184,20 @@
// An A8 buffer will already have the proper color filter attached to
// its paint, including the displayColorTransform as needed.
if (!paint.getColorFilter()) {
- paint.setColorFilter(displayColorTransform);
+ if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) {
+ // If we don't dim in linear space, then when we gamma correct the dimming ratio we
+ // can assume a gamma 2.2 transfer function.
+ static constexpr float kInverseGamma22 = 1.f / 2.2f;
+ const auto gammaCorrectedDimmingRatio =
+ std::pow(layerDimmingRatio, kInverseGamma22);
+ const auto dimmingMatrix =
+ mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio,
+ gammaCorrectedDimmingRatio, 1.f));
+ paint.setColorFilter(SkColorFilters::Matrix(
+ toSkColorMatrix(display.colorTransform * dimmingMatrix)));
+ } else {
+ paint.setColorFilter(displayColorTransform);
+ }
}
if (!roundRectClip.isEmpty()) {
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index d91af1e..e66fee1 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -47,6 +47,7 @@
],
shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libEGL",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 38ae2fd..2493242 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -2405,15 +2405,18 @@
TEST_P(RenderEngineTest, testDimming) {
if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
- return;
+ GTEST_SKIP();
}
+
initializeRenderEngine();
+ const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB_LINEAR;
+
const auto displayRect = Rect(3, 1);
const renderengine::DisplaySettings display{
.physicalDisplay = displayRect,
.clip = displayRect,
- .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .outputDataspace = dataspace,
.targetLuminanceNits = 1000.f,
};
@@ -2432,7 +2435,7 @@
},
},
.alpha = 1.0f,
- .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .sourceDataspace = dataspace,
.whitePointNits = 200.f,
};
@@ -2447,7 +2450,7 @@
},
},
.alpha = 1.0f,
- .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .sourceDataspace = dataspace,
.whitePointNits = 1000.f / 51.f,
};
@@ -2462,7 +2465,7 @@
},
},
.alpha = 1.0f,
- .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .sourceDataspace = dataspace,
// When the white point is not set for a layer, just ignore it and treat it as the same
// as the max layer
.whitePointNits = -1.f,
@@ -2476,6 +2479,84 @@
expectBufferColor(Rect(2, 0, 3, 1), 51, 0, 0, 255, 1);
}
+TEST_P(RenderEngineTest, testDimming_inGammaSpace) {
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ GTEST_SKIP();
+ }
+ initializeRenderEngine();
+
+ const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
+ ui::Dataspace::TRANSFER_GAMMA2_2 |
+ ui::Dataspace::RANGE_FULL);
+
+ const auto displayRect = Rect(3, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .outputDataspace = dataspace,
+ .targetLuminanceNits = 1000.f,
+ .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ };
+
+ const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+ const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+ const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255));
+
+ const renderengine::LayerSettings greenLayer{
+ .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = greenBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ .whitePointNits = 200.f,
+ };
+
+ const renderengine::LayerSettings blueLayer{
+ .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = blueBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ .whitePointNits = 1000.f / 51.f,
+ };
+
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = FloatRect(2.f, 0.f, 3.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = redBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ // When the white point is not set for a layer, just ignore it and treat it as the same
+ // as the max layer
+ .whitePointNits = -1.f,
+ };
+
+ std::vector<renderengine::LayerSettings> layers{greenLayer, blueLayer, redLayer};
+ invokeDraw(display, layers);
+
+ expectBufferColor(Rect(1, 1), 0, 122, 0, 255, 1);
+ expectBufferColor(Rect(1, 0, 2, 1), 0, 0, 42, 255, 1);
+ expectBufferColor(Rect(2, 0, 3, 1), 122, 0, 0, 255, 1);
+}
+
TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
initializeRenderEngine();
if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 22fbf45..831b64d 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -114,7 +114,6 @@
],
shared_libs: [
"libbinder",
- "libgui",
"liblog",
"libui",
"libutils",
diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
index 126a945..4c9d574 100644
--- a/libs/ui/tests/GraphicBufferOverBinder_test.cpp
+++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
@@ -20,9 +20,6 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
-#include <gui/BufferQueue.h>
-#include <gui/IGraphicBufferConsumer.h>
-#include <gui/IGraphicBufferProducer.h>
#include <ui/GraphicBuffer.h>
#include <utils/Log.h>
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6bab349..1cc4589 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -567,6 +567,17 @@
return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy();
}
+bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int32_t uid) {
+ if (windowHandle == nullptr) {
+ return false;
+ }
+ const WindowInfo* windowInfo = windowHandle->getInfo();
+ if (pid == windowInfo->ownerPid && uid == windowInfo->ownerUid) {
+ return true;
+ }
+ return false;
+}
+
} // namespace
// --- InputDispatcher ---
@@ -4990,21 +5001,11 @@
toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission));
}
if (!hasPermission) {
- const sp<IBinder> focusedToken =
- mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
-
- // TODO(b/218541064): if no window is currently focused, then we need to check the last
- // interacted window (within 1 second timeout). We should allow touch mode change
- // if the last interacted window owner's pid/uid match the calling ones.
- if (focusedToken == nullptr) {
- return false;
- }
- const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
- if (windowHandle == nullptr) {
- return false;
- }
- const WindowInfo* windowInfo = windowHandle->getInfo();
- if (pid != windowInfo->ownerPid || uid != windowInfo->ownerUid) {
+ if (!focusedWindowIsOwnedByLocked(pid, uid) &&
+ !recentWindowsAreOwnedByLocked(pid, uid)) {
+ ALOGD("Touch mode switch rejected, caller (pid=%d, uid=%d) doesn't own the focused "
+ "window nor none of the previously interacted window",
+ pid, uid);
return false;
}
}
@@ -5022,6 +5023,24 @@
return true;
}
+bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) {
+ const sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
+ if (focusedToken == nullptr) {
+ return false;
+ }
+ sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
+ return isWindowOwnedBy(windowHandle, pid, uid);
+}
+
+bool InputDispatcher::recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) {
+ return std::find_if(mInteractionConnectionTokens.begin(), mInteractionConnectionTokens.end(),
+ [&](const sp<IBinder>& connectionToken) REQUIRES(mLock) {
+ const sp<WindowInfoHandle> windowHandle =
+ getWindowHandleLocked(connectionToken);
+ return isWindowOwnedBy(windowHandle, pid, uid);
+ }) != mInteractionConnectionTokens.end();
+}
+
void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
if (opacity < 0 || opacity > 1) {
LOG_ALWAYS_FATAL("Maximum obscuring opacity for touch should be >= 0 and <= 1");
@@ -5121,28 +5140,54 @@
return true;
}
+/**
+ * Get the touched foreground window on the given display.
+ * Return null if there are no windows touched on that display, or if more than one foreground
+ * window is being touched.
+ */
+sp<WindowInfoHandle> InputDispatcher::findTouchedForegroundWindowLocked(int32_t displayId) const {
+ auto stateIt = mTouchStatesByDisplay.find(displayId);
+ if (stateIt == mTouchStatesByDisplay.end()) {
+ ALOGI("No touch state on display %" PRId32, displayId);
+ return nullptr;
+ }
+
+ const TouchState& state = stateIt->second;
+ sp<WindowInfoHandle> touchedForegroundWindow;
+ // If multiple foreground windows are touched, return nullptr
+ for (const TouchedWindow& window : state.windows) {
+ if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ if (touchedForegroundWindow != nullptr) {
+ ALOGI("Two or more foreground windows: %s and %s",
+ touchedForegroundWindow->getName().c_str(),
+ window.windowHandle->getName().c_str());
+ return nullptr;
+ }
+ touchedForegroundWindow = window.windowHandle;
+ }
+ }
+ return touchedForegroundWindow;
+}
+
// Binder call
-bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken) {
+bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken, int32_t displayId) {
sp<IBinder> fromToken;
{ // acquire lock
std::scoped_lock _l(mLock);
-
- auto it = std::find_if(mTouchStatesByDisplay.begin(), mTouchStatesByDisplay.end(),
- [](const auto& pair) { return pair.second.windows.size() == 1; });
- if (it == mTouchStatesByDisplay.end()) {
- ALOGW("Cannot transfer touch state because there is no exact window being touched");
- return false;
- }
- const int32_t displayId = it->first;
sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(destChannelToken, displayId);
if (toWindowHandle == nullptr) {
- ALOGW("Could not find window associated with token=%p", destChannelToken.get());
+ ALOGW("Could not find window associated with token=%p on display %" PRId32,
+ destChannelToken.get(), displayId);
return false;
}
- TouchState& state = it->second;
- const TouchedWindow& touchedWindow = state.windows[0];
- fromToken = touchedWindow.windowHandle->getToken();
+ sp<WindowInfoHandle> from = findTouchedForegroundWindowLocked(displayId);
+ if (from == nullptr) {
+ ALOGE("Could not find a source window in %s for %p", __func__, destChannelToken.get());
+ return false;
+ }
+
+ fromToken = from->getToken();
} // release lock
return transferTouchFocus(fromToken, destChannelToken);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 3c79c98..f3dac19 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -125,7 +125,7 @@
bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
bool isDragDrop = false) override;
- bool transferTouch(const sp<IBinder>& destChannelToken) override;
+ bool transferTouch(const sp<IBinder>& destChannelToken, int32_t displayId) override;
base::Result<std::unique_ptr<InputChannel>> createInputChannel(
const std::string& name) override;
@@ -245,6 +245,9 @@
std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked(
int32_t displayId, int32_t x, int32_t y, bool isStylus) const REQUIRES(mLock);
+ sp<android::gui::WindowInfoHandle> findTouchedForegroundWindowLocked(int32_t displayId) const
+ REQUIRES(mLock);
+
sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
REQUIRES(mLock);
@@ -433,7 +436,8 @@
// Dispatcher state at time of last ANR.
std::string mLastAnrState GUARDED_BY(mLock);
- // The connection tokens of the channels that the user last interacted, for debugging
+ // The connection tokens of the channels that the user last interacted (used for debugging and
+ // when switching touch mode state).
std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> mInteractionConnectionTokens
GUARDED_BY(mLock);
void updateInteractionTokensLocked(const EventEntry& entry,
@@ -677,6 +681,10 @@
void traceOutboundQueueLength(const Connection& connection);
void traceWaitQueueLength(const Connection& connection);
+ // Check window ownership
+ bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
+ bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
+
sp<InputReporterInterface> mReporter;
};
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 67e1b6f..d7bc5fb 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -155,7 +155,7 @@
*
* Return true on success, false if there was no on-going touch.
*/
- virtual bool transferTouch(const sp<IBinder>& destChannelToken) = 0;
+ virtual bool transferTouch(const sp<IBinder>& destChannelToken, int32_t displayId) = 0;
/**
* Sets focus on the specified window.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 8641287..a167271 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -56,6 +56,8 @@
static constexpr int32_t POINTER_1_DOWN =
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t POINTER_2_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
@@ -2245,6 +2247,53 @@
}
/**
+ * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
+ * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
+ * ACTION_OUTSIDE event is sent per gesture.
+ */
+TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
+ // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ window->setWatchOutsideTouch(true);
+ window->setFrame(Rect{0, 0, 100, 100});
+ sp<FakeWindowHandle> secondWindow =
+ new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ secondWindow->setFrame(Rect{100, 100, 200, 200});
+ sp<FakeWindowHandle> thirdWindow =
+ new FakeWindowHandle(application, mDispatcher, "Third Window", ADISPLAY_ID_DEFAULT);
+ thirdWindow->setFrame(Rect{200, 200, 300, 300});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, secondWindow, thirdWindow}}});
+
+ // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {PointF{-10, -10}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+ secondWindow->assertNoEvents();
+
+ // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
+ // Now, `window` should get ACTION_OUTSIDE.
+ motionArgs = generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {PointF{-10, -10}, PointF{105, 105}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionOutside();
+ secondWindow->consumeMotionDown();
+ thirdWindow->assertNoEvents();
+
+ // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
+ // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
+ motionArgs = generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+ secondWindow->consumeMotionMove();
+ thirdWindow->consumeMotionDown();
+}
+
+/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
* InputDispatcher works in the display space, so its coordinate system is relative to the display
@@ -2427,6 +2476,63 @@
secondWindow->consumeMotionUp();
}
+/**
+ * When 'transferTouch' API is invoked, dispatcher needs to find the "best" window to take touch
+ * from. When we have spy windows, there are several windows to choose from: either spy, or the
+ * 'real' (non-spy) window. Always prefer the 'real' window because that's what would be most
+ * natural to the user.
+ * In this test, we are sending a pointer to both spy window and first window. We then try to
+ * transfer touch to the second window. The dispatcher should identify the first window as the
+ * one that should lose the gesture, and therefore the action should be to move the gesture from
+ * the first window to the second.
+ * The main goal here is to test the behaviour of 'transferTouch' API, but it's still valid to test
+ * the other API, as well.
+ */
+TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ // Create a couple of windows + a spy window
+ sp<FakeWindowHandle> spyWindow =
+ new FakeWindowHandle(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ spyWindow->setTrustedOverlay(true);
+ spyWindow->setSpy(true);
+ sp<FakeWindowHandle> firstWindow =
+ new FakeWindowHandle(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> secondWindow =
+ new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+
+ // Add the windows to the dispatcher
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, firstWindow, secondWindow}}});
+
+ // Send down to the first window
+ NotifyMotionArgs downMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&downMotionArgs);
+ // Only the first window and spy should get the down event
+ spyWindow->consumeMotionDown();
+ firstWindow->consumeMotionDown();
+
+ // Transfer touch to the second window. Non-spy window should be preferred over the spy window
+ // if f === 'transferTouch'.
+ TransferFunction f = GetParam();
+ const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
+ ASSERT_TRUE(success);
+ // The first window gets cancel and the second gets down
+ firstWindow->consumeMotionCancel();
+ secondWindow->consumeMotionDown();
+
+ // Send up event to the second window
+ NotifyMotionArgs upMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&upMotionArgs);
+ // The first window gets no events and the second+spy get up
+ firstWindow->assertNoEvents();
+ spyWindow->consumeMotionUp();
+ secondWindow->consumeMotionUp();
+}
+
TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
@@ -2496,7 +2602,8 @@
::testing::Values(
[&](const std::unique_ptr<InputDispatcher>& dispatcher,
sp<IBinder> /*ignored*/, sp<IBinder> destChannelToken) {
- return dispatcher->transferTouch(destChannelToken);
+ return dispatcher->transferTouch(destChannelToken,
+ ADISPLAY_ID_DEFAULT);
},
[&](const std::unique_ptr<InputDispatcher>& dispatcher,
sp<IBinder> from, sp<IBinder> to) {
@@ -2604,7 +2711,8 @@
secondWindow->consumeMotionDown();
// Transfer touch focus to the second window
- const bool transferred = mDispatcher->transferTouch(secondWindow->getToken());
+ const bool transferred =
+ mDispatcher->transferTouch(secondWindow->getToken(), ADISPLAY_ID_DEFAULT);
// The 'transferTouch' call should not succeed, because there are 2 touched windows
ASSERT_FALSE(transferred);
firstWindow->assertNoEvents();
@@ -2728,7 +2836,7 @@
firstWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID);
// Transfer touch focus
- ASSERT_TRUE(mDispatcher->transferTouch(secondWindowInSecondary->getToken()));
+ ASSERT_TRUE(mDispatcher->transferTouch(secondWindowInSecondary->getToken(), SECOND_DISPLAY_ID));
// The first window gets cancel.
firstWindowInPrimary->consumeMotionCancel(SECOND_DISPLAY_ID);
@@ -6336,8 +6444,11 @@
mWindow->consumeFocusEvent(true);
// Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
- mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
- INJECTOR_UID, /* hasPermission */ true);
+ if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
+ INJECTOR_UID, /* hasPermission */ true)) {
+ mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
+ mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
+ }
}
void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
@@ -6382,6 +6493,23 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
+ // Interact with the window first.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+
+ // Then remove focus.
+ mWindow->setFocusable(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
+
+ // Assert that caller can switch touch mode by owning one of the last interacted window.
+ const WindowInfo& windowInfo = *mWindow->getInfo();
+ ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
+ windowInfo.ownerPid, windowInfo.ownerUid,
+ /* hasPermission= */ false));
+}
+
class InputDispatcherSpyWindowTest : public InputDispatcherTest {
public:
sp<FakeWindowHandle> createSpy() {
@@ -6666,9 +6794,7 @@
// Third finger goes down outside all windows, so injection should fail.
const MotionEvent thirdFingerDownEvent =
- MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
- (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- AINPUT_SOURCE_TOUCHSCREEN)
+ MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
.displayId(ADISPLAY_ID_DEFAULT)
.eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
.pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 516c3ef..11a9e19 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -42,6 +42,10 @@
"libtonemap",
"libtrace_proto",
"libaidlcommonsupport",
+ "libprocessgroup",
+ "libcgrouprc",
+ "libjsoncpp",
+ "libcgrouprc_format",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
@@ -69,6 +73,7 @@
"src/DisplayColorProfile.cpp",
"src/DisplaySurface.cpp",
"src/DumpHelpers.cpp",
+ "src/HwcAsyncWorker.cpp",
"src/HwcBufferCache.cpp",
"src/LayerFECompositionState.cpp",
"src/Output.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index c553fce..ca86f4c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -72,6 +72,9 @@
virtual void resizeBuffers(const ui::Size&) = 0;
virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
+
+ // Returns true if the render surface supports client composition prediction.
+ virtual bool supportsCompositionStrategyPrediction() const;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index d8644a4..5846e67 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -35,6 +35,7 @@
#include <utils/Vector.h>
#include <ui/DisplayIdentification.h>
+#include "DisplayHardware/HWComposer.h"
namespace android {
@@ -54,6 +55,7 @@
namespace impl {
struct OutputCompositionState;
+struct GpuCompositionResult;
} // namespace impl
/**
@@ -262,6 +264,9 @@
// Latches the front-end layer state for each output layer
virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0;
+ // Enables predicting composition strategy to run client composition earlier
+ virtual void setPredictCompositionStrategy(bool) = 0;
+
protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
@@ -278,13 +283,22 @@
virtual void updateColorProfile(const CompositionRefreshArgs&) = 0;
virtual void beginFrame() = 0;
virtual void prepareFrame() = 0;
+
+ using GpuCompositionResult = compositionengine::impl::GpuCompositionResult;
+ // Runs prepare frame in another thread while running client composition using
+ // the previous frame's composition strategy.
+ virtual GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) = 0;
virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0;
- virtual void finishFrame(const CompositionRefreshArgs&) = 0;
+ virtual void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) = 0;
virtual std::optional<base::unique_fd> composeSurfaces(
- const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) = 0;
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&) = 0;
virtual void postFramebuffer() = 0;
virtual void renderCachedSets(const CompositionRefreshArgs&) = 0;
- virtual void chooseCompositionStrategy() = 0;
+ virtual bool chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*) = 0;
+ virtual void applyCompositionStrategy(
+ const std::optional<android::HWComposer::DeviceRequestedChanges>& changes) = 0;
virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
virtual std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
@@ -295,6 +309,7 @@
std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
virtual void setExpensiveRenderingExpected(bool enabled) = 0;
virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
+ virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index daee83b..9ee779c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -100,6 +100,9 @@
// Debugging - gets the page flip count for the RenderSurface
virtual std::uint32_t getPageFlipCount() const = 0;
+
+ // Returns true if the render surface supports client composition prediction.
+ virtual bool supportsCompositionStrategyPrediction() const = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index e12d1b4..61a0e6a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -22,6 +22,7 @@
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/GpuCompositionResult.h>
#include <compositionengine/impl/Output.h>
#include <ui/PixelFormat.h>
#include <ui/Size.h>
@@ -51,11 +52,16 @@
void setReleasedLayers(const CompositionRefreshArgs&) override;
void setColorTransform(const CompositionRefreshArgs&) override;
void setColorProfile(const ColorProfile&) override;
- void chooseCompositionStrategy() override;
+
+ void beginFrame() override;
+ using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges;
+ bool chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*) override;
+ void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
void setExpensiveRenderingExpected(bool) override;
- void finishFrame(const CompositionRefreshArgs&) override;
+ void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override;
// compositionengine::Display overrides
DisplayId getId() const override;
@@ -72,12 +78,11 @@
using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests;
using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests;
using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty;
- virtual bool anyLayersRequireClientComposition() const;
virtual bool allLayersRequireClientComposition() const;
virtual void applyChangedTypesToLayers(const ChangedTypes&);
virtual void applyDisplayRequests(const DisplayRequests&);
virtual void applyLayerRequestsToLayers(const LayerRequests&);
- virtual void applyClientTargetRequests(const ClientTargetProperty&, float brightness);
+ virtual void applyClientTargetRequests(const ClientTargetProperty&);
// Internal
virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h
new file mode 100644
index 0000000..2b1f50f
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android::compositionengine::impl {
+
+struct GpuCompositionResult {
+ // Composition ready fence.
+ base::unique_fd fence{};
+
+ // Buffer to be used for gpu composition. If gpu composition was not successful,
+ // then we want to reuse the buffer instead of dequeuing another buffer.
+ std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
+
+ bool bufferAvailable() const { return buffer != nullptr; };
+};
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h
new file mode 100644
index 0000000..0c7da6c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <future>
+#include <optional>
+#include <thread>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine::impl {
+
+// HWC Validate call may take multiple milliseconds to complete and can account for
+// a signification amount of time in the display hotpath. This helper class allows
+// us to run the hwc validate function on a real time thread if we can predict what
+// the composition strategy will be and if composition includes client composition.
+// While the hwc validate runs, client composition is kicked off with the prediction.
+// When the worker returns with a value, the composition continues if the prediction
+// was successful otherwise the client composition is re-executed.
+//
+// Note: This does not alter the sequence between HWC and surfaceflinger.
+class HwcAsyncWorker final {
+public:
+ HwcAsyncWorker();
+ ~HwcAsyncWorker();
+ // Runs the provided function which calls hwc validate and returns the requested
+ // device changes as a future.
+ std::future<bool> send(std::function<bool()>);
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mCv GUARDED_BY(mMutex);
+ bool mDone GUARDED_BY(mMutex) = false;
+ bool mTaskRequested GUARDED_BY(mMutex) = false;
+ std::packaged_task<bool()> mTask GUARDED_BY(mMutex);
+ std::thread mThread;
+ void run();
+};
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index a7a8e97..0feb9f7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -17,9 +17,13 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/Output.h>
#include <compositionengine/impl/ClientCompositionRequestCache.h>
+#include <compositionengine/impl/GpuCompositionResult.h>
+#include <compositionengine/impl/HwcAsyncWorker.h>
#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/impl/planner/Planner.h>
#include <renderengine/DisplaySettings.h>
#include <renderengine/LayerSettings.h>
@@ -92,25 +96,42 @@
void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
void beginFrame() override;
void prepareFrame() override;
+ GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) override;
void devOptRepaintFlash(const CompositionRefreshArgs&) override;
- void finishFrame(const CompositionRefreshArgs&) override;
- std::optional<base::unique_fd> composeSurfaces(
- const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) override;
+ void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override;
+ std::optional<base::unique_fd> composeSurfaces(const Region&,
+ const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>,
+ base::unique_fd&) override;
void postFramebuffer() override;
void renderCachedSets(const CompositionRefreshArgs&) override;
void cacheClientCompositionRequests(uint32_t) override;
+ bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override;
+ void setPredictCompositionStrategy(bool) override;
// Testing
const ReleasedLayers& getReleasedLayersForTest() const;
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
bool plannerEnabled() const { return mPlanner != nullptr; }
+ virtual bool anyLayersRequireClientComposition() const;
+ virtual void updateProtectedContentState();
+ virtual bool dequeueRenderBuffer(base::unique_fd*,
+ std::shared_ptr<renderengine::ExternalTexture>*);
+ virtual std::future<bool> chooseCompositionStrategyAsync(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*);
+ virtual void resetCompositionStrategy();
protected:
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
std::optional<size_t> findCurrentOutputLayerForLayer(
const sp<compositionengine::LayerFE>&) const;
- void chooseCompositionStrategy() override;
+ using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges;
+ bool chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*) override {
+ return true;
+ };
+ void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override{};
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
@@ -131,6 +152,7 @@
private:
void dirtyEntireOutput();
compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const;
+ void finishPrepareFrame();
ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
compositionengine::Output::ColorProfile pickColorProfile(
const compositionengine::CompositionRefreshArgs&) const;
@@ -144,6 +166,7 @@
OutputLayer* mLayerRequestingBackgroundBlur = nullptr;
std::unique_ptr<ClientCompositionRequestCache> mClientCompositionRequestCache;
std::unique_ptr<planner::Planner> mPlanner;
+ std::unique_ptr<HwcAsyncWorker> mHwComposerAsyncWorker;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 66dd825..5fa0d67 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include "aidl/android/hardware/graphics/composer3/DimmingStage.h"
#include <math/mat4.h>
#include <ui/FenceTime.h>
@@ -37,6 +38,8 @@
#include <ui/Region.h>
#include <ui/Transform.h>
+#include "DisplayHardware/HWComposer.h"
+
namespace android {
namespace compositionengine::impl {
@@ -114,6 +117,10 @@
// Current target dataspace
ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
+ std::optional<android::HWComposer::DeviceRequestedChanges> previousDeviceRequestedChanges{};
+
+ bool previousDeviceRequestedSuccess = false;
+
// The earliest time to send the present command to the HAL
std::chrono::steady_clock::time_point earliestPresentTime;
@@ -133,10 +140,26 @@
// Brightness of the client target, normalized to display brightness
float clientTargetBrightness{1.f};
+ // Stage in which the client target should apply dimming
+ aidl::android::hardware::graphics::composer3::DimmingStage clientTargetDimmingStage{
+ aidl::android::hardware::graphics::composer3::DimmingStage::NONE};
+
// Display brightness that will take effect this frame.
// This is slightly distinct from nits, in that nits cannot be passed to hw composer.
std::optional<float> displayBrightness = std::nullopt;
+ enum class CompositionStrategyPredictionState : uint32_t {
+ // Composition strategy prediction did not run for this frame.
+ DISABLED = 0,
+ // Composition strategy predicted successfully for this frame.
+ SUCCESS = 1,
+ // Composition strategy prediction failed for this frame.
+ FAIL = 2,
+ };
+
+ CompositionStrategyPredictionState strategyPrediction =
+ CompositionStrategyPredictionState::DISABLED;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index a8a5380..e4cb113 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -63,6 +63,7 @@
void queueBuffer(base::unique_fd readyFence) override;
void onPresentDisplayCompleted() override;
void flip() override;
+ bool supportsCompositionStrategyPrediction() const override;
// Debugging
void dump(std::string& result) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index d90cc90..72e6f3b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -41,6 +41,7 @@
MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
+ MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index b68b95d..fa86076 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -22,6 +22,7 @@
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/GpuCompositionResult.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <gmock/gmock.h>
@@ -99,16 +100,24 @@
MOCK_METHOD0(beginFrame, void());
MOCK_METHOD0(prepareFrame, void());
- MOCK_METHOD0(chooseCompositionStrategy, void());
+ MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&));
+ MOCK_METHOD1(chooseCompositionStrategy,
+ bool(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD1(chooseCompositionStrategyAsync,
+ std::future<bool>(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD1(applyCompositionStrategy,
+ void(const std::optional<android::HWComposer::DeviceRequestedChanges>&));
MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD2(finishFrame,
+ void(const compositionengine::CompositionRefreshArgs&, GpuCompositionResult&&));
- MOCK_METHOD2(composeSurfaces,
+ MOCK_METHOD4(composeSurfaces,
std::optional<base::unique_fd>(
const Region&,
- const compositionengine::CompositionRefreshArgs& refreshArgs));
+ const compositionengine::CompositionRefreshArgs& refreshArgs,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
MOCK_CONST_METHOD0(getSkipColorTransform, bool());
MOCK_METHOD0(postFramebuffer, void());
@@ -121,6 +130,8 @@
void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t));
+ MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
+ MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index fe858c2..e12aebb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -45,6 +45,7 @@
MOCK_METHOD0(flip, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
+ MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 2165e1d..f545886 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -207,16 +207,8 @@
setReleasedLayers(std::move(releasedLayers));
}
-void Display::chooseCompositionStrategy() {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
- if (mIsDisconnected) {
- return;
- }
-
- // Default to the base settings -- client composition only.
- Output::chooseCompositionStrategy();
+void Display::beginFrame() {
+ Output::beginFrame();
// If we don't have a HWC display, then we are done.
const auto halDisplayId = HalDisplayId::tryCast(mId);
@@ -224,43 +216,66 @@
return;
}
- // Get any composition changes requested by the HWC device, and apply them.
- std::optional<android::HWComposer::DeviceRequestedChanges> changes;
auto& hwc = getCompositionEngine().getHwComposer();
if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
physicalDisplayId && getState().displayBrightness) {
const status_t result =
hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
+ getState().displayBrightnessNits,
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = false})
.get();
ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
getName().c_str(), result, strerror(-result));
}
+ // Clear out the display brightness now that it's been communicated to composer.
+ editState().displayBrightness.reset();
+}
+bool Display::chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (mIsDisconnected) {
+ return false;
+ }
+
+ // If we don't have a HWC display, then we are done.
+ const auto halDisplayId = HalDisplayId::tryCast(mId);
+ if (!halDisplayId) {
+ return false;
+ }
+
+ // Get any composition changes requested by the HWC device, and apply them.
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ auto& hwc = getCompositionEngine().getHwComposer();
if (status_t result =
hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
getState().earliestPresentTime,
getState().previousPresentFence,
- getState().expectedPresentTime, &changes);
+ getState().expectedPresentTime, outChanges);
result != NO_ERROR) {
ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
strerror(-result));
- return;
+ return false;
}
+
+ return true;
+}
+
+void Display::applyCompositionStrategy(const std::optional<DeviceRequestedChanges>& changes) {
if (changes) {
applyChangedTypesToLayers(changes->changedTypes);
applyDisplayRequests(changes->displayRequests);
applyLayerRequestsToLayers(changes->layerRequests);
- applyClientTargetRequests(changes->clientTargetProperty, changes->clientTargetBrightness);
+ applyClientTargetRequests(changes->clientTargetProperty);
}
// Determine what type of composition we are doing from the final state
auto& state = editState();
state.usesClientComposition = anyLayersRequireClientComposition();
state.usesDeviceComposition = !allLayersRequireClientComposition();
- // Clear out the display brightness now that it's been communicated to composer.
- state.displayBrightness.reset();
}
bool Display::getSkipColorTransform() const {
@@ -273,12 +288,6 @@
return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM);
}
-bool Display::anyLayersRequireClientComposition() const {
- const auto layers = getOutputLayersOrderedByZ();
- return std::any_of(layers.begin(), layers.end(),
- [](const auto& layer) { return layer->requiresClientComposition(); });
-}
-
bool Display::allLayersRequireClientComposition() const {
const auto layers = getOutputLayersOrderedByZ();
return std::all_of(layers.begin(), layers.end(),
@@ -327,16 +336,19 @@
}
}
-void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty,
- float brightness) {
- if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
+void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty) {
+ if (static_cast<ui::Dataspace>(clientTargetProperty.clientTargetProperty.dataspace) ==
+ ui::Dataspace::UNKNOWN) {
return;
}
- editState().dataspace = clientTargetProperty.dataspace;
- editState().clientTargetBrightness = brightness;
- getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
- getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
+ editState().dataspace =
+ static_cast<ui::Dataspace>(clientTargetProperty.clientTargetProperty.dataspace);
+ editState().clientTargetBrightness = clientTargetProperty.brightness;
+ editState().clientTargetDimmingStage = clientTargetProperty.dimmingStage;
+ getRenderSurface()->setBufferDataspace(editState().dataspace);
+ getRenderSurface()->setBufferPixelFormat(
+ static_cast<ui::PixelFormat>(clientTargetProperty.clientTargetProperty.pixelFormat));
}
compositionengine::Output::FrameFences Display::presentAndGetFrameFences() {
@@ -376,7 +388,8 @@
}
}
-void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ GpuCompositionResult&& result) {
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
@@ -386,7 +399,7 @@
return;
}
- impl::Output::finishFrame(refreshArgs);
+ impl::Output::finishFrame(refreshArgs, std::move(result));
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
index db6d4f2..28900af 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
@@ -20,4 +20,8 @@
DisplaySurface::~DisplaySurface() = default;
+bool DisplaySurface::supportsCompositionStrategyPrediction() const {
+ return true;
+}
+
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
new file mode 100644
index 0000000..6086f0b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include <compositionengine/impl/HwcAsyncWorker.h>
+#include <processgroup/sched_policy.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <system/thread_defs.h>
+
+#include <android-base/thread_annotations.h>
+#include <cutils/sched_policy.h>
+
+namespace android::compositionengine::impl {
+
+HwcAsyncWorker::HwcAsyncWorker() {
+ mThread = std::thread(&HwcAsyncWorker::run, this);
+ pthread_setname_np(mThread.native_handle(), "HwcAsyncWorker");
+}
+
+HwcAsyncWorker::~HwcAsyncWorker() {
+ {
+ std::scoped_lock lock(mMutex);
+ mDone = true;
+ mCv.notify_all();
+ }
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+std::future<bool> HwcAsyncWorker::send(std::function<bool()> task) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ android::base::ScopedLockAssertion assumeLock(mMutex);
+ mTask = std::packaged_task<bool()>([task = std::move(task)]() { return task(); });
+ mTaskRequested = true;
+ mCv.notify_one();
+ return mTask.get_future();
+}
+
+void HwcAsyncWorker::run() {
+ set_sched_policy(0, SP_FOREGROUND);
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ sched_setscheduler(gettid(), SCHED_FIFO, ¶m);
+
+ std::unique_lock<std::mutex> lock(mMutex);
+ android::base::ScopedLockAssertion assumeLock(mMutex);
+ while (!mDone) {
+ mCv.wait(lock);
+ if (mTaskRequested && mTask.valid()) {
+ mTask();
+ mTaskRequested = false;
+ }
+ }
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 4e67a63..e99b70f 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -22,6 +22,7 @@
#include <compositionengine/LayerFE.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/HwcAsyncWorker.h>
#include <compositionengine/impl/Output.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayer.h>
@@ -57,7 +58,8 @@
Output::~Output() = default;
namespace impl {
-
+using CompositionStrategyPredictionState =
+ OutputCompositionState::CompositionStrategyPredictionState;
namespace {
template <typename T>
@@ -434,9 +436,17 @@
writeCompositionState(refreshArgs);
setColorTransform(refreshArgs);
beginFrame();
- prepareFrame();
+
+ GpuCompositionResult result;
+ const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs);
+ if (predictCompositionStrategy) {
+ result = prepareFrameAsync(refreshArgs);
+ } else {
+ prepareFrame();
+ }
+
devOptRepaintFlash(refreshArgs);
- finishFrame(refreshArgs);
+ finishFrame(refreshArgs, std::move(result));
postFramebuffer();
renderCachedSets(refreshArgs);
}
@@ -953,19 +963,74 @@
ATRACE_CALL();
ALOGV(__FUNCTION__);
- const auto& outputState = getState();
+ auto& outputState = editState();
if (!outputState.isEnabled) {
return;
}
- chooseCompositionStrategy();
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ bool success = chooseCompositionStrategy(&changes);
+ resetCompositionStrategy();
+ outputState.strategyPrediction = CompositionStrategyPredictionState::DISABLED;
+ outputState.previousDeviceRequestedChanges = changes;
+ outputState.previousDeviceRequestedSuccess = success;
+ if (success) {
+ applyCompositionStrategy(changes);
+ }
+ finishPrepareFrame();
+}
- if (mPlanner) {
- mPlanner->reportFinalPlan(getOutputLayersOrderedByZ());
+std::future<bool> Output::chooseCompositionStrategyAsync(
+ std::optional<android::HWComposer::DeviceRequestedChanges>* changes) {
+ return mHwComposerAsyncWorker->send(
+ [&, changes]() { return chooseCompositionStrategy(changes); });
+}
+
+GpuCompositionResult Output::prepareFrameAsync(const CompositionRefreshArgs& refreshArgs) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+ auto& state = editState();
+ const auto& previousChanges = state.previousDeviceRequestedChanges;
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ resetCompositionStrategy();
+ auto hwcResult = chooseCompositionStrategyAsync(&changes);
+ if (state.previousDeviceRequestedSuccess) {
+ applyCompositionStrategy(previousChanges);
+ }
+ finishPrepareFrame();
+
+ base::unique_fd bufferFence;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ updateProtectedContentState();
+ const bool dequeueSucceeded = dequeueRenderBuffer(&bufferFence, &buffer);
+ GpuCompositionResult compositionResult;
+ if (dequeueSucceeded) {
+ std::optional<base::unique_fd> optFd =
+ composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence);
+ if (optFd) {
+ compositionResult.fence = std::move(*optFd);
+ }
}
- mRenderSurface->prepareFrame(outputState.usesClientComposition,
- outputState.usesDeviceComposition);
+ auto chooseCompositionSuccess = hwcResult.get();
+ const bool predictionSucceeded = dequeueSucceeded && changes == previousChanges;
+ state.strategyPrediction = predictionSucceeded ? CompositionStrategyPredictionState::SUCCESS
+ : CompositionStrategyPredictionState::FAIL;
+ if (!predictionSucceeded) {
+ ATRACE_NAME("CompositionStrategyPredictionMiss");
+ resetCompositionStrategy();
+ if (chooseCompositionSuccess) {
+ applyCompositionStrategy(changes);
+ }
+ finishPrepareFrame();
+ // Track the dequeued buffer to reuse so we don't need to dequeue another one.
+ compositionResult.buffer = buffer;
+ } else {
+ ATRACE_NAME("CompositionStrategyPredictionHit");
+ }
+ state.previousDeviceRequestedChanges = std::move(changes);
+ state.previousDeviceRequestedSuccess = chooseCompositionSuccess;
+ return compositionResult;
}
void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) {
@@ -975,7 +1040,11 @@
if (getState().isEnabled) {
if (const auto dirtyRegion = getDirtyRegion(); !dirtyRegion.isEmpty()) {
- static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs));
+ base::unique_fd bufferFence;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ updateProtectedContentState();
+ dequeueRenderBuffer(&bufferFence, &buffer);
+ static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs, buffer, bufferFence));
mRenderSurface->queueBuffer(base::unique_fd());
}
}
@@ -987,17 +1056,33 @@
prepareFrame();
}
-void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositionResult&& result) {
ATRACE_CALL();
ALOGV(__FUNCTION__);
-
- if (!getState().isEnabled) {
+ const auto& outputState = getState();
+ if (!outputState.isEnabled) {
return;
}
- // Repaint the framebuffer (if needed), getting the optional fence for when
- // the composition completes.
- auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs);
+ std::optional<base::unique_fd> optReadyFence;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ base::unique_fd bufferFence;
+ if (outputState.strategyPrediction == CompositionStrategyPredictionState::SUCCESS) {
+ optReadyFence = std::move(result.fence);
+ } else {
+ if (result.bufferAvailable()) {
+ buffer = std::move(result.buffer);
+ bufferFence = std::move(result.fence);
+ } else {
+ updateProtectedContentState();
+ if (!dequeueRenderBuffer(&bufferFence, &buffer)) {
+ return;
+ }
+ }
+ // Repaint the framebuffer (if needed), getting the optional fence for when
+ // the composition completes.
+ optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence);
+ }
if (!optReadyFence) {
return;
}
@@ -1006,16 +1091,8 @@
mRenderSurface->queueBuffer(std::move(*optReadyFence));
}
-std::optional<base::unique_fd> Output::composeSurfaces(
- const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs) {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
+void Output::updateProtectedContentState() {
const auto& outputState = getState();
- OutputCompositionState& outputCompositionState = editState();
- const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
- outputState.usesClientComposition};
-
auto& renderEngine = getCompositionEngine().getRenderEngine();
const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
@@ -1037,29 +1114,48 @@
} else if (!outputState.isSecure && renderEngine.isProtected()) {
renderEngine.useProtectedContext(false);
}
+}
- base::unique_fd fd;
-
- std::shared_ptr<renderengine::ExternalTexture> tex;
+bool Output::dequeueRenderBuffer(base::unique_fd* bufferFence,
+ std::shared_ptr<renderengine::ExternalTexture>* tex) {
+ const auto& outputState = getState();
// If we aren't doing client composition on this output, but do have a
// flipClientTarget request for this frame on this output, we still need to
// dequeue a buffer.
- if (hasClientComposition || outputState.flipClientTarget) {
- tex = mRenderSurface->dequeueBuffer(&fd);
- if (tex == nullptr) {
+ if (outputState.usesClientComposition || outputState.flipClientTarget) {
+ *tex = mRenderSurface->dequeueBuffer(bufferFence);
+ if (*tex == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
mName.c_str());
- return {};
+ return false;
}
}
+ return true;
+}
+std::optional<base::unique_fd> Output::composeSurfaces(
+ const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs,
+ std::shared_ptr<renderengine::ExternalTexture> tex, base::unique_fd& fd) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ const auto& outputState = getState();
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ outputState.usesClientComposition};
if (!hasClientComposition) {
setExpensiveRenderingExpected(false);
return base::unique_fd();
}
+ if (tex == nullptr) {
+ ALOGW("Buffer not valid for display [%s], bailing out of "
+ "client composition for this frame",
+ mName.c_str());
+ return {};
+ }
+
ALOGV("hasClientComposition");
renderengine::DisplaySettings clientCompositionDisplay;
@@ -1080,6 +1176,7 @@
mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
clientCompositionDisplay.targetLuminanceNits =
outputState.clientTargetBrightness * outputState.displayBrightnessNits;
+ clientCompositionDisplay.dimmingStage = outputState.clientTargetDimmingStage;
// Compute the global color transform matrix.
clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
@@ -1087,6 +1184,8 @@
outputState.usesDeviceComposition || getSkipColorTransform();
// Generate the client composition requests for the layers on this output.
+ auto& renderEngine = getCompositionEngine().getRenderEngine();
+ const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
std::vector<LayerFE*> clientCompositionLayersFE;
std::vector<LayerFE::LayerSettings> clientCompositionLayers =
generateClientCompositionRequests(supportsProtectedContent,
@@ -1094,16 +1193,19 @@
clientCompositionLayersFE);
appendRegionFlashRequests(debugRegion, clientCompositionLayers);
+ OutputCompositionState& outputCompositionState = editState();
// Check if the client composition requests were rendered into the provided graphic buffer. If
// so, we can reuse the buffer and avoid client composition.
if (mClientCompositionRequestCache) {
if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(),
clientCompositionDisplay,
clientCompositionLayers)) {
+ ATRACE_NAME("ClientCompositionCacheHit");
outputCompositionState.reusedClientComposition = true;
setExpensiveRenderingExpected(false);
return base::unique_fd();
}
+ ATRACE_NAME("ClientCompositionCacheMiss");
mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
clientCompositionLayers);
}
@@ -1355,7 +1457,7 @@
outputState.dirtyRegion.set(outputState.displaySpace.getBoundsAsRect());
}
-void Output::chooseCompositionStrategy() {
+void Output::resetCompositionStrategy() {
// The base output implementation can only do client composition
auto& outputState = editState();
outputState.usesClientComposition = true;
@@ -1375,5 +1477,63 @@
return result;
}
+void Output::setPredictCompositionStrategy(bool predict) {
+ if (predict) {
+ mHwComposerAsyncWorker = std::make_unique<HwcAsyncWorker>();
+ } else {
+ mHwComposerAsyncWorker.reset(nullptr);
+ }
+}
+
+bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
+ if (!getState().isEnabled || !mHwComposerAsyncWorker) {
+ ALOGV("canPredictCompositionStrategy disabled");
+ return false;
+ }
+
+ if (!getState().previousDeviceRequestedChanges) {
+ ALOGV("canPredictCompositionStrategy previous changes not available");
+ return false;
+ }
+
+ if (!mRenderSurface->supportsCompositionStrategyPrediction()) {
+ ALOGV("canPredictCompositionStrategy surface does not support");
+ return false;
+ }
+
+ if (refreshArgs.devOptFlashDirtyRegionsDelay) {
+ ALOGV("canPredictCompositionStrategy devOptFlashDirtyRegionsDelay");
+ return false;
+ }
+
+ // If no layer uses clientComposition, then don't predict composition strategy
+ // because we have less work to do in parallel.
+ if (!anyLayersRequireClientComposition()) {
+ ALOGV("canPredictCompositionStrategy no layer uses clientComposition");
+ return false;
+ }
+
+ if (!refreshArgs.updatingOutputGeometryThisFrame) {
+ return true;
+ }
+
+ ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame");
+ return false;
+}
+
+bool Output::anyLayersRequireClientComposition() const {
+ const auto layers = getOutputLayersOrderedByZ();
+ return std::any_of(layers.begin(), layers.end(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+void Output::finishPrepareFrame() {
+ const auto& state = getState();
+ if (mPlanner) {
+ mPlanner->reportFinalPlan(getOutputLayersOrderedByZ());
+ }
+ mRenderSurface->prepareFrame(state.usesClientComposition, state.usesDeviceComposition);
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 482250a..7188281 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -18,6 +18,19 @@
#include <compositionengine/impl/OutputCompositionState.h>
namespace android::compositionengine::impl {
+using CompositionStrategyPredictionState =
+ OutputCompositionState::CompositionStrategyPredictionState;
+
+std::string toString(CompositionStrategyPredictionState state) {
+ switch (state) {
+ case CompositionStrategyPredictionState::DISABLED:
+ return "Disabled";
+ case CompositionStrategyPredictionState::SUCCESS:
+ return "Success";
+ case CompositionStrategyPredictionState::FAIL:
+ return "Fail";
+ }
+}
void OutputCompositionState::dump(std::string& out) const {
out.append(" ");
@@ -56,6 +69,7 @@
dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
dumpVal(out, "displayBrightness", displayBrightness);
+ dumpVal(out, "compositionStrategyPredictionState", toString(strategyPrediction));
out.append("\n");
}
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 12c2c8e..5a3af7b 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -289,5 +289,9 @@
return mTexture;
}
+bool RenderSurface::supportsCompositionStrategyPrediction() const {
+ return mDisplaySurface->supportsCompositionStrategyPrediction();
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 5cc0f97..0e5a7b6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -30,7 +30,9 @@
#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
+
#include <ui/Rect.h>
#include <ui/StaticDisplayInfo.h>
@@ -43,6 +45,7 @@
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::Composition;
+using aidl::android::hardware::graphics::composer3::DimmingStage;
namespace android::compositionengine {
namespace {
@@ -113,8 +116,9 @@
return mCompositionEngine;
};
+ size_t getOutputLayerCount() const override { return 1u; }
+
// Mock implementation overrides
- MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex,
compositionengine::OutputLayer*(size_t));
MOCK_METHOD2(ensureOutputLayer,
@@ -197,6 +201,26 @@
std::shared_ptr<Display> mDisplay =
createPartialMockDisplay<Display>(mCompositionEngine,
getDisplayCreationArgsForPhysicalDisplay());
+
+ android::HWComposer::DeviceRequestedChanges mDeviceRequestedChanges{
+ {{nullptr, Composition::CLIENT}},
+ hal::DisplayRequest::FLIP_CLIENT_TARGET,
+ {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
+ {DEFAULT_DISPLAY_ID.value,
+ {aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888,
+ aidl::android::hardware::graphics::common::Dataspace::UNKNOWN},
+ -1.f,
+ DimmingStage::NONE},
+ };
+
+ void chooseCompositionStrategy(Display* display) {
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ bool success = display->chooseCompositionStrategy(&changes);
+ display->resetCompositionStrategy();
+ if (success) {
+ display->applyCompositionStrategy(changes);
+ }
+ }
};
struct FullDisplayImplTestCommon : public DisplayTestCommon {
@@ -213,6 +237,11 @@
std::unique_ptr<compositionengine::OutputLayer>(mLayer2.outputLayer));
mDisplay->injectOutputLayerForTest(
std::unique_ptr<compositionengine::OutputLayer>(mLayer3.outputLayer));
+ mResultWithBuffer.buffer = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
}
Layer mLayer1;
@@ -221,6 +250,8 @@
StrictMock<HWC2::mock::Layer> hwc2LayerUnknown;
std::shared_ptr<Display> mDisplay =
createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
+ impl::GpuCompositionResult mResultWithBuffer;
+ impl::GpuCompositionResult mResultWithoutBuffer;
};
/*
@@ -553,7 +584,7 @@
createPartialMockDisplay<Display>(mCompositionEngine, args);
EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId()));
- gpuDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(gpuDisplay.get());
auto& state = gpuDisplay->getState();
EXPECT_TRUE(state.usesClientComposition);
@@ -566,11 +597,12 @@
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _, _))
.WillOnce(Return(INVALID_OPERATION));
- mDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(mDisplay.get());
auto& state = mDisplay->getState();
EXPECT_TRUE(state.usesClientComposition);
EXPECT_FALSE(state.usesDeviceComposition);
+ EXPECT_FALSE(state.previousDeviceRequestedChanges.has_value());
}
TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
@@ -587,10 +619,16 @@
EXPECT_CALL(mHwComposer,
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(Return(NO_ERROR));
+ .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges),
+ Return(NO_ERROR)));
+ EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
+ .Times(1);
+ EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
+ EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
+ .Times(1);
EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
- mDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(mDisplay.get());
auto& state = mDisplay->getState();
EXPECT_FALSE(state.usesClientComposition);
@@ -602,42 +640,25 @@
// values, use a Sequence to control the matching so the values are returned in a known
// order.
constexpr float kDisplayBrightness = 0.5f;
- Sequence s;
- EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
- .InSequence(s)
- .WillOnce(Return(true));
- EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
- .InSequence(s)
- .WillOnce(Return(false));
+ constexpr float kDisplayBrightnessNits = 200.f;
EXPECT_CALL(mHwComposer,
- setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness,
+ setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness, kDisplayBrightnessNits,
Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately =
false}))
.WillOnce(Return(ByMove(ftl::yield<status_t>(NO_ERROR))));
- EXPECT_CALL(mHwComposer,
- getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
-
mDisplay->setNextBrightness(kDisplayBrightness);
- mDisplay->chooseCompositionStrategy();
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ EXPECT_CALL(*renderSurface, beginFrame(_)).Times(1);
+ mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+ mDisplay->editState().displayBrightnessNits = kDisplayBrightnessNits;
+ mDisplay->beginFrame();
auto& state = mDisplay->getState();
- EXPECT_FALSE(state.usesClientComposition);
- EXPECT_TRUE(state.usesDeviceComposition);
EXPECT_FALSE(state.displayBrightness.has_value());
}
TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
- android::HWComposer::DeviceRequestedChanges changes{
- {{nullptr, Composition::CLIENT}},
- hal::DisplayRequest::FLIP_CLIENT_TARGET,
- {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
- {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
- -1.f,
- };
-
// Since two calls are made to anyLayersRequireClientComposition with different return
// values, use a Sequence to control the matching so the values are returned in a known
// order.
@@ -651,13 +672,15 @@
EXPECT_CALL(mHwComposer,
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(DoAll(SetArgPointee<5>(changes), Return(NO_ERROR)));
- EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1);
- EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1);
- EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1);
+ .WillOnce(DoAll(SetArgPointee<5>(mDeviceRequestedChanges), Return(NO_ERROR)));
+ EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
+ .Times(1);
+ EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
+ EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
+ .Times(1);
EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
- mDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(mDisplay.get());
auto& state = mDisplay->getState();
EXPECT_FALSE(state.usesClientComposition);
@@ -822,23 +845,37 @@
using DisplayApplyClientTargetRequests = DisplayWithLayersTestCommon;
TEST_F(DisplayApplyLayerRequestsToLayersTest, applyClientTargetRequests) {
- Display::ClientTargetProperty clientTargetProperty = {
- .pixelFormat = hal::PixelFormat::RGB_565,
- .dataspace = hal::Dataspace::STANDARD_BT470M,
- };
-
static constexpr float kWhitePointNits = 800.f;
+ Display::ClientTargetProperty clientTargetProperty = {
+ .clientTargetProperty =
+ {
+ .pixelFormat =
+ aidl::android::hardware::graphics::common::PixelFormat::RGB_565,
+ .dataspace = aidl::android::hardware::graphics::common::Dataspace::
+ STANDARD_BT470M,
+ },
+ .brightness = kWhitePointNits,
+ .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ };
+
mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
- EXPECT_CALL(*renderSurface, setBufferPixelFormat(clientTargetProperty.pixelFormat));
- EXPECT_CALL(*renderSurface, setBufferDataspace(clientTargetProperty.dataspace));
- mDisplay->applyClientTargetRequests(clientTargetProperty, kWhitePointNits);
+ EXPECT_CALL(*renderSurface,
+ setBufferPixelFormat(static_cast<ui::PixelFormat>(
+ clientTargetProperty.clientTargetProperty.pixelFormat)));
+ EXPECT_CALL(*renderSurface,
+ setBufferDataspace(static_cast<ui::Dataspace>(
+ clientTargetProperty.clientTargetProperty.dataspace)));
+ mDisplay->applyClientTargetRequests(clientTargetProperty);
auto& state = mDisplay->getState();
- EXPECT_EQ(clientTargetProperty.dataspace, state.dataspace);
+ EXPECT_EQ(clientTargetProperty.clientTargetProperty.dataspace,
+ static_cast<aidl::android::hardware::graphics::common::Dataspace>(state.dataspace));
EXPECT_EQ(kWhitePointNits, state.clientTargetBrightness);
+ EXPECT_EQ(aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ state.clientTargetDimmingStage);
}
/*
@@ -921,7 +958,7 @@
mDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
mDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- mDisplay->finishFrame({});
+ mDisplay->finishFrame({}, std::move(mResultWithBuffer));
}
TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) {
@@ -939,7 +976,7 @@
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- gpuDisplay->finishFrame({});
+ gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer));
}
TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) {
@@ -956,7 +993,7 @@
gpuDisplay->editState().usesClientComposition = false;
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
- gpuDisplay->finishFrame({});
+ gpuDisplay->finishFrame({}, std::move(mResultWithBuffer));
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index af013b0..ff2aa15 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -84,8 +84,8 @@
MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t));
MOCK_METHOD4(getDisplayedContentSample,
status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
- MOCK_METHOD3(setDisplayBrightness,
- std::future<status_t>(PhysicalDisplayId, float,
+ MOCK_METHOD4(setDisplayBrightness,
+ std::future<status_t>(PhysicalDisplayId, float, float,
const Hwc2::Composer::DisplayBrightnessOptions&));
MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index dd3858b..31a89af 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -28,6 +28,7 @@
#include <gtest/gtest.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/impl/ExternalTexture.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -73,6 +74,9 @@
constexpr OutputColorSetting kVendorSpecifiedOutputColorSetting =
static_cast<OutputColorSetting>(0x100);
+using CompositionStrategyPredictionState = android::compositionengine::impl::
+ OutputCompositionState::CompositionStrategyPredictionState;
+
struct OutputPartialMockBase : public impl::Output {
// compositionengine::Output overrides
const OutputCompositionState& getState() const override { return mState; }
@@ -989,7 +993,9 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_METHOD0(chooseCompositionStrategy, void());
+ MOCK_METHOD1(chooseCompositionStrategy,
+ bool(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD0(resetCompositionStrategy, void());
};
OutputPrepareFrameTest() {
@@ -1015,11 +1021,13 @@
mOutput.editState().usesClientComposition = false;
mOutput.editState().usesDeviceComposition = true;
- EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
+ EXPECT_CALL(mOutput, chooseCompositionStrategy(_)).WillRepeatedly(Return(true));
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(1);
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
mOutput.prepareFrame();
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED);
}
// Note: Use OutputTest and not OutputPrepareFrameTest, so the real
@@ -1035,6 +1043,148 @@
EXPECT_TRUE(mOutput->getState().usesClientComposition);
EXPECT_FALSE(mOutput->getState().usesDeviceComposition);
+ EXPECT_EQ(mOutput->getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED);
+}
+
+struct OutputPrepareFrameAsyncTest : public testing::Test {
+ struct OutputPartialMock : public OutputPartialMockBase {
+ // Sets up the helper functions called by the function under test to use
+ // mock implementations.
+ MOCK_METHOD1(chooseCompositionStrategy,
+ bool(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD0(updateProtectedContentState, void());
+ MOCK_METHOD2(dequeueRenderBuffer,
+ bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
+ MOCK_METHOD1(
+ chooseCompositionStrategyAsync,
+ std::future<bool>(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD4(composeSurfaces,
+ std::optional<base::unique_fd>(
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
+ MOCK_METHOD0(resetCompositionStrategy, void());
+ };
+
+ OutputPrepareFrameAsyncTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ }
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<OutputPartialMock> mOutput;
+ CompositionRefreshArgs mRefreshArgs;
+};
+
+TEST_F(OutputPrepareFrameAsyncTest, delegatesToChooseCompositionStrategyAndRenderSurface) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ std::promise<bool> p;
+ p.set_value(true);
+
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(1);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(1);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_))
+ .WillOnce(DoAll(SetArgPointee<0>(mOutput.editState().previousDeviceRequestedChanges),
+ Return(ByMove(p.get_future()))));
+ EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::SUCCESS);
+ EXPECT_FALSE(result.bufferAvailable());
+}
+
+TEST_F(OutputPrepareFrameAsyncTest, skipCompositionOnDequeueFailure) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ std::promise<bool> p;
+ p.set_value(true);
+
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(false));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_))
+ .WillOnce(DoAll(SetArgPointee<0>(mOutput.editState().previousDeviceRequestedChanges),
+ Return(ByMove(p.get_future()))));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
+ EXPECT_FALSE(result.bufferAvailable());
+}
+
+// Tests that in the event of hwc error when choosing composition strategy, we would fall back
+// client composition
+TEST_F(OutputPrepareFrameAsyncTest, chooseCompositionStrategyFailureCallsPrepareFrame) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ std::promise<bool> p;
+ p.set_value(false);
+ std::shared_ptr<renderengine::ExternalTexture> tex =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 2);
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true)));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)).WillOnce([&] {
+ return p.get_future();
+ });
+ EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
+ EXPECT_TRUE(result.bufferAvailable());
+}
+
+TEST_F(OutputPrepareFrameAsyncTest, predictionMiss) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ auto newDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ newDeviceRequestedChanges->displayRequests = static_cast<hal::DisplayRequest>(0);
+ std::promise<bool> p;
+ p.set_value(false);
+ std::shared_ptr<renderengine::ExternalTexture> tex =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 2);
+
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true)));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)).WillOnce([&] {
+ return p.get_future();
+ });
+ EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
+ EXPECT_TRUE(result.bufferAvailable());
}
/*
@@ -1820,10 +1970,14 @@
MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD0(beginFrame, void());
MOCK_METHOD0(prepareFrame, void());
+ MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&));
MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD2(finishFrame,
+ void(const compositionengine::CompositionRefreshArgs&,
+ GpuCompositionResult&&));
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD1(renderCachedSets, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
};
StrictMock<OutputPartialMock> mOutput;
@@ -1839,9 +1993,30 @@
EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
EXPECT_CALL(mOutput, beginFrame());
+ EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(false));
EXPECT_CALL(mOutput, prepareFrame());
EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
- EXPECT_CALL(mOutput, finishFrame(Ref(args)));
+ EXPECT_CALL(mOutput, finishFrame(Ref(args), _));
+ EXPECT_CALL(mOutput, postFramebuffer());
+ EXPECT_CALL(mOutput, renderCachedSets(Ref(args)));
+
+ mOutput.present(args);
+}
+
+TEST_F(OutputPresentTest, predictingCompositionStrategyInvokesPrepareFrameAsync) {
+ CompositionRefreshArgs args;
+
+ InSequence seq;
+ EXPECT_CALL(mOutput, updateColorProfile(Ref(args)));
+ EXPECT_CALL(mOutput, updateCompositionState(Ref(args)));
+ EXPECT_CALL(mOutput, planComposition());
+ EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
+ EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
+ EXPECT_CALL(mOutput, beginFrame());
+ EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, prepareFrameAsync(Ref(args)));
+ EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
+ EXPECT_CALL(mOutput, finishFrame(Ref(args), _));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, renderCachedSets(Ref(args)));
@@ -2739,11 +2914,15 @@
// Sets up the helper functions called by the function under test to use
// mock implementations.
MOCK_METHOD(Region, getDirtyRegion, (), (const));
- MOCK_METHOD2(composeSurfaces,
+ MOCK_METHOD4(composeSurfaces,
std::optional<base::unique_fd>(
- const Region&, const compositionengine::CompositionRefreshArgs&));
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD0(prepareFrame, void());
+ MOCK_METHOD0(updateProtectedContentState, void());
+ MOCK_METHOD2(dequeueRenderBuffer,
+ bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
};
OutputDevOptRepaintFlashTest() {
@@ -2800,7 +2979,9 @@
InSequence seq;
EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kNotEmptyRegion));
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs)));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs), _, _));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, prepareFrame());
@@ -2816,10 +2997,14 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_METHOD2(composeSurfaces,
+ MOCK_METHOD4(composeSurfaces,
std::optional<base::unique_fd>(
- const Region&, const compositionengine::CompositionRefreshArgs&));
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
MOCK_METHOD0(postFramebuffer, void());
+ MOCK_METHOD0(updateProtectedContentState, void());
+ MOCK_METHOD2(dequeueRenderBuffer,
+ bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
};
OutputFinishFrameTest() {
@@ -2837,27 +3022,62 @@
TEST_F(OutputFinishFrameTest, ifNotEnabledDoesNothing) {
mOutput.mState.isEnabled = false;
- mOutput.finishFrame(mRefreshArgs);
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
}
TEST_F(OutputFinishFrameTest, takesEarlyOutifComposeSurfacesReturnsNoFence) {
mOutput.mState.isEnabled = true;
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _));
- InSequence seq;
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _));
-
- mOutput.finishFrame(mRefreshArgs);
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
}
TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) {
mOutput.mState.isEnabled = true;
InSequence seq;
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _))
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _))
.WillOnce(Return(ByMove(base::unique_fd())));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
- mOutput.finishFrame(mRefreshArgs);
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
+}
+
+TEST_F(OutputFinishFrameTest, predictionSucceeded) {
+ mOutput.mState.isEnabled = true;
+ mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::SUCCESS;
+ InSequence seq;
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
+}
+
+TEST_F(OutputFinishFrameTest, predictionFailedAndBufferIsReused) {
+ mOutput.mState.isEnabled = true;
+ mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::FAIL;
+
+ InSequence seq;
+
+ impl::GpuCompositionResult result;
+ result.buffer =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 2);
+
+ EXPECT_CALL(mOutput,
+ composeSurfaces(RegionEq(Region::INVALID_REGION), _, result.buffer,
+ Eq(ByRef(result.fence))))
+ .WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
}
/*
@@ -3104,8 +3324,15 @@
struct ExecuteState : public CallOrderStateMachineHelper<TestType, ExecuteState> {
auto execute() {
- getInstance()->mReadyFence =
- getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fence;
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+ const bool success =
+ getInstance()->mOutput.dequeueRenderBuffer(&fence, &externalTexture);
+ if (success) {
+ getInstance()->mReadyFence =
+ getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs,
+ externalTexture, fence);
+ }
return nextState<FenceCheckState>();
}
};
@@ -3475,6 +3702,15 @@
: public CallOrderStateMachineHelper<TestType, OutputWithDisplayBrightnessNits> {
auto withDisplayBrightnessNits(float nits) {
getInstance()->mOutput.mState.displayBrightnessNits = nits;
+ return nextState<OutputWithDimmingStage>();
+ }
+ };
+
+ struct OutputWithDimmingStage
+ : public CallOrderStateMachineHelper<TestType, OutputWithDimmingStage> {
+ auto withDimmingStage(
+ aidl::android::hardware::graphics::composer3::DimmingStage dimmingStage) {
+ getInstance()->mOutput.mState.clientTargetDimmingStage = dimmingStage;
return nextState<SkipColorTransformState>();
}
};
@@ -3507,16 +3743,20 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3526,16 +3766,45 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
+ .andIfSkipColorTransform(false)
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
+ .execute()
+ .expectAFenceWasReturned();
+}
+
+TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings,
+ forHdrMixedCompositionWithDimmingStage) {
+ verify().ifMixedCompositionIs(true)
+ .andIfUsesHdr(true)
+ .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(
+ aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF)
+
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDisplayLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
.orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage = aidl::android::hardware::graphics::
+ composer3::DimmingStage::GAMMA_OETF})
.execute()
.expectAFenceWasReturned();
}
@@ -3544,16 +3813,21 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(false)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3562,16 +3836,21 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = false,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = false,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3580,16 +3859,21 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = false,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = false,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3599,16 +3883,21 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
.andIfSkipColorTransform(true)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3666,7 +3955,11 @@
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
EXPECT_CALL(mRenderEngine, useProtectedContext(false));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotSupportIt) {
@@ -3674,7 +3967,11 @@
mLayer2.mLayerFEState.hasProtectedContent = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) {
@@ -3686,7 +3983,11 @@
EXPECT_CALL(mRenderEngine, useProtectedContext(false));
EXPECT_CALL(*mRenderSurface, setProtected(false));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) {
@@ -3708,7 +4009,11 @@
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) {
@@ -3718,7 +4023,11 @@
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRenderEngine) {
@@ -3729,7 +4038,11 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
EXPECT_CALL(mRenderEngine, useProtectedContext(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderEngine) {
@@ -3740,7 +4053,11 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
EXPECT_CALL(*mRenderSurface, setProtected(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) {
@@ -3751,7 +4068,11 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true));
EXPECT_CALL(mRenderEngine, useProtectedContext(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
struct OutputComposeSurfacesTest_SetsExpensiveRendering : public OutputComposeSurfacesTest {
@@ -3781,7 +4102,11 @@
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur
@@ -3816,7 +4141,12 @@
mOutput.writeCompositionState(mRefreshArgs);
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
- mOutput.composeSurfaces(kDebugRegion, mRefreshArgs);
+
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotExpensive) {
@@ -3826,7 +4156,12 @@
mOutput.writeCompositionState(mRefreshArgs);
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(0);
- mOutput.composeSurfaces(kDebugRegion, mRefreshArgs);
+
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd);
}
/*
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 9116fd3..3651c8b 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -91,6 +91,7 @@
static_cast<uint32_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers));
}
+ mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy);
mCompositionDisplay->createDisplayColorProfile(
compositionengine::DisplayColorProfileCreationArgsBuilder()
.setHasWideColorGamut(args.hasWideColorGamut)
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 297a776..79dcd15 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -41,6 +41,7 @@
using aidl::android::hardware::graphics::composer3::BnComposerCallback;
using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
using aidl::android::hardware::graphics::composer3::PowerMode;
using aidl::android::hardware::graphics::composer3::VirtualDisplay;
@@ -155,15 +156,6 @@
.refreshTimeNanos = x.refreshTimeNanos,
};
}
-
-template <>
-IComposerClient::ClientTargetProperty translate(ClientTargetProperty x) {
- return IComposerClient::ClientTargetProperty{
- .pixelFormat = translate<PixelFormat>(x.pixelFormat),
- .dataspace = translate<Dataspace>(x.dataspace),
- };
-}
-
mat4 makeMat4(std::vector<float> in) {
return mat4(static_cast<const float*>(in.data()));
}
@@ -935,9 +927,9 @@
return Error::NONE;
}
-Error AidlComposer::setDisplayBrightness(Display display, float brightness,
+Error AidlComposer::setDisplayBrightness(Display display, float brightness, float brightnessNits,
const DisplayBrightnessOptions& options) {
- mWriter.setDisplayBrightness(translate<int64_t>(display), brightness);
+ mWriter.setDisplayBrightness(translate<int64_t>(display), brightness, brightnessNits);
if (options.applyImmediately) {
return execute();
@@ -1082,12 +1074,8 @@
}
Error AidlComposer::getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) {
- const auto property = mReader.takeClientTargetProperty(translate<int64_t>(display));
- *outClientTargetProperty =
- translate<IComposerClient::ClientTargetProperty>(property.clientTargetProperty);
- *outBrightness = property.brightness;
+ Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) {
+ *outClientTargetProperty = mReader.takeClientTargetProperty(translate<int64_t>(display));
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 28ff167..18d2242 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -183,7 +183,7 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness,
+ Error setDisplayBrightness(Display display, float brightness, float brightnessNits,
const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
@@ -208,9 +208,10 @@
bool mandatory, const std::vector<uint8_t>& value) override;
V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
- Error getClientTargetProperty(Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) override;
+ Error getClientTargetProperty(
+ Display display,
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) override;
// AIDL Composer HAL
Error setLayerBrightness(Display display, Layer layer, float brightness) override;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 2dc0830..d266d94 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -33,6 +33,7 @@
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -236,7 +237,7 @@
return applyImmediately == other.applyImmediately;
}
};
- virtual Error setDisplayBrightness(Display display, float brightness,
+ virtual Error setDisplayBrightness(Display display, float brightness, float brightnessNits,
const DisplayBrightnessOptions& options) = 0;
// Composer HAL 2.4
@@ -264,8 +265,7 @@
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
virtual Error getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) = 0;
+ Display display, V3_0::ClientTargetPropertyWithBrightness* outClientTargetProperty) = 0;
// AIDL Composer
virtual Error setLayerBrightness(Display display, Layer layer, float brightness) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c0432bf..adf4be3 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -544,9 +544,11 @@
}
std::future<Error> Display::setDisplayBrightness(
- float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) {
- return ftl::defer([composer = &mComposer, id = mId, brightness, options] {
- const auto intError = composer->setDisplayBrightness(id, brightness, options);
+ float brightness, float brightnessNits,
+ const Hwc2::Composer::DisplayBrightnessOptions& options) {
+ return ftl::defer([composer = &mComposer, id = mId, brightness, brightnessNits, options] {
+ const auto intError =
+ composer->setDisplayBrightness(id, brightness, brightnessNits, options);
return static_cast<Error>(intError);
});
}
@@ -585,10 +587,10 @@
return static_cast<Error>(intError);
}
-Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty,
- float* outWhitePointNits) {
- const auto error =
- mComposer.getClientTargetProperty(mId, outClientTargetProperty, outWhitePointNits);
+Error Display::getClientTargetProperty(
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) {
+ const auto error = mComposer.getClientTargetProperty(mId, outClientTargetProperty);
return static_cast<Error>(error);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index a805566..cca20bd 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -39,6 +39,7 @@
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -147,7 +148,8 @@
android::sp<android::Fence>* outPresentFence,
uint32_t* state) = 0;
[[nodiscard]] virtual std::future<hal::Error> setDisplayBrightness(
- float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
+ float brightness, float brightnessNits,
+ const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
[[nodiscard]] virtual hal::Error setActiveConfigWithConstraints(
hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
@@ -160,7 +162,8 @@
std::vector<hal::ContentType>*) const = 0;
[[nodiscard]] virtual hal::Error setContentType(hal::ContentType) = 0;
[[nodiscard]] virtual hal::Error getClientTargetProperty(
- hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0;
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) = 0;
[[nodiscard]] virtual hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) = 0;
@@ -227,7 +230,8 @@
android::sp<android::Fence>* outPresentFence,
uint32_t* state) override;
std::future<hal::Error> setDisplayBrightness(
- float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) override;
+ float brightness, float brightnessNits,
+ const Hwc2::Composer::DisplayBrightnessOptions& options) override;
hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) override;
@@ -238,8 +242,9 @@
hal::Error getSupportedContentTypes(
std::vector<hal::ContentType>* outSupportedContentTypes) const override;
hal::Error setContentType(hal::ContentType) override;
- hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty,
- float* outWhitePointNits) override;
+ hal::Error getClientTargetProperty(
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) override;
hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) override;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 459291a..670233a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -376,6 +376,11 @@
}
ATRACE_CALL();
+ if (displayData.powerMode == hal::PowerMode::DOZE && enabled == hal::Vsync::ENABLE) {
+ ALOGV("%s will not enable vsync for display %s due to power mode %s", __FUNCTION__,
+ to_string(displayId).c_str(), to_string(displayData.powerMode).c_str());
+ return;
+ }
auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
RETURN_IF_HWC_ERROR(error, displayId);
@@ -479,12 +484,11 @@
RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
- float brightness = 1.f;
- error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &brightness);
+ error = hwcDisplay->getClientTargetProperty(&clientTargetProperty);
outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
std::move(layerRequests),
- std::move(clientTargetProperty), brightness});
+ std::move(clientTargetProperty)});
error = hwcDisplay->acceptChanges();
RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
@@ -553,6 +557,7 @@
setVsyncEnabled(displayId, hal::Vsync::DISABLE);
}
+ mDisplayData[displayId].powerMode = mode;
const auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
switch (mode) {
@@ -722,12 +727,12 @@
}
std::future<status_t> HWComposer::setDisplayBrightness(
- PhysicalDisplayId displayId, float brightness,
+ PhysicalDisplayId displayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions& options) {
RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX));
auto& display = mDisplayData[displayId].hwcDisplay;
- return ftl::chain(display->setDisplayBrightness(brightness, options))
+ return ftl::chain(display->setDisplayBrightness(brightness, brightnessNits, options))
.then([displayId](hal::Error error) -> status_t {
if (error == hal::Error::UNSUPPORTED) {
RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 0e15a7c..8d67589 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -45,6 +45,7 @@
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -78,7 +79,8 @@
using ChangedTypes =
std::unordered_map<HWC2::Layer*,
aidl::android::hardware::graphics::composer3::Composition>;
- using ClientTargetProperty = hal::ClientTargetProperty;
+ using ClientTargetProperty =
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
using DisplayRequests = hal::DisplayRequest;
using LayerRequests = std::unordered_map<HWC2::Layer*, hal::LayerRequest>;
@@ -86,7 +88,6 @@
DisplayRequests displayRequests;
LayerRequests layerRequests;
ClientTargetProperty clientTargetProperty;
- float clientTargetBrightness;
};
struct HWCDisplayMode {
@@ -195,7 +196,7 @@
// Sets the brightness of a display.
virtual std::future<status_t> setDisplayBrightness(
- PhysicalDisplayId, float brightness,
+ PhysicalDisplayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
// Events handling ---------------------------------------------------------
@@ -279,6 +280,13 @@
virtual Hwc2::AidlTransform getPhysicalDisplayOrientation(PhysicalDisplayId) const = 0;
};
+static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs,
+ const android::HWComposer::DeviceRequestedChanges& rhs) {
+ return lhs.changedTypes == rhs.changedTypes && lhs.displayRequests == rhs.displayRequests &&
+ lhs.layerRequests == rhs.layerRequests &&
+ lhs.clientTargetProperty == rhs.clientTargetProperty;
+}
+
namespace impl {
class HWComposer final : public android::HWComposer {
@@ -365,7 +373,7 @@
status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp,
DisplayedFrameStats* outStats) override;
std::future<status_t> setDisplayBrightness(
- PhysicalDisplayId, float brightness,
+ PhysicalDisplayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions&) override;
// Events handling ---------------------------------------------------------
@@ -454,6 +462,8 @@
std::mutex vsyncEnabledLock;
hal::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = hal::Vsync::DISABLE;
+ hal::PowerMode powerMode = hal::PowerMode::ON;
+
nsecs_t lastHwVsync = 0;
};
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index d9af553..2597ae6 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -37,6 +37,8 @@
#include <cinttypes>
using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
+using aidl::android::hardware::graphics::composer3::DimmingStage;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace android {
@@ -1113,7 +1115,7 @@
return Error::NONE;
}
-Error HidlComposer::setDisplayBrightness(Display display, float brightness,
+Error HidlComposer::setDisplayBrightness(Display display, float brightness, float,
const DisplayBrightnessOptions&) {
if (!mClient_2_3) {
return Error::UNSUPPORTED;
@@ -1302,10 +1304,17 @@
}
Error HidlComposer::getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) {
- mReader.takeClientTargetProperty(display, outClientTargetProperty);
- *outBrightness = 1.f;
+ Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) {
+ IComposerClient::ClientTargetProperty property;
+ mReader.takeClientTargetProperty(display, &property);
+ outClientTargetProperty->display = display;
+ outClientTargetProperty->clientTargetProperty.dataspace =
+ static_cast<::aidl::android::hardware::graphics::common::Dataspace>(property.dataspace);
+ outClientTargetProperty->clientTargetProperty.pixelFormat =
+ static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(
+ property.pixelFormat);
+ outClientTargetProperty->brightness = 1.f;
+ outClientTargetProperty->dimmingStage = DimmingStage::NONE;
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 5869ae5..d0d3c2e 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -292,7 +292,7 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness,
+ Error setDisplayBrightness(Display display, float brightness, float brightnessNits,
const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
@@ -317,9 +317,10 @@
bool mandatory, const std::vector<uint8_t>& value) override;
V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
- Error getClientTargetProperty(Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) override;
+ Error getClientTargetProperty(
+ Display display,
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) override;
// AIDL Composer HAL
Error setLayerBrightness(Display display, Layer layer, float brightness) override;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 307da41..e21095a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -89,6 +89,9 @@
virtual void dumpAsString(String8& result) const;
virtual void resizeBuffers(const ui::Size&) override;
virtual const sp<Fence>& getClientTargetAcquireFence() const override;
+ // Virtual display surface needs to prepare the frame based on composition type. Skip
+ // any client composition prediction.
+ virtual bool supportsCompositionStrategyPrediction() const override { return false; };
private:
enum Source : size_t {
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
index cc85352..e8c590e 100644
--- a/services/surfaceflinger/EffectLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -114,7 +114,13 @@
}
sp<compositionengine::LayerFE> EffectLayer::getCompositionEngineLayerFE() const {
- return asLayerFE();
+ // There's no need to get a CE Layer if the EffectLayer isn't going to draw anything. In that
+ // case, it acts more like a ContainerLayer so returning a null CE Layer makes more sense
+ if (hasSomethingToDraw()) {
+ return asLayerFE();
+ } else {
+ return nullptr;
+ }
}
compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 997b1a1..d8a5601 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2185,7 +2185,7 @@
layerInfo->set_owner_uid(mOwnerUid);
- if (traceFlags & LayerTracing::TRACE_INPUT) {
+ if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) {
WindowInfo info;
if (useDrawing) {
info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true);
@@ -2596,6 +2596,8 @@
return FrameRateCompatibility::ExactOrMultiple;
case ANATIVEWINDOW_FRAME_RATE_EXACT:
return FrameRateCompatibility::Exact;
+ case ANATIVEWINDOW_FRAME_RATE_NO_VOTE:
+ return FrameRateCompatibility::NoVote;
default:
LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility);
return FrameRateCompatibility::Default;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 80aa072..d4435c2 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -45,6 +45,15 @@
constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace;
constexpr int kBufferHeight = kDigitHeight;
+SurfaceComposerClient::Transaction createTransaction(const sp<SurfaceControl>& surface) {
+ constexpr float kFrameRate = 0.f;
+ constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE;
+ constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
+
+ return SurfaceComposerClient::Transaction().setFrameRate(surface, kFrameRate, kCompatibility,
+ kSeamlessness);
+}
+
} // namespace
void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color,
@@ -213,12 +222,7 @@
return;
}
- constexpr float kFrameRate = 0.f;
- constexpr int8_t kCompatibility = static_cast<int8_t>(Layer::FrameRateCompatibility::NoVote);
- constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
-
- SurfaceComposerClient::Transaction()
- .setFrameRate(mSurfaceControl, kFrameRate, kCompatibility, kSeamlessness)
+ createTransaction(mSurfaceControl)
.setLayer(mSurfaceControl, INT32_MAX - 2)
.setTrustedOverlay(mSurfaceControl, true)
.apply();
@@ -243,9 +247,7 @@
}
}();
- SurfaceComposerClient::Transaction t;
- t.setTransform(mSurfaceControl, transform);
- t.apply();
+ createTransaction(mSurfaceControl).setTransform(mSurfaceControl, transform).apply();
BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint});
if (it == mBufferCache.end()) {
@@ -287,25 +289,21 @@
Rect frame((3 * width) >> 4, height >> 5);
frame.offsetBy(width >> 5, height >> 4);
- SurfaceComposerClient::Transaction t;
- t.setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
- frame.getHeight() / static_cast<float>(kBufferHeight));
- t.setPosition(mSurfaceControl, frame.left, frame.top);
- t.apply();
+ createTransaction(mSurfaceControl)
+ .setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
+ frame.getHeight() / static_cast<float>(kBufferHeight))
+ .setPosition(mSurfaceControl, frame.left, frame.top)
+ .apply();
}
void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
- SurfaceComposerClient::Transaction t;
- t.setLayerStack(mSurfaceControl, stack);
- t.apply();
+ createTransaction(mSurfaceControl).setLayerStack(mSurfaceControl, stack).apply();
}
void RefreshRateOverlay::changeRefreshRate(Fps fps) {
mCurrentFps = fps;
const auto buffer = getOrCreateBuffers(fps)[mFrame];
- SurfaceComposerClient::Transaction t;
- t.setBuffer(mSurfaceControl, buffer);
- t.apply();
+ createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
}
void RefreshRateOverlay::animate() {
@@ -314,9 +312,7 @@
const auto& buffers = getOrCreateBuffers(*mCurrentFps);
mFrame = (mFrame + 1) % buffers.size();
const auto buffer = buffers[mFrame];
- SurfaceComposerClient::Transaction t;
- t.setBuffer(mSurfaceControl, buffer);
- t.apply();
+ createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
}
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 5ba8a1b..cbea77e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -346,6 +346,12 @@
VsyncEventData EventThread::getLatestVsyncEventData(
const sp<EventThreadConnection>& connection) const {
+ // Resync so that the vsync is accurate with hardware. getLatestVsyncEventData is an alternate
+ // way to get vsync data (instead of posting callbacks to Choreographer).
+ if (connection->resyncCallback) {
+ connection->resyncCallback();
+ }
+
VsyncEventData vsyncEventData;
nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
vsyncEventData.frameInterval = frameInterval;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4c83030..fb5d738 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -95,6 +95,7 @@
#include <cmath>
#include <cstdint>
#include <functional>
+#include <memory>
#include <mutex>
#include <optional>
#include <type_traits>
@@ -113,6 +114,7 @@
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/Hal.h"
+#include "DisplayHardware/PowerAdvisor.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "DisplayRenderArea.h"
#include "EffectLayer.h"
@@ -162,6 +164,8 @@
using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
+using CompositionStrategyPredictionState = android::compositionengine::impl::
+ OutputCompositionState::CompositionStrategyPredictionState;
using base::StringAppendF;
using gui::DisplayInfo;
@@ -325,7 +329,7 @@
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
- mPowerAdvisor(*this),
+ mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
}
@@ -411,6 +415,9 @@
property_get("debug.sf.disable_client_composition_cache", value, "0");
mDisableClientCompositionCache = atoi(value);
+ property_get("debug.sf.predict_hwc_composition_strategy", value, "1");
+ mPredictCompositionStrategy = atoi(value);
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -672,16 +679,16 @@
}
readPersistentProperties();
- mPowerAdvisor.onBootFinished();
- mPowerAdvisor.enablePowerHint(mFlagManager.use_adpf_cpu_hint());
- if (mPowerAdvisor.usePowerHintSession()) {
+ mPowerAdvisor->onBootFinished();
+ mPowerAdvisor->enablePowerHint(mFlagManager.use_adpf_cpu_hint());
+ if (mPowerAdvisor->usePowerHintSession()) {
std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
std::vector<int32_t> tidList;
tidList.emplace_back(gettid());
if (renderEngineTid.has_value()) {
tidList.emplace_back(*renderEngineTid);
}
- if (!mPowerAdvisor.startPowerHintSession(tidList)) {
+ if (!mPowerAdvisor->startPowerHintSession(tidList)) {
ALOGW("Cannot start power hint session");
}
}
@@ -807,7 +814,7 @@
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- mPowerAdvisor.init();
+ mPowerAdvisor->init();
char primeShaderCache[PROPERTY_VALUE_MAX];
property_get("service.sf.prime_shader_cache", primeShaderCache, "1");
@@ -1279,10 +1286,10 @@
const char* const whence = __func__;
auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
ATRACE_NAME(whence);
- if (mPowerAdvisor.isUsingExpensiveRendering()) {
+ if (mPowerAdvisor->isUsingExpensiveRendering()) {
for (const auto& [_, display] : mDisplays) {
constexpr bool kDisable = false;
- mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable);
+ mPowerAdvisor->setExpensiveRenderingExpected(display->getId(), kDisable);
}
}
});
@@ -1704,6 +1711,7 @@
return getHwComposer()
.setDisplayBrightness(display->getPhysicalId(),
brightness.displayBrightness,
+ brightness.displayBrightnessNits,
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = true});
}
@@ -1804,7 +1812,7 @@
if (hint == FrameHint::kActive) {
mScheduler->resetIdleTimer();
}
- mPowerAdvisor.notifyDisplayUpdateImminent();
+ mPowerAdvisor->notifyDisplayUpdateImminent();
mScheduler->scheduleFrame();
}
@@ -1974,7 +1982,7 @@
bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
FTL_FAKE_GUARD(kMainThreadContext) {
// we set this once at the beginning of commit to ensure consistency throughout the whole frame
- mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession();
+ mPowerHintSessionData.sessionEnabled = mPowerAdvisor->usePowerHintSession();
if (mPowerHintSessionData.sessionEnabled) {
mPowerHintSessionData.commitStart = systemTime();
}
@@ -1993,8 +2001,8 @@
mScheduledPresentTime = expectedVsyncTime;
if (mPowerHintSessionData.sessionEnabled) {
- mPowerAdvisor.setTargetWorkDuration(mExpectedPresentTime -
- mPowerHintSessionData.commitStart);
+ mPowerAdvisor->setTargetWorkDuration(mExpectedPresentTime -
+ mPowerHintSessionData.commitStart);
}
const auto vsyncIn = [&] {
if (!ATRACE_ENABLED()) return 0.f;
@@ -2219,24 +2227,24 @@
const bool prevFrameHadClientComposition = mHadClientComposition;
- mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
- const auto& state = pair.second->getCompositionDisplay()->getState();
- return state.usesClientComposition && !state.reusedClientComposition;
- });
- mHadDeviceComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
- const auto& state = pair.second->getCompositionDisplay()->getState();
- return state.usesDeviceComposition;
- });
- mReusedClientComposition =
- std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
- const auto& state = pair.second->getCompositionDisplay()->getState();
- return state.reusedClientComposition;
- });
- // Only report a strategy change if we move in and out of client composition
- if (prevFrameHadClientComposition != mHadClientComposition) {
- mTimeStats->incrementCompositionStrategyChanges();
+ mHadClientComposition = mHadDeviceComposition = mReusedClientComposition = false;
+ TimeStats::ClientCompositionRecord clientCompositionRecord;
+ for (const auto& [_, display] : displays) {
+ const auto& state = display->getCompositionDisplay()->getState();
+ mHadClientComposition |= state.usesClientComposition && !state.reusedClientComposition;
+ mHadDeviceComposition |= state.usesDeviceComposition;
+ mReusedClientComposition |= state.reusedClientComposition;
+ clientCompositionRecord.predicted |=
+ (state.strategyPrediction != CompositionStrategyPredictionState::DISABLED);
+ clientCompositionRecord.predictionSucceeded |=
+ (state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS);
}
+ clientCompositionRecord.hadClientComposition = mHadClientComposition;
+ clientCompositionRecord.reused = mReusedClientComposition;
+ clientCompositionRecord.changed = prevFrameHadClientComposition != mHadClientComposition;
+ mTimeStats->pushCompositionStrategyState(clientCompositionRecord);
+
// TODO: b/160583065 Enable skip validation when SF caches all client composition layers
const bool usedGpuComposition = mHadClientComposition || mReusedClientComposition;
modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
@@ -2258,7 +2266,7 @@
if (mPowerHintSessionData.sessionEnabled) {
const nsecs_t flingerDuration =
(mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart);
- mPowerAdvisor.sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
+ mPowerAdvisor->sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
}
}
@@ -2527,13 +2535,6 @@
}
mTimeStats->incrementTotalFrames();
- if (mHadClientComposition) {
- mTimeStats->incrementClientCompositionFrames();
- }
-
- if (mReusedClientComposition) {
- mTimeStats->incrementClientCompositionReusedFrames();
- }
mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime);
@@ -2920,7 +2921,7 @@
builder.setPixels(resolution);
builder.setIsSecure(state.isSecure);
- builder.setPowerAdvisor(&mPowerAdvisor);
+ builder.setPowerAdvisor(mPowerAdvisor.get());
builder.setName(state.displayName);
auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled);
@@ -3251,6 +3252,9 @@
const status_t error =
getHwComposer()
.setDisplayBrightness(display->getPhysicalId(), *brightness,
+ display->getCompositionDisplay()
+ ->getState()
+ .displayBrightnessNits,
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = true})
.get();
@@ -3629,11 +3633,11 @@
}
void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
- const sp<IBinder>& applyToken) {
+ const sp<IBinder>& applyToken, FrameHint frameHint) {
modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken);
if (const bool scheduled = mTransactionFlags.fetch_or(mask) & mask; !scheduled) {
- scheduleCommit(FrameHint::kActive);
+ scheduleCommit(frameHint);
}
}
@@ -4005,7 +4009,7 @@
}
void SurfaceFlinger::queueTransaction(TransactionState& state) {
- Mutex::Autolock _l(mQueueLock);
+ Mutex::Autolock lock(mQueueLock);
// Generate a CountDownLatch pending state if this is a synchronous transaction.
if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) {
@@ -4024,7 +4028,9 @@
return TransactionSchedule::Late;
}(state.flags);
- setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken);
+ const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone;
+
+ setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint);
}
void SurfaceFlinger::waitForSynchronousTransaction(
@@ -5467,30 +5473,21 @@
// access to SF.
case BOOT_FINISHED:
case CLEAR_ANIMATION_FRAME_STATS:
- case CREATE_DISPLAY:
- case DESTROY_DISPLAY:
case GET_ANIMATION_FRAME_STATS:
case OVERRIDE_HDR_TYPES:
case GET_HDR_CAPABILITIES:
case SET_DESIRED_DISPLAY_MODE_SPECS:
case GET_DESIRED_DISPLAY_MODE_SPECS:
case SET_ACTIVE_COLOR_MODE:
- case GET_BOOT_DISPLAY_MODE_SUPPORT:
case SET_BOOT_DISPLAY_MODE:
- case CLEAR_BOOT_DISPLAY_MODE:
case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
- case SET_AUTO_LOW_LATENCY_MODE:
case GET_GAME_CONTENT_TYPE_SUPPORT:
- case SET_GAME_CONTENT_TYPE:
- case SET_POWER_MODE:
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
case GET_DISPLAYED_CONTENT_SAMPLE:
case ADD_TUNNEL_MODE_ENABLED_LISTENER:
case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
- case NOTIFY_POWER_BOOST:
case SET_GLOBAL_SHADOW_SETTINGS:
- case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
// OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary
// permission dynamically. Don't use the permission cache for this check.
@@ -5521,15 +5518,11 @@
case AUTHENTICATE_SURFACE:
case GET_ACTIVE_COLOR_MODE:
case GET_ACTIVE_DISPLAY_MODE:
- case GET_PHYSICAL_DISPLAY_IDS:
- case GET_PHYSICAL_DISPLAY_TOKEN:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_NATIVE_PRIMARIES:
case GET_STATIC_DISPLAY_INFO:
case GET_DYNAMIC_DISPLAY_INFO:
case GET_DISPLAY_MODES:
- case GET_DISPLAY_STATE:
- case GET_DISPLAY_STATS:
case GET_SUPPORTED_FRAME_TIMESTAMPS:
// Calling setTransactionState is safe, because you need to have been
// granted a reference to Client* and Handle* to do anything with it.
@@ -5538,11 +5531,9 @@
case GET_COLOR_MANAGEMENT:
case GET_COMPOSITION_PREFERENCE:
case GET_PROTECTED_CONTENT_SUPPORT:
- case IS_WIDE_COLOR_DISPLAY:
// setFrameRate() is deliberately available for apps to call without any
// special permissions.
case SET_FRAME_RATE:
- case GET_DISPLAY_BRIGHTNESS_SUPPORT:
case GET_DISPLAY_DECORATION_SUPPORT:
case SET_FRAME_TIMELINE_INFO:
case GET_GPU_CONTEXT_PRIORITY:
@@ -5550,19 +5541,6 @@
// This is not sensitive information, so should not require permission control.
return OK;
}
- case SET_DISPLAY_BRIGHTNESS:
- case ADD_HDR_LAYER_INFO_LISTENER:
- case REMOVE_HDR_LAYER_INFO_LISTENER: {
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
- !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
- ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- return OK;
- }
case ADD_FPS_LISTENER:
case REMOVE_FPS_LISTENER:
case ADD_REGION_SAMPLING_LISTENER:
@@ -5608,10 +5586,28 @@
}
return PERMISSION_DENIED;
}
+ case CREATE_DISPLAY:
+ case DESTROY_DISPLAY:
+ case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
+ case GET_PHYSICAL_DISPLAY_IDS:
+ case GET_PHYSICAL_DISPLAY_TOKEN:
+ case SET_POWER_MODE:
+ case GET_DISPLAY_STATE:
+ case GET_DISPLAY_STATS:
+ case CLEAR_BOOT_DISPLAY_MODE:
+ case GET_BOOT_DISPLAY_MODE_SUPPORT:
+ case SET_AUTO_LOW_LATENCY_MODE:
+ case SET_GAME_CONTENT_TYPE:
case CAPTURE_LAYERS:
case CAPTURE_DISPLAY:
case CAPTURE_DISPLAY_BY_ID:
- LOG_FATAL("Deprecated opcode: %d", code);
+ case IS_WIDE_COLOR_DISPLAY:
+ case GET_DISPLAY_BRIGHTNESS_SUPPORT:
+ case SET_DISPLAY_BRIGHTNESS:
+ case ADD_HDR_LAYER_INFO_LISTENER:
+ case REMOVE_HDR_LAYER_INFO_LISTENER:
+ case NOTIFY_POWER_BOOST:
+ LOG_FATAL("Deprecated opcode: %d, migrated to AIDL", code);
return PERMISSION_DENIED;
}
@@ -7172,15 +7168,6 @@
return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
}
-void TransactionState::traverseStatesWithBuffers(
- std::function<void(const layer_state_t&)> visitor) {
- for (const auto& state : states) {
- if (state.state.hasBufferChanges() && state.state.hasValidBuffer() && state.state.surface) {
- visitor(state.state);
- }
- }
-}
-
void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) {
sp<Layer> layer = state.layer.promote();
if (!layer) {
@@ -7316,6 +7303,123 @@
}
// gui::ISurfaceComposer
+
+binder::Status SurfaceComposerAIDL::createDisplay(const std::string& displayName, bool secure,
+ sp<IBinder>* outDisplay) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ String8 displayName8 = String8::format("%s", displayName.c_str());
+ *outDisplay = mFlinger->createDisplay(displayName8, secure);
+ return binder::Status::ok();
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::destroyDisplay(const sp<IBinder>& display) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ mFlinger->destroyDisplay(display);
+ return binder::Status::ok();
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) {
+ std::vector<PhysicalDisplayId> physicalDisplayIds = mFlinger->getPhysicalDisplayIds();
+ std::vector<int64_t> displayIds;
+ displayIds.reserve(physicalDisplayIds.size());
+ for (auto item : physicalDisplayIds) {
+ displayIds.push_back(static_cast<int64_t>(item.value));
+ }
+ *outDisplayIds = displayIds;
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) {
+ status_t status = checkAccessPermission();
+ if (status != OK) {
+ return binder::Status::fromStatusT(status);
+ }
+
+ PhysicalDisplayId id;
+ status = mFlinger->getPrimaryPhysicalDisplayId(&id);
+ if (status == NO_ERROR) {
+ *outDisplayId = id.value;
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId,
+ sp<IBinder>* outDisplay) {
+ const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+ *outDisplay = mFlinger->getPhysicalDisplayToken(*id);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setPowerMode(const sp<IBinder>& display, int mode) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ mFlinger->setPowerMode(display, mode);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display,
+ gui::DisplayStatInfo* outStatInfo) {
+ DisplayStatInfo statInfo;
+ status_t status = mFlinger->getDisplayStats(display, &statInfo);
+ if (status == NO_ERROR) {
+ outStatInfo->vsyncTime = static_cast<long>(statInfo.vsyncTime);
+ outStatInfo->vsyncPeriod = static_cast<long>(statInfo.vsyncPeriod);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display,
+ gui::DisplayState* outState) {
+ ui::DisplayState state;
+ status_t status = mFlinger->getDisplayState(display, &state);
+ if (status == NO_ERROR) {
+ outState->layerStack = state.layerStack.id;
+ outState->orientation = static_cast<gui::Rotation>(state.orientation);
+ outState->layerStackSpaceRect.width = state.layerStackSpaceRect.width;
+ outState->layerStackSpaceRect.height = state.layerStackSpaceRect.height;
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->clearBootDisplayMode(display);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->getBootDisplayModeSupport(outMode);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ mFlinger->setAutoLowLatencyMode(display, on);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& display, bool on) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ mFlinger->setGameContentType(display, on);
+ return binder::Status::ok();
+}
+
binder::Status SurfaceComposerAIDL::captureDisplay(
const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
status_t status = mFlinger->captureDisplay(args, captureListener);
@@ -7342,6 +7446,75 @@
return binder::Status::fromStatusT(status);
}
+binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) {
+ status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) {
+ status_t status = mFlinger->getDisplayBrightnessSupport(displayToken, outSupport);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->setDisplayBrightness(displayToken, brightness);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->addHdrLayerInfoListener(displayToken, listener);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->removeHdrLayerInfoListener(displayToken, listener);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->notifyPowerBoost(boostId);
+ return binder::Status::fromStatusT(status);
+}
+
+status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) {
+ if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(),
+ ipc->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+ return OK;
+}
+
+status_t SurfaceComposerAIDL::checkControlDisplayBrightnessPermission() {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS) &&
+ !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
+ ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ return OK;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 97b0e8d..07da731 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -7,7 +7,6 @@
*
* 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
@@ -24,6 +23,8 @@
#include <android-base/thread_annotations.h>
#include <android/gui/BnSurfaceComposer.h>
+#include <android/gui/DisplayStatInfo.h>
+#include <android/gui/DisplayState.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <gui/BufferQueue.h>
@@ -342,6 +343,11 @@
void disableExpensiveRendering();
FloatRect getMaxDisplayBounds();
+ // If set, composition engine tries to predict the composition strategy provided by HWC
+ // based on the previous frame. If the strategy can be predicted, gpu composition will
+ // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect.
+ bool mPredictCompositionStrategy = false;
+
protected:
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -518,17 +524,30 @@
bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true)
EXCLUDES(mStateLock);
+ // the following two methods are moved from ISurfaceComposer.h
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+ const auto displayIds = getPhysicalDisplayIds();
+ return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
+ }
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+ }
+
// Implements ISurfaceComposer
sp<ISurfaceComposerClient> createConnection() override;
- sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
- void destroyDisplay(const sp<IBinder>& displayToken) override;
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override EXCLUDES(mStateLock) {
+ sp<IBinder> createDisplay(const String8& displayName, bool secure);
+ void destroyDisplay(const sp<IBinder>& displayToken);
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const EXCLUDES(mStateLock) {
Mutex::Autolock lock(mStateLock);
return getPhysicalDisplayIdsLocked();
}
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override EXCLUDES(mStateLock);
+ status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const EXCLUDES(mStateLock);
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
+ sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
@@ -550,9 +569,9 @@
status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
- status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
+ status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
- EXCLUDES(mStateLock) override;
+ EXCLUDES(mStateLock);
status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*)
EXCLUDES(mStateLock) override;
status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*)
@@ -560,12 +579,12 @@
status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
ui::DisplayPrimaries&) override;
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
- status_t getBootDisplayModeSupport(bool* outSupport) const override;
+ status_t getBootDisplayModeSupport(bool* outSupport) const;
status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override;
- status_t clearBootDisplayMode(const sp<IBinder>& displayToken) override;
- void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) override;
- void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
- void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
+ status_t clearBootDisplayMode(const sp<IBinder>& displayToken);
+ void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
+ void setGameContentType(const sp<IBinder>& displayToken, bool on);
+ void setPowerMode(const sp<IBinder>& displayToken, int mode);
status_t clearAnimationFrameStats() override;
status_t getAnimationFrameStats(FrameStats* outStats) const override;
status_t overrideHdrTypes(const sp<IBinder>& displayToken,
@@ -588,8 +607,7 @@
uint64_t timestamp,
DisplayedFrameStats* outStats) const override;
status_t getProtectedContentSupport(bool* outSupported) const override;
- status_t isWideColorDisplay(const sp<IBinder>& displayToken,
- bool* outIsWideColorDisplay) const override;
+ status_t isWideColorDisplay(const sp<IBinder>& displayToken, bool* outIsWideColorDisplay) const;
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
@@ -611,15 +629,14 @@
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) override;
- status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override;
+ status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const;
status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) override;
+ const gui::DisplayBrightness& brightness);
status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override;
+ const sp<gui::IHdrLayerInfoListener>& listener);
status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override;
- status_t notifyPowerBoost(int32_t boostId) override;
+ const sp<gui::IHdrLayerInfoListener>& listener);
+ status_t notifyPowerBoost(int32_t boostId);
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
status_t getDisplayDecorationSupport(
@@ -784,7 +801,8 @@
// Sets the masked bits, and schedules a commit if needed.
void setTransactionFlags(uint32_t mask, TransactionSchedule = TransactionSchedule::Late,
- const sp<IBinder>& applyToken = nullptr);
+ const sp<IBinder>& applyToken = nullptr,
+ FrameHint = FrameHint::kActive);
// Clears and returns the masked bits.
uint32_t clearTransactionFlags(uint32_t mask);
@@ -1365,7 +1383,7 @@
sp<os::IInputFlinger> mInputFlinger;
InputWindowCommands mInputWindowCommands;
- Hwc2::impl::PowerAdvisor mPowerAdvisor;
+ std::unique_ptr<Hwc2::PowerAdvisor> mPowerAdvisor;
void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock);
@@ -1438,11 +1456,43 @@
public:
SurfaceComposerAIDL(sp<SurfaceFlinger> sf) { mFlinger = sf; }
+ binder::Status createDisplay(const std::string& displayName, bool secure,
+ sp<IBinder>* outDisplay) override;
+ binder::Status destroyDisplay(const sp<IBinder>& display) override;
+ binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override;
+ binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override;
+ binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
+ binder::Status setPowerMode(const sp<IBinder>& display, int mode) override;
+ binder::Status getDisplayStats(const sp<IBinder>& display,
+ gui::DisplayStatInfo* outStatInfo) override;
+ binder::Status getDisplayState(const sp<IBinder>& display,
+ gui::DisplayState* outState) override;
+ binder::Status clearBootDisplayMode(const sp<IBinder>& display) override;
+ binder::Status getBootDisplayModeSupport(bool* outMode) override;
+ binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override;
+ binder::Status setGameContentType(const sp<IBinder>& display, bool on) override;
binder::Status captureDisplay(const DisplayCaptureArgs&,
const sp<IScreenCaptureListener>&) override;
binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override;
binder::Status captureLayers(const LayerCaptureArgs&,
const sp<IScreenCaptureListener>&) override;
+ binder::Status isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) override;
+ binder::Status getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) override;
+ binder::Status setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) override;
+ binder::Status addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
+ binder::Status removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
+ binder::Status notifyPowerBoost(int boostId) override;
+
+private:
+ static const constexpr bool kUsePermissionCache = true;
+ status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache);
+ status_t checkControlDisplayBrightnessPermission();
private:
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index b1a2bda..e5a9dd4 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -321,22 +321,19 @@
mTimeStats.missedFramesLegacy++;
}
-void TimeStats::incrementClientCompositionFrames() {
- if (!mEnabled.load()) return;
+void TimeStats::pushCompositionStrategyState(const TimeStats::ClientCompositionRecord& record) {
+ if (!mEnabled.load() || !record.hasInterestingData()) {
+ return;
+ }
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionFramesLegacy++;
-}
-
-void TimeStats::incrementClientCompositionReusedFrames() {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
-
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionReusedFramesLegacy++;
+ if (record.changed) mTimeStats.compositionStrategyChangesLegacy++;
+ if (record.hadClientComposition) mTimeStats.clientCompositionFramesLegacy++;
+ if (record.reused) mTimeStats.clientCompositionReusedFramesLegacy++;
+ if (record.predicted) mTimeStats.compositionStrategyPredictedLegacy++;
+ if (record.predictionSucceeded) mTimeStats.compositionStrategyPredictionSucceededLegacy++;
}
void TimeStats::incrementRefreshRateSwitches() {
@@ -348,15 +345,6 @@
mTimeStats.refreshRateSwitchesLegacy++;
}
-void TimeStats::incrementCompositionStrategyChanges() {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
-
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.compositionStrategyChangesLegacy++;
-}
-
void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
if (!mEnabled.load()) return;
@@ -1062,8 +1050,10 @@
mTimeStats.missedFramesLegacy = 0;
mTimeStats.clientCompositionFramesLegacy = 0;
mTimeStats.clientCompositionReusedFramesLegacy = 0;
- mTimeStats.refreshRateSwitchesLegacy = 0;
mTimeStats.compositionStrategyChangesLegacy = 0;
+ mTimeStats.compositionStrategyPredictedLegacy = 0;
+ mTimeStats.compositionStrategyPredictionSucceededLegacy = 0;
+ mTimeStats.refreshRateSwitchesLegacy = 0;
mTimeStats.displayEventConnectionsCountLegacy = 0;
mTimeStats.displayOnTimeLegacy = 0;
mTimeStats.presentToPresentLegacy.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 77c7973..7a159b8 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -45,7 +45,7 @@
virtual ~TimeStats() = default;
// Process a pull request from statsd.
- virtual bool onPullAtom(const int atomId, std::string* pulledData);
+ virtual bool onPullAtom(const int atomId, std::string* pulledData) = 0;
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
@@ -53,14 +53,8 @@
virtual void incrementTotalFrames() = 0;
virtual void incrementMissedFrames() = 0;
- virtual void incrementClientCompositionFrames() = 0;
- virtual void incrementClientCompositionReusedFrames() = 0;
// Increments the number of times the display refresh rate changed.
virtual void incrementRefreshRateSwitches() = 0;
- // Increments the number of changes in composition strategy
- // The intention is to reflect the number of changes between hwc and gpu
- // composition, where "gpu composition" may also include mixed composition.
- virtual void incrementCompositionStrategyChanges() = 0;
// Records the most up-to-date count of display event connections.
// The stored count will be the maximum ever recoded.
virtual void recordDisplayEventConnectionCount(int32_t count) = 0;
@@ -158,6 +152,24 @@
}
};
+ struct ClientCompositionRecord {
+ // Frame had client composition or mixed composition
+ bool hadClientComposition = false;
+ // Composition changed between hw composition and mixed/client composition
+ bool changed = false;
+ // Frame reused the client composition result from a previous frame
+ bool reused = false;
+ // Composition strategy predicted for frame
+ bool predicted = false;
+ // Composition strategy prediction succeeded
+ bool predictionSucceeded = false;
+
+ // Whether there is data we want to record.
+ bool hasInterestingData() const {
+ return hadClientComposition || changed || reused || predicted;
+ }
+ };
+
virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0;
// Clean up the layer record
virtual void onDestroy(int32_t layerId) = 0;
@@ -169,6 +181,7 @@
// Source of truth is RefrehRateStats.
virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
+ virtual void pushCompositionStrategyState(const ClientCompositionRecord&) = 0;
};
namespace impl {
@@ -236,10 +249,7 @@
void incrementTotalFrames() override;
void incrementMissedFrames() override;
- void incrementClientCompositionFrames() override;
- void incrementClientCompositionReusedFrames() override;
void incrementRefreshRateSwitches() override;
- void incrementCompositionStrategyChanges() override;
void recordDisplayEventConnectionCount(int32_t count) override;
void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
@@ -275,6 +285,8 @@
void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
+ void pushCompositionStrategyState(const ClientCompositionRecord&) override;
+
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 69afa2a..cf1ca65 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -143,6 +143,14 @@
clientCompositionReusedFramesLegacy);
StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
+ StringAppendF(&result, "compositionStrategyPredicted = %d\n",
+ compositionStrategyPredictedLegacy);
+ StringAppendF(&result, "compositionStrategyPredictionSucceeded = %d\n",
+ compositionStrategyPredictionSucceededLegacy);
+ StringAppendF(&result, "compositionStrategyPredictionFailed = %d\n",
+ compositionStrategyPredictedLegacy -
+ compositionStrategyPredictionSucceededLegacy);
+
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
StringAppendF(&result, "displayConfigStats is as below:\n");
for (const auto& [fps, duration] : refreshRateStatsLegacy) {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 438561c..237ae8d 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -178,6 +178,8 @@
Histogram frameDurationLegacy;
Histogram renderEngineTimingLegacy;
std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
+ int32_t compositionStrategyPredictedLegacy = 0;
+ int32_t compositionStrategyPredictionSucceededLegacy = 0;
std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 04ca347..bab5326 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 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.
@@ -16,12 +16,21 @@
#pragma once
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <vector>
+
#include <gui/LayerState.h>
+#include <system/window.h>
namespace android {
+
class CountDownLatch;
struct TransactionState {
+ TransactionState() = default;
+
TransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
@@ -47,9 +56,30 @@
originUid(originUid),
id(transactionId) {}
- TransactionState() {}
+ // Invokes `void(const layer_state_t&)` visitor for matching layers.
+ template <typename Visitor>
+ void traverseStatesWithBuffers(Visitor&& visitor) const {
+ for (const auto& [state] : states) {
+ if (state.hasBufferChanges() && state.hasValidBuffer() && state.surface) {
+ visitor(state);
+ }
+ }
+ }
- void traverseStatesWithBuffers(std::function<void(const layer_state_t&)> visitor);
+ // TODO(b/185535769): Remove FrameHint. Instead, reset the idle timer (of the relevant physical
+ // display) on the main thread if commit leads to composite. Then, RefreshRateOverlay should be
+ // able to setFrameRate once, rather than for each transaction.
+ bool isFrameActive() const {
+ if (!displays.empty()) return true;
+
+ for (const auto& [state] : states) {
+ if (state.frameRateCompatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE) {
+ return true;
+ }
+ }
+
+ return false;
+ }
FrameTimelineInfo frameTimelineInfo;
Vector<ComposerState> states;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index 3c4ab95..a605a2f 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -358,6 +358,7 @@
composer->setLayerPerFrameMetadataBlobs(display, outLayer, std::vector<PerFrameMetadataBlob>{});
composer->setDisplayBrightness(display, mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(),
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = mFdp.ConsumeIntegral<bool>()});
}
@@ -585,6 +586,7 @@
getDisplayedContentSample(halDisplayID);
mHwc.setDisplayBrightness(mPhysicalDisplayId, mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(),
Hwc2::Composer::DisplayBrightnessOptions{
.applyImmediately = mFdp.ConsumeIntegral<bool>()});
diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
index abdb16d..d70908e 100644
--- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp
+++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
@@ -20,28 +20,33 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
#include <chrono>
namespace android {
TEST(BootDisplayModeTest, setBootDisplayMode) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> sf_aidl(ComposerServiceAIDL::getComposerService());
auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
bool bootModeSupport = false;
- ASSERT_NO_FATAL_FAILURE(sf->getBootDisplayModeSupport(&bootModeSupport));
+ binder::Status status = sf_aidl->getBootDisplayModeSupport(&bootModeSupport);
+ ASSERT_NO_FATAL_FAILURE(status.transactionError());
if (bootModeSupport) {
ASSERT_EQ(NO_ERROR, sf->setBootDisplayMode(displayToken, 0));
}
}
TEST(BootDisplayModeTest, clearBootDisplayMode) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
bool bootModeSupport = false;
- ASSERT_NO_FATAL_FAILURE(sf->getBootDisplayModeSupport(&bootModeSupport));
+ binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
+ ASSERT_NO_FATAL_FAILURE(status.transactionError());
if (bootModeSupport) {
- ASSERT_EQ(NO_ERROR, sf->clearBootDisplayMode(displayToken));
+ status = sf->clearBootDisplayMode(displayToken);
+ ASSERT_EQ(NO_ERROR, status.transactionError());
}
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index cc9d48c..7823363 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -103,6 +103,7 @@
"SurfaceFlinger_HotplugTest.cpp",
"SurfaceFlinger_NotifyPowerBoostTest.cpp",
"SurfaceFlinger_OnInitializeDisplaysTest.cpp",
+ "SurfaceFlinger_PowerHintTest.cpp",
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
"SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 15c9d19..c541b92 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -113,8 +113,9 @@
mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
mComposer = new Hwc2::mock::Composer();
+ mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
+ mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
mFlinger.mutableMaxRenderTargetSize() = 16384;
}
@@ -188,7 +189,7 @@
Hwc2::mock::Composer* mComposer = nullptr;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
mock::TimeStats* mTimeStats = new mock::TimeStats();
- Hwc2::mock::PowerAdvisor mPowerAdvisor;
+ Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -300,7 +301,7 @@
.setId(DEFAULT_DISPLAY_ID)
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setIsSecure(Derived::IS_SECURE)
- .setPowerAdvisor(&test->mPowerAdvisor)
+ .setPowerAdvisor(test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
test_info->test_case_name() + "." + test_info->name())
.build();
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index fa36d9c..c033af8 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -415,6 +415,10 @@
EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData));
VsyncEventData vsyncEventData = mThread->getLatestVsyncEventData(mConnection);
+
+ // Check EventThread immediately requested a resync.
+ EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
+
EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
<< "Deadline timestamp should be greater than frame time";
for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 825f145..b9a5f36 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -337,10 +337,22 @@
ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, ""));
EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ // Privileged APIs.
+ EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ constexpr bool kPrivileged = true;
EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
- /*privileged=*/true));
+ kPrivileged));
+ EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
+ kPrivileged));
+ // Invalid frame rate.
EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
@@ -348,15 +360,12 @@
EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
-
- // Invalid compatibility
+ // Invalid compatibility.
EXPECT_FALSE(
ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- // Invalid change frame rate strategy
+ // Invalid change frame rate strategy.
EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, -1, ""));
EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, 2, ""));
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
new file mode 100644
index 0000000..0a157c4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2022 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 "SurfaceFlingerPowerHintTest"
+
+#include <compositionengine/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <algorithm>
+#include <chrono>
+#include <memory>
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockTimeStats.h"
+#include "mock/MockVsyncController.h"
+#include "mock/system/window/MockNativeWindow.h"
+
+using namespace android;
+using namespace android::Hwc2::mock;
+using namespace android::hardware::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+namespace android {
+namespace {
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
+constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+
+class SurfaceFlingerPowerHintTest : public Test {
+public:
+ void SetUp() override;
+
+ void setupScheduler();
+
+protected:
+ TestableSurfaceFlinger mFlinger;
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+ sp<DisplayDevice> mDisplay;
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ new compositionengine::mock::DisplaySurface();
+ mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+ mock::TimeStats* mTimeStats = new mock::TimeStats();
+ Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
+ Hwc2::mock::Composer* mComposer = nullptr;
+};
+
+void SurfaceFlingerPowerHintTest::SetUp() {
+ setupScheduler();
+ mComposer = new Hwc2::mock::Composer();
+ mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
+ mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+ mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+ mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
+ static constexpr bool kIsPrimary = true;
+ FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary)
+ .setPowerMode(hal::PowerMode::ON)
+ .inject(&mFlinger, mComposer);
+ auto compostionEngineDisplayArgs =
+ compositionengine::DisplayCreationArgsBuilder()
+ .setId(DEFAULT_DISPLAY_ID)
+ .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+ .setPowerAdvisor(mPowerAdvisor)
+ .setName("injected display")
+ .build();
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
+ std::move(compostionEngineDisplayArgs));
+ mDisplay =
+ FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+ ui::DisplayConnectionType::Internal, HWC_DISPLAY, kIsPrimary)
+ .setDisplaySurface(mDisplaySurface)
+ .setNativeWindow(mNativeWindow)
+ .setPowerMode(hal::PowerMode::ON)
+ .inject();
+}
+
+void SurfaceFlingerPowerHintTest::setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ auto vsyncController = std::make_unique<mock::VsyncController>();
+ auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*vsyncTracker, currentPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+
+ mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+ std::move(eventThread), std::move(sfEventThread),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+ TestableSurfaceFlinger::kTwoDisplayModes);
+}
+
+TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) {
+ ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
+
+ const std::chrono::nanoseconds mockVsyncPeriod = 15ms;
+ const std::chrono::nanoseconds expectedTargetTime = 14ms;
+ EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(Gt(expectedTargetTime.count()))).Times(1);
+
+ const nsecs_t now = systemTime();
+ const std::chrono::nanoseconds mockHwcRunTime = 20ms;
+ EXPECT_CALL(*mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc))
+ .Times(1);
+ EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _))
+ .WillOnce([mockHwcRunTime] {
+ std::this_thread::sleep_for(mockHwcRunTime);
+ return hardware::graphics::composer::V2_1::Error::NONE;
+ });
+ EXPECT_CALL(*mPowerAdvisor,
+ sendActualWorkDuration(Gt(mockHwcRunTime.count()),
+ Gt(now + mockHwcRunTime.count())))
+ .Times(1);
+ static constexpr bool kVsyncId = 123; // arbitrary
+ mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index bf2465f..866d9eb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,6 +17,7 @@
#pragma once
#include <algorithm>
+#include <chrono>
#include <variant>
#include <compositionengine/Display.h>
@@ -200,6 +201,10 @@
std::make_unique<impl::HWComposer>(std::move(composer)));
}
+ void setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor> powerAdvisor) {
+ mFlinger->mPowerAdvisor = std::move(powerAdvisor);
+ }
+
void setupTimeStats(const std::shared_ptr<TimeStats>& timeStats) {
mFlinger->mCompositionEngine->setTimeStats(timeStats);
}
@@ -328,11 +333,26 @@
/* ------------------------------------------------------------------------
* Forwarding for functions being tested
*/
+
+ nsecs_t commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVSyncTime) {
+ mFlinger->commit(frameTime, vsyncId, expectedVSyncTime);
+ return frameTime;
+ }
+
+ nsecs_t commit(nsecs_t frameTime, int64_t vsyncId) {
+ std::chrono::nanoseconds period = 10ms;
+ return commit(frameTime, vsyncId, frameTime + period.count());
+ }
+
nsecs_t commit() {
const nsecs_t now = systemTime();
const nsecs_t expectedVsyncTime = now + 10'000'000;
- mFlinger->commit(now, kVsyncId, expectedVsyncTime);
- return now;
+ return commit(now, kVsyncId, expectedVsyncTime);
+ }
+
+ void commitAndComposite(const nsecs_t frameTime, const int64_t vsyncId,
+ const nsecs_t expectedVsyncTime) {
+ mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), kVsyncId);
}
void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); }
@@ -458,11 +478,6 @@
mFlinger->onActiveDisplayChangedLocked(activeDisplay);
}
- auto commit(nsecs_t frameTime, int64_t vsyncId) {
- const nsecs_t expectedVsyncTime = frameTime + 10'000'000;
- mFlinger->commit(frameTime, vsyncId, expectedVsyncTime);
- }
-
auto createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
const sp<IBinder>& parentHandle, int32_t* outLayerId,
const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
@@ -515,7 +530,6 @@
auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
- auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; }
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 0ef8456..6ffc039 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -268,8 +268,11 @@
for (size_t i = 0; i < MISSED_FRAMES; i++) {
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
}
+ TimeStats::ClientCompositionRecord record;
+ record.hadClientComposition = true;
+
for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState(record));
}
SFTimeStatsGlobalProto globalProto;
@@ -459,19 +462,49 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
-TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
+TEST_F(TimeStatsTest, canIncreaseClientCompositionStats) {
// this stat is not in the proto so verify by checking the string dump
- constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
+ constexpr size_t COMPOSITION_STRATEGY_CHANGED_FRAMES = 1;
+ constexpr size_t HAD_CLIENT_COMPOSITION_FRAMES = 2;
+ constexpr size_t REUSED_CLIENT_COMPOSITION_FRAMES = 3;
+ constexpr size_t COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES = 4;
+ constexpr size_t COMPOSITION_STRATEGY_PREDICTED_FRAMES = 5;
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ for (size_t i = 0; i <= COMPOSITION_STRATEGY_PREDICTED_FRAMES; i++) {
+ TimeStats::ClientCompositionRecord record;
+ record.hadClientComposition = i < HAD_CLIENT_COMPOSITION_FRAMES;
+ record.changed = i < COMPOSITION_STRATEGY_CHANGED_FRAMES;
+ record.reused = i < REUSED_CLIENT_COMPOSITION_FRAMES;
+ record.predicted = i < COMPOSITION_STRATEGY_PREDICTED_FRAMES;
+ record.predictionSucceeded = i < COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES;
+ mTimeStats->pushCompositionStrategyState(record);
}
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- const std::string expectedResult =
- "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
- EXPECT_THAT(result, HasSubstr(expectedResult));
+ std::string expected =
+ "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "clientCompositionFrames = " + std::to_string(HAD_CLIENT_COMPOSITION_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected =
+ "clientCompositionReusedFrames = " + std::to_string(REUSED_CLIENT_COMPOSITION_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "compositionStrategyPredicted = " +
+ std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "compositionStrategyPredictionSucceeded = " +
+ std::to_string(COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "compositionStrategyPredictionFailed = " +
+ std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES -
+ COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
}
TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) {
@@ -489,21 +522,6 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
-TEST_F(TimeStatsTest, canIncreaseCompositionStrategyChanges) {
- // this stat is not in the proto so verify by checking the string dump
- constexpr size_t COMPOSITION_STRATEGY_CHANGES = 2;
-
- EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- for (size_t i = 0; i < COMPOSITION_STRATEGY_CHANGES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
- }
-
- const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- const std::string expectedResult =
- "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGES);
- EXPECT_THAT(result, HasSubstr(expectedResult));
-}
-
TEST_F(TimeStatsTest, canAverageFrameDuration) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
mTimeStats->setPowerMode(PowerMode::ON);
@@ -836,7 +854,7 @@
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({}));
ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
@@ -867,9 +885,8 @@
TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
// These stats are not in the proto so verify by checking the string dump.
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({}));
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
mTimeStats->setPowerMode(PowerMode::ON);
mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
std::chrono::nanoseconds(5ms).count());
@@ -1032,8 +1049,10 @@
for (size_t i = 0; i < MISSED_FRAMES; i++) {
mTimeStats->incrementMissedFrames();
}
+ TimeStats::ClientCompositionRecord record;
+ record.hadClientComposition = true;
for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- mTimeStats->incrementClientCompositionFrames();
+ mTimeStats->pushCompositionStrategyState(record);
}
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index c1d41bb..aa8b521 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -126,7 +126,8 @@
Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
- MOCK_METHOD3(setDisplayBrightness, Error(Display, float, const DisplayBrightnessOptions&));
+ MOCK_METHOD4(setDisplayBrightness,
+ Error(Display, float, float, const DisplayBrightnessOptions&));
MOCK_METHOD2(
getDisplayCapabilities,
Error(Display,
@@ -151,8 +152,10 @@
const std::vector<uint8_t>&));
MOCK_METHOD1(getLayerGenericMetadataKeys,
V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
- MOCK_METHOD3(getClientTargetProperty,
- Error(Display, IComposerClient::ClientTargetProperty*, float*));
+ MOCK_METHOD2(getClientTargetProperty,
+ Error(Display,
+ aidl::android::hardware::graphics::composer3::
+ ClientTargetPropertyWithBrightness*));
MOCK_METHOD3(setLayerBrightness, Error(Display, Layer, float));
MOCK_METHOD3(setLayerBlockingRegion,
Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index ac2ab199c..3e0d6d3 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -81,7 +81,7 @@
(nsecs_t, uint32_t *, uint32_t *, android::sp<android::Fence> *, uint32_t *),
(override));
MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness,
- (float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
+ (float, float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
MOCK_METHOD(hal::Error, setActiveConfigWithConstraints,
(hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &,
hal::VsyncPeriodChangeTimeline *),
@@ -93,8 +93,10 @@
MOCK_METHOD(hal::Error, getSupportedContentTypes, (std::vector<hal::ContentType> *),
(const, override));
MOCK_METHOD(hal::Error, setContentType, (hal::ContentType), (override));
- MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *, float *),
- (override));
+ MOCK_METHOD(
+ hal::Error, getClientTargetProperty,
+ (aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness *),
+ (override));
MOCK_METHOD(
hal::Error, getDisplayDecorationSupport,
(std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport> *),
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 0a69b56..0dee800 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -33,10 +33,7 @@
MOCK_METHOD0(miniDump, std::string());
MOCK_METHOD0(incrementTotalFrames, void());
MOCK_METHOD0(incrementMissedFrames, void());
- MOCK_METHOD0(incrementClientCompositionFrames, void());
- MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
MOCK_METHOD0(incrementRefreshRateSwitches, void());
- MOCK_METHOD0(incrementCompositionStrategyChanges, void());
MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
@@ -63,6 +60,8 @@
void(hardware::graphics::composer::V2_4::IComposerClient::PowerMode));
MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD(void, pushCompositionStrategyState,
+ (const android::TimeStats::ClientCompositionRecord&), (override));
};
} // namespace android::mock