Merge "Otapreopt: Introduce protocol version 10" am: 26311df43b am: 076b5c7a3a
am: 7690741e35
Change-Id: I36083c7251159deb43e18fe885fa4c27c88f9e73
diff --git a/cmds/bugreportz/bugreportz.cpp b/cmds/bugreportz/bugreportz.cpp
index 75855cf..ded0ed3 100644
--- a/cmds/bugreportz/bugreportz.cpp
+++ b/cmds/bugreportz/bugreportz.cpp
@@ -55,7 +55,7 @@
errno = ETIMEDOUT;
}
printf("FAIL:Bugreport read terminated abnormally (%s)\n", strerror(errno));
- break;
+ return EXIT_FAILURE;
}
// Writes line by line.
@@ -71,8 +71,5 @@
// Process final line, in case it didn't finish with newline
write_line(line, show_progress);
- if (close(s) == -1) {
- fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno));
- }
return EXIT_SUCCESS;
}
diff --git a/cmds/bugreportz/bugreportz.h b/cmds/bugreportz/bugreportz.h
index 304e4b3..7af289b 100644
--- a/cmds/bugreportz/bugreportz.h
+++ b/cmds/bugreportz/bugreportz.h
@@ -16,6 +16,7 @@
#define BUGREPORTZ_H
// Calls dumpstate using the given socket and output its result to stdout.
+// Ownership of the socket is not transferred.
int bugreportz(int s, bool show_progress);
#endif // BUGREPORTZ_H
diff --git a/cmds/bugreportz/main.cpp b/cmds/bugreportz/main.cpp
index a3ae1ff..74a95b0 100644
--- a/cmds/bugreportz/main.cpp
+++ b/cmds/bugreportz/main.cpp
@@ -82,7 +82,7 @@
if (s == -1) {
printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
- return EXIT_SUCCESS;
+ return EXIT_FAILURE;
}
// Set a timeout so that if nothing is read in 10 minutes, we'll stop
@@ -92,8 +92,16 @@
tv.tv_sec = 10 * 60;
tv.tv_usec = 0;
if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
- fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno));
+ fprintf(stderr,
+ "WARNING: Cannot set socket timeout, bugreportz might hang indefinitely: %s\n",
+ strerror(errno));
}
- bugreportz(s, show_progress);
+ int ret = bugreportz(s, show_progress);
+
+ if (close(s) == -1) {
+ fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno));
+ ret = EXIT_FAILURE;
+ }
+ return ret;
}
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 4238531..0616add 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -103,12 +103,12 @@
}
if (is_selinux_enabled() && seLinuxContext.size() > 0) {
String8 seLinuxContext8(seLinuxContext);
- security_context_t tmp = NULL;
+ security_context_t tmp = nullptr;
getfilecon(fullPath.string(), &tmp);
Unique_SecurityContext context(tmp);
if (checkWrite) {
int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
- "file", "write", NULL);
+ "file", "write", nullptr);
if (accessGranted != 0) {
#if DEBUG
ALOGD("openFile: failed selinux write check!");
@@ -122,7 +122,7 @@
}
if (checkRead) {
int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
- "file", "read", NULL);
+ "file", "read", nullptr);
if (accessGranted != 0) {
#if DEBUG
ALOGD("openFile: failed selinux read check!");
@@ -174,7 +174,7 @@
#endif
sp<IServiceManager> sm = defaultServiceManager();
fflush(stdout);
- if (sm == NULL) {
+ if (sm == nullptr) {
ALOGW("Unable to get default service manager!");
aerr << "cmd: Unable to get default service manager!" << endl;
return 20;
@@ -192,7 +192,7 @@
for (size_t i=0; i<services.size(); i++) {
sp<IBinder> service = sm->checkService(services[i]);
- if (service != NULL) {
+ if (service != nullptr) {
aout << " " << services[i] << endl;
}
}
@@ -205,7 +205,7 @@
}
String16 cmd = String16(argv[1]);
sp<IBinder> service = sm->checkService(cmd);
- if (service == NULL) {
+ if (service == nullptr) {
ALOGW("Can't find service %s", argv[1]);
aerr << "cmd: Can't find service: " << argv[1] << endl;
return 20;
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 85eb464..600a500 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -56,11 +56,11 @@
timespec ts;
ts.tv_sec = MSEC_TO_SEC(timeout_ms);
ts.tv_nsec = (timeout_ms % 1000) * 1000000;
- int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts));
+ int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
int saved_errno = errno;
// Set the signals back the way they were.
- if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
+ if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) {
printf("*** sigprocmask failed: %s\n", strerror(errno));
if (ret == 0) {
return false;
@@ -310,7 +310,7 @@
struct sigaction sigact;
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &sigact, NULL);
+ sigaction(SIGPIPE, &sigact, nullptr);
execvp(path, (char**)args.data());
// execvp's result will be handled after waitpid_with_timeout() below, but
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 3e12ed5..ff15794 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -101,7 +101,6 @@
#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
#define BLK_DEV_SYS_DIR "/sys/block"
-#define RAFT_DIR "/data/misc/raft"
#define RECOVERY_DIR "/cache/recovery"
#define RECOVERY_DATA_DIR "/data/misc/recovery"
#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
@@ -455,40 +454,6 @@
}
}
-static void dump_raft() {
- if (PropertiesHelper::IsUserBuild()) {
- return;
- }
-
- std::string raft_path = ds.GetPath("-raft_log.txt");
- if (raft_path.empty()) {
- MYLOGD("raft_path is empty\n");
- return;
- }
-
- struct stat s;
- if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
- MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
- return;
- }
-
- CommandOptions options = CommandOptions::WithTimeout(600).Build();
- if (!ds.IsZipping()) {
- // Write compressed and encoded raft logs to stdout if it's not a zipped bugreport.
- RunCommand("RAFT LOGS", {"logcompressor", "-r", RAFT_DIR}, options);
- return;
- }
-
- RunCommand("RAFT LOGS", {"logcompressor", "-n", "-r", RAFT_DIR, "-o", raft_path}, options);
- if (!ds.AddZipEntry("raft_log.txt", raft_path)) {
- MYLOGE("Unable to add raft log %s to zip file\n", raft_path.c_str());
- } else {
- if (remove(raft_path.c_str())) {
- MYLOGE("Error removing raft file %s: %s\n", raft_path.c_str(), strerror(errno));
- }
- }
-}
-
static bool skip_not_stat(const char *path) {
static const char stat[] = "/stat";
size_t len = strlen(path);
@@ -1372,7 +1337,7 @@
printf("== Running Application Services (platform)\n");
printf("========================================================\n");
- RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform"},
+ RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
DUMPSYS_COMPONENTS_OPTIONS);
printf("========================================================\n");
@@ -2085,9 +2050,6 @@
// keep the system stats as close to its initial state as possible.
RunDumpsysCritical();
- // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
- dump_raft();
-
/* collect stack traces from Dalvik and native processes (needs root) */
dump_traces_path = dump_traces();
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 5412d4d..9bfd710 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -65,7 +65,7 @@
" -l: only list services, do not dump them\n"
" -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
" -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
- " --proto: filter services that support dumping data in proto format. Dumps"
+ " --proto: filter services that support dumping data in proto format. Dumps\n"
" will be in proto format.\n"
" --priority LEVEL: filter services based on specified priority\n"
" LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 8f60881..3ada153 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -371,8 +371,8 @@
IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
ExpectCheckService("Locksmith");
ExpectCheckService("Valet");
- ExpectDumpWithArgs("Locksmith", {"-a", "--dump-priority", "NORMAL"}, "dump1");
- ExpectDumpWithArgs("Valet", {"-a", "--dump-priority", "NORMAL"}, "dump2");
+ ExpectDumpWithArgs("Locksmith", {"--dump-priority", "NORMAL", "-a"}, "dump1");
+ ExpectDumpWithArgs("Valet", {"--dump-priority", "NORMAL", "-a"}, "dump2");
CallMain({"--priority", "NORMAL"});
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index 515f915..e29ff4c 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -73,7 +73,7 @@
FTS *fts;
FTSENT *p;
char *argv[] = { (char*) path.c_str(), nullptr };
- if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
PLOG(WARNING) << "Failed to fts_open " << path;
return -1;
}
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index ea0cd9e..a7242c3 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -103,7 +103,7 @@
FTS *fts;
FTSENT *p;
char *argv[] = { (char*) path.c_str(), nullptr };
- if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
PLOG(WARNING) << "Failed to fts_open " << path;
return;
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 860a68b..2470a1d 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -95,15 +95,6 @@
static constexpr size_t kSha256Size = 32;
static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
-// NOTE: keep in sync with Installer
-static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
-static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
-static constexpr int FLAG_USE_QUOTA = 1 << 12;
-static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
-static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
-static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 15;
-static constexpr int FLAG_FORCE = 1 << 16;
-
namespace {
constexpr const char* kDump = "android.permission.DUMP";
@@ -613,6 +604,31 @@
remove_path_xattr(path, kXattrInodeCodeCache);
}
}
+
+ auto extPath = findDataMediaPath(uuid, userId);
+ if (flags & FLAG_CLEAR_CACHE_ONLY) {
+ // Clear only cached data from shared storage
+ path = StringPrintf("%s/Android/data/%s/cache", extPath.c_str(), pkgname);
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+ // No code cache on shared storage
+ } else {
+ // Clear everything on shared storage
+ path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ }
}
if (flags & FLAG_STORAGE_DE) {
std::string suffix = "";
@@ -681,6 +697,20 @@
if (delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
+
+ auto extPath = findDataMediaPath(uuid, userId);
+ path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
}
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
@@ -715,7 +745,7 @@
auto ce_path = create_data_user_ce_path(uuid_, user);
auto de_path = create_data_user_de_path(uuid_, user);
char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(), nullptr };
- if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
return error("Failed to fts_open");
}
while ((p = fts_read(fts)) != nullptr) {
@@ -840,7 +870,7 @@
};
LOG(DEBUG) << "Copying " << from << " to " << to;
- int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+ int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
goto fail;
@@ -886,7 +916,7 @@
argv[7] = (char*) to.c_str();
LOG(DEBUG) << "Copying " << from << " to " << to;
- int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+ int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
goto fail;
@@ -899,7 +929,7 @@
argv[7] = (char*) to.c_str();
LOG(DEBUG) << "Copying " << from << " to " << to;
- int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+ int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
goto fail;
@@ -922,20 +952,20 @@
// Nuke everything we might have already copied
{
auto to = create_data_app_package_path(to_uuid, data_app_name);
- if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to rollback " << to;
}
}
for (auto user : users) {
{
auto to = create_data_user_de_package_path(to_uuid, user, package_name);
- if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to rollback " << to;
}
}
{
auto to = create_data_user_ce_package_path(to_uuid, user, package_name);
- if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to rollback " << to;
}
}
@@ -1045,10 +1075,10 @@
auto media_path = findDataMediaPath(uuid, user) + "/Android/data/";
char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
(char*) media_path.c_str(), nullptr };
- if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
return error("Failed to fts_open");
}
- while ((p = fts_read(fts)) != NULL) {
+ while ((p = fts_read(fts)) != nullptr) {
if (p->fts_info == FTS_D && p->fts_level == 1) {
uid_t uid = p->fts_statp->st_uid;
if (multiuser_get_app_id(uid) == AID_MEDIA_RW) {
@@ -1398,11 +1428,11 @@
FTS *fts;
FTSENT *p;
char *argv[] = { (char*) path.c_str(), nullptr };
- if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
PLOG(ERROR) << "Failed to fts_open " << path;
return;
}
- while ((p = fts_read(fts)) != NULL) {
+ while ((p = fts_read(fts)) != nullptr) {
p->fts_number = p->fts_parent->fts_number;
switch (p->fts_info) {
case FTS_D:
@@ -1808,10 +1838,10 @@
FTSENT *p;
auto path = create_data_media_path(uuid_, userId);
char *argv[] = { (char*) path.c_str(), nullptr };
- if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
return error("Failed to fts_open " + path);
}
- while ((p = fts_read(fts)) != NULL) {
+ while ((p = fts_read(fts)) != nullptr) {
char* ext;
int64_t size = (p->fts_statp->st_blocks * 512);
switch (p->fts_info) {
@@ -2040,7 +2070,7 @@
}
} else {
if (S_ISDIR(libStat.st_mode)) {
- if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
+ if (delete_dir_contents(libsymlink, 1, nullptr) < 0) {
res = error("Failed to delete " + _libsymlink);
goto out;
}
@@ -2082,14 +2112,14 @@
static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
{
execl(kIdMapPath, kIdMapPath, "--fd", target_apk, overlay_apk,
- StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+ StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr);
PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
}
static void run_verify_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
{
execl(kIdMapPath, kIdMapPath, "--verify", target_apk, overlay_apk,
- StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+ StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr);
PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
}
@@ -2140,7 +2170,7 @@
static int flatten_path(const char *prefix, const char *suffix,
const char *overlay_path, char *idmap_path, size_t N)
{
- if (overlay_path == NULL || idmap_path == NULL) {
+ if (overlay_path == nullptr || idmap_path == nullptr) {
return -1;
}
const size_t len_overlay_path = strlen(overlay_path);
@@ -2481,7 +2511,7 @@
std::to_string(shmSize));
}
auto data = std::unique_ptr<void, std::function<void (void *)>>(
- mmap(NULL, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
+ mmap(nullptr, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
[contentSize] (void* ptr) {
if (ptr != MAP_FAILED) {
munmap(ptr, contentSize);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 91e20b7..89b08e5 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -102,4 +102,17 @@
boolean prepareAppProfile(@utf8InCpp String packageName,
int userId, int appId, @utf8InCpp String profileName, @utf8InCpp String codePath,
@nullable @utf8InCpp String dexMetadata);
+
+ const int FLAG_STORAGE_DE = 0x1;
+ const int FLAG_STORAGE_CE = 0x2;
+
+ const int FLAG_CLEAR_CACHE_ONLY = 0x10;
+ const int FLAG_CLEAR_CODE_CACHE_ONLY = 0x20;
+
+ const int FLAG_FREE_CACHE_V2 = 0x100;
+ const int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 0x200;
+ const int FLAG_FREE_CACHE_NOOP = 0x400;
+
+ const int FLAG_USE_QUOTA = 0x1000;
+ const int FLAG_FORCE = 0x2000;
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 03a411d..66dece7 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -190,9 +190,9 @@
strlcpy(buf, str, sizeof(buf));
char *pBuf = buf;
- while(strtok_r(pBuf, " ", &ctx) != NULL) {
+ while(strtok_r(pBuf, " ", &ctx) != nullptr) {
count++;
- pBuf = NULL;
+ pBuf = nullptr;
}
return count;
@@ -205,9 +205,9 @@
char *tok;
char *pBuf = buf;
- while((tok = strtok_r(pBuf, " ", &ctx)) != NULL) {
+ while((tok = strtok_r(pBuf, " ", &ctx)) != nullptr) {
argv[count++] = tok;
- pBuf = NULL;
+ pBuf = nullptr;
}
return count;
@@ -216,7 +216,7 @@
static const char* get_location_from_path(const char* path) {
static constexpr char kLocationSeparator = '/';
const char *location = strrchr(path, kLocationSeparator);
- if (location == NULL) {
+ if (location == nullptr) {
return path;
} else {
// Skip the separator character.
@@ -243,17 +243,17 @@
const char* relative_input_file_name = get_location_from_path(input_file_name);
char dex2oat_Xms_flag[kPropertyValueMax];
- bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;
+ bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, nullptr) > 0;
char dex2oat_Xmx_flag[kPropertyValueMax];
- bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;
+ bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, nullptr) > 0;
char dex2oat_threads_buf[kPropertyValueMax];
bool have_dex2oat_threads_flag = get_property(post_bootcomplete
? "dalvik.vm.dex2oat-threads"
: "dalvik.vm.boot-dex2oat-threads",
dex2oat_threads_buf,
- NULL) > 0;
+ nullptr) > 0;
char dex2oat_threads_arg[kPropertyValueMax + 2];
if (have_dex2oat_threads_flag) {
sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
@@ -263,20 +263,20 @@
sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
char dex2oat_isa_features[kPropertyValueMax];
bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
- dex2oat_isa_features, NULL) > 0;
+ dex2oat_isa_features, nullptr) > 0;
char dex2oat_isa_variant_key[kPropertyKeyMax];
sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
char dex2oat_isa_variant[kPropertyValueMax];
bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,
- dex2oat_isa_variant, NULL) > 0;
+ dex2oat_isa_variant, nullptr) > 0;
const char *dex2oat_norelocation = "-Xnorelocate";
bool have_dex2oat_relocation_skip_flag = false;
char dex2oat_flags[kPropertyValueMax];
int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
- dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags);
+ dex2oat_flags, nullptr) <= 0 ? 0 : split_count(dex2oat_flags);
ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
// If we are booting without the real /data, don't spend time compiling.
@@ -291,14 +291,14 @@
char app_image_format[kPropertyValueMax];
char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
bool have_app_image_format =
- image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+ image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
if (have_app_image_format) {
sprintf(image_format_arg, "--image-format=%s", app_image_format);
}
char dex2oat_large_app_threshold[kPropertyValueMax];
bool have_dex2oat_large_app_threshold =
- get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0;
+ get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, nullptr) > 0;
char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
if (have_dex2oat_large_app_threshold) {
sprintf(dex2oat_large_app_threshold_arg,
@@ -400,7 +400,7 @@
if (!have_dex2oat_compiler_filter_flag) {
char dex2oat_compiler_filter_flag[kPropertyValueMax];
have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
- dex2oat_compiler_filter_flag, NULL) > 0;
+ dex2oat_compiler_filter_flag, nullptr) > 0;
if (have_dex2oat_compiler_filter_flag) {
sprintf(dex2oat_compiler_filter_arg,
"--compiler-filter=%s",
@@ -552,7 +552,7 @@
argv[i++] = compilation_reason_arg.c_str();
}
// Do not add after dex2oat_flags, they should override others for debugging.
- argv[i] = NULL;
+ argv[i] = nullptr;
execv(dex2oat_bin, (char * const *)argv);
PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
@@ -792,7 +792,7 @@
}
// Do not add after dex2oat_flags, they should override others for debugging.
- argv[i] = NULL;
+ argv[i] = nullptr;
execv(profman_bin, (char * const *)argv);
PLOG(ERROR) << "execv(" << profman_bin << ") failed";
@@ -948,7 +948,7 @@
for (const std::string& profman_arg : profman_args) {
argv[i++] = profman_arg.c_str();
}
- argv[i] = NULL;
+ argv[i] = nullptr;
execv(PROFMAN_BIN, (char * const *)argv);
PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
@@ -1308,7 +1308,7 @@
}
char app_image_format[kPropertyValueMax];
bool have_app_image_format =
- get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+ get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
if (!have_app_image_format) {
return Dex2oatFileWrapper();
}
@@ -1629,7 +1629,7 @@
if (class_loader_context != nullptr) {
argv[i++] = class_loader_context_arg.c_str();
}
- argv[i] = NULL;
+ argv[i] = nullptr;
execv(dexoptanalyzer_bin, (char * const *)argv);
ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 95ed2ff..673ff0d 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -107,7 +107,7 @@
DIR *dir;
struct dirent *dirent;
dir = opendir("/data/user");
- if (dir != NULL) {
+ if (dir != nullptr) {
while ((dirent = readdir(dir))) {
const char *name = dirent->d_name;
@@ -146,10 +146,10 @@
closedir(dir);
if (access(keychain_added_dir, F_OK) == 0) {
- delete_dir_contents(keychain_added_dir, 1, 0);
+ delete_dir_contents(keychain_added_dir, 1, nullptr);
}
if (access(keychain_removed_dir, F_OK) == 0) {
- delete_dir_contents(keychain_removed_dir, 1, 0);
+ delete_dir_contents(keychain_removed_dir, 1, nullptr);
}
}
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index f950276..0c586b6 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -18,6 +18,9 @@
# This script will run as a postinstall step to drive otapreopt.
+# Temporarily disable for b/115853663.
+exit 0
+
TARGET_SLOT="$1"
STATUS_FD="$2"
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 2d58515..db09070 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -40,8 +40,8 @@
constexpr int64_t kGbInBytes = 1024 * kMbInBytes;
constexpr int64_t kTbInBytes = 1024 * kGbInBytes;
-static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
-static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
+#define FLAG_FREE_CACHE_V2 InstalldNativeService::FLAG_FREE_CACHE_V2
+#define FLAG_FREE_CACHE_V2_DEFY_QUOTA InstalldNativeService::FLAG_FREE_CACHE_V2_DEFY_QUOTA
int get_property(const char *key, char *value, const char *default_value) {
return property_get(key, value, default_value);
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index a5af5d7..9dad995 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -37,7 +37,7 @@
constexpr const char* kTestUuid = "TEST";
-static constexpr int FLAG_FORCE = 1 << 16;
+#define FLAG_FORCE InstalldNativeService::FLAG_FORCE
int get_property(const char *key, char *value, const char *default_value) {
return property_get(key, value, default_value);
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 1ff45e4..48f9eb4 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -310,7 +310,7 @@
std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX);
DIR* dir = opendir(path.c_str());
- if (dir == NULL) {
+ if (dir == nullptr) {
// Unable to discover other users, but at least return owner
PLOG(ERROR) << "Failed to opendir " << path;
return users;
@@ -340,13 +340,13 @@
FTSENT *p;
int64_t matchedSize = 0;
char *argv[] = { (char*) path.c_str(), nullptr };
- if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
if (errno != ENOENT) {
PLOG(ERROR) << "Failed to fts_open " << path;
}
return -1;
}
- while ((p = fts_read(fts)) != NULL) {
+ while ((p = fts_read(fts)) != nullptr) {
switch (p->fts_info) {
case FTS_D:
case FTS_DEFAULT:
@@ -469,7 +469,7 @@
continue;
}
subdir = fdopendir(subfd);
- if (subdir == NULL) {
+ if (subdir == nullptr) {
ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
close(subfd);
result = -1;
@@ -495,11 +495,11 @@
}
int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) {
- return delete_dir_contents(pathname.c_str(), 0, NULL, ignore_if_missing);
+ return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing);
}
int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) {
- return delete_dir_contents(pathname.c_str(), 1, NULL, ignore_if_missing);
+ return delete_dir_contents(pathname.c_str(), 1, nullptr, ignore_if_missing);
}
int delete_dir_contents(const char *pathname,
@@ -511,7 +511,7 @@
DIR *d;
d = opendir(pathname);
- if (d == NULL) {
+ if (d == nullptr) {
if (ignore_if_missing && (errno == ENOENT)) {
return 0;
}
@@ -540,12 +540,12 @@
return -1;
}
d = fdopendir(fd);
- if (d == NULL) {
+ if (d == nullptr) {
ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
close(fd);
return -1;
}
- res = _delete_dir_contents(d, 0);
+ res = _delete_dir_contents(d, nullptr);
closedir(d);
return res;
}
@@ -573,7 +573,7 @@
}
DIR *ds = fdopendir(sdfd);
- if (ds == NULL) {
+ if (ds == nullptr) {
ALOGE("Couldn't fdopendir: %s\n", strerror(errno));
return -1;
}
@@ -619,18 +619,18 @@
uid_t group)
{
int res = 0;
- DIR *ds = NULL;
- DIR *dd = NULL;
+ DIR *ds = nullptr;
+ DIR *dd = nullptr;
ds = opendir(srcname);
- if (ds == NULL) {
+ if (ds == nullptr) {
ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno));
return -errno;
}
mkdir(dstname, 0600);
dd = opendir(dstname);
- if (dd == NULL) {
+ if (dd == nullptr) {
ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno));
closedir(ds);
return -errno;
@@ -964,11 +964,11 @@
FTS *fts;
FTSENT *p;
char *argv[] = { (char*) path.c_str(), nullptr };
- if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
PLOG(ERROR) << "Failed to fts_open " << path;
return -1;
}
- while ((p = fts_read(fts)) != NULL) {
+ while ((p = fts_read(fts)) != nullptr) {
switch (p->fts_info) {
case FTS_DP:
if (chmod(p->fts_path, target_mode) != 0) {
@@ -1037,7 +1037,7 @@
}
DIR* subdir = fdopendir(subdir_fd);
- if (subdir == NULL) {
+ if (subdir == nullptr) {
PLOG(WARNING) << "Could not open dir path " << local_path;
result = false;
continue;
@@ -1055,7 +1055,7 @@
bool collect_profiles(std::vector<std::string>* profiles_paths) {
DIR* d = opendir(android_profiles_dir.c_str());
- if (d == NULL) {
+ if (d == nullptr) {
return false;
} else {
return collect_profiles(d, android_profiles_dir, profiles_paths);
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 0bc08a9..68ddeb0 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -30,14 +30,13 @@
message SurfaceChange {
required int32 id = 1;
-
+ reserved 7;
oneof SurfaceChange {
PositionChange position = 2;
SizeChange size = 3;
AlphaChange alpha = 4;
LayerChange layer = 5;
CropChange crop = 6;
- FinalCropChange final_crop = 7;
MatrixChange matrix = 8;
OverrideScalingModeChange override_scaling_mode = 9;
TransparentRegionHintChange transparent_region_hint = 10;
@@ -71,10 +70,6 @@
required Rectangle rectangle = 1;
}
-message FinalCropChange {
- required Rectangle rectangle = 1;
-}
-
message MatrixChange {
required float dsdx = 1;
required float dtdx = 2;
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 4140f40..6602546 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -388,9 +388,6 @@
case SurfaceChange::SurfaceChangeCase::kMatrix:
setMatrix(transaction, change.id(), change.matrix());
break;
- case SurfaceChange::SurfaceChangeCase::kFinalCrop:
- setFinalCrop(transaction, change.id(), change.final_crop());
- break;
case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
setOverrideScalingMode(transaction, change.id(),
change.override_scaling_mode());
@@ -489,17 +486,7 @@
Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
cc.rectangle().bottom());
- t.setCrop(mLayers[id], r);
-}
-
-void Replayer::setFinalCrop(SurfaceComposerClient::Transaction& t,
- layer_id id, const FinalCropChange& fcc) {
- ALOGV("Layer %d: Setting Final Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
- fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
- fcc.rectangle().bottom());
- Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
- fcc.rectangle().bottom());
- t.setFinalCrop(mLayers[id], r);
+ t.setCrop_legacy(mLayers[id], r);
}
void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
@@ -570,7 +557,7 @@
auto handle = mLayers[dtc.layer_id()]->getHandle();
- t.deferTransactionUntil(mLayers[id], handle, dtc.frame_number());
+ t.deferTransactionUntil_legacy(mLayers[id], handle, dtc.frame_number());
}
void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t,
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index 295403e..68390d3 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -92,8 +92,6 @@
layer_id id, const LayerChange& lc);
void setCrop(SurfaceComposerClient::Transaction& t,
layer_id id, const CropChange& cc);
- void setFinalCrop(SurfaceComposerClient::Transaction& t,
- layer_id id, const FinalCropChange& fcc);
void setMatrix(SurfaceComposerClient::Transaction& t,
layer_id id, const MatrixChange& mc);
void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
diff --git a/data/etc/android.hardware.face.xml b/data/etc/android.hardware.face.xml
new file mode 100644
index 0000000..abd23fb
--- /dev/null
+++ b/data/etc/android.hardware.face.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<!-- This is the standard set of features for a biometric face authentication sensor. -->
+<permissions>
+ <feature name="android.hardware.face" />
+</permissions>
diff --git a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
deleted file mode 100644
index b32c92e..0000000
--- a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#ifndef ANDROID_IARC_VIDEO_BRIDGE_H
-#define ANDROID_IARC_VIDEO_BRIDGE_H
-
-#include <arc/IArcBridgeService.h>
-#include <binder/IInterface.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-class IArcVideoBridge : public IInterface {
-public:
- DECLARE_META_INTERFACE(ArcVideoBridge);
-
- // Returns MojoBootstrapResult for creating mojo ipc channel of
- // VideoAcceleratorFactory.
- virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() = 0;
-
- // Get the version of the remote VideoHost on Chromium side.
- virtual int32_t hostVersion() = 0;
-};
-
-class BnArcVideoBridge : public BnInterface<IArcVideoBridge> {
-public:
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IARC_VIDEO_BRIDGE_H
diff --git a/include/android/input.h b/include/android/input.h
index 6810901..cfade6c 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -83,7 +83,7 @@
};
/**
- * Meta key / modifer state.
+ * Meta key / modifier state.
*/
enum {
/** No meta keys are pressed. */
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
new file mode 100644
index 0000000..79f666b
--- /dev/null
+++ b/include/android/system_fonts.h
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+/**
+ * @file system_fonts.h
+ * @brief Provides the system font configurations.
+ *
+ * These APIs provides the list of system installed font files with additional metadata about the
+ * font.
+ *
+ * The ASystemFontIterator_open method will give you an iterator which can iterate all system
+ * installed font files as shown in the following example.
+ *
+ * <code>
+ * ASystemFontIterator* iterator = ASystemFontIterator_open();
+ * ASystemFont* font = NULL;
+ *
+ * while ((font = ASystemFontIterator_next(iterator)) != nullptr) {
+ * // Look if the font is your desired one.
+ * if (ASystemFont_getWeight(font) == 400 && !ASystemFont_isItalic(font)
+ * && ASystemFont_getLocale(font) == NULL) {
+ * break;
+ * }
+ * ASystemFont_close(font);
+ * }
+ * ASystemFontIterator_close(iterator);
+ *
+ * int fd = open(ASystemFont_getFontFilePath(font), O_RDONLY);
+ * int collectionIndex = ASystemFont_getCollectionINdex(font);
+ * std::vector<std::pair<uint32_t, float>> variationSettings;
+ * for (size_t i = 0; i < ASystemFont_getAxisCount(font); ++i) {
+ * variationSettings.push_back(std::make_pair(
+ * ASystemFont_getAxisTag(font, i),
+ * ASystemFont_getAxisValue(font, i)));
+ * }
+ * ASystemFont_close(font);
+ *
+ * // Use this font for your text rendering engine.
+ *
+ * </code>
+ *
+ * Available since API level 29.
+ */
+
+#ifndef ANDROID_SYSTEM_FONTS_H
+#define ANDROID_SYSTEM_FONTS_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit).
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+enum {
+ /** The minimum value fot the font weight value. */
+ ASYSTEM_FONT_WEIGHT_MIN = 0,
+
+ /** A font weight value for the thin weight. */
+ ASYSTEM_FONT_WEIGHT_THIN = 100,
+
+ /** A font weight value for the extra-light weight. */
+ ASYSTEM_FONT_WEIGHT_EXTRA_LIGHT = 200,
+
+ /** A font weight value for the light weight. */
+ ASYSTEM_FONT_WEIGHT_LIGHT = 300,
+
+ /** A font weight value for the normal weight. */
+ ASYSTEM_FONT_WEIGHT_NORMAL = 400,
+
+ /** A font weight value for the medium weight. */
+ ASYSTEM_FONT_WEIGHT_MEDIUM = 500,
+
+ /** A font weight value for the semi-bold weight. */
+ ASYSTEM_FONT_WEIGHT_SEMI_BOLD = 600,
+
+ /** A font weight value for the bold weight. */
+ ASYSTEM_FONT_WEIGHT_BOLD = 700,
+
+ /** A font weight value for the extra-bold weight. */
+ ASYSTEM_FONT_WEIGHT_EXTRA_BOLD = 800,
+
+ /** A font weight value for the black weight. */
+ ASYSTEM_FONT_WEIGHT_BLACK = 900,
+
+ /** The maximum value for the font weight value. */
+ ASYSTEM_FONT_WEIGHT_MAX = 1000
+};
+
+/**
+ * ASystemFontIterator provides access to the system font configuration.
+ *
+ * ASystemFontIterator is an iterator for all available system font settings.
+ * This iterator is not a thread-safe object. Do not pass this iterator to other threads.
+ */
+struct ASystemFontIterator;
+
+/**
+ * ASystemFont provides information of the single system font configuration.
+ */
+struct ASystemFont;
+
+/**
+ * Create a system font iterator.
+ *
+ * Use ASystemFont_close() to close the iterator.
+ *
+ * \return a pointer for a newly allocated iterator, nullptr on failure.
+ */
+ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29);
+
+/**
+ * Close an opened system font iterator, freeing any related resources.
+ *
+ * \param a pointer of an iterator for the system fonts. Do nothing if NULL is passed.
+ */
+void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTRODUCED_IN(29);
+
+/**
+ * Move to the next system font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return true if more system fonts are available, otherwise false.
+ */
+ASystemFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29);
+
+/**
+ * Close an ASystemFont returned by ASystemFontIterator_next.
+ *
+ * \param font a font returned by ASystemFontIterator_next. Do nothing if NULL is passed.
+ */
+void ASystemFont_close(ASystemFont* _Nullable font) __INTRODUCED_IN(29);
+
+
+/**
+ * Return an absolute path to the current font file.
+ *
+ * Here is a list of font formats returned by this method:
+ * <ul>
+ * <li>OpenType</li>
+ * <li>OpenType Font Collection</li>
+ * <li>TrueType</li>
+ * <li>TrueType Collection</li>
+ * </ul>
+ * The file extension could be one of *.otf, *.ttf, *.otc or *.ttc.
+ *
+ * The font file returned is guaranteed to be opend with O_RDONLY.
+ * Note that the returned pointer is valid until ASystemFont_close() is called for the given font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a string of the font file path.
+ */
+const char* _Nonnull ASystemFont_getFontFilePath(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a weight value associated with the current font.
+ *
+ * The weight values are positive and less than or equal to 1000.
+ * Here are pairs of the common names and their values.
+ * <p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="center">Value</th>
+ * <th align="center">Name</th>
+ * <th align="center">NDK Definition</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="center">100</td>
+ * <td align="center">Thin</td>
+ * <td align="center">{@link ASYSTEM_FONT_WEIGHT_THIN}</td>
+ * </tr>
+ * <tr>
+ * <td align="center">200</td>
+ * <td align="center">Extra Light (Ultra Light)</td>
+ * <td align="center">{@link ASYSTEM_FONT_WEIGHT_EXTRA_LIGHT}</td>
+ * </tr>
+ * <tr>
+ * <td align="center">300</td>
+ * <td align="center">Light</td>
+ * <td align="center">{@link ASYSTEM_FONT_WEIGHT_LIGHT}</td>
+ * </tr>
+ * <tr>
+ * <td align="center">400</td>
+ * <td align="center">Normal (Regular)</td>
+ * <td align="center">{@link ASYSTEM_FONT_WEIGHT_NORMAL}</td>
+ * </tr>
+ * <tr>
+ * <td align="center">500</td>
+ * <td align="center">Medium</td>
+ * <td align="center">{@link ASYSTEM_FONT_WEIGHT_MEDIUM}</td>
+ * </tr>
+ * <tr>
+ * <td align="center">600</td>
+ * <td align="center">Semi Bold (Demi Bold)</td>
+ * <td align="center">{@link ASYSTEM_FONT_WEIGHT_SEMI_BOLD}</td>
+ * </tr>
+ * <tr>
+ * <td align="center">700</td>
+ * <td align="center">Bold</td>
+ * <td align="center">{@link ASYSTEM_FONT_WEIGHT_BOLD}</td>
+ * </tr>
+ * <tr>
+ * <td align="center">800</td>
+ * <td align="center">Extra Bold (Ultra Bold)</td>
+ * <td align="center">{@link ASYSTEM_FONT_WEIGHT_EXTRA_BOLD}</td>
+ * </tr>
+ * <tr>
+ * <td align="center">900</td>
+ * <td align="center">Black (Heavy)</td>
+ * <td align="center">{@link ASYSTEM_FONT_WEIGHT_BLACK}</td>
+ * </tr>
+ * </tbody>
+ * </p>
+ * Note that the weight value may fall in between above values, e.g. 250 weight.
+ *
+ * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass)
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned.
+ */
+uint16_t ASystemFont_getWeight(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return true if the current font is italic, otherwise returns false.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return true if italic, otherwise false.
+ */
+bool ASystemFont_isItalic(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a IETF BCP47 compliant language tag associated with the current font.
+ *
+ * For information about IETF BCP47, read [Locale.forLanguageTag(java.lang.String)](https://developer.android.com/reference/java/util/Locale.html#forLanguageTag(java.lang.String)")
+ *
+ * Note that the returned pointer is valid until ASystemFont_close() is called.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a IETF BCP47 compliant langauge tag or nullptr if not available.
+ */
+const char* _Nullable ASystemFont_getLocale(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a font collection index value associated with the current font.
+ *
+ * In case the target font file is a font collection (e.g. .ttc or .otc), this
+ * returns a non-negative value as an font offset in the collection. This
+ * always returns 0 if the target font file is a regular font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a font collection index.
+ */
+size_t ASystemFont_getCollectionIndex(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a count of font variation settings associated with the current font
+ *
+ * The font variation settings are provided as multiple tag-values pairs.
+ *
+ * For example, bold italic font may have following font variation settings:
+ * 'wght' 700, 'slnt' -12
+ * In this case, ASystemFont_getAxisCount returns 2 and ASystemFont_getAxisTag
+ * and ASystemFont_getAxisValue will return following values.
+ * <code>
+ * ASystemFont* font = ASystemFontIterator_next(ite);
+ *
+ * // Returns the number of axes
+ * ASystemFont_getAxisCount(font); // Returns 2
+ *
+ * // Returns the tag-value pair for the first axis.
+ * ASystemFont_getAxisTag(font, 0); // Returns 'wght'(0x77676874)
+ * ASystemFont_getAxisValue(font, 0); // Returns 700.0
+ *
+ * // Returns the tag-value pair for the second axis.
+ * ASystemFont_getAxisTag(font, 1); // Returns 'slnt'(0x736c6e74)
+ * ASystemFont_getAxisValue(font, 1); // Returns -12.0
+ * </code>
+ *
+ * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar)
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a number of font variation settings.
+ */
+size_t ASystemFont_getAxisCount(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+
+/**
+ * Return an OpenType axis tag associated with the current font.
+ *
+ * See ASystemFont_getAxisCount for more details.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \param an index to the font variation settings. Passing value larger than or
+ * equal to {@link ASystemFont_getAxisCount} is not allowed.
+ * \return an OpenType axis tag value for the given font variation setting.
+ */
+uint32_t ASystemFont_getAxisTag(const ASystemFont* _Nonnull font, uint32_t axisIndex)
+ __INTRODUCED_IN(29);
+
+/**
+ * Return an OpenType axis value associated with the current font.
+ *
+ * See ASystemFont_getAxisCount for more details.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \param an index to the font variation settings. Passing value larger than or
+ * equal to {@link ASYstemFont_getAxisCount} is not allwed.
+ * \return a float value for the given font variation setting.
+ */
+float ASystemFont_getAxisValue(const ASystemFont* _Nonnull font, uint32_t axisIndex)
+ __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_SYSTEM_FONTS_H
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 86da4d3..0f336dd 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -39,13 +39,13 @@
int32_t physicalBottom;
int32_t deviceWidth;
int32_t deviceHeight;
- String8 uniqueId;
+ std::string uniqueId;
DisplayViewport() :
displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
- deviceWidth(0), deviceHeight(0) {
+ deviceWidth(0), deviceHeight(0), uniqueId() {
}
bool operator==(const DisplayViewport& other) const {
diff --git a/include/input/Input.h b/include/input/Input.h
index cfcafab..819a89f 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -25,7 +25,6 @@
#include <utils/BitSet.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
-#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
#include <stdint.h>
@@ -302,12 +301,18 @@
inline void setSource(int32_t source) { mSource = source; }
+ inline int32_t getDisplayId() const { return mDisplayId; }
+
+ inline void setDisplayId(int32_t displayId) { mDisplayId = displayId; }
+
+
protected:
- void initialize(int32_t deviceId, int32_t source);
+ void initialize(int32_t deviceId, int32_t source, int32_t displayId);
void initialize(const InputEvent& from);
int32_t mDeviceId;
int32_t mSource;
+ int32_t mDisplayId;
};
/*
@@ -339,10 +344,11 @@
static const char* getLabel(int32_t keyCode);
static int32_t getKeyCodeFromLabel(const char* label);
-
+
void initialize(
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t flags,
int32_t keyCode,
@@ -556,6 +562,7 @@
void initialize(
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t actionButton,
int32_t flags,
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 1ea69d3..34d164c 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -31,9 +31,9 @@
}
// Information provided by the kernel.
- String8 name;
- String8 location;
- String8 uniqueId;
+ std::string name;
+ std::string location;
+ std::string uniqueId;
uint16_t bus;
uint16_t vendor;
uint16_t product;
@@ -45,7 +45,7 @@
// It is hashed from whatever kernel provided information is available.
// Ideally, the way this value is computed should not change between Android releases
// because that would invalidate persistent settings that rely on it.
- String8 descriptor;
+ std::string descriptor;
// A value added to uniquely identify a device in the absence of a unique id. This
// is intended to be a minimum way to distinguish from other active devices and may
@@ -73,16 +73,16 @@
};
void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+ const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
bool hasMic);
inline int32_t getId() const { return mId; }
inline int32_t getControllerNumber() const { return mControllerNumber; }
inline int32_t getGeneration() const { return mGeneration; }
inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; }
- inline const String8& getAlias() const { return mAlias; }
- inline const String8& getDisplayName() const {
- return mAlias.isEmpty() ? mIdentifier.name : mAlias;
+ inline const std::string& getAlias() const { return mAlias; }
+ inline const std::string& getDisplayName() const {
+ return mAlias.empty() ? mIdentifier.name : mAlias;
}
inline bool isExternal() const { return mIsExternal; }
inline bool hasMic() const { return mHasMic; }
@@ -121,7 +121,7 @@
int32_t mGeneration;
int32_t mControllerNumber;
InputDeviceIdentifier mIdentifier;
- String8 mAlias;
+ std::string mAlias;
bool mIsExternal;
bool mHasMic;
uint32_t mSources;
@@ -149,7 +149,7 @@
*
* Returns an empty string if not found.
*/
-extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+extern std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
const InputDeviceIdentifier& deviceIdentifier,
InputDeviceConfigurationFileType type);
@@ -162,8 +162,8 @@
*
* Returns an empty string if not found.
*/
-extern String8 getInputDeviceConfigurationFilePathByName(
- const String8& name, InputDeviceConfigurationFileType type);
+extern std::string getInputDeviceConfigurationFilePathByName(
+ const std::string& name, InputDeviceConfigurationFileType type);
} // namespace android
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 4b33a96..6d072a3 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -326,7 +326,7 @@
DEFINE_KEYCODE(ALL_APPS),
DEFINE_KEYCODE(REFRESH),
- { NULL, 0 }
+ { nullptr, 0 }
};
static const InputEventLabel AXES[] = {
@@ -375,7 +375,7 @@
// NOTE: If you add a new axis here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
- { NULL, 0 }
+ { nullptr, 0 }
};
static const InputEventLabel LEDS[] = {
@@ -396,7 +396,7 @@
DEFINE_LED(CONTROLLER_4),
// NOTE: If you add new LEDs here, you must also add them to Input.h
- { NULL, 0 }
+ { nullptr, 0 }
};
static const InputEventLabel FLAGS[] = {
@@ -404,7 +404,7 @@
DEFINE_FLAG(FUNCTION),
DEFINE_FLAG(GESTURE),
- { NULL, 0 }
+ { nullptr, 0 }
};
static int lookupValueByLabel(const char* literal, const InputEventLabel *list) {
@@ -424,7 +424,7 @@
}
list++;
}
- return NULL;
+ return nullptr;
}
static inline int32_t getKeyCodeByLabel(const char* label) {
@@ -435,7 +435,7 @@
if (keyCode >= 0 && keyCode < static_cast<int32_t>(size(KEYCODES))) {
return KEYCODES[keyCode].literal;
}
- return NULL;
+ return nullptr;
}
static inline uint32_t getKeyFlagByLabel(const char* label) {
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 1ea2c2c..5fd86b4 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -27,6 +27,8 @@
* The InputConsumer is used by the application to receive events from the input dispatcher.
*/
+#include <string>
+
#include <input/Input.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
@@ -212,6 +214,7 @@
uint32_t seq,
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t flags,
int32_t keyCode,
@@ -305,7 +308,7 @@
* Other errors probably indicate that the channel is broken.
*/
status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
/* Sends a finished signal to the publisher to inform it that the message
* with the specified sequence number has finished being process and whether
@@ -460,10 +463,9 @@
Vector<SeqChain> mSeqChains;
status_t consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
status_t consumeSamples(InputEventFactoryInterface* factory,
- Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent,
- int32_t* displayId);
+ Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
void updateTouchState(InputMessage& msg);
void resampleTouchState(nsecs_t frameTime, MotionEvent* event,
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 33d2757..9f4559f 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -27,7 +27,6 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
-#include <utils/String8.h>
#include <utils/Unicode.h>
#include <utils/RefBase.h>
@@ -75,10 +74,10 @@
};
/* Loads a key character map from a file. */
- static status_t load(const String8& filename, Format format, sp<KeyCharacterMap>* outMap);
+ static status_t load(const std::string& filename, Format format, sp<KeyCharacterMap>* outMap);
/* Loads a key character map from its string contents. */
- static status_t loadContents(const String8& filename,
+ static status_t loadContents(const std::string& filename,
const char* contents, Format format, sp<KeyCharacterMap>* outMap);
/* Combines a base key character map and an overlay. */
@@ -221,7 +220,7 @@
status_t parseKey();
status_t parseKeyProperty();
status_t finishKey(Key* key);
- status_t parseModifier(const String8& token, int32_t* outMetaState);
+ status_t parseModifier(const std::string& token, int32_t* outMetaState);
status_t parseCharacterLiteral(char16_t* outCharacter);
};
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index 1e8de71..73815fe 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -62,7 +62,7 @@
*/
class KeyLayoutMap : public RefBase {
public:
- static status_t load(const String8& filename, sp<KeyLayoutMap>* outMap);
+ static status_t load(const std::string& filename, sp<KeyLayoutMap>* outMap);
status_t mapKey(int32_t scanCode, int32_t usageCode,
int32_t* outKeyCode, uint32_t* outFlags) const;
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index d4903e9..8b66f69 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -21,7 +21,6 @@
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
#include <utils/Errors.h>
-#include <utils/String8.h>
#include <utils/PropertyMap.h>
namespace android {
@@ -43,10 +42,10 @@
*/
class KeyMap {
public:
- String8 keyLayoutFile;
+ std::string keyLayoutFile;
sp<KeyLayoutMap> keyLayoutMap;
- String8 keyCharacterMapFile;
+ std::string keyCharacterMapFile;
sp<KeyCharacterMap> keyCharacterMap;
KeyMap();
@@ -56,11 +55,11 @@
const PropertyMap* deviceConfiguration);
inline bool haveKeyLayout() const {
- return !keyLayoutFile.isEmpty();
+ return !keyLayoutFile.empty();
}
inline bool haveKeyCharacterMap() const {
- return !keyCharacterMapFile.isEmpty();
+ return !keyCharacterMapFile.empty();
}
inline bool isComplete() const {
@@ -68,12 +67,12 @@
}
private:
- bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
- status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
+ bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
+ status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name);
- String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name, InputDeviceConfigurationFileType type);
+ const std::string& name);
+ std::string getPath(const InputDeviceIdentifier& deviceIdentifier,
+ const std::string& name, InputDeviceConfigurationFileType type);
};
/**
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index ffa1614..727865a 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -63,7 +63,7 @@
// Creates a velocity tracker using the specified strategy.
// If strategy is NULL, uses the default strategy for the platform.
- VelocityTracker(const char* strategy = NULL);
+ VelocityTracker(const char* strategy = nullptr);
~VelocityTracker();
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index e245ead..24e0e0e 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -23,7 +23,6 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
-#include <utils/String8.h>
#include <utils/Unicode.h>
namespace android {
@@ -50,7 +49,7 @@
public:
~VirtualKeyMap();
- static status_t load(const String8& filename, VirtualKeyMap** outMap);
+ static status_t load(const std::string& filename, VirtualKeyMap** outMap);
inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
return mVirtualKeys;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 61b8818..b2a304a 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -107,6 +107,7 @@
"-Wall",
"-Wextra",
"-Werror",
+ "-Wzero-as-null-pointer-constant",
],
product_variables: {
binder32bit: {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b3ae09b..87c9842 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -74,7 +74,7 @@
}
// Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER
-#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
+#define STRICT_MODE_PENALTY_GATHER (1 << 31)
// XXX This can be made public if we want to provide
// support for typed data.
@@ -2307,6 +2307,15 @@
int fd = readFileDescriptor();
if (fd == int(BAD_TYPE)) return BAD_VALUE;
+ if (!ashmem_valid(fd)) {
+ ALOGE("invalid fd");
+ return BAD_VALUE;
+ }
+ int size = ashmem_get_size_region(fd);
+ if (size < 0 || size_t(size) < len) {
+ ALOGE("request size %zu does not match fd size %d", len, size);
+ return BAD_VALUE;
+ }
void* ptr = ::mmap(nullptr, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ,
MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) return NO_MEMORY;
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index c5b57c7..7870c7b 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -95,6 +95,20 @@
OP_USE_FINGERPRINT = 55,
OP_BODY_SENSORS = 56,
OP_AUDIO_ACCESSIBILITY_VOLUME = 64,
+ OP_READ_PHONE_NUMBERS = 65,
+ OP_REQUEST_INSTALL_PACKAGES = 66,
+ OP_PICTURE_IN_PICTURE = 67,
+ OP_INSTANT_APP_START_FOREGROUND = 68,
+ OP_ANSWER_PHONE_CALLS = 69,
+ OP_RUN_ANY_IN_BACKGROUND = 70,
+ OP_CHANGE_WIFI_STATE = 71,
+ OP_REQUEST_DELETE_PACKAGES = 72,
+ OP_BIND_ACCESSIBILITY_SERVICE = 73,
+ OP_ACCEPT_HANDOVER = 74,
+ OP_MANAGE_IPSEC_TUNNELS = 75,
+ OP_START_FOREGROUND = 76,
+ OP_BLUETOOTH_SCAN = 77,
+ OP_USE_FACE = 78,
};
AppOpsManager();
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index a998529..1d39aa3 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -86,7 +86,7 @@
const sp<IServiceManager> sm = defaultServiceManager();
if (sm != nullptr) {
*outService = interface_cast<INTERFACE>(sm->getService(name));
- if ((*outService) != NULL) return NO_ERROR;
+ if ((*outService) != nullptr) return NO_ERROR;
}
return NAME_NOT_FOUND;
}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 8b2f842..0d224d8 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -46,6 +46,7 @@
"android.hardware.bluetooth@1.0::IBluetoothHci",
"android.hardware.camera.provider@2.4::ICameraProvider",
"android.hardware.drm@1.0::IDrmFactory",
+ "android.hardware.graphics.allocator@2.0::IAllocator",
"android.hardware.graphics.composer@2.1::IComposer",
"android.hardware.media.omx@1.0::IOmx",
"android.hardware.media.omx@1.0::IOmxStore",
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index b29c1d5..98264ac 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -31,6 +31,7 @@
"-Werror",
],
cppflags: [
+ "-std=c++1z",
"-Weverything",
// The static constructors and destructors in this library have not been noted to
@@ -58,7 +59,7 @@
"-Wno-weak-vtables",
// Allow four-character integer literals
- "-Wno-four-char-constants",
+ "-Wno-four-char-constants",
// Allow documentation warnings
"-Wno-documentation",
@@ -116,14 +117,15 @@
"SyncFeatures.cpp",
"view/Surface.cpp",
"bufferqueue/1.0/B2HProducerListener.cpp",
- "bufferqueue/1.0/H2BGraphicBufferProducer.cpp"
+ "bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
],
shared_libs: [
"android.hardware.graphics.common@1.1",
"libsync",
"libbinder",
- "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
+ "libbufferhub",
+ "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
"libpdx_default_transport",
"libcutils",
"libEGL",
@@ -149,6 +151,7 @@
"BufferHubProducer.cpp",
],
exclude_shared_libs: [
+ "libbufferhub",
"libbufferhubqueue",
"libpdx_default_transport",
],
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index ae5cca2..06d597c 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -18,7 +18,9 @@
#include <gui/BufferHubProducer.h>
#include <inttypes.h>
#include <log/log.h>
+#include <private/dvr/detached_buffer.h>
#include <system/window.h>
+#include <ui/DetachedBufferHandle.h>
namespace android {
@@ -224,24 +226,224 @@
return ret;
}
-status_t BufferHubProducer::detachBuffer(int /* slot */) {
- ALOGE("BufferHubProducer::detachBuffer not implemented.");
- return INVALID_OPERATION;
+status_t BufferHubProducer::detachBuffer(int slot) {
+ ALOGV("detachBuffer: slot=%d", slot);
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ return DetachBufferLocked(static_cast<size_t>(slot));
}
-status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* /* out_buffer */,
- sp<Fence>* /* out_fence */) {
- ALOGE("BufferHubProducer::detachNextBuffer not implemented.");
- return INVALID_OPERATION;
+status_t BufferHubProducer::DetachBufferLocked(size_t slot) {
+ if (connected_api_ == kNoConnectedApi) {
+ ALOGE("detachBuffer: BufferHubProducer is not connected.");
+ return NO_INIT;
+ }
+
+ if (slot >= static_cast<size_t>(max_buffer_count_)) {
+ ALOGE("detachBuffer: slot index %zu out of range [0, %d)", slot, max_buffer_count_);
+ return BAD_VALUE;
+ } else if (!buffers_[slot].mBufferState.isDequeued()) {
+ ALOGE("detachBuffer: slot %zu is not owned by the producer (state = %s)", slot,
+ buffers_[slot].mBufferState.string());
+ return BAD_VALUE;
+ } else if (!buffers_[slot].mRequestBufferCalled) {
+ ALOGE("detachBuffer: buffer in slot %zu has not been requested", slot);
+ return BAD_VALUE;
+ }
+ std::shared_ptr<BufferProducer> buffer_producer = queue_->GetBuffer(slot);
+ if (buffer_producer == nullptr || buffer_producer->buffer() == nullptr) {
+ ALOGE("detachBuffer: Invalid BufferProducer at slot %zu.", slot);
+ return BAD_VALUE;
+ }
+ sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
+ if (graphic_buffer == nullptr) {
+ ALOGE("detachBuffer: Invalid GraphicBuffer at slot %zu.", slot);
+ return BAD_VALUE;
+ }
+
+ // Remove the BufferProducer from the ProducerQueue.
+ status_t error = RemoveBuffer(slot);
+ if (error != NO_ERROR) {
+ ALOGE("detachBuffer: Failed to remove buffer, slot=%zu, error=%d.", slot, error);
+ return error;
+ }
+
+ // Here we need to convert the existing ProducerBuffer into a DetachedBufferHandle and inject
+ // the handle into the GraphicBuffer object at the requested slot.
+ auto status_or_handle = buffer_producer->Detach();
+ if (!status_or_handle.ok()) {
+ ALOGE("detachBuffer: Failed to detach from a BufferProducer at slot %zu, error=%d.", slot,
+ status_or_handle.error());
+ return BAD_VALUE;
+ }
+ std::unique_ptr<DetachedBufferHandle> handle =
+ DetachedBufferHandle::Create(status_or_handle.take());
+ if (!handle->isValid()) {
+ ALOGE("detachBuffer: Failed to create a DetachedBufferHandle at slot %zu.", slot);
+ return BAD_VALUE;
+ }
+
+ return graphic_buffer->setDetachedBufferHandle(std::move(handle));
}
-status_t BufferHubProducer::attachBuffer(int* /* out_slot */,
- const sp<GraphicBuffer>& /* buffer */) {
- // With this BufferHub backed implementation, we assume (for now) all buffers
- // are allocated and owned by the BufferHub. Thus the attempt of transfering
- // ownership of a buffer to the buffer queue is intentionally unsupported.
- LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported.");
- return INVALID_OPERATION;
+status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) {
+ ALOGV("detachNextBuffer.");
+
+ if (out_buffer == nullptr || out_fence == nullptr) {
+ ALOGE("detachNextBuffer: Invalid parameter: out_buffer=%p, out_fence=%p", out_buffer,
+ out_fence);
+ return BAD_VALUE;
+ }
+
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (connected_api_ == kNoConnectedApi) {
+ ALOGE("detachNextBuffer: BufferHubProducer is not connected.");
+ return NO_INIT;
+ }
+
+ // detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer, and detachBuffer in
+ // sequence, except for two things:
+ //
+ // 1) It is unnecessary to know the dimensions, format, or usage of the next buffer, i.e. the
+ // function just returns whatever BufferProducer is available from the ProducerQueue and no
+ // buffer allocation or re-allocation will happen.
+ // 2) It will not block, since if it cannot find an appropriate buffer to return, it will return
+ // an error instead.
+ size_t slot = 0;
+ LocalHandle fence;
+
+ // First, dequeue a BufferProducer from the ProducerQueue with no timeout. Report error
+ // immediately if ProducerQueue::Dequeue() fails.
+ auto status_or_buffer = queue_->Dequeue(/*timeout=*/0, &slot, &fence);
+ if (!status_or_buffer.ok()) {
+ ALOGE("detachNextBuffer: Failed to dequeue buffer, error=%d.", status_or_buffer.error());
+ return NO_MEMORY;
+ }
+
+ std::shared_ptr<BufferProducer> buffer_producer = status_or_buffer.take();
+ if (buffer_producer == nullptr) {
+ ALOGE("detachNextBuffer: Dequeued buffer is null.");
+ return NO_MEMORY;
+ }
+
+ // With the BufferHub backed solution, slot returned from |queue_->Dequeue| is guaranteed to
+ // be available for producer's use. It's either in free state (if the buffer has never been used
+ // before) or in queued state (if the buffer has been dequeued and queued back to
+ // BufferHubQueue).
+ if (!buffers_[slot].mBufferState.isFree() && !buffers_[slot].mBufferState.isQueued()) {
+ ALOGE("detachNextBuffer: slot %zu is not free or queued, actual state: %s.", slot,
+ buffers_[slot].mBufferState.string());
+ return BAD_VALUE;
+ }
+ if (buffers_[slot].mBufferProducer == nullptr) {
+ ALOGE("detachNextBuffer: BufferProducer at slot %zu is null.", slot);
+ return BAD_VALUE;
+ }
+ if (buffers_[slot].mBufferProducer->id() != buffer_producer->id()) {
+ ALOGE("detachNextBuffer: BufferProducer at slot %zu has mismatched id, actual: "
+ "%d, expected: %d.",
+ slot, buffers_[slot].mBufferProducer->id(), buffer_producer->id());
+ return BAD_VALUE;
+ }
+
+ ALOGV("detachNextBuffer: slot=%zu", slot);
+ buffers_[slot].mBufferState.freeQueued();
+ buffers_[slot].mBufferState.dequeue();
+
+ // Second, request the buffer.
+ sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
+ buffers_[slot].mGraphicBuffer = buffer_producer->buffer()->buffer();
+
+ // Finally, detach the buffer and then return.
+ status_t error = DetachBufferLocked(slot);
+ if (error == NO_ERROR) {
+ *out_fence = new Fence(fence.Release());
+ *out_buffer = graphic_buffer;
+ }
+ return error;
+}
+
+status_t BufferHubProducer::attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) {
+ // In the BufferHub design, all buffers are allocated and owned by the BufferHub. Thus only
+ // GraphicBuffers that are originated from BufferHub can be attached to a BufferHubProducer.
+ ALOGV("queueBuffer: buffer=%p", buffer.get());
+
+ if (out_slot == nullptr) {
+ ALOGE("attachBuffer: out_slot cannot be NULL.");
+ return BAD_VALUE;
+ }
+ if (buffer == nullptr || !buffer->isDetachedBuffer()) {
+ ALOGE("attachBuffer: invalid GraphicBuffer.");
+ return BAD_VALUE;
+ }
+
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (connected_api_ == kNoConnectedApi) {
+ ALOGE("attachBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ // Before attaching the buffer, caller is supposed to call
+ // IGraphicBufferProducer::setGenerationNumber to inform the
+ // BufferHubProducer the next generation number.
+ if (buffer->getGenerationNumber() != generation_number_) {
+ ALOGE("attachBuffer: Mismatched generation number, buffer: %u, queue: %u.",
+ buffer->getGenerationNumber(), generation_number_);
+ return BAD_VALUE;
+ }
+
+ // Creates a BufferProducer from the GraphicBuffer.
+ std::unique_ptr<DetachedBufferHandle> detached_handle = buffer->takeDetachedBufferHandle();
+ if (detached_handle == nullptr) {
+ ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
+ return BAD_VALUE;
+ }
+ auto detached_buffer = DetachedBuffer::Import(std::move(detached_handle->handle()));
+ if (detached_buffer == nullptr) {
+ ALOGE("attachBuffer: DetachedBuffer cannot be NULL.");
+ return BAD_VALUE;
+ }
+ auto status_or_handle = detached_buffer->Promote();
+ if (!status_or_handle.ok()) {
+ ALOGE("attachBuffer: Failed to promote a DetachedBuffer into a BufferProducer, error=%d.",
+ status_or_handle.error());
+ return BAD_VALUE;
+ }
+ std::shared_ptr<BufferProducer> buffer_producer =
+ BufferProducer::Import(status_or_handle.take());
+ if (buffer_producer == nullptr) {
+ ALOGE("attachBuffer: Failed to import BufferProducer.");
+ return BAD_VALUE;
+ }
+
+ // Adds the BufferProducer into the Queue.
+ auto status_or_slot = queue_->InsertBuffer(buffer_producer);
+ if (!status_or_slot.ok()) {
+ ALOGE("attachBuffer: Failed to insert buffer, error=%d.", status_or_slot.error());
+ return BAD_VALUE;
+ }
+
+ size_t slot = status_or_slot.get();
+ ALOGV("attachBuffer: returning slot %zu.", slot);
+ if (slot >= static_cast<size_t>(max_buffer_count_)) {
+ ALOGE("attachBuffer: Invalid slot: %zu.", slot);
+ return BAD_VALUE;
+ }
+
+ // The just attached buffer should be in dequeued state according to IGraphicBufferProducer
+ // interface. In BufferHub's language the buffer should be in Gained state.
+ buffers_[slot].mGraphicBuffer = buffer;
+ buffers_[slot].mBufferState.attachProducer();
+ buffers_[slot].mEglFence = EGL_NO_SYNC_KHR;
+ buffers_[slot].mFence = Fence::NO_FENCE;
+ buffers_[slot].mRequestBufferCalled = true;
+ buffers_[slot].mAcquireCalled = false;
+ buffers_[slot].mNeedsReallocation = false;
+
+ *out_slot = static_cast<int>(slot);
+ return NO_ERROR;
}
status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
@@ -654,26 +856,28 @@
status_t BufferHubProducer::RemoveBuffer(size_t slot) {
auto status = queue_->RemoveBuffer(slot);
if (!status) {
- ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer: %s",
- status.GetErrorMessage().c_str());
+ ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer at slot: %zu, error: %s.",
+ slot, status.GetErrorMessage().c_str());
return INVALID_OPERATION;
}
// Reset in memory objects related the the buffer.
buffers_[slot].mBufferProducer = nullptr;
- buffers_[slot].mGraphicBuffer = nullptr;
buffers_[slot].mBufferState.detachProducer();
+ buffers_[slot].mFence = Fence::NO_FENCE;
+ buffers_[slot].mGraphicBuffer = nullptr;
+ buffers_[slot].mRequestBufferCalled = false;
return NO_ERROR;
}
status_t BufferHubProducer::FreeAllBuffers() {
for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
// Reset in memory objects related the the buffer.
- buffers_[slot].mGraphicBuffer = nullptr;
- buffers_[slot].mBufferState.reset();
- buffers_[slot].mRequestBufferCalled = false;
buffers_[slot].mBufferProducer = nullptr;
+ buffers_[slot].mBufferState.reset();
buffers_[slot].mFence = Fence::NO_FENCE;
+ buffers_[slot].mGraphicBuffer = nullptr;
+ buffers_[slot].mRequestBufferCalled = false;
}
auto status = queue_->FreeAllBuffers();
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index f50379b..5beba02 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -39,8 +39,8 @@
}
BufferItem::BufferItem() :
- mGraphicBuffer(NULL),
- mFence(NULL),
+ mGraphicBuffer(nullptr),
+ mFence(nullptr),
mCrop(Rect::INVALID_RECT),
mTransform(0),
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
@@ -91,11 +91,11 @@
size_t BufferItem::getFlattenedSize() const {
size_t size = sizeof(uint32_t); // Flags
- if (mGraphicBuffer != 0) {
+ if (mGraphicBuffer != nullptr) {
size += mGraphicBuffer->getFlattenedSize();
size = FlattenableUtils::align<4>(size);
}
- if (mFence != 0) {
+ if (mFence != nullptr) {
size += mFence->getFlattenedSize();
size = FlattenableUtils::align<4>(size);
}
@@ -107,10 +107,10 @@
size_t BufferItem::getFdCount() const {
size_t count = 0;
- if (mGraphicBuffer != 0) {
+ if (mGraphicBuffer != nullptr) {
count += mGraphicBuffer->getFdCount();
}
- if (mFence != 0) {
+ if (mFence != nullptr) {
count += mFence->getFdCount();
}
return count;
@@ -137,13 +137,13 @@
FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
flags = 0;
- if (mGraphicBuffer != 0) {
+ if (mGraphicBuffer != nullptr) {
status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
if (err) return err;
size -= FlattenableUtils::align<4>(buffer);
flags |= 1;
}
- if (mFence != 0) {
+ if (mFence != nullptr) {
status_t err = mFence->flatten(buffer, size, fds, count);
if (err) return err;
size -= FlattenableUtils::align<4>(buffer);
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 89bc0c4..f50bc20 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -107,7 +107,7 @@
void BufferItemConsumer::freeBufferLocked(int slotIndex) {
sp<BufferFreedListener> listener = mBufferFreedListener.promote();
- if (listener != NULL && mSlots[slotIndex].mGraphicBuffer != NULL) {
+ if (listener != nullptr && mSlots[slotIndex].mGraphicBuffer != nullptr) {
// Fire callback if we have a listener registered and the buffer being freed is valid.
BI_LOGV("actually calling onBufferFreed");
listener->onBufferFreed(mSlots[slotIndex].mGraphicBuffer);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index a8da134..5fb3f0b 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -38,7 +38,7 @@
void BufferQueue::ProxyConsumerListener::onDisconnect() {
sp<ConsumerListener> listener(mConsumerListener.promote());
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onDisconnect();
}
}
@@ -46,7 +46,7 @@
void BufferQueue::ProxyConsumerListener::onFrameAvailable(
const BufferItem& item) {
sp<ConsumerListener> listener(mConsumerListener.promote());
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onFrameAvailable(item);
}
}
@@ -54,21 +54,21 @@
void BufferQueue::ProxyConsumerListener::onFrameReplaced(
const BufferItem& item) {
sp<ConsumerListener> listener(mConsumerListener.promote());
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onFrameReplaced(item);
}
}
void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
sp<ConsumerListener> listener(mConsumerListener.promote());
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onBuffersReleased();
}
}
void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
sp<ConsumerListener> listener(mConsumerListener.promote());
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onSidebandStreamChanged();
}
}
@@ -85,21 +85,21 @@
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger) {
- LOG_ALWAYS_FATAL_IF(outProducer == NULL,
+ LOG_ALWAYS_FATAL_IF(outProducer == nullptr,
"BufferQueue: outProducer must not be NULL");
- LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
+ LOG_ALWAYS_FATAL_IF(outConsumer == nullptr,
"BufferQueue: outConsumer must not be NULL");
sp<BufferQueueCore> core(new BufferQueueCore());
- LOG_ALWAYS_FATAL_IF(core == NULL,
+ LOG_ALWAYS_FATAL_IF(core == nullptr,
"BufferQueue: failed to create BufferQueueCore");
sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
- LOG_ALWAYS_FATAL_IF(producer == NULL,
+ LOG_ALWAYS_FATAL_IF(producer == nullptr,
"BufferQueue: failed to create BufferQueueProducer");
sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
- LOG_ALWAYS_FATAL_IF(consumer == NULL,
+ LOG_ALWAYS_FATAL_IF(consumer == nullptr,
"BufferQueue: failed to create BufferQueueConsumer");
*outProducer = producer;
@@ -109,8 +109,8 @@
#ifndef NO_BUFFERHUB
void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer) {
- LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL");
- LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL");
+ LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BufferQueue: outProducer must not be NULL");
+ LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BufferQueue: outConsumer must not be NULL");
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
@@ -118,16 +118,16 @@
dvr::ProducerQueueConfigBuilder configBuilder;
std::shared_ptr<dvr::ProducerQueue> producerQueue =
dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{});
- LOG_ALWAYS_FATAL_IF(producerQueue == NULL, "BufferQueue: failed to create ProducerQueue.");
+ LOG_ALWAYS_FATAL_IF(producerQueue == nullptr, "BufferQueue: failed to create ProducerQueue.");
std::shared_ptr<dvr::ConsumerQueue> consumerQueue = producerQueue->CreateConsumerQueue();
- LOG_ALWAYS_FATAL_IF(consumerQueue == NULL, "BufferQueue: failed to create ConsumerQueue.");
+ LOG_ALWAYS_FATAL_IF(consumerQueue == nullptr, "BufferQueue: failed to create ConsumerQueue.");
producer = BufferHubProducer::Create(producerQueue);
consumer = BufferHubConsumer::Create(consumerQueue);
- LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer");
- LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer");
+ LOG_ALWAYS_FATAL_IF(producer == nullptr, "BufferQueue: failed to create BufferQueueProducer");
+ LOG_ALWAYS_FATAL_IF(consumer == nullptr, "BufferQueue: failed to create BufferQueueConsumer");
*outProducer = producer;
*outConsumer = consumer;
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index d70e142..3837c3e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -255,7 +255,7 @@
// mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
// on the consumer side
if (outBuffer->mAcquireCalled) {
- outBuffer->mGraphicBuffer = NULL;
+ outBuffer->mGraphicBuffer = nullptr;
}
mCore->mQueue.erase(front);
@@ -272,7 +272,7 @@
VALIDATE_CONSISTENCY();
}
- if (listener != NULL) {
+ if (listener != nullptr) {
for (int i = 0; i < numDroppedBuffers; ++i) {
listener->onBufferReleased();
}
@@ -321,10 +321,10 @@
const sp<android::GraphicBuffer>& buffer) {
ATRACE_CALL();
- if (outSlot == NULL) {
+ if (outSlot == nullptr) {
BQ_LOGE("attachBuffer: outSlot must not be NULL");
return BAD_VALUE;
- } else if (buffer == NULL) {
+ } else if (buffer == nullptr) {
BQ_LOGE("attachBuffer: cannot attach NULL buffer");
return BAD_VALUE;
}
@@ -413,7 +413,7 @@
ATRACE_BUFFER_INDEX(slot);
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
- releaseFence == NULL) {
+ releaseFence == nullptr) {
BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
releaseFence.get());
return BAD_VALUE;
@@ -465,7 +465,7 @@
} // Autolock scope
// Call back without lock held
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onBufferReleased();
}
@@ -476,7 +476,7 @@
const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
ATRACE_CALL();
- if (consumerListener == NULL) {
+ if (consumerListener == nullptr) {
BQ_LOGE("connect: consumerListener may not be NULL");
return BAD_VALUE;
}
@@ -504,13 +504,13 @@
Mutex::Autolock lock(mCore->mMutex);
- if (mCore->mConsumerListener == NULL) {
+ if (mCore->mConsumerListener == nullptr) {
BQ_LOGE("disconnect: no consumer is connected");
return BAD_VALUE;
}
mCore->mIsAbandoned = true;
- mCore->mConsumerListener = NULL;
+ mCore->mConsumerListener = nullptr;
mCore->mQueue.clear();
mCore->freeAllBuffersLocked();
mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
@@ -521,7 +521,7 @@
status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) {
ATRACE_CALL();
- if (outSlotMask == NULL) {
+ if (outSlotMask == nullptr) {
BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL");
return BAD_VALUE;
}
@@ -673,7 +673,7 @@
}
}
// Call back without lock held
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onBuffersReleased();
}
@@ -772,7 +772,7 @@
if (uid != shellUid) {
#endif
android_errorWriteWithInfoLog(0x534e4554, "27046057",
- static_cast<int32_t>(uid), NULL, 0);
+ static_cast<int32_t>(uid), nullptr, 0);
return PERMISSION_DENIED;
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index bb703da..960b194 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -349,7 +349,7 @@
BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
usleep(PAUSE_TIME);
}
- if (mSlots[slot].mGraphicBuffer != NULL) {
+ if (mSlots[slot].mGraphicBuffer != nullptr) {
BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
slot);
usleep(PAUSE_TIME);
@@ -371,7 +371,7 @@
BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
usleep(PAUSE_TIME);
}
- if (mSlots[slot].mGraphicBuffer != NULL) {
+ if (mSlots[slot].mGraphicBuffer != nullptr) {
BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
slot);
usleep(PAUSE_TIME);
@@ -394,7 +394,7 @@
BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
usleep(PAUSE_TIME);
}
- if (mSlots[slot].mGraphicBuffer == NULL) {
+ if (mSlots[slot].mGraphicBuffer == nullptr) {
BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
usleep(PAUSE_TIME);
}
@@ -418,7 +418,7 @@
BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
usleep(PAUSE_TIME);
}
- if (mSlots[slot].mGraphicBuffer == NULL && !mIsAllocating) {
+ if (mSlots[slot].mGraphicBuffer == nullptr && !mIsAllocating) {
BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
usleep(PAUSE_TIME);
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index c96a2dd..5e250a4 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -166,7 +166,7 @@
} // Autolock scope
// Call back without lock held
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onBuffersReleased();
}
@@ -221,7 +221,7 @@
} // Autolock scope
// Call back without lock held
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onBuffersReleased();
}
return NO_ERROR;
@@ -449,11 +449,11 @@
mSlots[found].mBufferState.dequeue();
- if ((buffer == NULL) ||
+ if ((buffer == nullptr) ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
mSlots[found].mAcquireCalled = false;
- mSlots[found].mGraphicBuffer = NULL;
+ mSlots[found].mGraphicBuffer = nullptr;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
@@ -471,7 +471,7 @@
BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
mCore->mBufferAge);
- if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
+ if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) {
BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
"slot=%d w=%d h=%d format=%u",
found, buffer->width, buffer->height, buffer->format);
@@ -612,7 +612,7 @@
listener = mCore->mConsumerListener;
}
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onBuffersReleased();
}
@@ -623,10 +623,10 @@
sp<Fence>* outFence) {
ATRACE_CALL();
- if (outBuffer == NULL) {
+ if (outBuffer == nullptr) {
BQ_LOGE("detachNextBuffer: outBuffer must not be NULL");
return BAD_VALUE;
- } else if (outFence == NULL) {
+ } else if (outFence == nullptr) {
BQ_LOGE("detachNextBuffer: outFence must not be NULL");
return BAD_VALUE;
}
@@ -670,7 +670,7 @@
listener = mCore->mConsumerListener;
}
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onBuffersReleased();
}
@@ -681,10 +681,10 @@
const sp<android::GraphicBuffer>& buffer) {
ATRACE_CALL();
- if (outSlot == NULL) {
+ if (outSlot == nullptr) {
BQ_LOGE("attachBuffer: outSlot must not be NULL");
return BAD_VALUE;
- } else if (buffer == NULL) {
+ } else if (buffer == nullptr) {
BQ_LOGE("attachBuffer: cannot attach NULL buffer");
return BAD_VALUE;
}
@@ -766,7 +766,7 @@
const Region& surfaceDamage = input.getSurfaceDamage();
const HdrMetadata& hdrMetadata = input.getHdrMetadata();
- if (acquireFence == NULL) {
+ if (acquireFence == nullptr) {
BQ_LOGE("queueBuffer: fence is NULL");
return BAD_VALUE;
}
@@ -972,9 +972,9 @@
mCallbackCondition.wait(mCallbackMutex);
}
- if (frameAvailableListener != NULL) {
+ if (frameAvailableListener != nullptr) {
frameAvailableListener->onFrameAvailable(item);
- } else if (frameReplacedListener != NULL) {
+ } else if (frameReplacedListener != nullptr) {
frameReplacedListener->onFrameReplaced(item);
}
@@ -1039,7 +1039,7 @@
BQ_LOGE("cancelBuffer: slot %d is not owned by the producer "
"(state = %s)", slot, mSlots[slot].mBufferState.string());
return BAD_VALUE;
- } else if (fence == NULL) {
+ } else if (fence == nullptr) {
BQ_LOGE("cancelBuffer: fence is NULL");
return BAD_VALUE;
}
@@ -1069,7 +1069,7 @@
ATRACE_CALL();
Mutex::Autolock lock(mCore->mMutex);
- if (outValue == NULL) {
+ if (outValue == nullptr) {
BQ_LOGE("query: outValue was NULL");
return BAD_VALUE;
}
@@ -1145,12 +1145,12 @@
return NO_INIT;
}
- if (mCore->mConsumerListener == NULL) {
+ if (mCore->mConsumerListener == nullptr) {
BQ_LOGE("connect: BufferQueue has no consumer");
return NO_INIT;
}
- if (output == NULL) {
+ if (output == nullptr) {
BQ_LOGE("connect: output was NULL");
return BAD_VALUE;
}
@@ -1188,10 +1188,10 @@
output->nextFrameNumber = mCore->mFrameCounter + 1;
output->bufferReplaced = false;
- if (listener != NULL) {
+ if (listener != nullptr) {
// Set up a death notification so that we can disconnect
// automatically if the remote producer dies
- if (IInterface::asBinder(listener)->remoteBinder() != NULL) {
+ if (IInterface::asBinder(listener)->remoteBinder() != nullptr) {
status = IInterface::asBinder(listener)->linkToDeath(
static_cast<IBinder::DeathRecipient*>(this));
if (status != NO_ERROR) {
@@ -1268,7 +1268,7 @@
mCore->freeAllBuffersLocked();
// Remove our death notification callback if we have one
- if (mCore->mLinkedToDeath != NULL) {
+ if (mCore->mLinkedToDeath != nullptr) {
sp<IBinder> token =
IInterface::asBinder(mCore->mLinkedToDeath);
// This can fail if we're here because of the death
@@ -1278,8 +1278,8 @@
}
mCore->mSharedBufferSlot =
BufferQueueCore::INVALID_BUFFER_SLOT;
- mCore->mLinkedToDeath = NULL;
- mCore->mConnectedProducerListener = NULL;
+ mCore->mLinkedToDeath = nullptr;
+ mCore->mConnectedProducerListener = nullptr;
mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
mCore->mConnectedPid = -1;
mCore->mSidebandStream.clear();
@@ -1302,7 +1302,7 @@
} // Autolock scope
// Call back without lock held
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onBuffersReleased();
listener->onDisconnect();
}
@@ -1318,7 +1318,7 @@
listener = mCore->mConsumerListener;
} // Autolock scope
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onSidebandStreamChanged();
}
return NO_ERROR;
@@ -1536,7 +1536,7 @@
Mutex::Autolock lock(mCore->mMutex);
listener = mCore->mConsumerListener;
}
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
}
}
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index f9e292e..abd9921 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -96,7 +96,7 @@
void ConsumerBase::freeBufferLocked(int slotIndex) {
CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
- mSlots[slotIndex].mGraphicBuffer = 0;
+ mSlots[slotIndex].mGraphicBuffer = nullptr;
mSlots[slotIndex].mFence = Fence::NO_FENCE;
mSlots[slotIndex].mFrameNumber = 0;
}
@@ -110,7 +110,7 @@
listener = mFrameAvailableListener.promote();
}
- if (listener != NULL) {
+ if (listener != nullptr) {
CB_LOGV("actually calling onFrameAvailable");
listener->onFrameAvailable(item);
}
@@ -125,7 +125,7 @@
listener = mFrameAvailableListener.promote();
}
- if (listener != NULL) {
+ if (listener != nullptr) {
CB_LOGV("actually calling onFrameReplaced");
listener->onFrameReplaced(item);
}
@@ -352,8 +352,8 @@
return err;
}
- if (item->mGraphicBuffer != NULL) {
- if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
+ if (item->mGraphicBuffer != nullptr) {
+ if (mSlots[item->mSlot].mGraphicBuffer != nullptr) {
freeBufferLocked(item->mSlot);
}
mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
@@ -468,7 +468,7 @@
if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
return false;
}
- return (mSlots[slot].mGraphicBuffer != NULL &&
+ return (mSlots[slot].mGraphicBuffer != nullptr &&
mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle);
}
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 1757ec1..f5cf1c4 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -34,9 +34,9 @@
DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- if (sf != NULL) {
+ if (sf != nullptr) {
mEventConnection = sf->createDisplayEventConnection(vsyncSource);
- if (mEventConnection != NULL) {
+ if (mEventConnection != nullptr) {
mDataChannel = std::make_unique<gui::BitTube>();
mEventConnection->stealReceiveChannel(mDataChannel.get());
}
@@ -47,13 +47,13 @@
}
status_t DisplayEventReceiver::initCheck() const {
- if (mDataChannel != NULL)
+ if (mDataChannel != nullptr)
return NO_ERROR;
return NO_INIT;
}
int DisplayEventReceiver::getFd() const {
- if (mDataChannel == NULL)
+ if (mDataChannel == nullptr)
return NO_INIT;
return mDataChannel->getFd();
@@ -63,7 +63,7 @@
if (int32_t(count) < 0)
return BAD_VALUE;
- if (mEventConnection != NULL) {
+ if (mEventConnection != nullptr) {
mEventConnection->setVsyncRate(count);
return NO_ERROR;
}
@@ -71,7 +71,7 @@
}
status_t DisplayEventReceiver::requestNextVsync() {
- if (mEventConnection != NULL) {
+ if (mEventConnection != nullptr) {
mEventConnection->requestNextVsync();
return NO_ERROR;
}
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 885efec..faf02f3 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -46,7 +46,6 @@
#include <utils/Trace.h>
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
#define EGL_PROTECTED_CONTENT_EXT 0x32C0
@@ -82,26 +81,6 @@
Mutex GLConsumer::sStaticInitLock;
sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
-static bool hasEglAndroidImageCropImpl() {
- EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
- size_t cropExtLen = strlen(CROP_EXT_STR);
- size_t extsLen = strlen(exts);
- bool equal = !strcmp(CROP_EXT_STR, exts);
- bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
- bool atEnd = (cropExtLen+1) < extsLen &&
- !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
- bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
- return equal || atStart || atEnd || inMiddle;
-}
-
-static bool hasEglAndroidImageCrop() {
- // Only compute whether the extension is present once the first time this
- // function is called.
- static bool hasIt = hasEglAndroidImageCropImpl();
- return hasIt;
-}
-
static bool hasEglProtectedContentImpl() {
EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
@@ -122,10 +101,6 @@
return hasIt;
}
-static bool isEglImageCroppable(const Rect& crop) {
- return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
-}
-
GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
ConsumerBase(bq, isControlledByApp),
@@ -291,7 +266,7 @@
return err;
}
- if (mReleasedTexImage == NULL) {
+ if (mReleasedTexImage == nullptr) {
mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
}
@@ -321,7 +296,7 @@
sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() {
Mutex::Autolock _l(sStaticInitLock);
- if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) {
+ if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
// The first time, create the debug texture in case the application
// continues to use it.
sp<GraphicBuffer> buffer = new GraphicBuffer(
@@ -357,7 +332,7 @@
// If item->mGraphicBuffer is not null, this buffer has not been acquired
// before, so any prior EglImage created is using a stale buffer. This
// replaces any old EglImage with a new one (using the new buffer).
- if (item->mGraphicBuffer != NULL) {
+ if (item->mGraphicBuffer != nullptr) {
int slot = item->mSlot;
mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
}
@@ -406,7 +381,7 @@
// ConsumerBase.
// We may have to do this even when item.mGraphicBuffer == NULL (which
// means the buffer was previously acquired).
- err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
+ err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay);
if (err != NO_ERROR) {
GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
mEglDisplay, slot);
@@ -430,8 +405,8 @@
}
GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
- mCurrentTexture, mCurrentTextureImage != NULL ?
- mCurrentTextureImage->graphicBufferHandle() : 0,
+ mCurrentTexture, mCurrentTextureImage != nullptr ?
+ mCurrentTextureImage->graphicBufferHandle() : nullptr,
slot, mSlots[slot].mGraphicBuffer->handle);
// Hang onto the pointer so that it isn't freed in the call to
@@ -491,13 +466,12 @@
glBindTexture(mTexTarget, mTexName);
if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
- mCurrentTextureImage == NULL) {
+ mCurrentTextureImage == nullptr) {
GLC_LOGE("bindTextureImage: no currently-bound texture");
return NO_INIT;
}
- status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
- mCurrentCrop);
+ status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay);
if (err != NO_ERROR) {
GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
mEglDisplay, mCurrentTexture);
@@ -511,9 +485,7 @@
// forcing the creation of a new image.
if ((error = glGetError()) != GL_NO_ERROR) {
glBindTexture(mTexTarget, mTexName);
- status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay,
- mCurrentCrop,
- true);
+ status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true);
if (result != NO_ERROR) {
GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
mEglDisplay, mCurrentTexture);
@@ -655,7 +627,7 @@
mTexName = tex;
mAttached = true;
- if (mCurrentTextureImage != NULL) {
+ if (mCurrentTextureImage != nullptr) {
// This may wait for a buffer a second time. This is likely required if
// this is a different context, since otherwise the wait could be skipped
// by bouncing through another context. For the same context the extra
@@ -676,7 +648,7 @@
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
if (SyncFeatures::getInstance().useNativeFenceSync()) {
EGLSyncKHR sync = eglCreateSyncKHR(dpy,
- EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+ EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
if (sync == EGL_NO_SYNC_KHR) {
GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
eglGetError());
@@ -720,7 +692,7 @@
// Create a fence for the outstanding accesses in the current
// OpenGL ES context.
- fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
+ fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
if (fence == EGL_NO_SYNC_KHR) {
GLC_LOGE("syncForReleaseLocked: error creating fence: %#x",
eglGetError());
@@ -752,11 +724,11 @@
bool needsRecompute = mFilteringEnabled != enabled;
mFilteringEnabled = enabled;
- if (needsRecompute && mCurrentTextureImage==NULL) {
+ if (needsRecompute && mCurrentTextureImage==nullptr) {
GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
}
- if (needsRecompute && mCurrentTextureImage != NULL) {
+ if (needsRecompute && mCurrentTextureImage != nullptr) {
computeCurrentTransformMatrixLocked();
}
}
@@ -769,8 +741,7 @@
GLC_LOGD("computeCurrentTransformMatrixLocked: "
"mCurrentTextureImage is NULL");
}
- computeTransformMatrix(mCurrentTransformMatrix, buf,
- isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
+ computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
mCurrentTransform, mFilteringEnabled);
}
@@ -863,10 +834,10 @@
xform = crop * xform;
}
- // SurfaceFlinger expects the top of its window textures to be at a Y
- // coordinate of 0, so GLConsumer must behave the same way. We don't
- // want to expose this to applications, however, so we must add an
- // additional vertical flip to the transform after all the other transforms.
+ // GLConsumer uses the GL convention where (0, 0) is the bottom-left
+ // corner and (1, 1) is the top-right corner. Add an additional vertical
+ // flip after all other transforms to map from GL convention to buffer
+ // queue memory layout, where (0, 0) is the top-left corner.
xform = mtxFlipV * xform;
memcpy(outTransform, xform.asArray(), sizeof(xform));
@@ -938,7 +909,7 @@
}
return (mCurrentTextureImage == nullptr) ?
- NULL : mCurrentTextureImage->graphicBuffer();
+ nullptr : mCurrentTextureImage->graphicBuffer();
}
Rect GLConsumer::getCurrentCrop() const {
@@ -1063,8 +1034,7 @@
GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
mGraphicBuffer(graphicBuffer),
mEglImage(EGL_NO_IMAGE_KHR),
- mEglDisplay(EGL_NO_DISPLAY),
- mCropRect(Rect::EMPTY_RECT) {
+ mEglDisplay(EGL_NO_DISPLAY) {
}
GLConsumer::EglImage::~EglImage() {
@@ -1077,13 +1047,11 @@
}
status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
- const Rect& cropRect,
bool forceCreation) {
// If there's an image and it's no longer valid, destroy it.
bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
bool displayInvalid = mEglDisplay != eglDisplay;
- bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
- if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
+ if (haveImage && (displayInvalid || forceCreation)) {
if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
ALOGE("createIfNeeded: eglDestroyImageKHR failed");
}
@@ -1095,14 +1063,12 @@
// If there's no image, create one.
if (mEglImage == EGL_NO_IMAGE_KHR) {
mEglDisplay = eglDisplay;
- mCropRect = cropRect;
- mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
+ mEglImage = createImage(mEglDisplay, mGraphicBuffer);
}
// Fail if we can't create a valid image.
if (mEglImage == EGL_NO_IMAGE_KHR) {
mEglDisplay = EGL_NO_DISPLAY;
- mCropRect.makeInvalid();
const sp<GraphicBuffer>& buffer = mGraphicBuffer;
ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
@@ -1119,38 +1085,19 @@
}
EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
+ const sp<GraphicBuffer>& graphicBuffer) {
EGLClientBuffer cbuf =
static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
const bool createProtectedImage =
(graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) &&
hasEglProtectedContent();
EGLint attrs[] = {
- EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
- EGL_IMAGE_CROP_LEFT_ANDROID, crop.left,
- EGL_IMAGE_CROP_TOP_ANDROID, crop.top,
- EGL_IMAGE_CROP_RIGHT_ANDROID, crop.right,
- EGL_IMAGE_CROP_BOTTOM_ANDROID, crop.bottom,
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
createProtectedImage ? EGL_TRUE : EGL_NONE,
EGL_NONE,
};
- if (!crop.isValid()) {
- // No crop rect to set, so leave the crop out of the attrib array. Make
- // sure to propagate the protected content attrs if they are set.
- attrs[2] = attrs[10];
- attrs[3] = attrs[11];
- attrs[4] = EGL_NONE;
- } else if (!isEglImageCroppable(crop)) {
- // The crop rect is not at the origin, so we can't set the crop on the
- // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
- // extension. In the future we can add a layered extension that
- // removes this restriction if there is hardware that can support it.
- attrs[2] = attrs[10];
- attrs[3] = attrs[11];
- attrs[4] = EGL_NONE;
- }
- eglInitialize(dpy, 0, 0);
+ eglInitialize(dpy, nullptr, nullptr);
EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
if (image == EGL_NO_IMAGE_KHR) {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0b37960..68a6b1f 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -190,10 +190,10 @@
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence) {
- if (outBuffer == NULL) {
+ if (outBuffer == nullptr) {
ALOGE("detachNextBuffer: outBuffer must not be NULL");
return BAD_VALUE;
- } else if (outFence == NULL) {
+ } else if (outFence == nullptr) {
ALOGE("detachNextBuffer: outFence must not be NULL");
return BAD_VALUE;
}
@@ -301,7 +301,7 @@
int api, bool producerControlledByApp, QueueBufferOutput* output) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
- if (listener != NULL) {
+ if (listener != nullptr) {
data.writeInt32(1);
data.writeStrongBinder(IInterface::asBinder(listener));
} else {
@@ -738,8 +738,8 @@
int bufferIdx = data.readInt32();
sp<GraphicBuffer> buffer;
int result = requestBuffer(bufferIdx, &buffer);
- reply->writeInt32(buffer != 0);
- if (buffer != 0) {
+ reply->writeInt32(buffer != nullptr);
+ if (buffer != nullptr) {
reply->write(*buffer);
}
reply->writeInt32(result);
@@ -797,12 +797,12 @@
int32_t result = detachNextBuffer(&buffer, &fence);
reply->writeInt32(result);
if (result == NO_ERROR) {
- reply->writeInt32(buffer != NULL);
- if (buffer != NULL) {
+ reply->writeInt32(buffer != nullptr);
+ if (buffer != nullptr) {
reply->write(*buffer);
}
- reply->writeInt32(fence != NULL);
- if (fence != NULL) {
+ reply->writeInt32(fence != nullptr);
+ if (fence != nullptr) {
reply->write(*fence);
}
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index d2d27e8..08fbfff 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -116,20 +116,20 @@
data.writeInt32(maxLayerZ);
data.writeInt32(static_cast<int32_t>(useIdentityTransform));
data.writeInt32(static_cast<int32_t>(rotation));
- status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
-
- if (err != NO_ERROR) {
- return err;
+ status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("captureScreen failed to transact: %d", result);
+ return result;
}
-
- err = reply.readInt32();
- if (err != NO_ERROR) {
- return err;
+ result = reply.readInt32();
+ if (result != NO_ERROR) {
+ ALOGE("captureScreen failed to readInt32: %d", result);
+ return result;
}
*outBuffer = new GraphicBuffer();
reply.read(**outBuffer);
- return err;
+ return result;
}
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
@@ -141,21 +141,20 @@
data.write(sourceCrop);
data.writeFloat(frameScale);
data.writeBool(childrenOnly);
- status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
-
- if (err != NO_ERROR) {
- return err;
+ status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("captureLayers failed to transact: %d", result);
+ return result;
}
-
- err = reply.readInt32();
- if (err != NO_ERROR) {
- return err;
+ result = reply.readInt32();
+ if (result != NO_ERROR) {
+ ALOGE("captureLayers failed to readInt32: %d", result);
+ return result;
}
-
*outBuffer = new GraphicBuffer();
reply.read(**outBuffer);
- return err;
+ return result;
}
virtual bool authenticateSurfaceTexture(
@@ -332,34 +331,6 @@
return result;
}
- virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_VIEWPORT, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to transact: %d", result);
- return result;
- }
- result = reply.readInt32();
- if (result == NO_ERROR) {
- result = reply.read(*outViewport);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to read: %d", result);
- return result;
- }
- }
- return result;
- }
-
virtual int getActiveConfig(const sp<IBinder>& display)
{
Parcel data, reply;
@@ -372,10 +343,26 @@
virtual status_t setActiveConfig(const sp<IBinder>& display, int id)
{
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- data.writeInt32(id);
- remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply);
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("setActiveConfig failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveConfig failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = data.writeInt32(id);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveConfig failed to writeInt32: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveConfig failed to transact: %d", result);
+ return result;
+ }
return reply.readInt32();
}
@@ -457,8 +444,16 @@
virtual status_t clearAnimationFrameStats() {
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("clearAnimationFrameStats failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("clearAnimationFrameStats failed to transact: %d", result);
+ return result;
+ }
return reply.readInt32();
}
@@ -563,6 +558,25 @@
outLayers->clear();
return reply.readParcelableVector(outLayers);
}
+
+ virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
+ ui::PixelFormat* pixelFormat) const {
+ Parcel data, reply;
+ status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (error != NO_ERROR) {
+ return error;
+ }
+ error = remote()->transact(BnSurfaceComposer::GET_COMPOSITION_PREFERENCE, data, &reply);
+ if (error != NO_ERROR) {
+ return error;
+ }
+ error = static_cast<status_t>(reply.readInt32());
+ if (error == NO_ERROR) {
+ *dataSpace = static_cast<ui::Dataspace>(reply.readInt32());
+ *pixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+ }
+ return error;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -752,26 +766,6 @@
}
return NO_ERROR;
}
- case GET_DISPLAY_VIEWPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- Rect outViewport;
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to readStrongBinder: %d", result);
- return result;
- }
- result = getDisplayViewport(display, &outViewport);
- result = reply->writeInt32(result);
- if (result == NO_ERROR) {
- result = reply->write(outViewport);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to write: %d", result);
- return result;
- }
- }
- return NO_ERROR;
- }
case GET_ACTIVE_CONFIG: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = data.readStrongBinder();
@@ -906,6 +900,18 @@
}
return result;
}
+ case GET_COMPOSITION_PREFERENCE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ ui::Dataspace dataSpace;
+ ui::PixelFormat pixelFormat;
+ status_t error = getCompositionPreference(&dataSpace, &pixelFormat);
+ reply->writeInt32(error);
+ if (error == NO_ERROR) {
+ reply->writeInt32(static_cast<int32_t>(dataSpace));
+ reply->writeInt32(static_cast<int32_t>(pixelFormat));
+ }
+ return NO_ERROR;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index d3dc16d..ccde9e0 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -42,7 +42,6 @@
RETURN_ON_ERROR(parcel->writeInt32(mWidth));
RETURN_ON_ERROR(parcel->writeInt32(mHeight));
RETURN_ON_ERROR(parcel->write(mCrop));
- RETURN_ON_ERROR(parcel->write(mFinalCrop));
RETURN_ON_ERROR(parcel->writeFloat(mColor.r));
RETURN_ON_ERROR(parcel->writeFloat(mColor.g));
RETURN_ON_ERROR(parcel->writeFloat(mColor.b));
@@ -81,7 +80,6 @@
RETURN_ON_ERROR(parcel->readInt32(&mWidth));
RETURN_ON_ERROR(parcel->readInt32(&mHeight));
RETURN_ON_ERROR(parcel->read(mCrop));
- RETURN_ON_ERROR(parcel->read(mFinalCrop));
mColor.r = parcel->readFloat();
RETURN_ON_ERROR(parcel->errorCheck());
mColor.g = parcel->readFloat();
@@ -121,8 +119,7 @@
info.mLayerStack, info.mZ, static_cast<double>(info.mX), static_cast<double>(info.mY),
info.mWidth, info.mHeight);
- result.appendFormat("crop=%s, finalCrop=%s, ",
- to_string(info.mCrop).c_str(), to_string(info.mFinalCrop).c_str());
+ result.appendFormat("crop=%s, ", to_string(info.mCrop).c_str());
result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 01acc2d..5a8d8db 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "LayerState"
+
#include <utils/Errors.h>
#include <binder/Parcel.h>
#include <gui/ISurfaceComposerClient.h>
@@ -37,19 +39,44 @@
output.writeUint32(mask);
*reinterpret_cast<layer_state_t::matrix22_t *>(
output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
- output.write(crop);
- output.write(finalCrop);
- output.writeStrongBinder(barrierHandle);
+ output.write(crop_legacy);
+ output.writeStrongBinder(barrierHandle_legacy);
output.writeStrongBinder(reparentHandle);
- output.writeUint64(frameNumber);
+ output.writeUint64(frameNumber_legacy);
output.writeInt32(overrideScalingMode);
- output.writeStrongBinder(IInterface::asBinder(barrierGbp));
+ output.writeStrongBinder(IInterface::asBinder(barrierGbp_legacy));
output.writeStrongBinder(relativeLayerHandle);
output.writeStrongBinder(parentHandleForChild);
output.writeFloat(color.r);
output.writeFloat(color.g);
output.writeFloat(color.b);
output.write(transparentRegion);
+ output.writeUint32(transform);
+ output.writeBool(transformToDisplayInverse);
+ output.write(crop);
+ if (buffer) {
+ output.writeBool(true);
+ output.write(*buffer);
+ } else {
+ output.writeBool(false);
+ }
+ if (acquireFence) {
+ output.writeBool(true);
+ output.write(*acquireFence);
+ } else {
+ output.writeBool(false);
+ }
+ output.writeUint32(static_cast<uint32_t>(dataspace));
+ output.write(hdrMetadata);
+ output.write(surfaceDamageRegion);
+ output.writeInt32(api);
+ if (sidebandStream) {
+ output.writeBool(true);
+ output.writeNativeHandle(sidebandStream->handle());
+ } else {
+ output.writeBool(false);
+ }
+
return NO_ERROR;
}
@@ -72,20 +99,37 @@
} else {
return BAD_VALUE;
}
- input.read(crop);
- input.read(finalCrop);
- barrierHandle = input.readStrongBinder();
+ input.read(crop_legacy);
+ barrierHandle_legacy = input.readStrongBinder();
reparentHandle = input.readStrongBinder();
- frameNumber = input.readUint64();
+ frameNumber_legacy = input.readUint64();
overrideScalingMode = input.readInt32();
- barrierGbp =
- interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
+ barrierGbp_legacy = interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
relativeLayerHandle = input.readStrongBinder();
parentHandleForChild = input.readStrongBinder();
color.r = input.readFloat();
color.g = input.readFloat();
color.b = input.readFloat();
input.read(transparentRegion);
+ transform = input.readUint32();
+ transformToDisplayInverse = input.readBool();
+ input.read(crop);
+ buffer = new GraphicBuffer();
+ if (input.readBool()) {
+ input.read(*buffer);
+ }
+ acquireFence = new Fence();
+ if (input.readBool()) {
+ input.read(*acquireFence);
+ }
+ dataspace = static_cast<ui::Dataspace>(input.readUint32());
+ input.read(hdrMetadata);
+ input.read(surfaceDamageRegion);
+ api = input.readInt32();
+ if (input.readBool()) {
+ sidebandStream = NativeHandle::create(input.readNativeHandle(), true);
+ }
+
return NO_ERROR;
}
@@ -194,19 +238,15 @@
what |= eLayerStackChanged;
layerStack = other.layerStack;
}
- if (other.what & eCropChanged) {
- what |= eCropChanged;
- crop = other.crop;
+ if (other.what & eCropChanged_legacy) {
+ what |= eCropChanged_legacy;
+ crop_legacy = other.crop_legacy;
}
- if (other.what & eDeferTransaction) {
- what |= eDeferTransaction;
- barrierHandle = other.barrierHandle;
- barrierGbp = other.barrierGbp;
- frameNumber = other.frameNumber;
- }
- if (other.what & eFinalCropChanged) {
- what |= eFinalCropChanged;
- finalCrop = other.finalCrop;
+ if (other.what & eDeferTransaction_legacy) {
+ what |= eDeferTransaction_legacy;
+ barrierHandle_legacy = other.barrierHandle_legacy;
+ barrierGbp_legacy = other.barrierGbp_legacy;
+ frameNumber_legacy = other.frameNumber_legacy;
}
if (other.what & eOverrideScalingModeChanged) {
what |= eOverrideScalingModeChanged;
@@ -234,6 +274,52 @@
if (other.what & eDestroySurface) {
what |= eDestroySurface;
}
+ if (other.what & eTransformChanged) {
+ what |= eTransformChanged;
+ transform = other.transform;
+ }
+ if (other.what & eTransformToDisplayInverseChanged) {
+ what |= eTransformToDisplayInverseChanged;
+ transformToDisplayInverse = other.transformToDisplayInverse;
+ }
+ if (other.what & eCropChanged) {
+ what |= eCropChanged;
+ crop = other.crop;
+ }
+ if (other.what & eBufferChanged) {
+ what |= eBufferChanged;
+ buffer = other.buffer;
+ }
+ if (other.what & eAcquireFenceChanged) {
+ what |= eAcquireFenceChanged;
+ acquireFence = other.acquireFence;
+ }
+ if (other.what & eDataspaceChanged) {
+ what |= eDataspaceChanged;
+ dataspace = other.dataspace;
+ }
+ if (other.what & eHdrMetadataChanged) {
+ what |= eHdrMetadataChanged;
+ hdrMetadata = other.hdrMetadata;
+ }
+ if (other.what & eSurfaceDamageRegionChanged) {
+ what |= eSurfaceDamageRegionChanged;
+ surfaceDamageRegion = other.surfaceDamageRegion;
+ }
+ if (other.what & eApiChanged) {
+ what |= eApiChanged;
+ api = other.api;
+ }
+ if (other.what & eSidebandStreamChanged) {
+ what |= eSidebandStreamChanged;
+ sidebandStream = other.sidebandStream;
+ }
+
+ if ((other.what & what) != other.what) {
+ ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
+ "other.what=0x%X what=0x%X",
+ other.what, what);
+ }
}
}; // namespace android
diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp
index 52c9067..2f8e104 100644
--- a/libs/gui/StreamSplitter.cpp
+++ b/libs/gui/StreamSplitter.cpp
@@ -38,11 +38,11 @@
status_t StreamSplitter::createSplitter(
const sp<IGraphicBufferConsumer>& inputQueue,
sp<StreamSplitter>* outSplitter) {
- if (inputQueue == NULL) {
+ if (inputQueue == nullptr) {
ALOGE("createSplitter: inputQueue must not be NULL");
return BAD_VALUE;
}
- if (outSplitter == NULL) {
+ if (outSplitter == nullptr) {
ALOGE("createSplitter: outSplitter must not be NULL");
return BAD_VALUE;
}
@@ -74,7 +74,7 @@
status_t StreamSplitter::addOutput(
const sp<IGraphicBufferProducer>& outputQueue) {
- if (outputQueue == NULL) {
+ if (outputQueue == nullptr) {
ALOGE("addOutput: outputQueue must not be NULL");
return BAD_VALUE;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 2de14c8..b505c6f 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -156,7 +156,7 @@
ATRACE_CALL();
DisplayStatInfo stats;
- status_t result = composerService()->getDisplayStats(NULL, &stats);
+ status_t result = composerService()->getDisplayStats(nullptr, &stats);
if (result != NO_ERROR) {
return result;
}
@@ -501,7 +501,7 @@
if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot !=
BufferItem::INVALID_BUFFER_SLOT) {
sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
- if (gbuf != NULL) {
+ if (gbuf != nullptr) {
*buffer = gbuf.get();
*fenceFd = -1;
return OK;
@@ -541,7 +541,7 @@
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
// this should never happen
- ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
+ ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
freeAllBuffers();
@@ -619,7 +619,7 @@
int Surface::getSlotFromBufferLocked(
android_native_buffer_t* buffer) const {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- if (mSlots[i].buffer != NULL &&
+ if (mSlots[i].buffer != nullptr &&
mSlots[i].buffer->handle == buffer->handle) {
return i;
}
@@ -1268,7 +1268,7 @@
ATRACE_CALL();
ALOGV("Surface::detachNextBuffer");
- if (outBuffer == NULL || outFence == NULL) {
+ if (outBuffer == nullptr || outFence == nullptr) {
return BAD_VALUE;
}
@@ -1277,8 +1277,8 @@
mRemovedBuffers.clear();
}
- sp<GraphicBuffer> buffer(NULL);
- sp<Fence> fence(NULL);
+ sp<GraphicBuffer> buffer(nullptr);
+ sp<Fence> fence(nullptr);
status_t result = mGraphicBufferProducer->detachNextBuffer(
&buffer, &fence);
if (result != NO_ERROR) {
@@ -1286,19 +1286,19 @@
}
*outBuffer = buffer;
- if (fence != NULL && fence->isValid()) {
+ if (fence != nullptr && fence->isValid()) {
*outFence = fence;
} else {
*outFence = Fence::NO_FENCE;
}
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- if (mSlots[i].buffer != NULL &&
+ if (mSlots[i].buffer != nullptr &&
mSlots[i].buffer->getId() == buffer->getId()) {
if (mReportRemovedBuffers) {
mRemovedBuffers.push_back(mSlots[i].buffer);
}
- mSlots[i].buffer = NULL;
+ mSlots[i].buffer = nullptr;
}
}
@@ -1349,7 +1349,7 @@
ATRACE_CALL();
Rect realRect(Rect::EMPTY_RECT);
- if (rect == NULL || rect->isEmpty()) {
+ if (rect == nullptr || rect->isEmpty()) {
realRect.clear();
} else {
realRect = *rect;
@@ -1576,7 +1576,7 @@
void Surface::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- mSlots[i].buffer = 0;
+ mSlots[i].buffer = nullptr;
}
}
@@ -1616,12 +1616,12 @@
// src and dst with, height and format must be identical. no verification
// is done here.
status_t err;
- uint8_t* src_bits = NULL;
+ uint8_t* src_bits = nullptr;
err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(),
reinterpret_cast<void**>(&src_bits));
ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
- uint8_t* dst_bits = NULL;
+ uint8_t* dst_bits = nullptr;
err = dst->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(),
reinterpret_cast<void**>(&dst_bits), *dstFenceFd);
ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
@@ -1669,7 +1669,7 @@
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
- if (mLockedBuffer != 0) {
+ if (mLockedBuffer != nullptr) {
ALOGE("Surface::lock failed, already locked");
return INVALID_OPERATION;
}
@@ -1701,7 +1701,7 @@
// figure out if we can copy the frontbuffer back
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
- const bool canCopyBack = (frontBuffer != 0 &&
+ const bool canCopyBack = (frontBuffer != nullptr &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format);
@@ -1763,7 +1763,7 @@
status_t Surface::unlockAndPost()
{
- if (mLockedBuffer == 0) {
+ if (mLockedBuffer == nullptr) {
ALOGE("Surface::unlockAndPost failed, no locked buffer");
return INVALID_OPERATION;
}
@@ -1777,7 +1777,7 @@
mLockedBuffer->handle, strerror(-err));
mPostedBuffer = mLockedBuffer;
- mLockedBuffer = 0;
+ mLockedBuffer = nullptr;
return err;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index f3c6fd2..4caadd1 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -60,7 +60,7 @@
while (getService(name, &mComposerService) != NO_ERROR) {
usleep(250000);
}
- assert(mComposerService != NULL);
+ assert(mComposerService != nullptr);
// Create the death listener.
class DeathObserver : public IBinder::DeathRecipient {
@@ -81,9 +81,9 @@
/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
ComposerService& instance = ComposerService::getInstance();
Mutex::Autolock _l(instance.mLock);
- if (instance.mComposerService == NULL) {
+ if (instance.mComposerService == nullptr) {
ComposerService::getInstance().connectLocked();
- assert(instance.mComposerService != NULL);
+ assert(instance.mComposerService != nullptr);
ALOGD("ComposerService reconnected");
}
return instance.mComposerService;
@@ -92,8 +92,8 @@
void ComposerService::composerServiceDied()
{
Mutex::Autolock _l(mLock);
- mComposerService = NULL;
- mDeathObserver = NULL;
+ mComposerService = nullptr;
+ mDeathObserver = nullptr;
}
// ---------------------------------------------------------------------------
@@ -240,9 +240,6 @@
s->w = w;
s->h = h;
- // Resizing a surface makes the transaction synchronous.
- mForceSynchronous = true;
-
return *this;
}
@@ -344,54 +341,45 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop_legacy(
const sp<SurfaceControl>& sc, const Rect& crop) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eCropChanged;
- s->crop = crop;
+ s->what |= layer_state_t::eCropChanged_legacy;
+ s->crop_legacy = crop;
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) {
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+ const sp<IBinder>& handle,
+ uint64_t frameNumber) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eFinalCropChanged;
- s->finalCrop = crop;
+ s->what |= layer_state_t::eDeferTransaction_legacy;
+ s->barrierHandle_legacy = handle;
+ s->frameNumber_legacy = frameNumber;
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
- const sp<SurfaceControl>& sc,
- const sp<IBinder>& handle, uint64_t frameNumber) {
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+ const sp<Surface>& barrierSurface,
+ uint64_t frameNumber) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eDeferTransaction;
- s->barrierHandle = handle;
- s->frameNumber = frameNumber;
- return *this;
-}
-
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
- const sp<SurfaceControl>& sc,
- const sp<Surface>& barrierSurface, uint64_t frameNumber) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eDeferTransaction;
- s->barrierGbp = barrierSurface->getIGraphicBufferProducer();
- s->frameNumber = frameNumber;
+ s->what |= layer_state_t::eDeferTransaction_legacy;
+ s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer();
+ s->frameNumber_legacy = frameNumber;
return *this;
}
@@ -434,6 +422,127 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransform(
+ const sp<SurfaceControl>& sc, uint32_t transform) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eTransformChanged;
+ s->transform = transform;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
+ bool transformToDisplayInverse) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eTransformToDisplayInverseChanged;
+ s->transformToDisplayInverse = transformToDisplayInverse;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+ const sp<SurfaceControl>& sc, const Rect& crop) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eCropChanged;
+ s->crop = crop;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
+ const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eBufferChanged;
+ s->buffer = buffer;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence(
+ const sp<SurfaceControl>& sc, const sp<Fence>& fence) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eAcquireFenceChanged;
+ s->acquireFence = fence;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDataspace(
+ const sp<SurfaceControl>& sc, ui::Dataspace dataspace) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eDataspaceChanged;
+ s->dataspace = dataspace;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setHdrMetadata(
+ const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eHdrMetadataChanged;
+ s->hdrMetadata = hdrMetadata;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSurfaceDamageRegion(
+ const sp<SurfaceControl>& sc, const Region& surfaceDamageRegion) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eSurfaceDamageRegionChanged;
+ s->surfaceDamageRegion = surfaceDamageRegion;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApi(
+ const sp<SurfaceControl>& sc, int32_t api) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eApiChanged;
+ s->api = api;
+ return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSidebandStream(
+ const sp<SurfaceControl>& sc, const sp<NativeHandle>& sidebandStream) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eSidebandStreamChanged;
+ s->sidebandStream = sidebandStream;
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
const sp<SurfaceControl>& sc) {
layer_state_t* s = getLayerState(sc);
@@ -571,12 +680,12 @@
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- if (sf != 0 && mStatus == NO_INIT) {
+ if (sf != nullptr && mStatus == NO_INIT) {
auto rootProducer = mParent.promote();
sp<ISurfaceComposerClient> conn;
conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
sf->createConnection();
- if (conn != 0) {
+ if (conn != nullptr) {
mClient = conn;
mStatus = NO_ERROR;
}
@@ -606,7 +715,7 @@
// this can be called more than once.
sp<ISurfaceComposerClient> client;
Mutex::Autolock _lm(mLock);
- if (mClient != 0) {
+ if (mClient != nullptr) {
client = mClient; // hold ref while lock is held
mClient.clear();
}
@@ -718,10 +827,6 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
- return ComposerService::getComposerService()->getDisplayViewport(display, outViewport);
-}
-
int SurfaceComposerClient::getActiveConfig(const sp<IBinder>& display) {
return ComposerService::getComposerService()->getActiveConfig(display);
}
@@ -749,6 +854,11 @@
ComposerService::getComposerService()->setPowerMode(token, mode);
}
+status_t SurfaceComposerClient::getCompositionPreference(ui::Dataspace* dataSpace,
+ ui::PixelFormat* pixelFormat) {
+ return ComposerService::getComposerService()->getCompositionPreference(dataSpace, pixelFormat);
+}
+
status_t SurfaceComposerClient::clearAnimationFrameStats() {
return ComposerService::getComposerService()->clearAnimationFrameStats();
}
@@ -770,7 +880,7 @@
bool useIdentityTransform, uint32_t rotation,
sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (s == NULL) return NO_INIT;
+ if (s == nullptr) return NO_INIT;
status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, minLayerZ,
maxLayerZ, useIdentityTransform,
static_cast<ISurfaceComposer::Rotation>(rotation));
@@ -783,7 +893,7 @@
status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (s == NULL) return NO_INIT;
+ if (s == nullptr) return NO_INIT;
status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
false /* childrenOnly */);
return ret;
@@ -792,7 +902,7 @@
status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (s == NULL) return NO_INIT;
+ if (s == nullptr) return NO_INIT;
status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
true /* childrenOnly */);
return ret;
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 5eafbb3..3a6dfda 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -86,7 +86,7 @@
}
void SurfaceControl::disconnect() {
- if (mGraphicBufferProducer != NULL) {
+ if (mGraphicBufferProducer != nullptr) {
mGraphicBufferProducer->disconnect(
BufferQueueCore::CURRENTLY_CONNECTED_API);
}
@@ -95,28 +95,28 @@
bool SurfaceControl::isSameSurface(
const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
{
- if (lhs == 0 || rhs == 0)
+ if (lhs == nullptr || rhs == nullptr)
return false;
return lhs->mHandle == rhs->mHandle;
}
status_t SurfaceControl::clearLayerFrameStats() const {
status_t err = validate();
- if (err < 0) return err;
+ if (err != NO_ERROR) return err;
const sp<SurfaceComposerClient>& client(mClient);
return client->clearLayerFrameStats(mHandle);
}
status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const {
status_t err = validate();
- if (err < 0) return err;
+ if (err != NO_ERROR) return err;
const sp<SurfaceComposerClient>& client(mClient);
return client->getLayerFrameStats(mHandle, outStats);
}
status_t SurfaceControl::validate() const
{
- if (mHandle==0 || mClient==0) {
+ if (mHandle==nullptr || mClient==nullptr) {
ALOGE("invalid handle (%p) or client (%p)",
mHandle.get(), mClient.get());
return NO_INIT;
@@ -128,7 +128,7 @@
const sp<SurfaceControl>& control, Parcel* parcel)
{
sp<IGraphicBufferProducer> bp;
- if (control != NULL) {
+ if (control != nullptr) {
bp = control->mGraphicBufferProducer;
}
return parcel->writeStrongBinder(IInterface::asBinder(bp));
@@ -146,7 +146,7 @@
sp<Surface> SurfaceControl::getSurface() const
{
Mutex::Autolock _l(mLock);
- if (mSurfaceData == 0) {
+ if (mSurfaceData == nullptr) {
return generateSurfaceLocked();
}
return mSurfaceData;
diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp
index afa15c5..fcae05c 100644
--- a/libs/gui/SyncFeatures.cpp
+++ b/libs/gui/SyncFeatures.cpp
@@ -41,7 +41,7 @@
// This can only be called after EGL has been initialized; otherwise the
// check below will abort.
const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
- LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed");
+ LOG_ALWAYS_FATAL_IF(exts == nullptr, "eglQueryStringImplementationANDROID failed");
if (strstr(exts, "EGL_ANDROID_native_fence_sync")) {
// This makes GLConsumer use the EGL_ANDROID_native_fence_sync
// extension to create Android native fences to signal when all
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index 3b89291..8af1a67 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -100,7 +100,12 @@
*/
// convert: Return<Status> -> status_t
inline status_t toStatusT(Return<Status> const& t) {
- return t.isOk() ? static_cast<status_t>(static_cast<Status>(t)) : UNKNOWN_ERROR;
+ if (t.isOk()) {
+ return static_cast<status_t>(static_cast<Status>(t));
+ } else if (t.isDeadObject()) {
+ return DEAD_OBJECT;
+ }
+ return UNKNOWN_ERROR;
}
/**
@@ -111,7 +116,7 @@
*/
// convert: Return<void> -> status_t
inline status_t toStatusT(Return<void> const& t) {
- return t.isOk() ? OK : UNKNOWN_ERROR;
+ return t.isOk() ? OK : (t.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR);
}
/**
diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h
index 23c9909..f7af19b 100644
--- a/libs/gui/include/gui/BufferHubProducer.h
+++ b/libs/gui/include/gui/BufferHubProducer.h
@@ -165,6 +165,10 @@
// buffers are acquired by the consumer, we can't .
status_t FreeAllBuffers();
+ // Helper function that implements the detachBuffer() call, but assuming |mutex_| has been
+ // locked already.
+ status_t DetachBufferLocked(size_t slot);
+
// Concreate implementation backed by BufferHubBuffer.
std::shared_ptr<dvr::ProducerQueue> queue_;
diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
index d375611..806fbe8 100644
--- a/libs/gui/include/gui/CpuConsumer.h
+++ b/libs/gui/include/gui/CpuConsumer.h
@@ -70,7 +70,7 @@
uint32_t chromaStep;
LockedBuffer() :
- data(NULL),
+ data(nullptr),
width(0),
height(0),
format(PIXEL_FORMAT_NONE),
@@ -82,8 +82,8 @@
dataSpace(HAL_DATASPACE_UNKNOWN),
frameNumber(0),
flexFormat(PIXEL_FORMAT_NONE),
- dataCb(NULL),
- dataCr(NULL),
+ dataCb(nullptr),
+ dataCr(nullptr),
chromaStride(0),
chromaStep(0)
{}
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 71ed3bf..46a99e1 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -140,7 +140,8 @@
// Scale the crop down horizontally or vertically such that it has the
// same aspect ratio as the buffer does.
- static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight);
+ static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth,
+ uint32_t bufferHeight);
// getTimestamp retrieves the timestamp associated with the texture image
// set by the most recent call to updateTexImage.
@@ -305,7 +306,6 @@
// createIfNeeded creates an EGLImage if required (we haven't created
// one yet, or the EGLDisplay or crop-rect has changed).
status_t createIfNeeded(EGLDisplay display,
- const Rect& cropRect,
bool forceCreate = false);
// This calls glEGLImageTargetTexture2DOES to bind the image to the
@@ -314,7 +314,7 @@
const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
const native_handle* graphicBufferHandle() {
- return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle;
+ return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
}
private:
@@ -324,7 +324,7 @@
// createImage creates a new EGLImage from a GraphicBuffer.
EGLImageKHR createImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+ const sp<GraphicBuffer>& graphicBuffer);
// Disallow copying
EglImage(const EglImage& rhs);
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 887654e..8ff8d81 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -345,7 +345,7 @@
*outScalingMode = scalingMode;
*outTransform = transform;
*outFence = fence;
- if (outStickyTransform != NULL) {
+ if (outStickyTransform != nullptr) {
*outStickyTransform = stickyTransform;
}
if (outGetFrameTimestamps) {
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 99a3a75..46103c4 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -157,9 +157,6 @@
virtual status_t getDisplayStats(const sp<IBinder>& display,
DisplayStatInfo* stats) = 0;
- /* returns display viewport information of the given display */
- virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) = 0;
-
/* indicates which of the configurations returned by getDisplayInfo is
* currently active */
virtual int getActiveConfig(const sp<IBinder>& display) = 0;
@@ -174,8 +171,25 @@
virtual status_t setActiveColorMode(const sp<IBinder>& display,
ui::ColorMode colorMode) = 0;
- /* Capture the specified screen. requires READ_FRAME_BUFFER permission
- * This function will fail if there is a secure window on screen.
+ /**
+ * Capture the specified screen. This requires READ_FRAME_BUFFER
+ * permission. This function will fail if there is a secure window on
+ * screen.
+ *
+ * This function can capture a subregion (the source crop) of the screen.
+ * The subregion can be optionally rotated. It will also be scaled to
+ * match the size of the output buffer.
+ *
+ * At the moment, sourceCrop is ignored and is always set to the visible
+ * region (projected display viewport) of the screen.
+ *
+ * reqWidth and reqHeight specifies the size of the buffer. When either
+ * of them is 0, they are set to the size of the logical display viewport.
+ *
+ * When useIdentityTransform is true, layer transformations are disabled.
+ *
+ * rotation specifies the rotation of the source crop (and the pixels in
+ * it) around its center.
*/
virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
@@ -217,18 +231,21 @@
* Requires the ACCESS_SURFACE_FLINGER permission.
*/
virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
+
+ virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
+ ui::PixelFormat* pixelFormat) const = 0;
};
// ----------------------------------------------------------------------------
class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
public:
- enum {
+ enum ISurfaceComposerTag {
// Note: BOOT_FINISHED must remain this value, it is called from
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
- UNUSED, // formerly CREATE_GRAPHIC_BUFFER_ALLOC
+ CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED, // unused, fails permissions check
CREATE_DISPLAY_EVENT_CONNECTION,
CREATE_DISPLAY,
DESTROY_DISPLAY,
@@ -239,7 +256,7 @@
GET_DISPLAY_CONFIGS,
GET_ACTIVE_CONFIG,
SET_ACTIVE_CONFIG,
- CONNECT_DISPLAY,
+ CONNECT_DISPLAY_UNUSED, // unused, fails permissions check
CAPTURE_SCREEN,
CAPTURE_LAYERS,
CLEAR_ANIMATION_FRAME_STATS,
@@ -254,7 +271,7 @@
INJECT_VSYNC,
GET_LAYER_DEBUG_INFO,
CREATE_SCOPED_CONNECTION,
- GET_DISPLAY_VIEWPORT
+ GET_COMPOSITION_PREFERENCE,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 8dfc99a..82b01b8 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -40,8 +40,10 @@
eProtectedByDRM = 0x00001000,
eCursorWindow = 0x00002000,
- eFXSurfaceNormal = 0x00000000,
+ eFXSurfaceBufferQueue = 0x00000000,
eFXSurfaceColor = 0x00020000,
+ eFXSurfaceBufferState = 0x00040000,
+ eFXSurfaceContainer = 0x00080000,
eFXSurfaceMask = 0x000F0000,
};
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index 92bd8c5..66a7b4d 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -52,7 +52,6 @@
int32_t mWidth = -1;
int32_t mHeight = -1;
Rect mCrop = Rect::INVALID_RECT;
- Rect mFinalCrop = Rect::INVALID_RECT;
half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf);
uint32_t mFlags = 0;
PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 788962e..9a9f633 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -22,10 +22,11 @@
#include <utils/Errors.h>
-#include <ui/Region.h>
-#include <ui/Rect.h>
#include <gui/IGraphicBufferProducer.h>
#include <math/vec3.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
namespace android {
@@ -36,113 +37,143 @@
* Used to communicate layer information between SurfaceFlinger and its clients.
*/
struct layer_state_t {
-
-
enum {
- eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java
- eLayerOpaque = 0x02, // SURFACE_OPAQUE
- eLayerSecure = 0x80, // SECURE
+ eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java
+ eLayerOpaque = 0x02, // SURFACE_OPAQUE
+ eLayerSecure = 0x80, // SECURE
};
enum {
- ePositionChanged = 0x00000001,
- eLayerChanged = 0x00000002,
- eSizeChanged = 0x00000004,
- eAlphaChanged = 0x00000008,
- eMatrixChanged = 0x00000010,
- eTransparentRegionChanged = 0x00000020,
- eFlagsChanged = 0x00000040,
- eLayerStackChanged = 0x00000080,
- eCropChanged = 0x00000100,
- eDeferTransaction = 0x00000200,
- eFinalCropChanged = 0x00000400,
- eOverrideScalingModeChanged = 0x00000800,
- eGeometryAppliesWithResize = 0x00001000,
- eReparentChildren = 0x00002000,
- eDetachChildren = 0x00004000,
- eRelativeLayerChanged = 0x00008000,
- eReparent = 0x00010000,
- eColorChanged = 0x00020000,
- eDestroySurface = 0x00040000
+ ePositionChanged = 0x00000001,
+ eLayerChanged = 0x00000002,
+ eSizeChanged = 0x00000004,
+ eAlphaChanged = 0x00000008,
+ eMatrixChanged = 0x00000010,
+ eTransparentRegionChanged = 0x00000020,
+ eFlagsChanged = 0x00000040,
+ eLayerStackChanged = 0x00000080,
+ eCropChanged_legacy = 0x00000100,
+ eDeferTransaction_legacy = 0x00000200,
+ eOverrideScalingModeChanged = 0x00000400,
+ eGeometryAppliesWithResize = 0x00000800,
+ eReparentChildren = 0x00001000,
+ eDetachChildren = 0x00002000,
+ eRelativeLayerChanged = 0x00004000,
+ eReparent = 0x00008000,
+ eColorChanged = 0x00010000,
+ eDestroySurface = 0x00020000,
+ eTransformChanged = 0x00040000,
+ eTransformToDisplayInverseChanged = 0x00080000,
+ eCropChanged = 0x00100000,
+ eBufferChanged = 0x00200000,
+ eAcquireFenceChanged = 0x00400000,
+ eDataspaceChanged = 0x00800000,
+ eHdrMetadataChanged = 0x01000000,
+ eSurfaceDamageRegionChanged = 0x02000000,
+ eApiChanged = 0x04000000,
+ eSidebandStreamChanged = 0x08000000,
};
layer_state_t()
- : what(0),
- x(0), y(0), z(0), w(0), h(0), layerStack(0),
- alpha(0), flags(0), mask(0),
- reserved(0), crop(Rect::INVALID_RECT),
- finalCrop(Rect::INVALID_RECT), frameNumber(0),
- overrideScalingMode(-1)
- {
+ : what(0),
+ x(0),
+ y(0),
+ z(0),
+ w(0),
+ h(0),
+ layerStack(0),
+ alpha(0),
+ flags(0),
+ mask(0),
+ reserved(0),
+ crop_legacy(Rect::INVALID_RECT),
+ frameNumber_legacy(0),
+ overrideScalingMode(-1),
+ transform(0),
+ transformToDisplayInverse(false),
+ crop(Rect::INVALID_RECT),
+ dataspace(ui::Dataspace::UNKNOWN),
+ surfaceDamageRegion(),
+ api(-1) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
+ hdrMetadata.validTypes = 0;
}
void merge(const layer_state_t& other);
- status_t write(Parcel& output) const;
- status_t read(const Parcel& input);
+ status_t write(Parcel& output) const;
+ status_t read(const Parcel& input);
- struct matrix22_t {
- float dsdx{0};
- float dtdx{0};
- float dtdy{0};
- float dsdy{0};
- };
- sp<IBinder> surface;
- uint32_t what;
- float x;
- float y;
- int32_t z;
- uint32_t w;
- uint32_t h;
- uint32_t layerStack;
- float alpha;
- uint8_t flags;
- uint8_t mask;
- uint8_t reserved;
- matrix22_t matrix;
- Rect crop;
- Rect finalCrop;
- sp<IBinder> barrierHandle;
- sp<IBinder> reparentHandle;
- uint64_t frameNumber;
- int32_t overrideScalingMode;
+ struct matrix22_t {
+ float dsdx{0};
+ float dtdx{0};
+ float dtdy{0};
+ float dsdy{0};
+ };
+ sp<IBinder> surface;
+ uint32_t what;
+ float x;
+ float y;
+ int32_t z;
+ uint32_t w;
+ uint32_t h;
+ uint32_t layerStack;
+ float alpha;
+ uint8_t flags;
+ uint8_t mask;
+ uint8_t reserved;
+ matrix22_t matrix;
+ Rect crop_legacy;
+ sp<IBinder> barrierHandle_legacy;
+ sp<IBinder> reparentHandle;
+ uint64_t frameNumber_legacy;
+ int32_t overrideScalingMode;
- sp<IGraphicBufferProducer> barrierGbp;
+ sp<IGraphicBufferProducer> barrierGbp_legacy;
- sp<IBinder> relativeLayerHandle;
+ sp<IBinder> relativeLayerHandle;
- sp<IBinder> parentHandleForChild;
+ sp<IBinder> parentHandleForChild;
- half3 color;
+ half3 color;
- // non POD must be last. see write/read
- Region transparentRegion;
+ // non POD must be last. see write/read
+ Region transparentRegion;
+
+ uint32_t transform;
+ bool transformToDisplayInverse;
+ Rect crop;
+ sp<GraphicBuffer> buffer;
+ sp<Fence> acquireFence;
+ ui::Dataspace dataspace;
+ HdrMetadata hdrMetadata;
+ Region surfaceDamageRegion;
+ int32_t api;
+ sp<NativeHandle> sidebandStream;
};
struct ComposerState {
sp<ISurfaceComposerClient> client;
layer_state_t state;
- status_t write(Parcel& output) const;
- status_t read(const Parcel& input);
+ status_t write(Parcel& output) const;
+ status_t read(const Parcel& input);
};
struct DisplayState {
-
enum {
- eOrientationDefault = 0,
- eOrientation90 = 1,
- eOrientation180 = 2,
- eOrientation270 = 3,
- eOrientationUnchanged = 4,
- eOrientationSwapMask = 0x01
+ eOrientationDefault = 0,
+ eOrientation90 = 1,
+ eOrientation180 = 2,
+ eOrientation270 = 3,
+ eOrientationUnchanged = 4,
+ eOrientationSwapMask = 0x01
};
enum {
- eSurfaceChanged = 0x01,
- eLayerStackChanged = 0x02,
- eDisplayProjectionChanged = 0x04,
- eDisplaySizeChanged = 0x08
+ eSurfaceChanged = 0x01,
+ eLayerStackChanged = 0x02,
+ eDisplayProjectionChanged = 0x04,
+ eDisplaySizeChanged = 0x08
};
DisplayState();
@@ -152,29 +183,40 @@
sp<IBinder> token;
sp<IGraphicBufferProducer> surface;
uint32_t layerStack;
+
+ // These states define how layers are projected onto the physical display.
+ //
+ // Layers are first clipped to `viewport'. They are then translated and
+ // scaled from `viewport' to `frame'. Finally, they are rotated according
+ // to `orientation', `width', and `height'.
+ //
+ // For example, assume viewport is Rect(0, 0, 200, 100), frame is Rect(20,
+ // 10, 420, 210), and the size of the display is WxH. When orientation is
+ // 0, layers will be scaled by a factor of 2 and translated by (20, 10).
+ // When orientation is 1, layers will be additionally rotated by 90
+ // degrees around the origin clockwise and translated by (W, 0).
uint32_t orientation;
Rect viewport;
Rect frame;
+
uint32_t width, height;
+
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
};
-static inline
-int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
+static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
if (lhs.client < rhs.client) return -1;
if (lhs.client > rhs.client) return 1;
- if (lhs.state.surface < rhs.state.surface) return -1;
- if (lhs.state.surface > rhs.state.surface) return 1;
+ if (lhs.state.surface < rhs.state.surface) return -1;
+ if (lhs.state.surface > rhs.state.surface) return 1;
return 0;
}
-static inline
-int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
+static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
return compare_type(lhs.token, rhs.token);
}
}; // namespace android
#endif // ANDROID_SF_LAYER_STATE_H
-
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 9aeafae..32ee595 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -80,7 +80,7 @@
/* convenience function to check that the given surface is non NULL as
* well as its IGraphicBufferProducer */
static bool isValid(const sp<Surface>& surface) {
- return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
+ return surface != nullptr && surface->getIGraphicBufferProducer() != nullptr;
}
/* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index ad8a8b0..662acc9 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -69,7 +69,7 @@
// callback when the composer is dies
status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
- void* cookie = NULL, uint32_t flags = 0);
+ void* cookie = nullptr, uint32_t flags = 0);
// Get a list of supported configurations for a given display
static status_t getDisplayConfigs(const sp<IBinder>& display,
@@ -79,9 +79,6 @@
static status_t getDisplayInfo(const sp<IBinder>& display,
DisplayInfo* info);
- // Get the display viewport for the given display
- static status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport);
-
// Get the index of the current active configuration (relative to the list
// returned by getDisplayInfo)
static int getActiveConfig(const sp<IBinder>& display);
@@ -104,6 +101,10 @@
/* Triggers screen on/off or low power mode and waits for it to complete */
static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
+ //
+ static status_t getCompositionPreference(ui::Dataspace* dataSpace,
+ ui::PixelFormat* pixelFormat);
+
// ------------------------------------------------------------------------
// surface creation / destruction
@@ -203,22 +204,20 @@
float alpha);
Transaction& setMatrix(const sp<SurfaceControl>& sc,
float dsdx, float dtdx, float dtdy, float dsdy);
- Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
- Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+ Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
// Defers applying any changes made in this transaction until the Layer
// identified by handle reaches the given frameNumber. If the Layer identified
// by handle is removed, then we will apply this transaction regardless of
// what frame number has been reached.
- Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
- const sp<IBinder>& handle,
- uint64_t frameNumber);
- // A variant of deferTransactionUntil which identifies the Layer we wait for by
+ Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+ const sp<IBinder>& handle, uint64_t frameNumber);
+ // A variant of deferTransactionUntil_legacy which identifies the Layer we wait for by
// Surface instead of Handle. Useful for clients which may not have the
// SurfaceControl for some of their Surfaces. Otherwise behaves identically.
- Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
- const sp<Surface>& barrierSurface,
- uint64_t frameNumber);
+ Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+ const sp<Surface>& barrierSurface,
+ uint64_t frameNumber);
// Reparents all children of this layer to the new parent handle.
Transaction& reparentChildren(const sp<SurfaceControl>& sc,
const sp<IBinder>& newParentHandle);
@@ -231,6 +230,20 @@
Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
+ Transaction& setTransform(const sp<SurfaceControl>& sc, uint32_t transform);
+ Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
+ bool transformToDisplayInverse);
+ Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+ Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer);
+ Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence);
+ Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
+ Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
+ Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
+ const Region& surfaceDamageRegion);
+ Transaction& setApi(const sp<SurfaceControl>& sc, int32_t api);
+ Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
+ const sp<NativeHandle>& sidebandStream);
+
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
// The child SurfaceControls will not throw exceptions or return errors,
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index bd987dd..ccb30fa 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -48,11 +48,11 @@
void writeToParcel(Parcel* parcel);
static bool isValid(const sp<SurfaceControl>& surface) {
- return (surface != 0) && surface->isValid();
+ return (surface != nullptr) && surface->isValid();
}
bool isValid() {
- return mHandle!=0 && mClient!=0;
+ return mHandle!=nullptr && mClient!=nullptr;
}
static bool isSameSurface(
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 01e90e0..02064c6 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -50,9 +50,12 @@
],
}
-// Build a separate binary for each source file to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+// Build a separate binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+// This test has a main method, and requires a separate binary to be built.
+// To add move tests like this, just add additional cc_test statements,
+// as opposed to adding more source files to this one.
cc_test {
- name: "libgui_separate_binary_test",
+ name: "SurfaceParcelable_test",
test_suites: ["device-tests"],
clang: true,
@@ -61,7 +64,6 @@
"-Werror",
],
- test_per_src: true,
srcs: [
"SurfaceParcelable_test.cpp",
],
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 9a20859..119e888 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -61,7 +61,7 @@
}
void GetMinUndequeuedBufferCount(int* bufferCount) {
- ASSERT_TRUE(bufferCount != NULL);
+ ASSERT_TRUE(bufferCount != nullptr);
ASSERT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
bufferCount));
ASSERT_GE(*bufferCount, 0);
@@ -82,7 +82,7 @@
sp<Fence> fence;
input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop,
- &scalingMode, &transform, &fence, NULL);
+ &scalingMode, &transform, &fence, nullptr);
ASSERT_EQ(timestamp, item.mTimestamp);
ASSERT_EQ(isAutoTimestamp, item.mIsAutoTimestamp);
ASSERT_EQ(dataSpace, item.mDataSpace);
@@ -128,17 +128,17 @@
sp<IBinder> binderProducer =
serviceManager->getService(PRODUCER_NAME);
mProducer = interface_cast<IGraphicBufferProducer>(binderProducer);
- EXPECT_TRUE(mProducer != NULL);
+ EXPECT_TRUE(mProducer != nullptr);
sp<IBinder> binderConsumer =
serviceManager->getService(CONSUMER_NAME);
mConsumer = interface_cast<IGraphicBufferConsumer>(binderConsumer);
- EXPECT_TRUE(mConsumer != NULL);
+ EXPECT_TRUE(mConsumer != nullptr);
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
IGraphicBufferProducer::QueueBufferOutput output;
ASSERT_EQ(OK,
- mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+ mProducer->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
int slot;
sp<Fence> fence;
@@ -353,8 +353,8 @@
ASSERT_EQ(OK, buffer->unlock());
int newSlot;
- ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(NULL, safeToClobberBuffer));
- ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, NULL));
+ ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(nullptr, safeToClobberBuffer));
+ ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, nullptr));
ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, buffer));
IGraphicBufferProducer::QueueBufferInput input(0, false,
@@ -412,8 +412,8 @@
int newSlot;
sp<GraphicBuffer> safeToClobberBuffer;
- ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(NULL, safeToClobberBuffer));
- ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&newSlot, NULL));
+ ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(nullptr, safeToClobberBuffer));
+ ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&newSlot, nullptr));
ASSERT_EQ(OK, mConsumer->attachBuffer(&newSlot, item.mGraphicBuffer));
ASSERT_EQ(OK, mConsumer->releaseBuffer(newSlot, 0, EGL_NO_DISPLAY,
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 36be7d9..00e32d9 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -484,12 +484,12 @@
err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
ASSERT_NO_ERROR(err, "dequeueBuffer error: ");
- ASSERT_TRUE(anb != NULL);
+ ASSERT_TRUE(anb != nullptr);
sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
*stride = buf->getStride();
- uint8_t* img = NULL;
+ uint8_t* img = nullptr;
ALOGVV("Lock buffer from %p for write", anw.get());
err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
@@ -554,7 +554,7 @@
err = mCC->lockNextBuffer(&b);
ASSERT_NO_ERROR(err, "getNextBuffer error: ");
- ASSERT_TRUE(b.data != NULL);
+ ASSERT_TRUE(b.data != nullptr);
EXPECT_EQ(params.width, b.width);
EXPECT_EQ(params.height, b.height);
EXPECT_EQ(params.format, b.format);
@@ -595,7 +595,7 @@
err = mCC->lockNextBuffer(&b);
ASSERT_NO_ERROR(err, "getNextBuffer error: ");
- ASSERT_TRUE(b.data != NULL);
+ ASSERT_TRUE(b.data != nullptr);
EXPECT_EQ(params.width, b.width);
EXPECT_EQ(params.height, b.height);
EXPECT_EQ(params.format, b.format);
@@ -637,7 +637,7 @@
err = mCC->lockNextBuffer(&b[i]);
ASSERT_NO_ERROR(err, "getNextBuffer error: ");
- ASSERT_TRUE(b[i].data != NULL);
+ ASSERT_TRUE(b[i].data != nullptr);
EXPECT_EQ(params.width, b[i].width);
EXPECT_EQ(params.height, b[i].height);
EXPECT_EQ(params.format, b[i].format);
@@ -660,7 +660,7 @@
err = mCC->lockNextBuffer(&bTooMuch);
ASSERT_NO_ERROR(err, "Did not allow new lock after unlock");
- ASSERT_TRUE(bTooMuch.data != NULL);
+ ASSERT_TRUE(bTooMuch.data != nullptr);
EXPECT_EQ(params.width, bTooMuch.width);
EXPECT_EQ(params.height, bTooMuch.height);
EXPECT_EQ(params.format, bTooMuch.format);
diff --git a/libs/gui/tests/FillBuffer.cpp b/libs/gui/tests/FillBuffer.cpp
index ccd674f..b60995a 100644
--- a/libs/gui/tests/FillBuffer.cpp
+++ b/libs/gui/tests/FillBuffer.cpp
@@ -93,11 +93,11 @@
android_native_buffer_t* anb;
ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(),
&anb));
- ASSERT_TRUE(anb != NULL);
+ ASSERT_TRUE(anb != nullptr);
sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
- uint8_t* img = NULL;
+ uint8_t* img = nullptr;
ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
(void**)(&img)));
fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride());
diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp
index a91552f..a1405fc 100644
--- a/libs/gui/tests/GLTest.cpp
+++ b/libs/gui/tests/GLTest.cpp
@@ -50,7 +50,7 @@
ASSERT_EQ(EGL_SUCCESS, eglGetError());
char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
- if (displaySecsEnv != NULL) {
+ if (displaySecsEnv != nullptr) {
mDisplaySecs = atoi(displaySecsEnv);
if (mDisplaySecs < 0) {
mDisplaySecs = 0;
@@ -67,7 +67,7 @@
String8("Test Surface"), getSurfaceWidth(), getSurfaceHeight(),
PIXEL_FORMAT_RGB_888, 0);
- ASSERT_TRUE(mSurfaceControl != NULL);
+ ASSERT_TRUE(mSurfaceControl != nullptr);
ASSERT_TRUE(mSurfaceControl->isValid());
Transaction t;
@@ -117,7 +117,7 @@
sleep(mDisplaySecs);
}
- if (mComposerClient != NULL) {
+ if (mComposerClient != nullptr) {
mComposerClient->dispose();
}
if (mEglContext != EGL_NO_CONTEXT) {
@@ -171,7 +171,7 @@
EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config,
sp<ANativeWindow>& window) const {
- return eglCreateWindowSurface(display, config, window.get(), NULL);
+ return eglCreateWindowSurface(display, config, window.get(), nullptr);
}
::testing::AssertionResult GLTest::checkPixel(int x, int y,
@@ -256,7 +256,7 @@
GLuint shader = glCreateShader(shaderType);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
if (shader) {
- glShaderSource(shader, 1, &pSource, NULL);
+ glShaderSource(shader, 1, &pSource, nullptr);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
glCompileShader(shader);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
@@ -270,7 +270,7 @@
if (infoLen) {
char* buf = (char*) malloc(infoLen);
if (buf) {
- glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ glGetShaderInfoLog(shader, infoLen, nullptr, buf);
printf("Shader compile log:\n%s\n", buf);
free(buf);
FAIL();
@@ -278,7 +278,7 @@
} else {
char* buf = (char*) malloc(0x1000);
if (buf) {
- glGetShaderInfoLog(shader, 0x1000, NULL, buf);
+ glGetShaderInfoLog(shader, 0x1000, nullptr, buf);
printf("Shader compile log:\n%s\n", buf);
free(buf);
FAIL();
@@ -322,7 +322,7 @@
if (bufLength) {
char* buf = (char*) malloc(bufLength);
if (buf) {
- glGetProgramInfoLog(program, bufLength, NULL, buf);
+ glGetProgramInfoLog(program, bufLength, nullptr, buf);
printf("Program link log:\n%s\n", buf);
free(buf);
FAIL();
diff --git a/libs/gui/tests/GLTest.h b/libs/gui/tests/GLTest.h
index f0d27a8..f290b3c 100644
--- a/libs/gui/tests/GLTest.h
+++ b/libs/gui/tests/GLTest.h
@@ -39,7 +39,7 @@
mEglDisplay(EGL_NO_DISPLAY),
mEglSurface(EGL_NO_SURFACE),
mEglContext(EGL_NO_CONTEXT),
- mGlConfig(NULL) {
+ mGlConfig(nullptr) {
}
virtual void SetUp();
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index a35cf11..6d03374 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -228,9 +228,9 @@
void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence,
sp<GraphicBuffer> *buffer)
{
- ASSERT_TRUE(slot != NULL);
- ASSERT_TRUE(fence != NULL);
- ASSERT_TRUE(buffer != NULL);
+ ASSERT_TRUE(slot != nullptr);
+ ASSERT_TRUE(fence != nullptr);
+ ASSERT_TRUE(buffer != nullptr);
ASSERT_NO_FATAL_FAILURE(ConnectProducer());
@@ -263,7 +263,7 @@
EXPECT_EQ(BAD_VALUE, mProducer->connect(TEST_TOKEN,
TEST_API,
TEST_CONTROLLED_BY_APP,
- /*output*/NULL));
+ /*output*/nullptr));
// Invalid API returns bad value
EXPECT_EQ(BAD_VALUE, mProducer->connect(TEST_TOKEN,
@@ -359,7 +359,7 @@
// TODO: Consider documented the above enums as unsupported or make a new enum for IGBP
// Value was NULL
- EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/NULL));
+ EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/nullptr));
ASSERT_OK(mConsumer->consumerDisconnect());
@@ -465,7 +465,7 @@
// Fence was NULL
{
- sp<Fence> nullFence = NULL;
+ sp<Fence> nullFence = nullptr;
IGraphicBufferProducer::QueueBufferInput input =
QueueBufferInputBuilder().setFence(nullFence).build();
@@ -695,10 +695,7 @@
sp<Fence> fence;
sp<GraphicBuffer> buffer;
- if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
- // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
- ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
- }
+ ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
}
TEST_P(IGraphicBufferProducerTest,
@@ -735,10 +732,7 @@
ASSERT_OK(mProducer->disconnect(TEST_API));
- if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
- // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
- ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
- }
+ ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
}
TEST_P(IGraphicBufferProducerTest,
@@ -778,18 +772,46 @@
sp<GraphicBuffer> buffer;
setupDequeueRequestBuffer(&slot, &fence, &buffer);
+ ASSERT_TRUE(buffer != nullptr);
- if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
- // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
- ASSERT_OK(mProducer->detachBuffer(slot));
+ ASSERT_OK(mProducer->detachBuffer(slot));
+ EXPECT_OK(buffer->initCheck());
+
+ if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
+ // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
+ // isDetachedBuffer() set. Note that this only applies to BufferHub.
+ EXPECT_TRUE(buffer->isDetachedBuffer());
+ } else {
+ EXPECT_FALSE(buffer->isDetachedBuffer());
}
ASSERT_OK(mProducer->disconnect(TEST_API));
- if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
- // TODO(b/69981968): Implement BufferHubProducer::attachBuffer
- ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+ ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+}
+
+TEST_P(IGraphicBufferProducerTest, DetachThenAttach_Succeeds) {
+ int slot = -1;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buffer;
+
+ setupDequeueRequestBuffer(&slot, &fence, &buffer);
+ ASSERT_TRUE(buffer != nullptr);
+
+ ASSERT_OK(mProducer->detachBuffer(slot));
+ EXPECT_OK(buffer->initCheck());
+
+ if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
+ // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
+ // isDetachedBuffer() set. Note that this only applies to BufferHub.
+ EXPECT_TRUE(buffer->isDetachedBuffer());
+ } else {
+ EXPECT_FALSE(buffer->isDetachedBuffer());
}
+
+ EXPECT_OK(mProducer->attachBuffer(&slot, buffer));
+ EXPECT_FALSE(buffer->isDetachedBuffer());
+ EXPECT_OK(buffer->initCheck());
}
#if USE_BUFFER_HUB_AS_BUFFER_QUEUE
diff --git a/libs/gui/tests/MultiTextureConsumer_test.cpp b/libs/gui/tests/MultiTextureConsumer_test.cpp
index 3a25ac5..7d3d4aa 100644
--- a/libs/gui/tests/MultiTextureConsumer_test.cpp
+++ b/libs/gui/tests/MultiTextureConsumer_test.cpp
@@ -47,7 +47,7 @@
GLTest::TearDown();
}
virtual EGLint const* getContextAttribs() {
- return NULL;
+ return nullptr;
}
virtual EGLint const* getConfigAttribs() {
static EGLint sDefaultConfigAttribs[] = {
@@ -105,7 +105,7 @@
glClear(GL_COLOR_BUFFER_BIT);
for (int i=0 ; i<8 ; i++) {
- mSurface->lock(&buffer, NULL);
+ mSurface->lock(&buffer, nullptr);
memset(buffer.bits, (i&7) * 0x20, buffer.stride * buffer.height * 4);
mSurface->unlockAndPost();
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index d5b2f00..65e09f2 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -29,7 +29,6 @@
#include <utils/Thread.h>
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
namespace android {
@@ -39,7 +38,7 @@
mEglDisplay(EGL_NO_DISPLAY),
mEglSurface(EGL_NO_SURFACE),
mEglContext(EGL_NO_CONTEXT),
- mEglConfig(NULL) {
+ mEglConfig(nullptr) {
}
virtual void SetUp() {
@@ -82,7 +81,7 @@
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
- mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT, 0);
+ mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT, nullptr);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
@@ -127,7 +126,7 @@
TEST_F(SurfaceTextureClientTest, GetISurfaceTextureIsNotNull) {
sp<IGraphicBufferProducer> ist(mSTC->getIGraphicBufferProducer());
- ASSERT_TRUE(ist != NULL);
+ ASSERT_TRUE(ist != nullptr);
}
TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) {
@@ -155,7 +154,7 @@
EXPECT_TRUE(eglInitialize(dpy, &majorVersion, &minorVersion));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
- EGLConfig myConfig = {0};
+ EGLConfig myConfig = {nullptr};
EGLint numConfigs = 0;
EGLint configAttribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
@@ -172,7 +171,7 @@
ASSERT_EQ(EGL_SUCCESS, eglGetError());
EGLSurface eglSurface = eglCreateWindowSurface(dpy, myConfig, mANW.get(),
- NULL);
+ nullptr);
EXPECT_NE(EGL_NO_SURFACE, eglSurface);
EXPECT_EQ(EGL_SUCCESS, eglGetError());
@@ -185,7 +184,7 @@
TEST_F(SurfaceTextureClientTest, EglSwapBuffersAbandonErrorIsEglBadSurface) {
- EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mANW.get(), NULL);
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mANW.get(), nullptr);
EXPECT_NE(EGL_NO_SURFACE, eglSurface);
EXPECT_EQ(EGL_SUCCESS, eglGetError());
@@ -638,18 +637,6 @@
}
TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
- // Query to see if the image crop extension exists
- EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
- size_t cropExtLen = strlen(CROP_EXT_STR);
- size_t extsLen = strlen(exts);
- bool equal = !strcmp(CROP_EXT_STR, exts);
- bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
- bool atEnd = (cropExtLen+1) < extsLen &&
- !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
- bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
- bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle;
-
android_native_buffer_t* buf[3];
float mtx[16] = {};
android_native_rect_t crop;
@@ -669,17 +656,15 @@
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
mST->getTransformMatrix(mtx);
- // If the egl image crop extension is not present, this accounts for the
- // .5 texel shrink for each edge that's included in the transform matrix
- // to avoid texturing outside the crop region. Otherwise the crop is not
- // included in the transform matrix.
- EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]);
+ // This accounts for the .5 texel shrink for each edge that's included in
+ // the transform matrix to avoid texturing outside the crop region.
+ EXPECT_EQ(0.5f, mtx[0]);
EXPECT_EQ(0.f, mtx[1]);
EXPECT_EQ(0.f, mtx[2]);
EXPECT_EQ(0.f, mtx[3]);
EXPECT_EQ(0.f, mtx[4]);
- EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]);
+ EXPECT_EQ(-0.5f, mtx[5]);
EXPECT_EQ(0.f, mtx[6]);
EXPECT_EQ(0.f, mtx[7]);
@@ -688,8 +673,8 @@
EXPECT_EQ(1.f, mtx[10]);
EXPECT_EQ(0.f, mtx[11]);
- EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]);
- EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]);
+ EXPECT_EQ(0.0625f, mtx[12]);
+ EXPECT_EQ(0.5625f, mtx[13]);
EXPECT_EQ(0.f, mtx[14]);
EXPECT_EQ(1.f, mtx[15]);
}
@@ -753,7 +738,7 @@
ASSERT_EQ(EGL_SUCCESS, eglGetError());
mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
- 0);
+ nullptr);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
@@ -765,7 +750,7 @@
GLConsumer::TEXTURE_EXTERNAL, true, false));
sp<Surface> stc(new Surface(producer));
mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
- static_cast<ANativeWindow*>(stc.get()), NULL);
+ static_cast<ANativeWindow*>(stc.get()), nullptr);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_SURFACE, mEglSurfaces[i]);
}
diff --git a/libs/gui/tests/SurfaceTextureFBO.h b/libs/gui/tests/SurfaceTextureFBO.h
index 7f1ae84..70f988d 100644
--- a/libs/gui/tests/SurfaceTextureFBO.h
+++ b/libs/gui/tests/SurfaceTextureFBO.h
@@ -34,7 +34,7 @@
glGenTextures(1, &mFboTex);
glBindTexture(GL_TEXTURE_2D, mFboTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(),
- getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, 0);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp
index 0134273..f34561f 100644
--- a/libs/gui/tests/SurfaceTextureFBO_test.cpp
+++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp
@@ -39,12 +39,12 @@
android_native_buffer_t* anb;
ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
&anb));
- ASSERT_TRUE(anb != NULL);
+ ASSERT_TRUE(anb != nullptr);
sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
// Fill the buffer with green
- uint8_t* img = NULL;
+ uint8_t* img = nullptr;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
0, 255);
@@ -63,7 +63,7 @@
ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
&anb));
- ASSERT_TRUE(anb != NULL);
+ ASSERT_TRUE(anb != nullptr);
buf = GraphicBuffer::from(anb);
diff --git a/libs/gui/tests/SurfaceTextureGLThreadToGL.h b/libs/gui/tests/SurfaceTextureGLThreadToGL.h
index 2ce20eb..03975b1 100644
--- a/libs/gui/tests/SurfaceTextureGLThreadToGL.h
+++ b/libs/gui/tests/SurfaceTextureGLThreadToGL.h
@@ -158,7 +158,7 @@
}
virtual void TearDown() {
- if (mProducerThread != NULL) {
+ if (mProducerThread != nullptr) {
mProducerThread->requestExitAndWait();
}
mProducerThread.clear();
@@ -167,7 +167,7 @@
}
void runProducerThread(const sp<ProducerThread> producerThread) {
- ASSERT_TRUE(mProducerThread == NULL);
+ ASSERT_TRUE(mProducerThread == nullptr);
mProducerThread = producerThread;
producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
mProducerEglContext);
diff --git a/libs/gui/tests/SurfaceTextureGLToGL.h b/libs/gui/tests/SurfaceTextureGLToGL.h
index 5d43a48..3a87c12 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL.h
+++ b/libs/gui/tests/SurfaceTextureGLToGL.h
@@ -38,7 +38,7 @@
void SetUpWindowAndContext() {
mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
- mANW.get(), NULL);
+ mANW.get(), nullptr);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index 5639286..e2b4f3d 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -40,12 +40,12 @@
ANativeWindowBuffer* anb;
ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
&anb));
- ASSERT_TRUE(anb != NULL);
+ ASSERT_TRUE(anb != nullptr);
sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
// Fill the buffer with the a checkerboard pattern
- uint8_t* img = NULL;
+ uint8_t* img = nullptr;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
buf->unlock();
@@ -90,12 +90,12 @@
ANativeWindowBuffer* anb;
ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
&anb));
- ASSERT_TRUE(anb != NULL);
+ ASSERT_TRUE(anb != nullptr);
sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
// Fill the buffer with the a checkerboard pattern
- uint8_t* img = NULL;
+ uint8_t* img = nullptr;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
buf->unlock();
@@ -155,11 +155,11 @@
ANativeWindowBuffer* anb;
ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
&anb));
- ASSERT_TRUE(anb != NULL);
+ ASSERT_TRUE(anb != nullptr);
sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
- uint8_t* img = NULL;
+ uint8_t* img = nullptr;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
buf->unlock();
@@ -234,7 +234,7 @@
&anb) != NO_ERROR) {
return false;
}
- if (anb == NULL) {
+ if (anb == nullptr) {
return false;
}
@@ -248,7 +248,7 @@
int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2;
int yuvTexStrideU = yuvTexStrideV;
- uint8_t* img = NULL;
+ uint8_t* img = nullptr;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
// Gray out all the test pixels first, so we're more likely to
@@ -457,7 +457,7 @@
&anb) != NO_ERROR) {
return false;
}
- if (anb == NULL) {
+ if (anb == nullptr) {
return false;
}
if (mANW->queueBuffer(mANW.get(), anb, -1)
@@ -641,7 +641,7 @@
&anb) != NO_ERROR) {
return false;
}
- if (anb == NULL) {
+ if (anb == nullptr) {
return false;
}
if (mANW->queueBuffer(mANW.get(), anb, -1)
@@ -654,7 +654,7 @@
&anb) != NO_ERROR) {
return false;
}
- if (anb == NULL) {
+ if (anb == nullptr) {
return false;
}
if (mANW->queueBuffer(mANW.get(), anb, -1)
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 6e196bf..243f27f 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -72,7 +72,7 @@
mSurfaceControl = mComposerClient->createSurface(
String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mSurfaceControl != NULL);
+ ASSERT_TRUE(mSurfaceControl != nullptr);
ASSERT_TRUE(mSurfaceControl->isValid());
Transaction t;
@@ -81,7 +81,7 @@
.apply());
mSurface = mSurfaceControl->getSurface();
- ASSERT_TRUE(mSurface != NULL);
+ ASSERT_TRUE(mSurface != nullptr);
}
virtual void TearDown() {
@@ -145,7 +145,7 @@
ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
GRALLOC_USAGE_PROTECTED));
ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
- ANativeWindowBuffer* buf = 0;
+ ANativeWindowBuffer* buf = nullptr;
status_t err = native_window_dequeue_buffer_and_wait(anw.get(), &buf);
if (err) {
@@ -581,9 +581,6 @@
Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
status_t getDisplayStats(const sp<IBinder>& /*display*/,
DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
- status_t getDisplayViewport(const sp<IBinder>& /*display*/, Rect* /*outViewport*/) override {
- return NO_ERROR;
- }
int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
override {
@@ -625,6 +622,10 @@
status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
return NO_ERROR;
}
+ status_t getCompositionPreference(ui::Dataspace* /*outDataSpace*/,
+ ui::PixelFormat* /*outPixelFormat*/) const override {
+ return NO_ERROR;
+ }
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index a624663..8a15e2f 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -31,14 +31,16 @@
// --- InputEvent ---
-void InputEvent::initialize(int32_t deviceId, int32_t source) {
+void InputEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId) {
mDeviceId = deviceId;
mSource = source;
+ mDisplayId = displayId;
}
void InputEvent::initialize(const InputEvent& from) {
mDeviceId = from.mDeviceId;
mSource = from.mSource;
+ mDisplayId = from.mDisplayId;
}
// --- KeyEvent ---
@@ -54,6 +56,7 @@
void KeyEvent::initialize(
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t flags,
int32_t keyCode,
@@ -62,7 +65,7 @@
int32_t repeatCount,
nsecs_t downTime,
nsecs_t eventTime) {
- InputEvent::initialize(deviceId, source);
+ InputEvent::initialize(deviceId, source, displayId);
mAction = action;
mFlags = flags;
mKeyCode = keyCode;
@@ -215,6 +218,7 @@
void MotionEvent::initialize(
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t actionButton,
int32_t flags,
@@ -230,7 +234,7 @@
size_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
- InputEvent::initialize(deviceId, source);
+ InputEvent::initialize(deviceId, source, displayId);
mAction = action;
mActionButton = actionButton;
mFlags = flags;
@@ -250,7 +254,7 @@
}
void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
- InputEvent::initialize(other->mDeviceId, other->mSource);
+ InputEvent::initialize(other->mDeviceId, other->mSource, other->mDisplayId);
mAction = other->mAction;
mActionButton = other->mActionButton;
mFlags = other->mFlags;
@@ -431,6 +435,7 @@
mDeviceId = parcel->readInt32();
mSource = parcel->readInt32();
+ mDisplayId = parcel->readInt32();
mAction = parcel->readInt32();
mActionButton = parcel->readInt32();
mFlags = parcel->readInt32();
@@ -480,6 +485,7 @@
parcel->writeInt32(mDeviceId);
parcel->writeInt32(mSource);
+ parcel->writeInt32(mDisplayId);
parcel->writeInt32(mAction);
parcel->writeInt32(mActionButton);
parcel->writeInt32(mFlags);
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 4287abe..778c453 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -20,9 +20,12 @@
#include <unistd.h>
#include <ctype.h>
+#include <android-base/stringprintf.h>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
+using android::base::StringPrintf;
+
namespace android {
static const char* CONFIGURATION_FILE_DIR[] = {
@@ -41,8 +44,8 @@
return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
}
-static void appendInputDeviceConfigurationFileRelativePath(String8& path,
- const String8& name, InputDeviceConfigurationFileType type) {
+static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
+ const std::string& name, InputDeviceConfigurationFileType type) {
path.append(CONFIGURATION_FILE_DIR[type]);
for (size_t i = 0; i < name.length(); i++) {
char ch = name[i];
@@ -54,28 +57,28 @@
path.append(CONFIGURATION_FILE_EXTENSION[type]);
}
-String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
const InputDeviceIdentifier& deviceIdentifier,
InputDeviceConfigurationFileType type) {
if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
if (deviceIdentifier.version != 0) {
// Try vendor product version.
- String8 versionPath(getInputDeviceConfigurationFilePathByName(
- String8::format("Vendor_%04x_Product_%04x_Version_%04x",
+ std::string versionPath = getInputDeviceConfigurationFilePathByName(
+ StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
deviceIdentifier.vendor, deviceIdentifier.product,
deviceIdentifier.version),
- type));
- if (!versionPath.isEmpty()) {
+ type);
+ if (!versionPath.empty()) {
return versionPath;
}
}
// Try vendor product.
- String8 productPath(getInputDeviceConfigurationFilePathByName(
- String8::format("Vendor_%04x_Product_%04x",
+ std::string productPath = getInputDeviceConfigurationFilePathByName(
+ StringPrintf("Vendor_%04x_Product_%04x",
deviceIdentifier.vendor, deviceIdentifier.product),
- type));
- if (!productPath.isEmpty()) {
+ type);
+ if (!productPath.empty()) {
return productPath;
}
}
@@ -84,22 +87,25 @@
return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
}
-String8 getInputDeviceConfigurationFilePathByName(
- const String8& name, InputDeviceConfigurationFileType type) {
+std::string getInputDeviceConfigurationFilePathByName(
+ const std::string& name, InputDeviceConfigurationFileType type) {
// Search system repository.
- String8 path;
+ std::string path;
// Treblized input device config files will be located /odm/usr or /vendor/usr.
const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
for (size_t i = 0; i < size(rootsForPartition); i++) {
- path.setTo(rootsForPartition[i]);
- path.append("/usr/");
+ if (rootsForPartition[i] == nullptr) {
+ continue;
+ }
+ path = rootsForPartition[i];
+ path += "/usr/";
appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
ALOGD("Probing for system provided input device configuration file: path='%s'",
- path.string());
+ path.c_str());
#endif
- if (!access(path.string(), R_OK)) {
+ if (!access(path.c_str(), R_OK)) {
#if DEBUG_PROBE
ALOGD("Found");
#endif
@@ -109,13 +115,17 @@
// Search user repository.
// TODO Should only look here if not in safe mode.
- path.setTo(getenv("ANDROID_DATA"));
- path.append("/system/devices/");
+ path = "";
+ char *androidData = getenv("ANDROID_DATA");
+ if (androidData != nullptr) {
+ path += androidData;
+ }
+ path += "/system/devices/";
appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
- ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
+ ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
#endif
- if (!access(path.string(), R_OK)) {
+ if (!access(path.c_str(), R_OK)) {
#if DEBUG_PROBE
ALOGD("Found");
#endif
@@ -125,16 +135,16 @@
// Not found.
#if DEBUG_PROBE
ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
- name.string(), type);
+ name.c_str(), type);
#endif
- return String8();
+ return "";
}
// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {
- initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false);
+ initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false);
}
InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
@@ -150,7 +160,7 @@
}
void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+ const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
bool hasMic) {
mId = id;
mGeneration = generation;
@@ -175,7 +185,7 @@
return ⦥
}
}
- return NULL;
+ return nullptr;
}
void InputDeviceInfo::addSource(uint32_t source) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index aa0bf17..770d483 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -226,7 +226,7 @@
sp<InputChannel> InputChannel::dup() const {
int fd = ::dup(getFd());
- return fd >= 0 ? new InputChannel(getName(), fd) : NULL;
+ return fd >= 0 ? new InputChannel(getName(), fd) : nullptr;
}
@@ -243,6 +243,7 @@
uint32_t seq,
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t flags,
int32_t keyCode,
@@ -270,6 +271,7 @@
msg.body.key.seq = seq;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
+ msg.body.key.displayId = displayId;
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
@@ -303,13 +305,15 @@
const PointerCoords* pointerCoords) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
+ "displayId=%" PRId32 ", "
"action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
"metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
"xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
"pointerCount=%" PRIu32,
mChannel->getName().c_str(), seq,
- deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
- xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
+ deviceId, source, displayId, action, actionButton, flags, edgeFlags, metaState,
+ buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime,
+ pointerCount);
#endif
if (!seq) {
@@ -384,7 +388,7 @@
bool InputConsumer::isTouchResamplingEnabled() {
char value[PROPERTY_VALUE_MAX];
- int length = property_get("ro.input.noresample", value, NULL);
+ int length = property_get("ro.input.noresample", value, nullptr);
if (length > 0) {
if (!strcmp("1", value)) {
return false;
@@ -398,16 +402,14 @@
}
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
- bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
- int32_t* displayId) {
+ bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime);
#endif
*outSeq = 0;
- *outEvent = NULL;
- *displayId = -1; // Invalid display.
+ *outEvent = nullptr;
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
@@ -422,7 +424,7 @@
if (result) {
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
- result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId);
+ result = consumeBatch(factory, frameTime, outSeq, outEvent);
if (*outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
@@ -466,7 +468,7 @@
// the previous batch right now and defer the new message until later.
mMsgDeferred = true;
status_t result = consumeSamples(factory,
- batch, batch.samples.size(), outSeq, outEvent, displayId);
+ batch, batch.samples.size(), outSeq, outEvent);
mBatches.removeAt(batchIndex);
if (result) {
return result;
@@ -500,7 +502,7 @@
initializeMotionEvent(motionEvent, &mMsg);
*outSeq = mMsg.body.motion.seq;
*outEvent = motionEvent;
- *displayId = mMsg.body.motion.displayId;
+
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
mChannel->getName().c_str(), *outSeq);
@@ -518,14 +520,13 @@
}
status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
status_t result;
for (size_t i = mBatches.size(); i > 0; ) {
i--;
Batch& batch = mBatches.editItemAt(i);
if (frameTime < 0) {
- result = consumeSamples(factory, batch, batch.samples.size(),
- outSeq, outEvent, displayId);
+ result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent);
mBatches.removeAt(i);
return result;
}
@@ -539,11 +540,11 @@
continue;
}
- result = consumeSamples(factory, batch, split + 1, outSeq, outEvent, displayId);
+ result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
const InputMessage* next;
if (batch.samples.isEmpty()) {
mBatches.removeAt(i);
- next = NULL;
+ next = nullptr;
} else {
next = &batch.samples.itemAt(0);
}
@@ -557,7 +558,7 @@
}
status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
- Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
+ Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
MotionEvent* motionEvent = factory->createMotionEvent();
if (! motionEvent) return NO_MEMORY;
@@ -572,7 +573,6 @@
mSeqChains.push(seqChain);
addSample(motionEvent, &msg);
} else {
- *displayId = msg.body.motion.displayId;
initializeMotionEvent(motionEvent, &msg);
}
chain = msg.body.motion.seq;
@@ -928,6 +928,7 @@
event->initialize(
msg->body.key.deviceId,
msg->body.key.source,
+ msg->body.key.displayId,
msg->body.key.action,
msg->body.key.flags,
msg->body.key.keyCode,
@@ -950,6 +951,7 @@
event->initialize(
msg->body.motion.deviceId,
msg->body.motion.source,
+ msg->body.motion.displayId,
msg->body.motion.action,
msg->body.motion.actionButton,
msg->body.motion.flags,
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index cba1111..e189d20 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -106,14 +106,14 @@
}
}
-status_t KeyCharacterMap::load(const String8& filename,
+status_t KeyCharacterMap::load(const std::string& filename,
Format format, sp<KeyCharacterMap>* outMap) {
outMap->clear();
Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
+ status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
if (status) {
- ALOGE("Error %d opening key character map file %s.", status, filename.string());
+ ALOGE("Error %d opening key character map file %s.", status, filename.c_str());
} else {
status = load(tokenizer, format, outMap);
delete tokenizer;
@@ -121,12 +121,12 @@
return status;
}
-status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
+status_t KeyCharacterMap::loadContents(const std::string& filename, const char* contents,
Format format, sp<KeyCharacterMap>* outMap) {
outMap->clear();
Tokenizer* tokenizer;
- status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
+ status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
if (status) {
ALOGE("Error %d opening key character map.", status);
} else {
@@ -164,10 +164,10 @@
sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
const sp<KeyCharacterMap>& overlay) {
- if (overlay == NULL) {
+ if (overlay == nullptr) {
return base;
}
- if (base == NULL) {
+ if (base == nullptr) {
return overlay;
}
@@ -468,7 +468,7 @@
// Try to find the most general behavior that maps to this character.
// For example, the base key behavior will usually be last in the list.
- const Behavior* found = NULL;
+ const Behavior* found = nullptr;
for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
if (behavior->character == ch) {
found = behavior;
@@ -487,7 +487,7 @@
int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
outEvents.push();
KeyEvent& event = outEvents.editTop();
- event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
+ event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
0, keyCode, 0, metaState, 0, time, time);
}
@@ -605,11 +605,11 @@
map->mType = parcel->readInt32();
size_t numKeys = parcel->readInt32();
if (parcel->errorCheck()) {
- return NULL;
+ return nullptr;
}
if (numKeys > MAX_KEYS) {
ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
- return NULL;
+ return nullptr;
}
for (size_t i = 0; i < numKeys; i++) {
@@ -617,7 +617,7 @@
char16_t label = parcel->readInt32();
char16_t number = parcel->readInt32();
if (parcel->errorCheck()) {
- return NULL;
+ return nullptr;
}
Key* key = new Key();
@@ -625,14 +625,14 @@
key->number = number;
map->mKeys.add(keyCode, key);
- Behavior* lastBehavior = NULL;
+ Behavior* lastBehavior = nullptr;
while (parcel->readInt32()) {
int32_t metaState = parcel->readInt32();
char16_t character = parcel->readInt32();
int32_t fallbackKeyCode = parcel->readInt32();
int32_t replacementKeyCode = parcel->readInt32();
if (parcel->errorCheck()) {
- return NULL;
+ return nullptr;
}
Behavior* behavior = new Behavior();
@@ -649,7 +649,7 @@
}
if (parcel->errorCheck()) {
- return NULL;
+ return nullptr;
}
}
return map;
@@ -666,7 +666,7 @@
parcel->writeInt32(keyCode);
parcel->writeInt32(key->label);
parcel->writeInt32(key->number);
- for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
+ for (const Behavior* behavior = key->firstBehavior; behavior != nullptr;
behavior = behavior->next) {
parcel->writeInt32(1);
parcel->writeInt32(behavior->metaState);
@@ -683,12 +683,12 @@
// --- KeyCharacterMap::Key ---
KeyCharacterMap::Key::Key() :
- label(0), number(0), firstBehavior(NULL) {
+ label(0), number(0), firstBehavior(nullptr) {
}
KeyCharacterMap::Key::Key(const Key& other) :
label(other.label), number(other.number),
- firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
+ firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : nullptr) {
}
KeyCharacterMap::Key::~Key() {
@@ -704,11 +704,11 @@
// --- KeyCharacterMap::Behavior ---
KeyCharacterMap::Behavior::Behavior() :
- next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
+ next(nullptr), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
}
KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
- next(other.next ? new Behavior(*other.next) : NULL),
+ next(other.next ? new Behavior(*other.next) : nullptr),
metaState(other.metaState), character(other.character),
fallbackKeyCode(other.fallbackKeyCode),
replacementKeyCode(other.replacementKeyCode) {
@@ -944,7 +944,7 @@
properties.add(Property(PROPERTY_NUMBER));
} else {
int32_t metaState;
- status_t status = parseModifier(token, &metaState);
+ status_t status = parseModifier(token.string(), &metaState);
if (status) {
ALOGE("%s: Expected a property name or modifier, got '%s'.",
mTokenizer->getLocation().string(), token.string());
@@ -1137,7 +1137,7 @@
return NO_ERROR;
}
-status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
+status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
if (token == "base") {
*outMetaState = 0;
return NO_ERROR;
@@ -1145,7 +1145,7 @@
int32_t combinedMeta = 0;
- const char* str = token.string();
+ const char* str = token.c_str();
const char* start = str;
for (const char* cur = str; ; cur++) {
char ch = *cur;
@@ -1164,7 +1164,7 @@
}
if (combinedMeta & metaState) {
ALOGE("%s: Duplicate modifier combination '%s'.",
- mTokenizer->getLocation().string(), token.string());
+ mTokenizer->getLocation().string(), token.c_str());
return BAD_VALUE;
}
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index 2b2f13e..88cb0db 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -49,13 +49,13 @@
KeyLayoutMap::~KeyLayoutMap() {
}
-status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {
+status_t KeyLayoutMap::load(const std::string& filename, sp<KeyLayoutMap>* outMap) {
outMap->clear();
Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
+ status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
if (status) {
- ALOGE("Error %d opening key layout map file %s.", status, filename.string());
+ ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
} else {
sp<KeyLayoutMap> map = new KeyLayoutMap();
if (!map.get()) {
@@ -117,7 +117,7 @@
return &mKeysByScanCode.valueAt(index);
}
}
- return NULL;
+ return nullptr;
}
status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 11842ee..0c22bfe 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -45,22 +45,22 @@
String8 keyLayoutName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
keyLayoutName)) {
- status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
+ status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
- deviceIdenfifier.name.string(), keyLayoutName.string());
+ deviceIdenfifier.name.c_str(), keyLayoutName.string());
}
}
String8 keyCharacterMapName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
keyCharacterMapName)) {
- status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
+ status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
- deviceIdenfifier.name.string(), keyLayoutName.string());
+ deviceIdenfifier.name.c_str(), keyLayoutName.string());
}
}
@@ -70,30 +70,30 @@
}
// Try searching by device identifier.
- if (probeKeyMap(deviceIdenfifier, String8::empty())) {
+ if (probeKeyMap(deviceIdenfifier, "")) {
return OK;
}
// Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
// generic key map to use (US English, etc.) for typical external keyboards.
- if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
+ if (probeKeyMap(deviceIdenfifier, "Generic")) {
return OK;
}
// Try the Virtual key map as a last resort.
- if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
+ if (probeKeyMap(deviceIdenfifier, "Virtual")) {
return OK;
}
// Give up!
ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
- deviceIdenfifier.name.string());
+ deviceIdenfifier.name.c_str());
return NAME_NOT_FOUND;
}
bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
- const String8& keyMapName) {
+ const std::string& keyMapName) {
if (!haveKeyLayout()) {
loadKeyLayout(deviceIdentifier, keyMapName);
}
@@ -104,10 +104,10 @@
}
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name) {
- String8 path(getPath(deviceIdentifier, name,
+ const std::string& name) {
+ std::string path(getPath(deviceIdentifier, name,
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
- if (path.isEmpty()) {
+ if (path.empty()) {
return NAME_NOT_FOUND;
}
@@ -116,15 +116,15 @@
return status;
}
- keyLayoutFile.setTo(path);
+ keyLayoutFile = path;
return OK;
}
status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name) {
- String8 path(getPath(deviceIdentifier, name,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
- if (path.isEmpty()) {
+ const std::string& name) {
+ std::string path = getPath(deviceIdentifier, name,
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP);
+ if (path.empty()) {
return NAME_NOT_FOUND;
}
@@ -134,13 +134,13 @@
return status;
}
- keyCharacterMapFile.setTo(path);
+ keyCharacterMapFile = path;
return OK;
}
-String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name, InputDeviceConfigurationFileType type) {
- return name.isEmpty()
+std::string KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
+ const std::string& name, InputDeviceConfigurationFileType type) {
+ return name.empty()
? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
: getInputDeviceConfigurationFilePathByName(name, type);
}
@@ -174,7 +174,7 @@
}
}
- return strstr(deviceIdentifier.name.string(), "-keypad");
+ return strstr(deviceIdentifier.name.c_str(), "-keypad");
}
static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index f72e49b..1bbd82b 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -117,7 +117,7 @@
// Allow the default strategy to be overridden using a system property for debugging.
if (!strategy) {
- int length = property_get("debug.velocitytracker.strategy", value, NULL);
+ int length = property_get("persist.input.velocitytracker.strategy", value, nullptr);
if (length > 0) {
strategy = value;
} else {
@@ -141,7 +141,7 @@
bool VelocityTracker::configureStrategy(const char* strategy) {
mStrategy = createStrategy(strategy);
- return mStrategy != NULL;
+ return mStrategy != nullptr;
}
VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
@@ -206,7 +206,7 @@
// time to adjust to changes in direction.
return new LegacyVelocityTrackerStrategy();
}
- return NULL;
+ return nullptr;
}
void VelocityTracker::clear() {
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 28ea717..3ec53bf 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -46,13 +46,13 @@
VirtualKeyMap::~VirtualKeyMap() {
}
-status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
- *outMap = NULL;
+status_t VirtualKeyMap::load(const std::string& filename, VirtualKeyMap** outMap) {
+ *outMap = nullptr;
Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
+ status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
if (status) {
- ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
+ ALOGE("Error %d opening virtual key map file %s.", status, filename.c_str());
} else {
VirtualKeyMap* map = new VirtualKeyMap();
if (!map) {
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index aca9521..f06119f 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -1,7 +1,6 @@
// Build the unit tests.
cc_test {
name: "libinput_tests",
- test_per_src: true,
srcs: [
"InputChannel_test.cpp",
"InputEvent_test.cpp",
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index fd3b7c8..99f83ba 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -22,6 +22,9 @@
namespace android {
+// Default display id.
+static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
+
class BaseTest : public testing::Test {
protected:
virtual void SetUp() { }
@@ -178,13 +181,14 @@
// Initialize and get properties.
const nsecs_t ARBITRARY_DOWN_TIME = 1;
const nsecs_t ARBITRARY_EVENT_TIME = 2;
- event.initialize(2, AINPUT_SOURCE_GAMEPAD, AKEY_EVENT_ACTION_DOWN,
+ event.initialize(2, AINPUT_SOURCE_GAMEPAD, DISPLAY_ID, AKEY_EVENT_ACTION_DOWN,
AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121,
AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME);
ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
ASSERT_EQ(2, event.getDeviceId());
ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_GAMEPAD), event.getSource());
+ ASSERT_EQ(DISPLAY_ID, event.getDisplayId());
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags());
ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode());
@@ -197,6 +201,11 @@
// Set source.
event.setSource(AINPUT_SOURCE_JOYSTICK);
ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
+
+ // Set display id.
+ constexpr int32_t newDisplayId = 2;
+ event.setDisplayId(newDisplayId);
+ ASSERT_EQ(newDisplayId, event.getDisplayId());
}
@@ -248,7 +257,7 @@
pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
- event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, 0,
+ event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
@@ -301,6 +310,7 @@
ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
ASSERT_EQ(2, event->getDeviceId());
ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_TOUCHSCREEN), event->getSource());
+ ASSERT_EQ(DISPLAY_ID, event->getDisplayId());
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
@@ -434,6 +444,11 @@
event.setSource(AINPUT_SOURCE_JOYSTICK);
ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
+ // Set displayId.
+ constexpr int32_t newDisplayId = 2;
+ event.setDisplayId(newDisplayId);
+ ASSERT_EQ(newDisplayId, event.getDisplayId());
+
// Set action.
event.setAction(AMOTION_EVENT_ACTION_CANCEL);
ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction());
@@ -557,7 +572,7 @@
pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
}
MotionEvent event;
- event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
+ event.initialize(0, 0, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
float originalRawX = 0 + 3;
float originalRawY = -RADIUS + 2;
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index c532241..0788c89 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -46,12 +46,12 @@
virtual void TearDown() {
if (mPublisher) {
delete mPublisher;
- mPublisher = NULL;
+ mPublisher = nullptr;
}
if (mConsumer) {
delete mConsumer;
- mConsumer = NULL;
+ mConsumer = nullptr;
}
serverChannel.clear();
@@ -70,32 +70,31 @@
void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
status_t status;
- const uint32_t seq = 15;
- const int32_t deviceId = 1;
- const int32_t source = AINPUT_SOURCE_KEYBOARD;
- const int32_t action = AKEY_EVENT_ACTION_DOWN;
- const int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
- const int32_t keyCode = AKEYCODE_ENTER;
- const int32_t scanCode = 13;
- const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
- const int32_t repeatCount = 1;
- const nsecs_t downTime = 3;
- const nsecs_t eventTime = 4;
+ constexpr uint32_t seq = 15;
+ constexpr int32_t deviceId = 1;
+ constexpr int32_t source = AINPUT_SOURCE_KEYBOARD;
+ constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
+ constexpr int32_t action = AKEY_EVENT_ACTION_DOWN;
+ constexpr int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
+ constexpr int32_t keyCode = AKEYCODE_ENTER;
+ constexpr int32_t scanCode = 13;
+ constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
+ constexpr int32_t repeatCount = 1;
+ constexpr nsecs_t downTime = 3;
+ constexpr nsecs_t eventTime = 4;
- status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags,
+ status = mPublisher->publishKeyEvent(seq, deviceId, source, displayId, action, flags,
keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
ASSERT_EQ(OK, status)
<< "publisher publishKeyEvent should return OK";
uint32_t consumeSeq;
InputEvent* event;
- int32_t displayId;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
- &displayId);
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
- ASSERT_TRUE(event != NULL)
+ ASSERT_TRUE(event != nullptr)
<< "consumer should have returned non-NULL event";
ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event->getType())
<< "consumer should have returned a key event";
@@ -104,6 +103,7 @@
EXPECT_EQ(seq, consumeSeq);
EXPECT_EQ(deviceId, keyEvent->getDeviceId());
EXPECT_EQ(source, keyEvent->getSource());
+ EXPECT_EQ(displayId, keyEvent->getDisplayId());
EXPECT_EQ(action, keyEvent->getAction());
EXPECT_EQ(flags, keyEvent->getFlags());
EXPECT_EQ(keyCode, keyEvent->getKeyCode());
@@ -131,23 +131,23 @@
void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
status_t status;
- const uint32_t seq = 15;
- const int32_t deviceId = 1;
- const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
- int32_t displayId = 0;
- const int32_t action = AMOTION_EVENT_ACTION_MOVE;
- const int32_t actionButton = 0;
- const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
- const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
- const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
- const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
- const float xOffset = -10;
- const float yOffset = -20;
- const float xPrecision = 0.25;
- const float yPrecision = 0.5;
- const nsecs_t downTime = 3;
- const size_t pointerCount = 3;
- const nsecs_t eventTime = 4;
+ constexpr uint32_t seq = 15;
+ constexpr int32_t deviceId = 1;
+ constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+ constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
+ constexpr int32_t action = AMOTION_EVENT_ACTION_MOVE;
+ constexpr int32_t actionButton = 0;
+ constexpr int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+ constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
+ constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
+ constexpr int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
+ constexpr float xOffset = -10;
+ constexpr float yOffset = -20;
+ constexpr float xPrecision = 0.25;
+ constexpr float yPrecision = 0.5;
+ constexpr nsecs_t downTime = 3;
+ constexpr size_t pointerCount = 3;
+ constexpr nsecs_t eventTime = 4;
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
for (size_t i = 0; i < pointerCount; i++) {
@@ -176,12 +176,11 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
- &displayId);
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
- ASSERT_TRUE(event != NULL)
+ ASSERT_TRUE(event != nullptr)
<< "consumer should have returned non-NULL event";
ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
<< "consumer should have returned a motion event";
@@ -190,6 +189,7 @@
EXPECT_EQ(seq, consumeSeq);
EXPECT_EQ(deviceId, motionEvent->getDeviceId());
EXPECT_EQ(source, motionEvent->getSource());
+ EXPECT_EQ(displayId, motionEvent->getDisplayId());
EXPECT_EQ(action, motionEvent->getAction());
EXPECT_EQ(flags, motionEvent->getFlags());
EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 43b6012..5242a18 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -26,6 +26,8 @@
namespace android {
+constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; // default display id
+
constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually defined tests
// velocity must be in the range (1-tol)*EV <= velocity <= (1+tol)*EV
@@ -89,7 +91,7 @@
// First sample added separately with initialize
coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
- event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+ event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
for (size_t i = 1; i < numSamples; i++) {
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index a0e368c..d9a986e 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -318,7 +318,7 @@
// If the sensor is protected by a permission we need to know if it is
// a runtime one to determine whether we can use the permission cache.
sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
- if (binder != 0) {
+ if (binder != nullptr) {
sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
mRequiredPermissionRuntime = permCtrl->isRuntimePermission(
String16(mRequiredPermission));
diff --git a/libs/sensor/SensorEventQueue.cpp b/libs/sensor/SensorEventQueue.cpp
index 6f68fb5..46ba7c6 100644
--- a/libs/sensor/SensorEventQueue.cpp
+++ b/libs/sensor/SensorEventQueue.cpp
@@ -37,7 +37,7 @@
// ----------------------------------------------------------------------------
SensorEventQueue::SensorEventQueue(const sp<ISensorEventConnection>& connection)
- : mSensorEventConnection(connection), mRecBuffer(NULL), mAvailable(0), mConsumed(0),
+ : mSensorEventConnection(connection), mRecBuffer(nullptr), mAvailable(0), mConsumed(0),
mNumAcksToSend(0) {
mRecBuffer = new ASensorEvent[MAX_RECEIVE_BUFFER_EVENT_COUNT];
}
@@ -82,9 +82,9 @@
sp<Looper> SensorEventQueue::getLooper() const
{
Mutex::Autolock _l(mLock);
- if (mLooper == 0) {
+ if (mLooper == nullptr) {
mLooper = new Looper(true);
- mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL);
+ mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, nullptr, nullptr);
}
return mLooper;
}
@@ -97,7 +97,7 @@
int events;
int32_t result;
do {
- result = looper->pollOnce(-1, NULL, &events, NULL);
+ result = looper->pollOnce(-1, nullptr, &events, nullptr);
if (result == ALOOPER_POLL_ERROR) {
ALOGE("SensorEventQueue::waitForEvent error (errno=%d)", errno);
result = -EPIPE; // unknown error, so we make up one
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index b9ae524..5840d51 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -62,7 +62,7 @@
// to the wrong package and stats based on app ops may be slightly off.
if (opPackageName.size() <= 0) {
sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
- if (binder != 0) {
+ if (binder != nullptr) {
const uid_t uid = IPCThreadState::self()->getCallingUid();
Vector<String16> packages;
interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
@@ -93,7 +93,7 @@
}
SensorManager::SensorManager(const String16& opPackageName)
- : mSensorList(0), mOpPackageName(opPackageName), mDirectConnectionHandle(1) {
+ : mSensorList(nullptr), mOpPackageName(opPackageName), mDirectConnectionHandle(1) {
// okay we're not locked here, but it's not needed during construction
assertStateLocked();
}
@@ -128,13 +128,13 @@
Mutex::Autolock _l(mLock);
mSensorServer.clear();
free(mSensorList);
- mSensorList = NULL;
+ mSensorList = nullptr;
mSensors.clear();
}
status_t SensorManager::assertStateLocked() {
bool initSensorManager = false;
- if (mSensorServer == NULL) {
+ if (mSensorServer == nullptr) {
initSensorManager = true;
} else {
// Ping binder to check if sensorservice is alive.
@@ -164,7 +164,7 @@
size_t count = mSensors.size();
mSensorList =
static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
- LOG_ALWAYS_FATAL_IF(mSensorList == NULL, "mSensorList NULL");
+ LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL");
for (size_t i=0 ; i<count ; i++) {
mSensorList[i] = mSensors.array() + i;
@@ -222,7 +222,7 @@
}
}
}
- return NULL;
+ return nullptr;
}
sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
@@ -232,10 +232,10 @@
while (assertStateLocked() == NO_ERROR) {
sp<ISensorEventConnection> connection =
mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);
- if (connection == NULL) {
+ if (connection == nullptr) {
// SensorService just died or the app doesn't have required permissions.
ALOGE("createEventQueue: connection is NULL.");
- return NULL;
+ return nullptr;
}
queue = new SensorEventQueue(connection);
break;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index d25ad1a..1605050 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -26,6 +26,7 @@
"-Werror",
],
cppflags: [
+ "-std=c++1z",
"-Weverything",
// The static constructors and destructors in this library have not been noted to
@@ -65,6 +66,7 @@
"PixelFormat.cpp",
"Rect.cpp",
"Region.cpp",
+ "Transform.cpp",
"UiConfig.cpp",
],
diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp
index 1414766..340231d 100644
--- a/libs/ui/FenceTime.cpp
+++ b/libs/ui/FenceTime.cpp
@@ -33,18 +33,6 @@
const auto FenceTime::NO_FENCE = std::make_shared<FenceTime>(Fence::NO_FENCE);
-void* FenceTime::operator new(size_t byteCount) noexcept {
- void *p = nullptr;
- if (posix_memalign(&p, alignof(FenceTime), byteCount)) {
- return nullptr;
- }
- return p;
-}
-
-void FenceTime::operator delete(void *p) {
- free(p);
-}
-
FenceTime::FenceTime(const sp<Fence>& fence)
: mState(((fence.get() != nullptr) && fence->isValid()) ?
State::VALID : State::INVALID),
diff --git a/services/surfaceflinger/Transform.cpp b/libs/ui/Transform.cpp
similarity index 81%
rename from services/surfaceflinger/Transform.cpp
rename to libs/ui/Transform.cpp
index e05ed53..8e949ec 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -17,17 +17,12 @@
#include <math.h>
#include <cutils/compiler.h>
-#include <utils/String8.h>
#include <ui/Region.h>
-
-#include "Transform.h"
-#include "clz.h"
-
-// ---------------------------------------------------------------------------
+#include <ui/Transform.h>
+#include <utils/String8.h>
namespace android {
-
-// ---------------------------------------------------------------------------
+namespace ui {
Transform::Transform() {
reset();
@@ -41,8 +36,7 @@
set(orientation, 0, 0);
}
-Transform::~Transform() {
-}
+Transform::~Transform() = default;
static const float EPSILON = 0.0f;
@@ -67,7 +61,7 @@
const mat33& A(mMatrix);
const mat33& B(rhs.mMatrix);
mat33& D(r.mMatrix);
- for (int i=0 ; i<3 ; i++) {
+ for (size_t i = 0; i < 3; i++) {
const float v0 = A[0][i];
const float v1 = A[1][i];
const float v2 = A[2][i];
@@ -83,6 +77,12 @@
return r;
}
+Transform& Transform::operator=(const Transform& other) {
+ mMatrix = other.mMatrix;
+ mType = other.mType;
+ return *this;
+}
+
const vec3& Transform::operator [] (size_t i) const {
return mMatrix[i];
}
@@ -97,10 +97,10 @@
void Transform::reset() {
mType = IDENTITY;
- for(int i=0 ; i<3 ; i++) {
+ for(size_t i = 0; i < 3; i++) {
vec3& v(mMatrix[i]);
- for (int j=0 ; j<3 ; j++)
- v[j] = ((i==j) ? 1.0f : 0.0f);
+ for (size_t j = 0; j < 3; j++)
+ v[j] = ((i == j) ? 1.0f : 0.0f);
}
}
@@ -137,7 +137,7 @@
Transform H, V, R;
if (flags & ROT_90) {
// w & h are inverted when rotating by 90 degrees
- swap(w, h);
+ std::swap(w, h);
}
if (flags & FLIP_H) {
@@ -210,15 +210,15 @@
rb = transform(rb);
if (roundOutwards) {
- r.left = floorf(min(lt[0], rt[0], lb[0], rb[0]));
- r.top = floorf(min(lt[1], rt[1], lb[1], rb[1]));
- r.right = ceilf(max(lt[0], rt[0], lb[0], rb[0]));
- r.bottom = ceilf(max(lt[1], rt[1], lb[1], rb[1]));
+ r.left = static_cast<int32_t>(floorf(std::min({lt[0], rt[0], lb[0], rb[0]})));
+ r.top = static_cast<int32_t>(floorf(std::min({lt[1], rt[1], lb[1], rb[1]})));
+ r.right = static_cast<int32_t>(ceilf(std::max({lt[0], rt[0], lb[0], rb[0]})));
+ r.bottom = static_cast<int32_t>(ceilf(std::max({lt[1], rt[1], lb[1], rb[1]})));
} else {
- r.left = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
- r.top = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
- r.right = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
- r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
+ r.left = static_cast<int32_t>(floorf(std::min({lt[0], rt[0], lb[0], rb[0]}) + 0.5f));
+ r.top = static_cast<int32_t>(floorf(std::min({lt[1], rt[1], lb[1], rb[1]}) + 0.5f));
+ r.right = static_cast<int32_t>(floorf(std::max({lt[0], rt[0], lb[0], rb[0]}) + 0.5f));
+ r.bottom = static_cast<int32_t>(floorf(std::max({lt[1], rt[1], lb[1], rb[1]}) + 0.5f));
}
return r;
@@ -237,10 +237,10 @@
rb = transform(rb);
FloatRect r;
- r.left = min(lt[0], rt[0], lb[0], rb[0]);
- r.top = min(lt[1], rt[1], lb[1], rb[1]);
- r.right = max(lt[0], rt[0], lb[0], rb[0]);
- r.bottom = max(lt[1], rt[1], lb[1], rb[1]);
+ r.left = std::min({lt[0], rt[0], lb[0], rb[0]});
+ r.top = std::min({lt[1], rt[1], lb[1], rb[1]});
+ r.right = std::max({lt[0], rt[0], lb[0], rb[0]});
+ r.bottom = std::max({lt[1], rt[1], lb[1], rb[1]});
return r;
}
@@ -259,8 +259,8 @@
out.set(transform(reg.bounds()));
}
} else {
- int xpos = floorf(tx() + 0.5f);
- int ypos = floorf(ty() + 0.5f);
+ int xpos = static_cast<int>(floorf(tx() + 0.5f));
+ int ypos = static_cast<int>(floorf(ty() + 0.5f));
out = reg.translate(xpos, ypos);
}
return out;
@@ -343,7 +343,7 @@
const float x = M[2][0];
const float y = M[2][1];
- const float idet = 1.0 / (a*d - b*c);
+ const float idet = 1.0f / (a*d - b*c);
result.mMatrix[0][0] = d*idet;
result.mMatrix[0][1] = -c*idet;
result.mMatrix[1][0] = -b*idet;
@@ -404,28 +404,13 @@
type.append("TRANSLATE ");
ALOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string());
- ALOGD("%.4f %.4f %.4f", m[0][0], m[1][0], m[2][0]);
- ALOGD("%.4f %.4f %.4f", m[0][1], m[1][1], m[2][1]);
- ALOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]);
+ ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][0]), static_cast<double>(m[1][0]),
+ static_cast<double>(m[2][0]));
+ ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][1]), static_cast<double>(m[1][1]),
+ static_cast<double>(m[2][1]));
+ ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][2]), static_cast<double>(m[1][2]),
+ static_cast<double>(m[2][2]));
}
-Transform::orientation_flags Transform::fromRotation(ISurfaceComposer::Rotation rotation) {
- // Convert to surfaceflinger's internal rotation type.
- switch (rotation) {
- case ISurfaceComposer::eRotateNone:
- return Transform::ROT_0;
- case ISurfaceComposer::eRotate90:
- return Transform::ROT_90;
- case ISurfaceComposer::eRotate180:
- return Transform::ROT_180;
- case ISurfaceComposer::eRotate270:
- return Transform::ROT_270;
- default:
- ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
- return Transform::ROT_0;
- }
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
+} // namespace ui
+} // namespace android
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 94caf6b..8976d2d 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -35,6 +35,8 @@
bool secure{false};
nsecs_t appVsyncOffset{0};
nsecs_t presentationDeadline{0};
+ uint32_t viewportW{0};
+ uint32_t viewportH{0};
};
/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
diff --git a/libs/ui/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h
index 871fcf2..a5a1fcb 100644
--- a/libs/ui/include/ui/FenceTime.h
+++ b/libs/ui/include/ui/FenceTime.h
@@ -113,11 +113,6 @@
void signalForTest(nsecs_t signalTime);
- // Override new and delete since this needs 8-byte alignment, which
- // is not guaranteed on x86.
- static void* operator new(size_t nbytes) noexcept;
- static void operator delete(void *p);
-
private:
// For tests only. If forceValidForTest is true, then getSignalTime will
// never return SIGNAL_TIME_INVALID and isValid will always return true.
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 7788452..68b60fc 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -25,6 +25,8 @@
#include <ui/Rect.h>
#include <utils/Flattenable.h>
+#include <android-base/macros.h>
+
namespace android {
// ---------------------------------------------------------------------------
@@ -93,11 +95,11 @@
Region& subtractSelf(const Region& rhs, int dx, int dy);
// these translate rhs first
- const Region translate(int dx, int dy) const;
- const Region merge(const Region& rhs, int dx, int dy) const;
- const Region mergeExclusive(const Region& rhs, int dx, int dy) const;
- const Region intersect(const Region& rhs, int dx, int dy) const;
- const Region subtract(const Region& rhs, int dx, int dy) const;
+ const Region translate(int dx, int dy) const WARN_UNUSED;
+ const Region merge(const Region& rhs, int dx, int dy) const WARN_UNUSED;
+ const Region mergeExclusive(const Region& rhs, int dx, int dy) const WARN_UNUSED;
+ const Region intersect(const Region& rhs, int dx, int dy) const WARN_UNUSED;
+ const Region subtract(const Region& rhs, int dx, int dy) const WARN_UNUSED;
// convenience operators overloads
inline const Region operator | (const Region& rhs) const;
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
new file mode 100644
index 0000000..42dca75
--- /dev/null
+++ b/libs/ui/include/ui/Transform.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_TRANSFORM_H
+#define ANDROID_TRANSFORM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/hardware.h>
+#include <math/vec2.h>
+#include <math/vec3.h>
+#include <ui/Point.h>
+#include <ui/Rect.h>
+
+namespace android {
+
+class Region;
+
+namespace ui {
+
+class Transform {
+public:
+ Transform();
+ Transform(const Transform& other);
+ explicit Transform(uint32_t orientation);
+ ~Transform();
+
+ enum orientation_flags {
+ ROT_0 = 0x00000000,
+ FLIP_H = HAL_TRANSFORM_FLIP_H,
+ FLIP_V = HAL_TRANSFORM_FLIP_V,
+ ROT_90 = HAL_TRANSFORM_ROT_90,
+ ROT_180 = FLIP_H|FLIP_V,
+ ROT_270 = ROT_180|ROT_90,
+ ROT_INVALID = 0x80
+ };
+
+ enum type_mask : uint32_t {
+ IDENTITY = 0,
+ TRANSLATE = 0x1,
+ ROTATE = 0x2,
+ SCALE = 0x4,
+ UNKNOWN = 0x8
+ };
+
+ // query the transform
+ bool preserveRects() const;
+ uint32_t getType() const;
+ uint32_t getOrientation() const;
+
+ const vec3& operator [] (size_t i) const; // returns column i
+ float tx() const;
+ float ty() const;
+
+ // modify the transform
+ void reset();
+ void set(float tx, float ty);
+ void set(float a, float b, float c, float d);
+ status_t set(uint32_t flags, float w, float h);
+
+ // transform data
+ Rect makeBounds(int w, int h) const;
+ vec2 transform(int x, int y) const;
+ Region transform(const Region& reg) const;
+ Rect transform(const Rect& bounds,
+ bool roundOutwards = false) const;
+ FloatRect transform(const FloatRect& bounds) const;
+ Transform& operator = (const Transform& other);
+ Transform operator * (const Transform& rhs) const;
+ // assumes the last row is < 0 , 0 , 1 >
+ vec2 transform(const vec2& v) const;
+ vec3 transform(const vec3& v) const;
+
+ Transform inverse() const;
+
+ // for debugging
+ void dump(const char* name) const;
+
+private:
+ struct mat33 {
+ vec3 v[3];
+ inline const vec3& operator [] (size_t i) const { return v[i]; }
+ inline vec3& operator [] (size_t i) { return v[i]; }
+ };
+
+ enum { UNKNOWN_TYPE = 0x80000000 };
+
+ uint32_t type() const;
+ static bool absIsOne(float f);
+ static bool isZero(float f);
+
+ mat33 mMatrix;
+ mutable uint32_t mType;
+};
+
+} // namespace ui
+} // namespace android
+
+#endif /* ANDROID_TRANSFORM_H */
diff --git a/libs/vr/CleanSpec.mk b/libs/vr/CleanSpec.mk
new file mode 100644
index 0000000..a17c9b2
--- /dev/null
+++ b/libs/vr/CleanSpec.mk
@@ -0,0 +1,52 @@
+# Copyright (C) 2012 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index e247398..37b9a03 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -593,7 +593,7 @@
LocalHandle fence;
- EXPECT_EQ(0, p->Post<void>(LocalHandle()));
+ EXPECT_EQ(0, p->Post(LocalHandle()));
EXPECT_EQ(0, c->Acquire(&fence));
}
@@ -945,3 +945,46 @@
EXPECT_EQ(b1_id, p2_id);
EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
}
+
+TEST_F(LibBufferHubTest, TestDuplicateDetachedBuffer) {
+ auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, kUserMetadataSize);
+ int b1_id = b1->id();
+ EXPECT_TRUE(b1->IsValid());
+
+ auto status_or_handle = b1->Duplicate();
+ EXPECT_TRUE(status_or_handle);
+
+ // The detached buffer should still be valid.
+ EXPECT_TRUE(b1->IsConnected());
+ EXPECT_TRUE(b1->IsValid());
+
+ // Gets the channel handle for the duplicated buffer.
+ LocalChannelHandle h2 = status_or_handle.take();
+ EXPECT_TRUE(h2.valid());
+
+ std::unique_ptr<DetachedBuffer> b2 = DetachedBuffer::Import(std::move(h2));
+ EXPECT_FALSE(h2.valid());
+ ASSERT_TRUE(b2 != nullptr);
+ int b2_id = b2->id();
+
+ // These two buffer instances are based on the same physical buffer under the
+ // hood, so they should share the same id.
+ EXPECT_EQ(b1_id, b2_id);
+ // We use buffer_state_bit() to tell those two instances apart.
+ EXPECT_NE(b1->buffer_state_bit(), b2->buffer_state_bit());
+ EXPECT_NE(b1->buffer_state_bit(), 0ULL);
+ EXPECT_NE(b2->buffer_state_bit(), 0ULL);
+ EXPECT_NE(b1->buffer_state_bit(), kProducerStateBit);
+ EXPECT_NE(b2->buffer_state_bit(), kProducerStateBit);
+
+ // Both buffer instances should be in gained state.
+ EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
+ EXPECT_TRUE(IsBufferGained(b2->buffer_state()));
+
+ // Promote the detached buffer should fail as b1 is no longer the exclusive
+ // owner of the buffer..
+ status_or_handle = b1->Promote();
+ EXPECT_FALSE(status_or_handle.ok());
+ EXPECT_EQ(status_or_handle.error(), EINVAL);
+}
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 159f2bd..577cba9 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -42,11 +42,13 @@
BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle)
: Client{pdx::default_transport::ClientChannel::Create(
std::move(channel_handle))},
- id_(-1) {}
+ id_(-1),
+ cid_(-1) {}
BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path)
: Client{pdx::default_transport::ClientChannelFactory::Create(
endpoint_path)},
- id_(-1) {}
+ id_(-1),
+ cid_(-1) {}
BufferHubBuffer::~BufferHubBuffer() {
if (metadata_header_ != nullptr) {
@@ -136,6 +138,7 @@
}
id_ = new_id;
+ cid_ = buffer_desc.buffer_cid();
buffer_state_bit_ = buffer_desc.buffer_state_bit();
// Note that here the buffer state is mapped from shared memory as an atomic
diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp
index 6fae16d..02abd91 100644
--- a/libs/vr/libbufferhub/detached_buffer.cpp
+++ b/libs/vr/libbufferhub/detached_buffer.cpp
@@ -49,7 +49,7 @@
}
int DetachedBuffer::ImportGraphicBuffer() {
- ATRACE_NAME("DetachedBuffer::DetachedBuffer");
+ ATRACE_NAME("DetachedBuffer::ImportGraphicBuffer");
auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Import>();
if (!status) {
@@ -76,9 +76,53 @@
return ret;
}
+ // Import the metadata.
+ IonBuffer metadata_buffer;
+ if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
+ ALOGE("Failed to import metadata buffer, error=%d", ret);
+ return ret;
+ }
+ size_t metadata_buf_size = metadata_buffer.width();
+ if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
+ ALOGE("DetachedBuffer::ImportGraphicBuffer: metadata buffer too small: %zu",
+ metadata_buf_size);
+ return -EINVAL;
+ }
+
// If all imports succeed, replace the previous buffer and id.
id_ = buffer_id;
buffer_ = std::move(ion_buffer);
+ metadata_buffer_ = std::move(metadata_buffer);
+ user_metadata_size_ = metadata_buf_size - BufferHubDefs::kMetadataHeaderSize;
+
+ void* metadata_ptr = nullptr;
+ if (const int ret =
+ metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
+ /*y=*/0, metadata_buf_size,
+ /*height=*/1, &metadata_ptr)) {
+ ALOGE("DetachedBuffer::ImportGraphicBuffer: Failed to lock metadata.");
+ return ret;
+ }
+
+ // TODO(b/112012161) Set up shared fences.
+
+ // Note that here the buffer state is mapped from shared memory as an atomic
+ // object. The std::atomic's constructor will not be called so that the
+ // original value stored in the memory region can be preserved.
+ metadata_header_ = static_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
+ if (user_metadata_size_) {
+ user_metadata_ptr_ = static_cast<void*>(metadata_header_ + 1);
+ } else {
+ user_metadata_ptr_ = nullptr;
+ }
+
+ id_ = buffer_desc.id();
+ buffer_state_bit_ = buffer_desc.buffer_state_bit();
+
+ ALOGD_IF(TRACE,
+ "DetachedBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64
+ ".",
+ id(), metadata_header_->buffer_state.load());
return 0;
}
@@ -104,6 +148,20 @@
return status_or_handle;
}
+Status<LocalChannelHandle> DetachedBuffer::Duplicate() {
+ ATRACE_NAME("DetachedBuffer::Duplicate");
+ ALOGD_IF(TRACE, "DetachedBuffer::Duplicate: id=%d.", id_);
+
+ auto status_or_handle =
+ client_.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
+
+ if (!status_or_handle.ok()) {
+ ALOGE("DetachedBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.",
+ id_, status_or_handle.GetErrorMessage().c_str());
+ }
+ return status_or_handle;
+}
+
sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() {
if (!client_.IsValid() || !buffer_.buffer()) {
ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer.");
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index 0ea77c8..0b2666a 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -107,8 +107,14 @@
IonBuffer* buffer() { return &buffer_; }
const IonBuffer* buffer() const { return &buffer_; }
+ // Gets ID of the buffer client. All BufferHubBuffer clients derived from the
+ // same buffer in bufferhubd share the same buffer id.
int id() const { return id_; }
+ // Gets the channel id of the buffer client. Each BufferHubBuffer client has
+ // its system unique channel id.
+ int cid() const { return cid_; }
+
// Returns the buffer buffer state.
uint64_t buffer_state() { return buffer_state_->load(); };
@@ -170,6 +176,7 @@
// for logging and debugging purposes only and should not be used for lookup
// or any other functional purpose as a security precaution.
int id_;
+ int cid_;
uint64_t buffer_state_bit_{0ULL};
IonBuffer buffer_;
IonBuffer metadata_buffer_;
@@ -205,11 +212,10 @@
int Post(const LocalHandle& ready_fence, const void* meta,
size_t user_metadata_size);
- template <typename Meta,
- typename = typename std::enable_if<std::is_void<Meta>::value>::type>
int Post(const LocalHandle& ready_fence) {
return Post(ready_fence, nullptr, 0);
}
+
template <typename Meta, typename = typename std::enable_if<
!std::is_void<Meta>::value>::type>
int Post(const LocalHandle& ready_fence, const Meta& meta) {
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
new file mode 100644
index 0000000..8b2bf91
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -0,0 +1,89 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_DEFS_H_
+#define ANDROID_DVR_BUFFER_HUB_DEFS_H_
+
+#include <dvr/dvr_api.h>
+#include <hardware/gralloc.h>
+
+#include <atomic>
+
+namespace android {
+namespace dvr {
+
+namespace BufferHubDefs {
+
+static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint32_t kMetadataUsage =
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+// Single producuer multiple (up to 63) consumers ownership signal.
+// 64-bit atomic unsigned int.
+//
+// MSB LSB
+// | |
+// v v
+// [P|C62|...|C1|C0]
+// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
+// Post'ed state: [1|..|0|0]
+// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
+// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
+static constexpr uint64_t kProducerStateBit = 1ULL << 63;
+static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+
+static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
+ uint64_t clear_mask, uint64_t set_mask) {
+ uint64_t old_state;
+ uint64_t new_state;
+ do {
+ old_state = buffer_state->load();
+ new_state = (old_state & ~clear_mask) | set_mask;
+ } while (!buffer_state->compare_exchange_weak(old_state, new_state));
+}
+
+static inline bool IsBufferGained(uint64_t state) { return state == 0; }
+
+static inline bool IsBufferPosted(uint64_t state,
+ uint64_t consumer_bit = kConsumerStateMask) {
+ return (state & kProducerStateBit) && !(state & consumer_bit);
+}
+
+static inline bool IsBufferAcquired(uint64_t state) {
+ return (state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline bool IsBufferReleased(uint64_t state) {
+ return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline uint64_t FindNextClearedBit(uint64_t bits) {
+ return ~bits - (~bits & (~bits - 1));
+}
+
+static inline uint64_t FindFirstClearedBit() {
+ return FindNextClearedBit(kProducerStateBit);
+}
+
+struct __attribute__((packed, aligned(8))) MetadataHeader {
+ // Internal data format, which can be updated as long as the size, padding and
+ // field alignment of the struct is consistent within the same ABI. As this
+ // part is subject for future updates, it's not stable cross Android version,
+ // so don't have it visible from outside of the Android platform (include Apps
+ // and vendor HAL).
+ std::atomic<uint64_t> buffer_state;
+ std::atomic<uint64_t> fence_state;
+ uint64_t queue_index;
+
+ // Public data format, which should be updated with caution. See more details
+ // in dvr_api.h
+ DvrNativeBufferMetadata metadata;
+};
+
+static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
+
+} // namespace BufferHubDefs
+
+} // namespace dvr
+} // namespace android
+
+
+#endif // ANDROID_DVR_BUFFER_HUB_DEFS_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index f4918c4..e163216 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -1,11 +1,11 @@
#ifndef ANDROID_DVR_BUFFERHUB_RPC_H_
#define ANDROID_DVR_BUFFERHUB_RPC_H_
+#include "buffer_hub_defs.h"
+
#include <cutils/native_handle.h>
-#include <sys/types.h>
#include <ui/BufferQueueDefs.h>
-#include <dvr/dvr_api.h>
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/remote_method.h>
@@ -15,71 +15,6 @@
namespace android {
namespace dvr {
-namespace BufferHubDefs {
-
-static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr uint32_t kMetadataUsage =
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
-
-// Single producuer multiple (up to 63) consumers ownership signal.
-// 64-bit atomic unsigned int.
-//
-// MSB LSB
-// | |
-// v v
-// [P|C62|...|C1|C0]
-// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
-// Post'ed state: [1|..|0|0]
-// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
-// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
-static constexpr uint64_t kProducerStateBit = 1ULL << 63;
-static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
-
-static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
- uint64_t clear_mask, uint64_t set_mask) {
- uint64_t old_state;
- uint64_t new_state;
- do {
- old_state = buffer_state->load();
- new_state = (old_state & ~clear_mask) | set_mask;
- } while (!buffer_state->compare_exchange_weak(old_state, new_state));
-}
-
-static inline bool IsBufferGained(uint64_t state) { return state == 0; }
-
-static inline bool IsBufferPosted(uint64_t state,
- uint64_t consumer_bit = kConsumerStateMask) {
- return (state & kProducerStateBit) && !(state & consumer_bit);
-}
-
-static inline bool IsBufferAcquired(uint64_t state) {
- return (state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-static inline bool IsBufferReleased(uint64_t state) {
- return !(state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-struct __attribute__((packed, aligned(8))) MetadataHeader {
- // Internal data format, which can be updated as long as the size, padding and
- // field alignment of the struct is consistent within the same ABI. As this
- // part is subject for future updates, it's not stable cross Android version,
- // so don't have it visible from outside of the Android platform (include Apps
- // and vendor HAL).
- std::atomic<uint64_t> buffer_state;
- std::atomic<uint64_t> fence_state;
- uint64_t queue_index;
-
- // Public data format, which should be updated with caution. See more details
- // in dvr_api.h
- DvrNativeBufferMetadata metadata;
-};
-
-static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
-static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
-
-} // namespace BufferHubDefs
-
template <typename FileHandleType>
class NativeBufferHandle {
public:
@@ -164,10 +99,11 @@
public:
BufferDescription() = default;
BufferDescription(const IonBuffer& buffer, const IonBuffer& metadata, int id,
- uint64_t buffer_state_bit,
+ int buffer_cid, uint64_t buffer_state_bit,
const FileHandleType& acquire_fence_fd,
const FileHandleType& release_fence_fd)
: id_(id),
+ buffer_cid_(buffer_cid),
buffer_state_bit_(buffer_state_bit),
buffer_(buffer, id),
metadata_(metadata, id),
@@ -180,6 +116,9 @@
// ID of the buffer client. All BufferHubBuffer clients derived from the same
// buffer in bufferhubd share the same buffer id.
int id() const { return id_; }
+ // Channel ID of the buffer client. Each BufferHubBuffer client has its system
+ // unique channel id.
+ int buffer_cid() const { return buffer_cid_; }
// State mask of the buffer client. Each BufferHubBuffer client backed by the
// same buffer channel has uniqued state bit among its siblings. For a
// producer buffer the bit must be kProducerStateBit; for a consumer the bit
@@ -193,6 +132,7 @@
private:
int id_{-1};
+ int buffer_cid_{-1};
uint64_t buffer_state_bit_{0};
// Two IonBuffers: one for the graphic buffer and one for metadata.
NativeBufferHandle<FileHandleType> buffer_;
@@ -202,7 +142,7 @@
FileHandleType acquire_fence_fd_;
FileHandleType release_fence_fd_;
- PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_,
+ PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_, buffer_cid_,
buffer_state_bit_, buffer_, metadata_,
acquire_fence_fd_, release_fence_fd_);
@@ -381,6 +321,7 @@
kOpCreateConsumerQueue,
kOpGetQueueInfo,
kOpProducerQueueAllocateBuffers,
+ kOpProducerQueueInsertBuffer,
kOpProducerQueueRemoveBuffer,
kOpConsumerQueueImportBuffers,
// TODO(b/77153033): Separate all those RPC operations into subclasses.
@@ -430,6 +371,8 @@
std::vector<std::pair<LocalChannelHandle, size_t>>(
uint32_t width, uint32_t height, uint32_t layer_count,
uint32_t format, uint64_t usage, size_t buffer_count));
+ PDX_REMOTE_METHOD(ProducerQueueInsertBuffer, kOpProducerQueueInsertBuffer,
+ size_t(int buffer_cid));
PDX_REMOTE_METHOD(ProducerQueueRemoveBuffer, kOpProducerQueueRemoveBuffer,
void(size_t slot));
PDX_REMOTE_METHOD(ConsumerQueueImportBuffers, kOpConsumerQueueImportBuffers,
@@ -442,6 +385,7 @@
kOpCreate = kOpDetachedBufferBase,
kOpImport,
kOpPromote,
+ kOpDuplicate,
};
public:
@@ -451,8 +395,9 @@
size_t user_metadata_size));
PDX_REMOTE_METHOD(Import, kOpImport, BufferDescription<LocalHandle>(Void));
PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
+ PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
- PDX_REMOTE_API(API, Create, Promote);
+ PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
};
} // namespace dvr
diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
index 6d0b502..1fc011b 100644
--- a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
@@ -30,8 +30,17 @@
const sp<GraphicBuffer>& buffer() const { return buffer_.buffer(); }
+ // Gets ID of the buffer client. All DetachedBuffer clients derived from the
+ // same buffer in bufferhubd share the same buffer id.
int id() const { return id_; }
+ // Returns the current value of MetadataHeader::buffer_state.
+ uint64_t buffer_state() { return metadata_header_->buffer_state.load(); }
+
+ // A state mask which is unique to a buffer hub client among all its siblings
+ // sharing the same concrete graphic buffer.
+ uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+
// Returns true if the buffer holds an open PDX channels towards bufferhubd.
bool IsConnected() const { return client_.IsValid(); }
@@ -57,6 +66,9 @@
// return. Further IPCs towards this channel will return error.
pdx::Status<pdx::LocalChannelHandle> Promote();
+ // Creates a DetachedBuffer from an existing one.
+ pdx::Status<pdx::LocalChannelHandle> Duplicate();
+
// Takes the underlying graphic buffer out of this DetachedBuffer. This call
// immediately invalidates this DetachedBuffer object and transfers the
// underlying pdx::LocalChannelHandle into the GraphicBuffer.
@@ -72,7 +84,18 @@
// Global id for the buffer that is consistent across processes.
int id_;
+ uint64_t buffer_state_bit_;
+
+ // The concrete Ion buffers.
IonBuffer buffer_;
+ IonBuffer metadata_buffer_;
+
+ // buffer metadata.
+ size_t user_metadata_size_ = 0;
+ BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
+ void* user_metadata_ptr_ = nullptr;
+
+ // PDX backend.
BufferHubClient client_;
};
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
index 5089b87..ef1eed6 100644
--- a/libs/vr/libbufferhubqueue/benchmarks/Android.bp
+++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
@@ -5,7 +5,7 @@
"libbase",
"libbinder",
"libcutils",
- "libdvr",
+ "libdvr.google",
"libgui",
"liblog",
"libhardware",
diff --git a/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
index 4ca8671..b2b4d7a 100644
--- a/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
+++ b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
@@ -206,7 +206,7 @@
class DvrApi {
public:
DvrApi() {
- handle_ = dlopen("libdvr.so", RTLD_NOW | RTLD_LOCAL);
+ handle_ = dlopen("libdvr.google.so", RTLD_NOW | RTLD_LOCAL);
CHECK(handle_);
auto dvr_get_api =
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 8feb1cd..1f2c517 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -524,6 +524,40 @@
return BufferHubQueue::Enqueue({buffer, slot, 0ULL});
}
+Status<size_t> ProducerQueue::InsertBuffer(
+ const std::shared_ptr<BufferProducer>& buffer) {
+ if (buffer == nullptr ||
+ !BufferHubDefs::IsBufferGained(buffer->buffer_state())) {
+ ALOGE(
+ "ProducerQueue::InsertBuffer: Can only insert a buffer when it's in "
+ "gained state.");
+ return ErrorStatus(EINVAL);
+ }
+
+ auto status_or_slot =
+ InvokeRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>(
+ buffer->cid());
+ if (!status_or_slot) {
+ ALOGE(
+ "ProducerQueue::InsertBuffer: Failed to insert producer buffer: "
+ "buffer_cid=%d, error: %s.",
+ buffer->cid(), status_or_slot.GetErrorMessage().c_str());
+ return status_or_slot.error_status();
+ }
+
+ size_t slot = status_or_slot.get();
+
+ // Note that we are calling AddBuffer() from the base class to explicitly
+ // avoid Enqueue() the BufferProducer.
+ auto status = BufferHubQueue::AddBuffer(buffer, slot);
+ if (!status) {
+ ALOGE("ProducerQueue::InsertBuffer: Failed to add buffer: %s.",
+ status.GetErrorMessage().c_str());
+ return status.error_status();
+ }
+ return {slot};
+}
+
Status<void> ProducerQueue::RemoveBuffer(size_t slot) {
auto status =
InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 60e1c4b..df500b4 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -331,6 +331,13 @@
pdx::Status<void> AddBuffer(const std::shared_ptr<BufferProducer>& buffer,
size_t slot);
+ // Inserts a ProducerBuffer into the queue. On success, the method returns the
+ // |slot| number where the new buffer gets inserted. Note that the buffer
+ // being inserted should be in Gain'ed state prior to the call and it's
+ // considered as already Dequeued when the function returns.
+ pdx::Status<size_t> InsertBuffer(
+ const std::shared_ptr<BufferProducer>& buffer);
+
// Remove producer buffer from the queue.
pdx::Status<void> RemoveBuffer(size_t slot) override;
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 47a2734..2975f56 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -181,6 +181,40 @@
}
}
+TEST_F(BufferHubQueueTest, TestInsertBuffer) {
+ ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
+
+ consumer_queue_ = producer_queue_->CreateConsumerQueue();
+ ASSERT_TRUE(consumer_queue_ != nullptr);
+ EXPECT_EQ(producer_queue_->capacity(), 0);
+ EXPECT_EQ(consumer_queue_->capacity(), 0);
+
+ std::shared_ptr<BufferProducer> p1 = BufferProducer::Create(
+ kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage, 0);
+ ASSERT_TRUE(p1 != nullptr);
+
+ // Inserting a posted buffer will fail.
+ DvrNativeBufferMetadata meta;
+ EXPECT_EQ(p1->PostAsync(&meta, LocalHandle()), 0);
+ auto status_or_slot = producer_queue_->InsertBuffer(p1);
+ EXPECT_FALSE(status_or_slot.ok());
+ EXPECT_EQ(status_or_slot.error(), EINVAL);
+
+ // Inserting a gained buffer will succeed.
+ std::shared_ptr<BufferProducer> p2 = BufferProducer::Create(
+ kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage);
+ ASSERT_TRUE(p2 != nullptr);
+ status_or_slot = producer_queue_->InsertBuffer(p2);
+ EXPECT_TRUE(status_or_slot.ok());
+ // This is the first buffer inserted, should take slot 0.
+ size_t slot = status_or_slot.get();
+ EXPECT_EQ(slot, 0);
+
+ // Wait and expect the consumer to kick up the newly inserted buffer.
+ WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs);
+ EXPECT_EQ(consumer_queue_->capacity(), 1ULL);
+}
+
TEST_F(BufferHubQueueTest, TestRemoveBuffer) {
ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
DvrNativeBufferMetadata mo;
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index 9c67881..8c354fb 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -16,8 +16,8 @@
"display_client.cpp",
"display_manager_client.cpp",
"display_protocol.cpp",
- "vsync_client.cpp",
"shared_buffer_helpers.cpp",
+ "vsync_service.cpp",
]
localIncludeFiles = [
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_client.h b/libs/vr/libdisplay/include/private/dvr/vsync_client.h
deleted file mode 100644
index 1eeb80e..0000000
--- a/libs/vr/libdisplay/include/private/dvr/vsync_client.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef ANDROID_DVR_VSYNC_CLIENT_H_
-#define ANDROID_DVR_VSYNC_CLIENT_H_
-
-#include <stdint.h>
-
-#include <pdx/client.h>
-
-struct dvr_vsync_client {};
-
-namespace android {
-namespace dvr {
-
-/*
- * VSyncClient is a remote interface to the vsync service in displayd.
- * This class is used to wait for and retrieve information about the
- * display vsync.
- */
-class VSyncClient : public pdx::ClientBase<VSyncClient>,
- public dvr_vsync_client {
- public:
- /*
- * Wait for the next vsync signal.
- * The timestamp (in ns) is written into *ts when ts is non-NULL.
- */
- int Wait(int64_t* timestamp_ns);
-
- /*
- * Returns the file descriptor used to communicate with the vsync system
- * service or -1 on error.
- */
- int GetFd();
-
- /*
- * Clears the select/poll/epoll event so that subsequent calls to
- * these will not signal until the next vsync.
- */
- int Acknowledge();
-
- /*
- * Get the timestamp of the last vsync event in ns. This call has
- * the same side effect on events as Acknowledge(), which saves
- * an IPC message.
- */
- int GetLastTimestamp(int64_t* timestamp_ns);
-
- /*
- * Get vsync scheduling info.
- * Get the estimated timestamp of the next GPU lens warp preemption event in
- * ns. Also returns the corresponding vsync count that the next lens warp
- * operation will target. This call has the same side effect on events as
- * Acknowledge(), which saves an IPC message.
- */
- int GetSchedInfo(int64_t* vsync_period_ns, int64_t* next_timestamp_ns,
- uint32_t* next_vsync_count);
-
- private:
- friend BASE;
-
- VSyncClient();
- explicit VSyncClient(long timeout_ms);
-
- VSyncClient(const VSyncClient&) = delete;
- void operator=(const VSyncClient&) = delete;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_VSYNC_CLIENT_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_service.h b/libs/vr/libdisplay/include/private/dvr/vsync_service.h
new file mode 100644
index 0000000..152464a
--- /dev/null
+++ b/libs/vr/libdisplay/include/private/dvr/vsync_service.h
@@ -0,0 +1,65 @@
+#ifndef ANDROID_DVR_VSYNC_SERVICE_H_
+#define ANDROID_DVR_VSYNC_SERVICE_H_
+
+#include <binder/IInterface.h>
+
+namespace android {
+namespace dvr {
+
+class IVsyncCallback : public IInterface {
+ public:
+ DECLARE_META_INTERFACE(VsyncCallback)
+
+ enum {
+ ON_VSYNC = IBinder::FIRST_CALL_TRANSACTION
+ };
+
+ virtual status_t onVsync(int64_t vsync_timestamp) = 0;
+};
+
+class BnVsyncCallback : public BnInterface<IVsyncCallback> {
+ public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+};
+
+// Register a callback with IVsyncService to be notified of vsync events and
+// timestamps. There's also a shared memory vsync buffer defined in
+// dvr_shared_buffers.h. IVsyncService has advantages over the vsync shared
+// memory buffer that make it preferable in certain situations:
+//
+// 1. The shared memory buffer lifetime is controlled by VrCore. IVsyncService
+// is always available as long as surface flinger is running.
+//
+// 2. IVsyncService will make a binder callback when a vsync event occurs. This
+// allows the client to not write code to implement periodic "get the latest
+// vsync" calls, which is necessary with the vsync shared memory buffer.
+//
+// 3. The IVsyncService provides the real vsync timestamp reported by hardware
+// composer, whereas the vsync shared memory buffer only has predicted vsync
+// times.
+class IVsyncService : public IInterface {
+public:
+ DECLARE_META_INTERFACE(VsyncService)
+
+ static const char* GetServiceName() { return "vrflinger_vsync"; }
+
+ enum {
+ REGISTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
+ UNREGISTER_CALLBACK
+ };
+
+ virtual status_t registerCallback(const sp<IVsyncCallback> callback) = 0;
+ virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) = 0;
+};
+
+class BnVsyncService : public BnInterface<IVsyncService> {
+ public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_VSYNC_SERVICE_H_
diff --git a/libs/vr/libdisplay/vsync_client.cpp b/libs/vr/libdisplay/vsync_client.cpp
deleted file mode 100644
index bc6cf6c..0000000
--- a/libs/vr/libdisplay/vsync_client.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "include/private/dvr/vsync_client.h"
-
-#include <log/log.h>
-
-#include <pdx/default_transport/client_channel_factory.h>
-#include <private/dvr/display_protocol.h>
-
-using android::dvr::display::VSyncProtocol;
-using android::pdx::Transaction;
-
-namespace android {
-namespace dvr {
-
-VSyncClient::VSyncClient(long timeout_ms)
- : BASE(pdx::default_transport::ClientChannelFactory::Create(
- VSyncProtocol::kClientPath),
- timeout_ms) {}
-
-VSyncClient::VSyncClient()
- : BASE(pdx::default_transport::ClientChannelFactory::Create(
- VSyncProtocol::kClientPath)) {}
-
-int VSyncClient::Wait(int64_t* timestamp_ns) {
- auto status = InvokeRemoteMethod<VSyncProtocol::Wait>();
- if (!status) {
- ALOGE("VSyncClient::Wait: Failed to wait for vsync: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
- }
-
- if (timestamp_ns != nullptr) {
- *timestamp_ns = status.get();
- }
- return 0;
-}
-
-int VSyncClient::GetFd() { return event_fd(); }
-
-int VSyncClient::GetLastTimestamp(int64_t* timestamp_ns) {
- auto status = InvokeRemoteMethod<VSyncProtocol::GetLastTimestamp>();
- if (!status) {
- ALOGE("VSyncClient::GetLastTimestamp: Failed to get vsync timestamp: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
- }
- *timestamp_ns = status.get();
- return 0;
-}
-
-int VSyncClient::GetSchedInfo(int64_t* vsync_period_ns, int64_t* timestamp_ns,
- uint32_t* next_vsync_count) {
- if (!vsync_period_ns || !timestamp_ns || !next_vsync_count)
- return -EINVAL;
-
- auto status = InvokeRemoteMethod<VSyncProtocol::GetSchedInfo>();
- if (!status) {
- ALOGE("VSyncClient::GetSchedInfo:: Failed to get warp timestamp: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
- }
-
- *vsync_period_ns = status.get().vsync_period_ns;
- *timestamp_ns = status.get().timestamp_ns;
- *next_vsync_count = status.get().next_vsync_count;
- return 0;
-}
-
-int VSyncClient::Acknowledge() {
- auto status = InvokeRemoteMethod<VSyncProtocol::Acknowledge>();
- ALOGE_IF(!status, "VSuncClient::Acknowledge: Failed to ack vsync because: %s",
- status.GetErrorMessage().c_str());
- return ReturnStatusOrError(status);
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libdisplay/vsync_service.cpp b/libs/vr/libdisplay/vsync_service.cpp
new file mode 100644
index 0000000..43b1196
--- /dev/null
+++ b/libs/vr/libdisplay/vsync_service.cpp
@@ -0,0 +1,146 @@
+#include "include/private/dvr/vsync_service.h"
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+
+namespace android {
+namespace dvr {
+
+status_t BnVsyncCallback::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+ switch (code) {
+ case ON_VSYNC: {
+ CHECK_INTERFACE(IVsyncCallback, data, reply);
+ int64_t vsync_timestamp = 0;
+ status_t result = data.readInt64(&vsync_timestamp);
+ if (result != NO_ERROR) {
+ ALOGE("onVsync failed to readInt64: %d", result);
+ return result;
+ }
+ onVsync(vsync_timestamp);
+ return NO_ERROR;
+ }
+ default: {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ }
+}
+
+class BpVsyncCallback : public BpInterface<IVsyncCallback> {
+public:
+ explicit BpVsyncCallback(const sp<IBinder>& impl)
+ : BpInterface<IVsyncCallback>(impl) {}
+ virtual ~BpVsyncCallback() {}
+
+ virtual status_t onVsync(int64_t vsync_timestamp) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(
+ IVsyncCallback::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("onVsync failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeInt64(vsync_timestamp);
+ if (result != NO_ERROR) {
+ ALOGE("onVsync failed to writeInt64: %d", result);
+ return result;
+ }
+ result = remote()->transact(
+ BnVsyncCallback::ON_VSYNC, data, &reply, TF_ONE_WAY);
+ if (result != NO_ERROR) {
+ ALOGE("onVsync failed to transact: %d", result);
+ return result;
+ }
+ return result;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(VsyncCallback, "android.dvr.IVsyncCallback");
+
+
+status_t BnVsyncService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+ switch (code) {
+ case REGISTER_CALLBACK: {
+ CHECK_INTERFACE(IVsyncService, data, reply);
+ sp<IBinder> callback;
+ status_t result = data.readStrongBinder(&callback);
+ if (result != NO_ERROR) {
+ ALOGE("registerCallback failed to readStrongBinder: %d", result);
+ return result;
+ }
+ registerCallback(interface_cast<IVsyncCallback>(callback));
+ return NO_ERROR;
+ }
+ case UNREGISTER_CALLBACK: {
+ CHECK_INTERFACE(IVsyncService, data, reply);
+ sp<IBinder> callback;
+ status_t result = data.readStrongBinder(&callback);
+ if (result != NO_ERROR) {
+ ALOGE("unregisterCallback failed to readStrongBinder: %d", result);
+ return result;
+ }
+ unregisterCallback(interface_cast<IVsyncCallback>(callback));
+ return NO_ERROR;
+ }
+ default: {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ }
+}
+
+class BpVsyncService : public BpInterface<IVsyncService> {
+public:
+ explicit BpVsyncService(const sp<IBinder>& impl)
+ : BpInterface<IVsyncService>(impl) {}
+ virtual ~BpVsyncService() {}
+
+ virtual status_t registerCallback(const sp<IVsyncCallback> callback) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(
+ IVsyncService::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("registerCallback failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(IInterface::asBinder(callback));
+ if (result != NO_ERROR) {
+ ALOGE("registerCallback failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = remote()->transact(
+ BnVsyncService::REGISTER_CALLBACK, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("registerCallback failed to transact: %d", result);
+ return result;
+ }
+ return result;
+ }
+
+ virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(
+ IVsyncService::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("unregisterCallback failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(IInterface::asBinder(callback));
+ if (result != NO_ERROR) {
+ ALOGE("unregisterCallback failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = remote()->transact(
+ BnVsyncService::UNREGISTER_CALLBACK, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("unregisterCallback failed to transact: %d", result);
+ return result;
+ }
+ return result;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(VsyncService, "android.dvr.IVsyncService");
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 16906f5..81a9b2d 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -19,7 +19,14 @@
vendor_available: true,
}
+cc_library_headers {
+ name: "libdvr_private_headers",
+ export_include_dirs: ["."],
+ vendor_available: false,
+}
+
cflags = [
+ "-DDVR_TRACKING_IMPLEMENTED=0",
"-DLOG_TAG=\"libdvr\"",
"-DTRACE=0",
"-Wall",
@@ -36,7 +43,7 @@
"dvr_performance.cpp",
"dvr_pose.cpp",
"dvr_surface.cpp",
- "dvr_vsync.cpp",
+ "dvr_tracking.cpp",
]
static_libs = [
@@ -66,7 +73,7 @@
]
cc_library_shared {
- name: "libdvr",
+ name: "libdvr.google",
owner: "google",
cflags: cflags,
header_libs: ["libdvr_headers"],
@@ -81,7 +88,7 @@
// restricting function access in the shared lib makes it inconvenient to use in
// test code.
cc_library_static {
- name: "libdvr_static",
+ name: "libdvr_static.google",
owner: "google",
cflags: cflags,
header_libs: ["libdvr_headers"],
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index d14f040..e099f6a 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -12,6 +12,7 @@
#include <dvr/dvr_display_manager.h>
#include <dvr/dvr_performance.h>
#include <dvr/dvr_surface.h>
+#include <dvr/dvr_tracking.h>
#include <dvr/dvr_vsync.h>
// Headers not yet moved into libdvr.
diff --git a/libs/vr/libdvr/dvr_tracking.cpp b/libs/vr/libdvr/dvr_tracking.cpp
new file mode 100644
index 0000000..73addc9
--- /dev/null
+++ b/libs/vr/libdvr/dvr_tracking.cpp
@@ -0,0 +1,82 @@
+#include "include/dvr/dvr_tracking.h"
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#if !DVR_TRACKING_IMPLEMENTED
+
+extern "C" {
+
+// This file provides the stub implementation of dvrTrackingXXX APIs. On
+// platforms that implement these APIs, set -DDVR_TRACKING_IMPLEMENTED=1 in the
+// build file.
+int dvrTrackingCameraCreate(DvrTrackingCamera**) {
+ ALOGE("dvrTrackingCameraCreate is not implemented.");
+ return -ENOSYS;
+}
+
+void dvrTrackingCameraDestroy(DvrTrackingCamera*) {
+ ALOGE("dvrTrackingCameraDestroy is not implemented.");
+}
+
+int dvrTrackingCameraStart(DvrTrackingCamera*, DvrWriteBufferQueue*) {
+ ALOGE("dvrTrackingCameraCreate is not implemented.");
+ return -ENOSYS;
+}
+
+int dvrTrackingCameraStop(DvrTrackingCamera*) {
+ ALOGE("dvrTrackingCameraCreate is not implemented.");
+ return -ENOSYS;
+}
+
+int dvrTrackingFeatureExtractorCreate(DvrTrackingFeatureExtractor**) {
+ ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
+ return -ENOSYS;
+}
+
+void dvrTrackingFeatureExtractorDestroy(DvrTrackingFeatureExtractor*) {
+ ALOGE("dvrTrackingFeatureExtractorDestroy is not implemented.");
+}
+
+int dvrTrackingFeatureExtractorStart(DvrTrackingFeatureExtractor*,
+ DvrTrackingFeatureCallback, void*) {
+ ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
+ return -ENOSYS;
+}
+
+int dvrTrackingFeatureExtractorStop(DvrTrackingFeatureExtractor*) {
+ ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
+ return -ENOSYS;
+}
+
+int dvrTrackingFeatureExtractorProcessBuffer(DvrTrackingFeatureExtractor*,
+ DvrReadBuffer*,
+ const DvrTrackingBufferMetadata*,
+ bool*) {
+ ALOGE("dvrTrackingFeatureExtractorProcessBuffer is not implemented.");
+ return -ENOSYS;
+}
+
+int dvrTrackingSensorsCreate(DvrTrackingSensors**, const char*) {
+ ALOGE("dvrTrackingSensorsCreate is not implemented.");
+ return -ENOSYS;
+}
+
+void dvrTrackingSensorsDestroy(DvrTrackingSensors*) {
+ ALOGE("dvrTrackingSensorsDestroy is not implemented.");
+}
+
+int dvrTrackingSensorsStart(DvrTrackingSensors*, DvrTrackingSensorEventCallback,
+ void*) {
+ ALOGE("dvrTrackingStart is not implemented.");
+ return -ENOSYS;
+}
+
+int dvrTrackingSensorsStop(DvrTrackingSensors*) {
+ ALOGE("dvrTrackingStop is not implemented.");
+ return -ENOSYS;
+}
+
+} // extern "C"
+
+#endif // DVR_TRACKING_IMPLEMENTED
diff --git a/libs/vr/libdvr/dvr_vsync.cpp b/libs/vr/libdvr/dvr_vsync.cpp
deleted file mode 100644
index 099240e..0000000
--- a/libs/vr/libdvr/dvr_vsync.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "include/dvr/dvr_vsync.h"
-
-#include <utils/Log.h>
-
-#include <private/dvr/vsync_client.h>
-
-extern "C" {
-
-struct DvrVSyncClient {
- std::unique_ptr<android::dvr::VSyncClient> client;
-};
-
-int dvrVSyncClientCreate(DvrVSyncClient** client_out) {
- auto client = android::dvr::VSyncClient::Create();
- if (!client) {
- ALOGE("dvrVSyncClientCreate: Failed to create vsync client!");
- return -EIO;
- }
-
- *client_out = new DvrVSyncClient{std::move(client)};
- return 0;
-}
-
-void dvrVSyncClientDestroy(DvrVSyncClient* client) { delete client; }
-
-int dvrVSyncClientGetSchedInfo(DvrVSyncClient* client, int64_t* vsync_period_ns,
- int64_t* next_timestamp_ns,
- uint32_t* next_vsync_count) {
- return client->client->GetSchedInfo(vsync_period_ns, next_timestamp_ns,
- next_vsync_count);
-}
-
-} // extern "C"
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 80ffc82..fef8512 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -10,6 +10,7 @@
#include <dvr/dvr_display_types.h>
#include <dvr/dvr_hardware_composer_types.h>
#include <dvr/dvr_pose.h>
+#include <dvr/dvr_tracking_types.h>
#ifdef __cplusplus
extern "C" {
@@ -50,6 +51,12 @@
typedef struct DvrSurfaceAttributeValue DvrSurfaceAttributeValue;
typedef struct DvrSurfaceAttribute DvrSurfaceAttribute;
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct DvrTrackingCamera DvrTrackingCamera;
+typedef struct DvrTrackingFeatureExtractor DvrTrackingFeatureExtractor;
+typedef struct DvrTrackingSensors DvrTrackingSensors;
+typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+
// Note: To avoid breaking others during active development, only modify this
// struct by appending elements to the end.
// If you do feel we should to re-arrange or remove elements, please make a
@@ -367,6 +374,38 @@
typedef int (*DvrPerformanceSetSchedulerPolicyPtr)(
pid_t task_id, const char* scheduler_policy);
+// dvr_tracking.h
+typedef int (*DvrTrackingCameraCreatePtr)(DvrTrackingCamera** out_camera);
+typedef void (*DvrTrackingCameraDestroyPtr)(DvrTrackingCamera* camera);
+typedef int (*DvrTrackingCameraStartPtr)(DvrTrackingCamera* camera,
+ DvrWriteBufferQueue* write_queue);
+typedef int (*DvrTrackingCameraStopPtr)(DvrTrackingCamera* camera);
+
+typedef int (*DvrTrackingFeatureExtractorCreatePtr)(
+ DvrTrackingFeatureExtractor** out_extractor);
+typedef void (*DvrTrackingFeatureExtractorDestroyPtr)(
+ DvrTrackingFeatureExtractor* extractor);
+typedef void (*DvrTrackingFeatureCallback)(void* context,
+ const DvrTrackingFeatures* event);
+typedef int (*DvrTrackingFeatureExtractorStartPtr)(
+ DvrTrackingFeatureExtractor* extractor,
+ DvrTrackingFeatureCallback callback, void* context);
+typedef int (*DvrTrackingFeatureExtractorStopPtr)(
+ DvrTrackingFeatureExtractor* extractor);
+typedef int (*DvrTrackingFeatureExtractorProcessBufferPtr)(
+ DvrTrackingFeatureExtractor* extractor, DvrReadBuffer* buffer,
+ const DvrTrackingBufferMetadata* metadata, bool* out_skipped);
+
+typedef void (*DvrTrackingSensorEventCallback)(void* context,
+ DvrTrackingSensorEvent* event);
+typedef int (*DvrTrackingSensorsCreatePtr)(DvrTrackingSensors** out_sensors,
+ const char* mode);
+typedef void (*DvrTrackingSensorsDestroyPtr)(DvrTrackingSensors* sensors);
+typedef int (*DvrTrackingSensorsStartPtr)(
+ DvrTrackingSensors* sensors, DvrTrackingSensorEventCallback callback,
+ void* context);
+typedef int (*DvrTrackingSensorsStopPtr)(DvrTrackingSensors* sensors);
+
// The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
// will populate. A DvrWriteBufferQueue must be created with this metadata iff
// ANativeWindow access is needed. Please do not remove, modify, or reorder
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index f0d8ec6..3006b61 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -85,9 +85,9 @@
DVR_V1_API_ENTRY(ReadBufferQueueHandleEvents);
// V-Sync client
-DVR_V1_API_ENTRY(VSyncClientCreate);
-DVR_V1_API_ENTRY(VSyncClientDestroy);
-DVR_V1_API_ENTRY(VSyncClientGetSchedInfo);
+DVR_V1_API_ENTRY_DEPRECATED(VSyncClientCreate);
+DVR_V1_API_ENTRY_DEPRECATED(VSyncClientDestroy);
+DVR_V1_API_ENTRY_DEPRECATED(VSyncClientGetSchedInfo);
// Display surface
DVR_V1_API_ENTRY(SurfaceCreate);
@@ -181,3 +181,20 @@
DVR_V1_API_ENTRY(PoseClientGetDataReader);
DVR_V1_API_ENTRY(PoseClientDataCapture);
DVR_V1_API_ENTRY(PoseClientDataReaderDestroy);
+
+// Tracking
+DVR_V1_API_ENTRY(TrackingCameraCreate);
+DVR_V1_API_ENTRY(TrackingCameraDestroy);
+DVR_V1_API_ENTRY(TrackingCameraStart);
+DVR_V1_API_ENTRY(TrackingCameraStop);
+
+DVR_V1_API_ENTRY(TrackingFeatureExtractorCreate);
+DVR_V1_API_ENTRY(TrackingFeatureExtractorDestroy);
+DVR_V1_API_ENTRY(TrackingFeatureExtractorStart);
+DVR_V1_API_ENTRY(TrackingFeatureExtractorStop);
+DVR_V1_API_ENTRY(TrackingFeatureExtractorProcessBuffer);
+
+DVR_V1_API_ENTRY(TrackingSensorsCreate);
+DVR_V1_API_ENTRY(TrackingSensorsDestroy);
+DVR_V1_API_ENTRY(TrackingSensorsStart);
+DVR_V1_API_ENTRY(TrackingSensorsStop);
diff --git a/libs/vr/libdvr/include/dvr/dvr_deleter.h b/libs/vr/libdvr/include/dvr/dvr_deleter.h
index 943384f..fe59d1f 100644
--- a/libs/vr/libdvr/include/dvr/dvr_deleter.h
+++ b/libs/vr/libdvr/include/dvr/dvr_deleter.h
@@ -20,7 +20,6 @@
typedef struct DvrSurface DvrSurface;
typedef struct DvrHwcClient DvrHwcClient;
typedef struct DvrHwcFrame DvrHwcFrame;
-typedef struct DvrVSyncClient DvrVSyncClient;
void dvrBufferDestroy(DvrBuffer* buffer);
void dvrReadBufferDestroy(DvrReadBuffer* read_buffer);
@@ -32,7 +31,6 @@
void dvrSurfaceDestroy(DvrSurface* surface);
void dvrHwcClientDestroy(DvrHwcClient* client);
void dvrHwcFrameDestroy(DvrHwcFrame* frame);
-void dvrVSyncClientDestroy(DvrVSyncClient* client);
__END_DECLS
@@ -55,7 +53,6 @@
void operator()(DvrSurface* p) { dvrSurfaceDestroy(p); }
void operator()(DvrHwcClient* p) { dvrHwcClientDestroy(p); }
void operator()(DvrHwcFrame* p) { dvrHwcFrameDestroy(p); }
- void operator()(DvrVSyncClient* p) { dvrVSyncClientDestroy(p); }
};
// Helper to define unique pointers for DVR object types.
@@ -73,7 +70,6 @@
using UniqueDvrSurface = MakeUniqueDvrPointer<DvrSurface>;
using UniqueDvrHwcClient = MakeUniqueDvrPointer<DvrHwcClient>;
using UniqueDvrHwcFrame = MakeUniqueDvrPointer<DvrHwcFrame>;
-using UniqueDvrVSyncClient = MakeUniqueDvrPointer<DvrVSyncClient>;
// TODO(eieio): Add an adapter for std::shared_ptr that injects the deleter into
// the relevant constructors.
diff --git a/libs/vr/libdvr/include/dvr/dvr_tracking.h b/libs/vr/libdvr/include/dvr/dvr_tracking.h
new file mode 100644
index 0000000..5e388f3
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_tracking.h
@@ -0,0 +1,185 @@
+#ifndef ANDROID_DVR_TRACKING_H_
+#define ANDROID_DVR_TRACKING_H_
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+#include <dvr/dvr_tracking_types.h>
+
+__BEGIN_DECLS
+
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct DvrTrackingCamera DvrTrackingCamera;
+typedef struct DvrTrackingFeatureExtractor DvrTrackingFeatureExtractor;
+typedef struct DvrTrackingSensors DvrTrackingSensors;
+typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+
+// The callback for DvrTrackingFeatureExtractor that will deliver the feature
+// events. This callback is passed to dvrTrackingFeatureExtractorStart.
+typedef void (*DvrTrackingFeatureCallback)(void* context,
+ const DvrTrackingFeatures* event);
+
+// The callback for DvrTrackingSensors session that will deliver the events.
+// This callback is passed to dvrTrackingSensorsStart.
+typedef void (*DvrTrackingSensorEventCallback)(void* context,
+ DvrTrackingSensorEvent* event);
+
+// Creates a DvrTrackingCamera session.
+//
+// On creation, the session is not in operating mode. Client code must call
+// dvrTrackingCameraStart to bootstrap the underlying camera stack.
+//
+// There is no plan to expose camera configuration through this API. All camera
+// parameters are determined by the system optimized for better tracking
+// results. See b/78662281 for detailed deprecation plan of this API and the
+// Stage 2 of VR tracking data source refactoring.
+//
+// @param out_camera The pointer of a DvrTrackingCamera will be filled here if
+// the method call succeeds.
+// @return Zero on success, or negative error code.
+int dvrTrackingCameraCreate(DvrTrackingCamera** out_camera);
+
+// Destroys a DvrTrackingCamera handle.
+//
+// @param camera The DvrTrackingCamera of interest.
+void dvrTrackingCameraDestroy(DvrTrackingCamera* camera);
+
+// Starts the DvrTrackingCamera.
+//
+// On successful return, all DvrReadBufferQueue's associated with the given
+// write_queue will start to receive buffers from the camera stack. Note that
+// clients of this API should not assume the buffer dimension, format, and/or
+// usage of the outcoming buffers, as they are governed by the underlying camera
+// logic. Also note that it's the client's responsibility to consume buffers
+// from DvrReadBufferQueue on time and return them back to the producer;
+// otherwise the camera stack might be blocked.
+//
+// @param camera The DvrTrackingCamera of interest.
+// @param write_queue A DvrWriteBufferQueue that the camera stack can use to
+// populate the buffer into. The queue must be empty and the camera stack
+// will request buffer allocation with proper buffer dimension, format, and
+// usage. Note that the write queue must be created with user_metadata_size
+// set to sizeof(DvrTrackingBufferMetadata). On success, the write_queue
+// handle will become invalid and the ownership of the queue handle will be
+// transferred into the camera; otherwise, the write_queue handle will keep
+// untouched and the caller still has the ownership.
+// @return Zero on success, or negative error code.
+int dvrTrackingCameraStart(DvrTrackingCamera* camera,
+ DvrWriteBufferQueue* write_queue);
+
+// Stops the DvrTrackingCamera.
+//
+// On successful return, the DvrWriteBufferQueue set during
+// dvrTrackingCameraStart will stop getting new buffers from the camera stack.
+//
+// @param camera The DvrTrackingCamera of interest.
+// @return Zero on success, or negative error code.
+int dvrTrackingCameraStop(DvrTrackingCamera* camera);
+
+// Creates a DvrTrackingSensors session.
+//
+// This will initialize but not start device sensors (gyro / accel). Upon
+// successfull creation, the clients can call dvrTrackingSensorsStart to start
+// receiving sensor events.
+//
+// @param out_sensors The pointer of a DvrTrackingSensors will be filled here if
+// the method call succeeds.
+// @param mode The sensor mode.
+// mode="ndk": Use the Android NDK.
+// mode="direct": Use direct mode sensors (lower latency).
+// @return Zero on success, or negative error code.
+int dvrTrackingSensorsCreate(DvrTrackingSensors** out_sensors,
+ const char* mode);
+
+// Destroys a DvrTrackingSensors session.
+//
+// @param sensors The DvrTrackingSensors struct to destroy.
+void dvrTrackingSensorsDestroy(DvrTrackingSensors* sensors);
+
+// Starts the tracking sensor session.
+//
+// This will start the device sensors and start pumping the feature and sensor
+// events as they arrive.
+//
+// @param client A tracking client created by dvrTrackingSensorsCreate.
+// @param context A client supplied pointer that will be passed to the callback.
+// @param callback A callback that will receive the sensor events on an
+// arbitrary thread.
+// @return Zero on success, or negative error code.
+int dvrTrackingSensorsStart(DvrTrackingSensors* sensors,
+ DvrTrackingSensorEventCallback callback,
+ void* context);
+
+// Stops a DvrTrackingSensors session.
+//
+// This will stop the device sensors. dvrTrackingSensorsStart can be called to
+// restart them again.
+//
+// @param client A tracking client created by dvrTrackingClientCreate.
+// @return Zero on success, or negative error code.
+int dvrTrackingSensorsStop(DvrTrackingSensors* sensors);
+
+// Creates a tracking feature extractor.
+//
+// This will initialize but not start the feature extraction session. Upon
+// successful creation, the client can call dvrTrackingFeatureExtractorStart to
+// start receiving features.
+//
+// @param out_extractor The pointer of a DvrTrackingFeatureExtractor will be
+// filled here if the method call succeeds.
+int dvrTrackingFeatureExtractorCreate(
+ DvrTrackingFeatureExtractor** out_extractor);
+
+// Destroys a tracking feature extractor.
+//
+// @param extractor The DvrTrackingFeatureExtractor to destroy.
+void dvrTrackingFeatureExtractorDestroy(DvrTrackingFeatureExtractor* extractor);
+
+// Starts the tracking feature extractor.
+//
+// This will start the extractor and start pumping the output feature events to
+// the registered callback. Note that this method will create one or more
+// threads to handle feature processing.
+//
+// @param extractor The DvrTrackingFeatureExtractor to destroy.
+int dvrTrackingFeatureExtractorStart(DvrTrackingFeatureExtractor* extractor,
+ DvrTrackingFeatureCallback callback,
+ void* context);
+
+// Stops the tracking feature extractor.
+//
+// This will stop the extractor session and clean up all internal resourcse
+// related to this extractor. On succssful return, all internal therad started
+// by dvrTrackingFeatureExtractorStart should be stopped.
+//
+// @param extractor The DvrTrackingFeatureExtractor to destroy.
+int dvrTrackingFeatureExtractorStop(DvrTrackingFeatureExtractor* extractor);
+
+// Processes one buffer to extract features from.
+//
+// The buffer will be sent over to DSP for feature extraction. Once the process
+// is done, the processing thread will invoke DvrTrackingFeatureCallback with
+// newly extracted features. Note that not all buffers will be processed, as the
+// underlying DSP can only process buffers at a certain framerate. If a buffer
+// needs to be skipped, out_skipped filed will be set to true. Also note that
+// for successfully processed stereo buffer, two callbacks (one for each eye)
+// will be fired.
+//
+// @param extractor The DvrTrackingFeatureExtractor to destroy.
+// @param buffer The buffer to extract features from. Note that the buffer must
+// be in acquired state for the buffer to be processed. Also note that the
+// buffer will be released back to its producer on successful return of the
+// method.
+// @param metadata The metadata associated with the buffer. Should be populated
+// by DvrTrackingCamera session as user defined metadata.
+// @param out_skipped On successful return, the field will be set to true iff
+// the buffer was skipped; and false iff the buffer was processed. This
+// field is optional and nullptr can be passed here to ignore the field.
+// @return Zero on success, or negative error code.
+int dvrTrackingFeatureExtractorProcessBuffer(
+ DvrTrackingFeatureExtractor* extractor, DvrReadBuffer* buffer,
+ const DvrTrackingBufferMetadata* metadata, bool* out_skipped);
+
+__END_DECLS
+
+#endif // ANDROID_DVR_TRACKING_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_tracking_types.h b/libs/vr/libdvr/include/dvr/dvr_tracking_types.h
new file mode 100644
index 0000000..81310d2
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_tracking_types.h
@@ -0,0 +1,104 @@
+#ifndef ANDROID_DVR_TRACKING_TYPES_H_
+#define ANDROID_DVR_TRACKING_TYPES_H_
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef struct DvrTrackingBufferMetadata {
+ // Specifies the source of this image.
+ uint32_t camera_mask;
+ // Specifies the memory format of this image.
+ uint32_t format;
+ /// The width of the image data.
+ uint32_t width;
+ /// The height of the image data.
+ uint32_t height;
+ /// The number of bytes per scanline of image data.
+ uint32_t stride;
+ /// The frame number of this image.
+ int32_t frame_number;
+ /// The timestamp of this image in nanoseconds. Taken in the middle of the
+ /// exposure interval.
+ int64_t timestamp_ns;
+ // This is the timestamp for recording when the system using the HAL
+ // received the callback. It will not be populated by the HAL.
+ int64_t callback_timestamp_ns;
+ /// The exposure duration of this image in nanoseconds.
+ int64_t exposure_duration_ns;
+} DvrTrackingBufferMetadata;
+
+// Represents a set of features extracted from a camera frame. Note that this
+// should be in sync with TangoHalCallbacks defined in tango-hal.h.
+typedef struct DvrTrackingFeatures {
+ // Specifies the source of the features.
+ uint32_t camera_mask;
+
+ // This is unused.
+ uint32_t unused;
+
+ // The timestamp in nanoseconds from the image that generated the features.
+ // Taken in the middle of the exposure interval.
+ int64_t timestamp_ns;
+
+ // This is the timestamp for recording when the system using the HAL
+ // received the callback. It will not be populated by the HAL.
+ int64_t callback_timestamp_ns;
+
+ // The frame number from the image that generated the features.
+ int64_t frame_number;
+
+ // The number of features.
+ int count;
+
+ // An array of 2D image points for each feature in the current image.
+ // This is sub-pixel refined extremum location at the fine resolution.
+ float (*positions)[2];
+
+ // The id of these measurements.
+ int32_t* ids;
+
+ // The feature descriptors.
+ uint64_t (*descriptors)[8];
+
+ // Laplacian scores for each feature.
+ float* scores;
+
+ // Is this feature a minimum or maximum in the Laplacian image.
+ // 0 if the feature is a maximum, 1 if it is a minimum.
+ int32_t* is_minimum;
+
+ // This corresponds to the sub-pixel index of the laplacian image
+ // that the extremum was found.
+ float* scales;
+
+ // Computed orientation of keypoint as part of FREAK extraction, except
+ // it's represented in radians and measured anti-clockwise.
+ float* angles;
+
+ // Edge scores for each feature.
+ float* edge_scores;
+} DvrTrackingFeatures;
+
+// Represents a sensor event.
+typedef struct DvrTrackingSensorEvent {
+ // The sensor type.
+ int32_t sensor;
+
+ // Event type.
+ int32_t type;
+
+ // This is the timestamp recorded from the device. Taken in the middle
+ // of the integration interval and adjusted for any low pass filtering.
+ int64_t timestamp_ns;
+
+ // The event data.
+ float x;
+ float y;
+ float z;
+} DvrTrackingSensorEvent;
+
+__END_DECLS
+
+#endif // ANDROID_DVR_TRACKING_TYPES_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_vsync.h b/libs/vr/libdvr/include/dvr/dvr_vsync.h
index 87fdf31..498bb5c 100644
--- a/libs/vr/libdvr/include/dvr/dvr_vsync.h
+++ b/libs/vr/libdvr/include/dvr/dvr_vsync.h
@@ -6,8 +6,6 @@
__BEGIN_DECLS
-typedef struct DvrVSyncClient DvrVSyncClient;
-
// Represents a vsync sample. The size of this struct is 32 bytes.
typedef struct __attribute__((packed, aligned(16))) DvrVsync {
// The timestamp for the last vsync in nanoseconds.
@@ -29,19 +27,6 @@
uint8_t padding[8];
} DvrVsync;
-// Creates a new client to the system vsync service.
-int dvrVSyncClientCreate(DvrVSyncClient** client_out);
-
-// Destroys the vsync client.
-void dvrVSyncClientDestroy(DvrVSyncClient* client);
-
-// Get the estimated timestamp of the next GPU lens warp preemption event in/
-// ns. Also returns the corresponding vsync count that the next lens warp
-// operation will target.
-int dvrVSyncClientGetSchedInfo(DvrVSyncClient* client, int64_t* vsync_period_ns,
- int64_t* next_timestamp_ns,
- uint32_t* next_vsync_count);
-
__END_DECLS
#endif // ANDROID_DVR_VSYNC_H_
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 1ae75fb..3260447 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -12,38 +12,36 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-shared_libraries = [
- "libbase",
- "libbinder",
- "libbufferhubqueue",
- "libcutils",
- "libgui",
- "liblog",
- "libhardware",
- "libui",
- "libutils",
- "libnativewindow",
- "libpdx_default_transport",
-]
-
-static_libraries = [
- "libdvr_static",
- "libchrome",
- "libdvrcommon",
- "libdisplay",
- "libbroadcastring",
-]
-
cc_test {
srcs: [
"dvr_display_manager-test.cpp",
"dvr_named_buffer-test.cpp",
+ "dvr_tracking-test.cpp",
],
header_libs: ["libdvr_headers"],
- static_libs: static_libraries,
- shared_libs: shared_libraries,
+ static_libs: [
+ "libdvr_static.google",
+ "libchrome",
+ "libdvrcommon",
+ "libdisplay",
+ "libbroadcastring",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libbufferhubqueue",
+ "libcutils",
+ "libgui",
+ "liblog",
+ "libhardware",
+ "libui",
+ "libutils",
+ "libnativewindow",
+ "libpdx_default_transport",
+ ],
cflags: [
+ "-DDVR_TRACKING_IMPLEMENTED=0",
"-DLOG_TAG=\"dvr_api-test\"",
"-DTRACE=0",
"-Wno-missing-field-initializers",
@@ -52,3 +50,55 @@
],
name: "dvr_api-test",
}
+
+cc_test {
+ name: "dvr_buffer_queue-test",
+
+ // Includes the dvr_api.h header. Tests should only include "dvr_api.h",
+ // and shall only get access to |dvrGetApi|, as other symbols are hidden
+ // from the library.
+ include_dirs: ["frameworks/native/libs/vr/libdvr/include"],
+
+ srcs: ["dvr_buffer_queue-test.cpp"],
+
+ shared_libs: [
+ "libandroid",
+ "liblog",
+ ],
+
+ cflags: [
+ "-DTRACE=0",
+ "-O2",
+ "-g",
+ ],
+
+ // DTS Should only link to NDK libraries.
+ sdk_version: "26",
+ stl: "c++_static",
+}
+
+cc_test {
+ name: "dvr_display-test",
+
+ include_dirs: [
+ "frameworks/native/libs/vr/libdvr/include",
+ "frameworks/native/libs/nativewindow/include",
+ ],
+
+ srcs: ["dvr_display-test.cpp"],
+
+ shared_libs: [
+ "libandroid",
+ "liblog",
+ ],
+
+ cflags: [
+ "-DTRACE=0",
+ "-O2",
+ "-g",
+ ],
+
+ // DTS Should only link to NDK libraries.
+ sdk_version: "26",
+ stl: "c++_static",
+}
diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk
deleted file mode 100644
index 0f3840d..0000000
--- a/libs/vr/libdvr/tests/Android.mk
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2018 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# TODO(b/73133405): Currently, building cc_test against NDK using Android.bp
-# doesn't work well. Migrate to use Android.bp once b/73133405 gets fixed.
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= dvr_buffer_queue-test
-
-# Includes the dvr_api.h header. Tests should only include "dvr_api.h",
-# and shall only get access to |dvrGetApi|, as other symbols are hidden from the
-# library.
-LOCAL_C_INCLUDES := \
- frameworks/native/libs/vr/libdvr/include \
-
-LOCAL_SANITIZE := thread
-
-LOCAL_SRC_FILES := dvr_buffer_queue-test.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid \
- liblog \
-
-LOCAL_CFLAGS := \
- -DTRACE=0 \
- -O2 \
- -g \
-
-# DTS Should only link to NDK libraries.
-LOCAL_SDK_VERSION := 26
-LOCAL_NDK_STL_VARIANT := c++_static
-
-include $(BUILD_NATIVE_TEST)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= dvr_display-test
-
-LOCAL_C_INCLUDES := \
- frameworks/native/libs/vr/libdvr/include \
- frameworks/native/libs/nativewindow/include
-
-LOCAL_SANITIZE := thread
-
-LOCAL_SRC_FILES := dvr_display-test.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid \
- liblog
-
-LOCAL_CFLAGS := \
- -DTRACE=0 \
- -O2 \
- -g
-
-# DTS Should only link to NDK libraries.
-LOCAL_SDK_VERSION := 26
-LOCAL_NDK_STL_VARIANT := c++_static
-
-include $(BUILD_NATIVE_TEST)
\ No newline at end of file
diff --git a/libs/vr/libdvr/tests/dvr_api_test.h b/libs/vr/libdvr/tests/dvr_api_test.h
index d8359e7..5d2ec28 100644
--- a/libs/vr/libdvr/tests/dvr_api_test.h
+++ b/libs/vr/libdvr/tests/dvr_api_test.h
@@ -14,7 +14,7 @@
// workaround for an Android NDK bug. See more detail:
// https://github.com/android-ndk/ndk/issues/360
flags |= RTLD_NODELETE;
- platform_handle_ = dlopen("libdvr.so", flags);
+ platform_handle_ = dlopen("libdvr.google.so", flags);
ASSERT_NE(nullptr, platform_handle_) << "Dvr shared library missing.";
auto dvr_get_api = reinterpret_cast<decltype(&dvrGetApi)>(
diff --git a/libs/vr/libdvr/tests/dvr_tracking-test.cpp b/libs/vr/libdvr/tests/dvr_tracking-test.cpp
new file mode 100644
index 0000000..3b6d6e1
--- /dev/null
+++ b/libs/vr/libdvr/tests/dvr_tracking-test.cpp
@@ -0,0 +1,103 @@
+#include <android/log.h>
+#include <gtest/gtest.h>
+
+#include "dvr_api_test.h"
+
+namespace {
+
+class DvrTrackingTest : public DvrApiTest {};
+
+#if DVR_TRACKING_IMPLEMENTED
+
+TEST_F(DvrTrackingTest, Implemented) {
+ ASSERT_TRUE(api_.TrackingCameraCreate != nullptr);
+ ASSERT_TRUE(api_.TrackingCameraStart != nullptr);
+ ASSERT_TRUE(api_.TrackingCameraStop != nullptr);
+
+ ASSERT_TRUE(api_.TrackingFeatureExtractorCreate != nullptr);
+ ASSERT_TRUE(api_.TrackingFeatureExtractorDestroy != nullptr);
+ ASSERT_TRUE(api_.TrackingFeatureExtractorStart != nullptr);
+ ASSERT_TRUE(api_.TrackingFeatureExtractorStop != nullptr);
+ ASSERT_TRUE(api_.TrackingFeatureExtractorProcessBuffer != nullptr);
+}
+
+TEST_F(DvrTrackingTest, CameraCreateFailsForInvalidInput) {
+ int ret;
+ ret = api_.TrackingCameraCreate(nullptr);
+ EXPECT_EQ(ret, -EINVAL);
+
+ DvrTrackingCamera* camera = reinterpret_cast<DvrTrackingCamera*>(42);
+ ret = api_.TrackingCameraCreate(&camera);
+ EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(DvrTrackingTest, CameraCreateDestroy) {
+ DvrTrackingCamera* camera = nullptr;
+ int ret = api_.TrackingCameraCreate(&camera);
+
+ EXPECT_EQ(ret, 0);
+ ASSERT_TRUE(camera != nullptr);
+
+ api_.TrackingCameraDestroy(camera);
+}
+
+TEST_F(DvrTrackingTest, FeatureExtractorCreateFailsForInvalidInput) {
+ int ret;
+ ret = api_.TrackingFeatureExtractorCreate(nullptr);
+ EXPECT_EQ(ret, -EINVAL);
+
+ DvrTrackingFeatureExtractor* camera =
+ reinterpret_cast<DvrTrackingFeatureExtractor*>(42);
+ ret = api_.TrackingFeatureExtractorCreate(&camera);
+ EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(DvrTrackingTest, FeatureExtractorCreateDestroy) {
+ DvrTrackingFeatureExtractor* camera = nullptr;
+ int ret = api_.TrackingFeatureExtractorCreate(&camera);
+
+ EXPECT_EQ(ret, 0);
+ ASSERT_TRUE(camera != nullptr);
+
+ api_.TrackingFeatureExtractorDestroy(camera);
+}
+
+#else // !DVR_TRACKING_IMPLEMENTED
+
+TEST_F(DvrTrackingTest, NotImplemented) {
+ ASSERT_TRUE(api_.TrackingCameraCreate != nullptr);
+ ASSERT_TRUE(api_.TrackingCameraDestroy != nullptr);
+ ASSERT_TRUE(api_.TrackingCameraStart != nullptr);
+ ASSERT_TRUE(api_.TrackingCameraStop != nullptr);
+
+ EXPECT_EQ(api_.TrackingCameraCreate(nullptr), -ENOSYS);
+ EXPECT_EQ(api_.TrackingCameraStart(nullptr, nullptr), -ENOSYS);
+ EXPECT_EQ(api_.TrackingCameraStop(nullptr), -ENOSYS);
+
+ ASSERT_TRUE(api_.TrackingFeatureExtractorCreate != nullptr);
+ ASSERT_TRUE(api_.TrackingFeatureExtractorDestroy != nullptr);
+ ASSERT_TRUE(api_.TrackingFeatureExtractorStart != nullptr);
+ ASSERT_TRUE(api_.TrackingFeatureExtractorStop != nullptr);
+ ASSERT_TRUE(api_.TrackingFeatureExtractorProcessBuffer != nullptr);
+
+ EXPECT_EQ(api_.TrackingFeatureExtractorCreate(nullptr), -ENOSYS);
+ EXPECT_EQ(api_.TrackingFeatureExtractorStart(nullptr, nullptr, nullptr),
+ -ENOSYS);
+ EXPECT_EQ(api_.TrackingFeatureExtractorStop(nullptr), -ENOSYS);
+ EXPECT_EQ(api_.TrackingFeatureExtractorProcessBuffer(nullptr, nullptr,
+ nullptr, nullptr),
+ -ENOSYS);
+
+ ASSERT_TRUE(api_.TrackingSensorsCreate != nullptr);
+ ASSERT_TRUE(api_.TrackingSensorsDestroy != nullptr);
+ ASSERT_TRUE(api_.TrackingSensorsStart != nullptr);
+ ASSERT_TRUE(api_.TrackingSensorsStop != nullptr);
+
+ EXPECT_EQ(api_.TrackingSensorsCreate(nullptr, nullptr), -ENOSYS);
+ EXPECT_EQ(api_.TrackingSensorsStart(nullptr, nullptr, nullptr), -ENOSYS);
+ EXPECT_EQ(api_.TrackingSensorsStop(nullptr), -ENOSYS);
+}
+
+#endif // DVR_TRACKING_IMPLEMENTED
+
+} // namespace
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 13aa3e9..15fa327 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -59,9 +59,18 @@
virtual ~Channel() {}
/*
+ * Accessors to the pid of the last active client.
+ */
+ pid_t GetActiveProcessId() const { return client_pid_; }
+ void SetActiveProcessId(pid_t pid) { client_pid_ = pid; }
+
+ /*
* Utility to get a shared_ptr reference from the channel context pointer.
*/
static std::shared_ptr<Channel> GetFromMessageInfo(const MessageInfo& info);
+
+ private:
+ pid_t client_pid_ = 0;
};
/*
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 32d40e8..ecbfdba 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -521,6 +521,9 @@
info.flags = 0;
info.service = service_;
info.channel = GetChannelState(channel_id);
+ if (info.channel != nullptr) {
+ info.channel->SetActiveProcessId(request.cred.pid);
+ }
info.send_len = request.send_len;
info.recv_len = request.max_recv_len;
info.fd_count = request.file_descriptors.size();
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 4dc669b..07904fb 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -20,7 +20,6 @@
"display_surface.cpp",
"hardware_composer.cpp",
"vr_flinger.cpp",
- "vsync_service.cpp",
]
includeFiles = [ "include" ]
@@ -40,6 +39,7 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
"libbinder",
"libbase",
"libbufferhubqueue",
@@ -64,6 +64,7 @@
headerLibraries = [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
"libdvr_headers",
"libsurfaceflinger_headers",
]
@@ -92,3 +93,7 @@
header_libs: headerLibraries,
name: "libvrflinger",
}
+
+subdirs = [
+ "tests",
+]
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 3090bd1..6fad58e 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -60,11 +60,6 @@
void SetDisplayConfigurationUpdateNotifier(
DisplayConfigurationUpdateNotifier notifier);
- using VSyncCallback = HardwareComposer::VSyncCallback;
- void SetVSyncCallback(VSyncCallback callback) {
- hardware_composer_.SetVSyncCallback(callback);
- }
-
void GrantDisplayOwnership() { hardware_composer_.Enable(); }
void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
void OnBootFinished() { hardware_composer_.OnBootFinished(); }
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 44ce78c..e98d592 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -1,5 +1,6 @@
#include "hardware_composer.h"
+#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <fcntl.h>
@@ -52,6 +53,10 @@
const char kUseExternalDisplayProperty[] = "persist.vr.use_external_display";
+// Surface flinger uses "VSYNC-sf" and "VSYNC-app" for its version of these
+// events. Name ours similarly.
+const char kVsyncTraceEventName[] = "VSYNC-vrflinger";
+
// How long to wait after boot finishes before we turn the display off.
constexpr int kBootFinishedDisplayOffTimeoutSec = 10;
@@ -131,6 +136,7 @@
UpdatePostThreadState(PostThreadState::Quit, true);
if (post_thread_.joinable())
post_thread_.join();
+ composer_callback_->SetVsyncService(nullptr);
}
bool HardwareComposer::Initialize(
@@ -147,6 +153,13 @@
primary_display_ = GetDisplayParams(composer, primary_display_id, true);
+ vsync_service_ = new VsyncService;
+ sp<IServiceManager> sm(defaultServiceManager());
+ auto result = sm->addService(String16(VsyncService::GetServiceName()),
+ vsync_service_, false);
+ LOG_ALWAYS_FATAL_IF(result != android::OK,
+ "addService(%s) failed", VsyncService::GetServiceName());
+
post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
LOG_ALWAYS_FATAL_IF(
!post_thread_event_fd_,
@@ -223,6 +236,7 @@
LOG_ALWAYS_FATAL_IF(!composer_callback_->GotFirstHotplug(),
"Registered composer callback but didn't get hotplug for primary"
" display");
+ composer_callback_->SetVsyncService(vsync_service_);
}
void HardwareComposer::OnPostThreadResumed() {
@@ -242,7 +256,10 @@
// Standalones only create the composer client once and then use SetPowerMode
// to control the screen on pause/resume.
if (!is_standalone_device_) {
- composer_callback_ = nullptr;
+ if (composer_callback_ != nullptr) {
+ composer_callback_->SetVsyncService(nullptr);
+ composer_callback_ = nullptr;
+ }
composer_.reset(nullptr);
} else {
EnableDisplay(*target_display_, false);
@@ -336,7 +353,6 @@
// According to the documentation, this fence is signaled at the time of
// vsync/DMA for physical displays.
if (error == HWC::Error::None) {
- ATRACE_INT("HardwareComposer: VsyncFence", present_fence);
retire_fence_fds_.emplace_back(present_fence);
} else {
ATRACE_INT("HardwareComposer: PresentResult", error);
@@ -775,6 +791,11 @@
std::unique_lock<std::mutex> lock(post_thread_mutex_);
ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
+ if (was_running) {
+ vsync_trace_parity_ = false;
+ ATRACE_INT(kVsyncTraceEventName, 0);
+ }
+
// Tear down resources.
OnPostThreadPaused();
was_running = false;
@@ -848,6 +869,9 @@
vsync_timestamp = status.get();
}
+ vsync_trace_parity_ = !vsync_trace_parity_;
+ ATRACE_INT(kVsyncTraceEventName, vsync_trace_parity_ ? 1 : 0);
+
// Advance the vsync counter only if the system is keeping up with hardware
// vsync to give clients an indication of the delays.
if (vsync_prediction_interval_ == 1)
@@ -867,11 +891,6 @@
vsync_ring_->Publish(vsync);
}
- // Signal all of the vsync clients. Because absolute time is used for the
- // wakeup time below, this can take a little time if necessary.
- if (vsync_callback_)
- vsync_callback_(vsync_timestamp, /*frame_time_estimate*/ 0, vsync_count_);
-
{
// Sleep until shortly before vsync.
ATRACE_NAME("sleep");
@@ -1063,8 +1082,45 @@
layers_.size());
}
-void HardwareComposer::SetVSyncCallback(VSyncCallback callback) {
- vsync_callback_ = callback;
+std::vector<sp<IVsyncCallback>>::const_iterator
+HardwareComposer::VsyncService::FindCallback(
+ const sp<IVsyncCallback>& callback) const {
+ sp<IBinder> binder = IInterface::asBinder(callback);
+ return std::find_if(callbacks_.cbegin(), callbacks_.cend(),
+ [&](const sp<IVsyncCallback>& callback) {
+ return IInterface::asBinder(callback) == binder;
+ });
+}
+
+status_t HardwareComposer::VsyncService::registerCallback(
+ const sp<IVsyncCallback> callback) {
+ std::lock_guard<std::mutex> autolock(mutex_);
+ if (FindCallback(callback) == callbacks_.cend()) {
+ callbacks_.push_back(callback);
+ }
+ return NO_ERROR;
+}
+
+status_t HardwareComposer::VsyncService::unregisterCallback(
+ const sp<IVsyncCallback> callback) {
+ std::lock_guard<std::mutex> autolock(mutex_);
+ auto iter = FindCallback(callback);
+ if (iter != callbacks_.cend()) {
+ callbacks_.erase(iter);
+ }
+ return NO_ERROR;
+}
+
+void HardwareComposer::VsyncService::OnVsync(int64_t vsync_timestamp) {
+ ATRACE_NAME("VsyncService::OnVsync");
+ std::lock_guard<std::mutex> autolock(mutex_);
+ for (auto iter = callbacks_.begin(); iter != callbacks_.end();) {
+ if ((*iter)->onVsync(vsync_timestamp) == android::DEAD_OBJECT) {
+ iter = callbacks_.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
}
Return<void> HardwareComposer::ComposerCallback::onHotplug(
@@ -1123,16 +1179,26 @@
Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
int64_t timestamp) {
+ TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
+ display, timestamp);
+ std::lock_guard<std::mutex> lock(mutex_);
DisplayInfo* display_info = GetDisplayInfo(display);
if (display_info) {
- TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
- display, timestamp);
display_info->callback_vsync_timestamp = timestamp;
}
+ if (primary_display_.id == display && vsync_service_ != nullptr) {
+ vsync_service_->OnVsync(timestamp);
+ }
return Void();
}
+void HardwareComposer::ComposerCallback::SetVsyncService(
+ const sp<VsyncService>& vsync_service) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ vsync_service_ = vsync_service;
+}
+
HardwareComposer::ComposerCallback::Displays
HardwareComposer::ComposerCallback::GetDisplays() {
std::lock_guard<std::mutex> lock(mutex_);
@@ -1149,6 +1215,7 @@
Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
hwc2_display_t display) {
+ std::lock_guard<std::mutex> autolock(mutex_);
DisplayInfo* display_info = GetDisplayInfo(display);
if (!display_info) {
ALOGW("Attempt to get vsync time for unknown display %" PRIu64, display);
@@ -1160,7 +1227,6 @@
if (!event_fd) {
// Fall back to returning the last timestamp returned by the vsync
// callback.
- std::lock_guard<std::mutex> autolock(mutex_);
return display_info->callback_vsync_timestamp;
}
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 1d8d463..80fa7ac 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -24,6 +24,7 @@
#include <pdx/rpc/variant.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/shared_buffer_helpers.h>
+#include <private/dvr/vsync_service.h>
#include "acquired_buffer.h"
#include "display_surface.h"
@@ -300,8 +301,6 @@
// will access the state and whether it needs to be synchronized.
class HardwareComposer {
public:
- // Type for vsync callback.
- using VSyncCallback = std::function<void(int64_t, int64_t, uint32_t)>;
using RequestDisplayCallback = std::function<void(bool)>;
HardwareComposer();
@@ -325,8 +324,6 @@
std::string Dump();
- void SetVSyncCallback(VSyncCallback callback);
-
const DisplayParams& GetPrimaryDisplayParams() const {
return primary_display_;
}
@@ -350,6 +347,18 @@
// on/off. Returns true on success, false on failure.
bool EnableDisplay(const DisplayParams& display, bool enabled);
+ class VsyncService : public BnVsyncService {
+ public:
+ status_t registerCallback(const sp<IVsyncCallback> callback) override;
+ status_t unregisterCallback(const sp<IVsyncCallback> callback) override;
+ void OnVsync(int64_t vsync_timestamp);
+ private:
+ std::vector<sp<IVsyncCallback>>::const_iterator FindCallback(
+ const sp<IVsyncCallback>& callback) const;
+ std::mutex mutex_;
+ std::vector<sp<IVsyncCallback>> callbacks_;
+ };
+
class ComposerCallback : public Hwc2::IComposerCallback {
public:
ComposerCallback() = default;
@@ -360,6 +369,7 @@
int64_t timestamp) override;
bool GotFirstHotplug() { return got_first_hotplug_; }
+ void SetVsyncService(const sp<VsyncService>& vsync_service);
struct Displays {
hwc2_display_t primary_display = 0;
@@ -385,6 +395,7 @@
DisplayInfo primary_display_;
std::optional<DisplayInfo> external_display_;
bool external_display_was_hotplugged_ = false;
+ sp<VsyncService> vsync_service_;
};
HWC::Error Validate(hwc2_display_t display);
@@ -484,9 +495,6 @@
// vector must be sorted by surface_id in ascending order.
std::vector<Layer> layers_;
- // Handler to hook vsync events outside of this class.
- VSyncCallback vsync_callback_;
-
// The layer posting thread. This thread wakes up a short time before vsync to
// hand buffers to hardware composer.
std::thread post_thread_;
@@ -534,6 +542,9 @@
DvrConfig post_thread_config_;
std::mutex shared_config_mutex_;
+ bool vsync_trace_parity_ = false;
+ sp<VsyncService> vsync_service_;
+
static constexpr int kPostThreadInterrupted = 1;
HardwareComposer(const HardwareComposer&) = delete;
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
new file mode 100644
index 0000000..d500278
--- /dev/null
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -0,0 +1,37 @@
+shared_libs = [
+ "android.hardware.configstore-utils",
+ "android.hardware.configstore@1.0",
+ "libbinder",
+ "libbufferhubqueue",
+ "libcutils",
+ "libgui",
+ "libhidlbase",
+ "liblog",
+ "libui",
+ "libutils",
+ "libnativewindow",
+ "libpdx_default_transport",
+]
+
+static_libs = [
+ "libdisplay",
+]
+
+cc_test {
+ srcs: ["vrflinger_test.cpp"],
+ // See go/apct-presubmit for documentation on how this .filter file is used
+ // by Android's automated testing infrastructure for test filtering.
+ data: ["vrflinger_test.filter"],
+ static_libs: static_libs,
+ shared_libs: shared_libs,
+ cflags: [
+ "-DLOG_TAG=\"VrFlingerTest\"",
+ "-DTRACE=0",
+ "-O0",
+ "-g",
+ "-Wall",
+ "-Werror",
+ ],
+ cppflags: ["-std=c++1z"],
+ name: "vrflinger_test",
+}
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
new file mode 100644
index 0000000..e1c7adb
--- /dev/null
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
@@ -0,0 +1,264 @@
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.1/types.h>
+#include <android/hardware_buffer.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <configstore/Utils.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+#include <gui/ISurfaceComposer.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <thread>
+
+#include <private/dvr/display_client.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+using android::dvr::display::DisplayClient;
+using android::dvr::display::Surface;
+using android::dvr::display::SurfaceAttribute;
+using android::dvr::display::SurfaceAttributeValue;
+
+namespace android {
+namespace dvr {
+
+// The transaction code for asking surface flinger if vr flinger is active. This
+// is done as a hidden api since it's only used for tests. See the "case 1028"
+// block in SurfaceFlinger::onTransact() in SurfaceFlinger.cpp.
+constexpr uint32_t kIsVrFlingerActiveTransactionCode = 1028;
+
+// The maximum amount of time to give vr flinger to activate/deactivate. If the
+// switch hasn't completed in this amount of time, the test will fail.
+constexpr auto kVrFlingerSwitchMaxTime = std::chrono::seconds(1);
+
+// How long to wait between each check to see if the vr flinger switch
+// completed.
+constexpr auto kVrFlingerSwitchPollInterval = std::chrono::milliseconds(50);
+
+// How long to wait for a device that boots to VR to have vr flinger ready.
+constexpr auto kBootVrFlingerWaitTimeout = std::chrono::seconds(30);
+
+// A Binder connection to surface flinger.
+class SurfaceFlingerConnection {
+ public:
+ static std::unique_ptr<SurfaceFlingerConnection> Create() {
+ sp<ISurfaceComposer> surface_flinger = interface_cast<ISurfaceComposer>(
+ defaultServiceManager()->getService(String16("SurfaceFlinger")));
+ if (surface_flinger == nullptr) {
+ return nullptr;
+ }
+
+ return std::unique_ptr<SurfaceFlingerConnection>(
+ new SurfaceFlingerConnection(surface_flinger));
+ }
+
+ // Returns true if the surface flinger process is still running. We use this
+ // to detect if surface flinger has crashed.
+ bool IsAlive() {
+ IInterface::asBinder(surface_flinger_)->pingBinder();
+ return IInterface::asBinder(surface_flinger_)->isBinderAlive();
+ }
+
+ // Return true if vr flinger is currently active, false otherwise. If there's
+ // an error communicating with surface flinger, std::nullopt is returned.
+ std::optional<bool> IsVrFlingerActive() {
+ Parcel data, reply;
+ status_t result =
+ data.writeInterfaceToken(surface_flinger_->getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ return std::nullopt;
+ }
+ result = IInterface::asBinder(surface_flinger_)
+ ->transact(kIsVrFlingerActiveTransactionCode, data, &reply);
+ if (result != NO_ERROR) {
+ return std::nullopt;
+ }
+ bool vr_flinger_active;
+ result = reply.readBool(&vr_flinger_active);
+ if (result != NO_ERROR) {
+ return std::nullopt;
+ }
+ return vr_flinger_active;
+ }
+
+ enum class VrFlingerSwitchResult : int8_t {
+ kSuccess,
+ kTimedOut,
+ kCommunicationError,
+ kSurfaceFlingerDied
+ };
+
+ // Wait for vr flinger to become active or inactive.
+ VrFlingerSwitchResult WaitForVrFlinger(bool wait_active) {
+ return WaitForVrFlingerTimed(wait_active, kVrFlingerSwitchPollInterval,
+ kVrFlingerSwitchMaxTime);
+ }
+
+ // Wait for vr flinger to become active or inactive, specifying custom timeouts.
+ VrFlingerSwitchResult WaitForVrFlingerTimed(bool wait_active,
+ std::chrono::milliseconds pollInterval, std::chrono::seconds timeout) {
+ auto start_time = std::chrono::steady_clock::now();
+ while (1) {
+ std::this_thread::sleep_for(pollInterval);
+ if (!IsAlive()) {
+ return VrFlingerSwitchResult::kSurfaceFlingerDied;
+ }
+ std::optional<bool> vr_flinger_active = IsVrFlingerActive();
+ if (!vr_flinger_active.has_value()) {
+ return VrFlingerSwitchResult::kCommunicationError;
+ }
+ if (vr_flinger_active.value() == wait_active) {
+ return VrFlingerSwitchResult::kSuccess;
+ } else if (std::chrono::steady_clock::now() - start_time > timeout) {
+ return VrFlingerSwitchResult::kTimedOut;
+ }
+ }
+ }
+
+ private:
+ SurfaceFlingerConnection(sp<ISurfaceComposer> surface_flinger)
+ : surface_flinger_(surface_flinger) {}
+
+ sp<ISurfaceComposer> surface_flinger_ = nullptr;
+};
+
+// This test activates vr flinger by creating a vr flinger surface, then
+// deactivates vr flinger by destroying the surface. We verify that vr flinger
+// is activated and deactivated as expected, and that surface flinger doesn't
+// crash.
+//
+// If the device doesn't support vr flinger (as repoted by ConfigStore), the
+// test does nothing.
+//
+// If the device is a standalone vr device, the test also does nothing, since
+// this test verifies the behavior of display handoff from surface flinger to vr
+// flinger and back, and standalone devices never hand control of the display
+// back to surface flinger.
+TEST(VrFlingerTest, ActivateDeactivate) {
+ android::ProcessState::self()->startThreadPool();
+
+ // Exit immediately if the device doesn't support vr flinger. This ConfigStore
+ // check is the same mechanism used by surface flinger to decide if it should
+ // initialize vr flinger.
+ bool vr_flinger_enabled =
+ getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::useVrFlinger>(
+ false);
+ if (!vr_flinger_enabled) {
+ return;
+ }
+
+ // This test doesn't apply to standalone vr devices.
+ if (property_get_bool("ro.boot.vr", false)) {
+ return;
+ }
+
+ auto surface_flinger_connection = SurfaceFlingerConnection::Create();
+ ASSERT_NE(surface_flinger_connection, nullptr);
+
+ // Verify we start off with vr flinger disabled.
+ ASSERT_TRUE(surface_flinger_connection->IsAlive());
+ auto vr_flinger_active = surface_flinger_connection->IsVrFlingerActive();
+ ASSERT_TRUE(vr_flinger_active.has_value());
+ ASSERT_FALSE(vr_flinger_active.value());
+
+ // Create a vr flinger surface, and verify vr flinger becomes active.
+ // Introduce a scope so that, at the end of the scope, the vr flinger surface
+ // is destroyed, and vr flinger deactivates.
+ {
+ auto display_client = DisplayClient::Create();
+ ASSERT_NE(display_client, nullptr);
+ auto metrics = display_client->GetDisplayMetrics();
+ ASSERT_TRUE(metrics.ok());
+
+ auto surface = Surface::CreateSurface({
+ {SurfaceAttribute::Direct, SurfaceAttributeValue(true)},
+ {SurfaceAttribute::Visible, SurfaceAttributeValue(true)},
+ });
+ ASSERT_TRUE(surface.ok());
+ ASSERT_TRUE(surface.get() != nullptr);
+
+ auto queue = surface.get()->CreateQueue(
+ metrics.get().display_width, metrics.get().display_height,
+ /*layer_count=*/1, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ /*capacity=*/1,
+ /*metadata_size=*/0);
+ ASSERT_TRUE(queue.ok());
+ ASSERT_TRUE(queue.get() != nullptr);
+
+ size_t slot;
+ pdx::LocalHandle release_fence;
+ auto buffer = queue.get()->Dequeue(/*timeout=*/0, &slot, &release_fence);
+ ASSERT_TRUE(buffer.ok());
+ ASSERT_TRUE(buffer.get() != nullptr);
+
+ ASSERT_EQ(buffer.get()->width(), metrics.get().display_width);
+ ASSERT_EQ(buffer.get()->height(), metrics.get().display_height);
+
+ void* raw_buf = nullptr;
+ ASSERT_GE(buffer.get()->Lock(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ /*x=*/0, /*y=*/0, buffer.get()->width(),
+ buffer.get()->height(), &raw_buf),
+ 0);
+ ASSERT_NE(raw_buf, nullptr);
+ uint32_t* pixels = static_cast<uint32_t*>(raw_buf);
+
+ for (int i = 0; i < buffer.get()->stride() * buffer.get()->height(); ++i) {
+ pixels[i] = 0x0000ff00;
+ }
+
+ ASSERT_GE(buffer.get()->Unlock(), 0);
+
+ ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle(),
+ /*meta=*/nullptr,
+ /*user_metadata_size=*/0),
+ 0);
+
+ ASSERT_EQ(
+ surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/true),
+ SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
+ }
+
+ // Now that the vr flinger surface is destroyed, vr flinger should deactivate.
+ ASSERT_EQ(
+ surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/false),
+ SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
+}
+
+// This test runs only on devices that boot to vr. Such a device should boot to
+// a state where vr flinger is running, and the test verifies this after a
+// delay.
+TEST(BootVrFlingerTest, BootsToVrFlinger) {
+ // Exit if we are not running on a device that boots to vr.
+ if (!property_get_bool("ro.boot.vr", false)) {
+ return;
+ }
+
+ auto surface_flinger_connection = SurfaceFlingerConnection::Create();
+ ASSERT_NE(surface_flinger_connection, nullptr);
+
+ // Verify that vr flinger is enabled.
+ ASSERT_TRUE(surface_flinger_connection->IsAlive());
+ auto vr_flinger_active = surface_flinger_connection->IsVrFlingerActive();
+ ASSERT_TRUE(vr_flinger_active.has_value());
+
+ bool active_value = vr_flinger_active.value();
+ if (!active_value) {
+ // Try again, but delay up to 30 seconds.
+ ASSERT_EQ(surface_flinger_connection->WaitForVrFlingerTimed(true,
+ kVrFlingerSwitchPollInterval, kBootVrFlingerWaitTimeout),
+ SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
+ }
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.filter b/libs/vr/libvrflinger/tests/vrflinger_test.filter
new file mode 100644
index 0000000..030bb7b
--- /dev/null
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.filter
@@ -0,0 +1,5 @@
+{
+ "presubmit": {
+ "filter": "BootVrFlingerTest.*"
+ }
+}
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 26aed4f..b57383a 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -23,7 +23,6 @@
#include "DisplayHardware/ComposerHal.h"
#include "display_manager_service.h"
#include "display_service.h"
-#include "vsync_service.h"
namespace android {
namespace dvr {
@@ -85,16 +84,6 @@
CHECK_ERROR(!service, error, "Failed to create display manager service.");
dispatcher_->AddService(service);
- service = android::dvr::VSyncService::Create();
- CHECK_ERROR(!service, error, "Failed to create vsync service.");
- dispatcher_->AddService(service);
-
- display_service_->SetVSyncCallback(
- std::bind(&android::dvr::VSyncService::VSyncEvent,
- std::static_pointer_cast<android::dvr::VSyncService>(service),
- std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3));
-
dispatcher_thread_ = std::thread([this]() {
prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
ALOGI("Entering message loop.");
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
deleted file mode 100644
index b8d8b08..0000000
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-#include "vsync_service.h"
-
-#include <hardware/hwcomposer.h>
-#include <log/log.h>
-#include <poll.h>
-#include <sys/prctl.h>
-#include <time.h>
-#include <utils/Trace.h>
-
-#include <dvr/dvr_display_types.h>
-#include <pdx/default_transport/service_endpoint.h>
-#include <private/dvr/clock_ns.h>
-#include <private/dvr/display_protocol.h>
-
-using android::dvr::display::VSyncProtocol;
-using android::dvr::display::VSyncSchedInfo;
-using android::pdx::Channel;
-using android::pdx::Message;
-using android::pdx::MessageInfo;
-using android::pdx::default_transport::Endpoint;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-VSyncService::VSyncService()
- : BASE("VSyncService", Endpoint::Create(VSyncProtocol::kClientPath)),
- last_vsync_(0),
- current_vsync_(0),
- compositor_time_ns_(0),
- current_vsync_count_(0) {}
-
-VSyncService::~VSyncService() {}
-
-void VSyncService::VSyncEvent(int64_t timestamp_ns,
- int64_t compositor_time_ns,
- uint32_t vsync_count) {
- ATRACE_NAME("VSyncService::VSyncEvent");
- std::lock_guard<std::mutex> autolock(mutex_);
-
- last_vsync_ = current_vsync_;
- current_vsync_ = timestamp_ns;
- compositor_time_ns_ = compositor_time_ns;
- current_vsync_count_ = vsync_count;
-
- NotifyWaiters();
- UpdateClients();
-}
-
-std::shared_ptr<Channel> VSyncService::OnChannelOpen(pdx::Message& message) {
- const MessageInfo& info = message.GetInfo();
-
- auto client = std::make_shared<VSyncChannel>(*this, info.pid, info.cid);
- AddClient(client);
-
- return client;
-}
-
-void VSyncService::OnChannelClose(pdx::Message& /*message*/,
- const std::shared_ptr<Channel>& channel) {
- auto client = std::static_pointer_cast<VSyncChannel>(channel);
- if (!client) {
- ALOGW("WARNING: VSyncChannel was NULL!!!\n");
- return;
- }
-
- RemoveClient(client);
-}
-
-void VSyncService::AddWaiter(pdx::Message& message) {
- std::lock_guard<std::mutex> autolock(mutex_);
- std::unique_ptr<VSyncWaiter> waiter(new VSyncWaiter(message));
- waiters_.push_back(std::move(waiter));
-}
-
-void VSyncService::AddClient(const std::shared_ptr<VSyncChannel>& client) {
- std::lock_guard<std::mutex> autolock(mutex_);
- clients_.push_back(client);
-}
-
-void VSyncService::RemoveClient(const std::shared_ptr<VSyncChannel>& client) {
- std::lock_guard<std::mutex> autolock(mutex_);
- clients_.remove(client);
-}
-
-// Private. Assumes mutex is held.
-void VSyncService::NotifyWaiters() {
- ATRACE_NAME("VSyncService::NotifyWaiters");
- auto first = waiters_.begin();
- auto last = waiters_.end();
-
- while (first != last) {
- (*first)->Notify(current_vsync_);
- waiters_.erase(first++);
- }
-}
-
-// Private. Assumes mutex is held.
-void VSyncService::UpdateClients() {
- ATRACE_NAME("VSyncService::UpdateClients");
- auto first = clients_.begin();
- auto last = clients_.end();
-
- while (first != last) {
- (*first)->Signal();
- first++;
- }
-}
-
-pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) {
- ATRACE_NAME("VSyncService::HandleMessage");
- switch (message.GetOp()) {
- case VSyncProtocol::Wait::Opcode:
- AddWaiter(message);
- return {};
-
- case VSyncProtocol::GetLastTimestamp::Opcode:
- DispatchRemoteMethod<VSyncProtocol::GetLastTimestamp>(
- *this, &VSyncService::OnGetLastTimestamp, message);
- return {};
-
- case VSyncProtocol::GetSchedInfo::Opcode:
- DispatchRemoteMethod<VSyncProtocol::GetSchedInfo>(
- *this, &VSyncService::OnGetSchedInfo, message);
- return {};
-
- case VSyncProtocol::Acknowledge::Opcode:
- DispatchRemoteMethod<VSyncProtocol::Acknowledge>(
- *this, &VSyncService::OnAcknowledge, message);
- return {};
-
- default:
- return Service::HandleMessage(message);
- }
-}
-
-pdx::Status<int64_t> VSyncService::OnGetLastTimestamp(pdx::Message& message) {
- auto client = std::static_pointer_cast<VSyncChannel>(message.GetChannel());
- std::lock_guard<std::mutex> autolock(mutex_);
-
- // Getting the timestamp has the side effect of ACKing.
- client->Ack();
- return {current_vsync_};
-}
-
-pdx::Status<VSyncSchedInfo> VSyncService::OnGetSchedInfo(
- pdx::Message& message) {
- auto client = std::static_pointer_cast<VSyncChannel>(message.GetChannel());
- std::lock_guard<std::mutex> autolock(mutex_);
-
- // Getting the timestamp has the side effect of ACKing.
- client->Ack();
-
- uint32_t next_vsync_count = current_vsync_count_ + 1;
- int64_t current_time = GetSystemClockNs();
- int64_t vsync_period_ns = 0;
- int64_t next_warp;
- if (current_vsync_ == 0 || last_vsync_ == 0) {
- // Handle startup when current_vsync_ or last_vsync_ are 0.
- // Normally should not happen because vsync_service is running before
- // applications, but in case it does a sane time prevents applications
- // from malfunctioning.
- vsync_period_ns = 20000000;
- next_warp = current_time;
- } else {
- // TODO(jbates) When we have an accurate reading of the true vsync
- // period, use that instead of this estimated value.
- vsync_period_ns = current_vsync_ - last_vsync_;
- // Clamp the period, because when there are no surfaces the last_vsync_
- // value will get stale. Note this is temporary and goes away as soon
- // as we have an accurate vsync period reported by the system.
- vsync_period_ns = std::min(vsync_period_ns, INT64_C(20000000));
- next_warp = current_vsync_ + vsync_period_ns - compositor_time_ns_;
- // If the request missed the present window, move up to the next vsync.
- if (current_time > next_warp) {
- next_warp += vsync_period_ns;
- ++next_vsync_count;
- }
- }
-
- return {{vsync_period_ns, next_warp, next_vsync_count}};
-}
-
-pdx::Status<void> VSyncService::OnAcknowledge(pdx::Message& message) {
- auto client = std::static_pointer_cast<VSyncChannel>(message.GetChannel());
- std::lock_guard<std::mutex> autolock(mutex_);
- client->Ack();
- return {};
-}
-
-void VSyncWaiter::Notify(int64_t timestamp) {
- timestamp_ = timestamp;
- DispatchRemoteMethod<VSyncProtocol::Wait>(*this, &VSyncWaiter::OnWait,
- message_);
-}
-
-pdx::Status<int64_t> VSyncWaiter::OnWait(pdx::Message& /*message*/) {
- return {timestamp_};
-}
-
-void VSyncChannel::Ack() {
- ALOGD_IF(TRACE > 1, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
- service_.ModifyChannelEvents(cid_, POLLPRI, 0);
-}
-
-void VSyncChannel::Signal() {
- ALOGD_IF(TRACE > 1, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
- service_.ModifyChannelEvents(cid_, 0, POLLPRI);
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrflinger/vsync_service.h b/libs/vr/libvrflinger/vsync_service.h
deleted file mode 100644
index 822f02b..0000000
--- a/libs/vr/libvrflinger/vsync_service.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef ANDROID_DVR_SERVICES_DISPLAYD_VSYNC_SERVICE_H_
-#define ANDROID_DVR_SERVICES_DISPLAYD_VSYNC_SERVICE_H_
-
-#include <pdx/service.h>
-
-#include <list>
-#include <memory>
-#include <mutex>
-#include <thread>
-
-#include "display_service.h"
-
-namespace android {
-namespace dvr {
-
-// VSyncWaiter encapsulates a client blocked waiting for the next vsync.
-// It is used to enqueue the Message to reply to when the next vsync event
-// occurs.
-class VSyncWaiter {
- public:
- explicit VSyncWaiter(pdx::Message& message) : message_(std::move(message)) {}
-
- void Notify(int64_t timestamp);
-
- private:
- pdx::Status<int64_t> OnWait(pdx::Message& message);
-
- pdx::Message message_;
- int64_t timestamp_ = 0;
-
- VSyncWaiter(const VSyncWaiter&) = delete;
- void operator=(const VSyncWaiter&) = delete;
-};
-
-// VSyncChannel manages the service-side per-client context for each client
-// using the service.
-class VSyncChannel : public pdx::Channel {
- public:
- VSyncChannel(pdx::Service& service, int pid, int cid)
- : service_(service), pid_(pid), cid_(cid) {}
-
- void Ack();
- void Signal();
-
- private:
- pdx::Service& service_;
- pid_t pid_;
- int cid_;
-
- VSyncChannel(const VSyncChannel&) = delete;
- void operator=(const VSyncChannel&) = delete;
-};
-
-// VSyncService implements the displayd vsync service over ServiceFS.
-class VSyncService : public pdx::ServiceBase<VSyncService> {
- public:
- ~VSyncService() override;
-
- pdx::Status<void> HandleMessage(pdx::Message& message) override;
-
- std::shared_ptr<pdx::Channel> OnChannelOpen(pdx::Message& message) override;
- void OnChannelClose(pdx::Message& message,
- const std::shared_ptr<pdx::Channel>& channel) override;
-
- // Called by the hardware composer HAL, or similar, whenever a vsync event
- // occurs on the primary display. |compositor_time_ns| is the number of ns
- // before the next vsync when the compositor will preempt the GPU to do EDS
- // and lens warp.
- void VSyncEvent(int64_t timestamp_ns, int64_t compositor_time_ns,
- uint32_t vsync_count);
-
- private:
- friend BASE;
-
- VSyncService();
-
- pdx::Status<int64_t> OnGetLastTimestamp(pdx::Message& message);
- pdx::Status<display::VSyncSchedInfo> OnGetSchedInfo(pdx::Message& message);
- pdx::Status<void> OnAcknowledge(pdx::Message& message);
-
- void NotifierThreadFunction();
-
- void AddWaiter(pdx::Message& message);
- void NotifyWaiters();
- void UpdateClients();
-
- void AddClient(const std::shared_ptr<VSyncChannel>& client);
- void RemoveClient(const std::shared_ptr<VSyncChannel>& client);
-
- int64_t last_vsync_;
- int64_t current_vsync_;
- int64_t compositor_time_ns_;
- uint32_t current_vsync_count_;
-
- std::mutex mutex_;
-
- std::list<std::unique_ptr<VSyncWaiter>> waiters_;
- std::list<std::shared_ptr<VSyncChannel>> clients_;
-
- VSyncService(const VSyncService&) = delete;
- void operator=(VSyncService&) = delete;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_SERVICES_DISPLAYD_VSYNC_SERVICE_H_
diff --git a/libs/vr/public.libraries-google.txt b/libs/vr/public.libraries-google.txt
new file mode 100644
index 0000000..8271b94
--- /dev/null
+++ b/libs/vr/public.libraries-google.txt
@@ -0,0 +1 @@
+libdvr.google.so
\ No newline at end of file
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 44f4dbc..0fd91eb 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -1285,17 +1285,6 @@
#define EGL_NATIVE_SURFACE_TIZEN 0x32A1
#endif /* EGL_TIZEN_image_native_surface */
-/* This is a private Android extension that does not exist in the EGL registry,
- * formerly used to work around a hardware issue on Nexus 4. It is deprecated
- * and unimplemented. It has been added to this header manually. */
-#ifndef EGL_ANDROID_image_crop
-#define EGL_ANDROID_image_crop 1
-#define EGL_IMAGE_CROP_LEFT_ANDROID 0x3148
-#define EGL_IMAGE_CROP_TOP_ANDROID 0x3149
-#define EGL_IMAGE_CROP_RIGHT_ANDROID 0x314A
-#define EGL_IMAGE_CROP_BOTTOM_ANDROID 0x314B
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index b3752f5..74c4d7d 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -79,7 +79,7 @@
}
std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
- CacheEntry dummyEntry(dummyKey, NULL);
+ CacheEntry dummyEntry(dummyKey, nullptr);
while (true) {
auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
@@ -139,7 +139,7 @@
return 0;
}
std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
- CacheEntry dummyEntry(dummyKey, NULL);
+ CacheEntry dummyEntry(dummyKey, nullptr);
auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
if (index == mCacheEntries.end() || dummyEntry < *index) {
ALOGV("get: no cache entry found for key of size %zu", keySize);
@@ -308,7 +308,7 @@
mData(copyData ? malloc(size) : data),
mSize(size),
mOwnsData(copyData) {
- if (data != NULL && copyData) {
+ if (data != nullptr && copyData) {
memcpy(const_cast<void*>(mData), data, size);
}
}
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
index 1f5d535..e5c5e5b 100644
--- a/opengl/libs/EGL/BlobCache.h
+++ b/opengl/libs/EGL/BlobCache.h
@@ -97,6 +97,10 @@
//
int unflatten(void const* buffer, size_t size);
+ // clear flushes out all contents of the cache then the BlobCache, leaving
+ // it in an empty state.
+ void clear() { mCacheEntries.clear(); }
+
protected:
// mMaxTotalSize is the maximum size that all cache entries can occupy. This
// includes space for both keys and values. When a call to BlobCache::set
diff --git a/opengl/libs/EGL/BlobCache_test.cpp b/opengl/libs/EGL/BlobCache_test.cpp
index edbaaf0..cf67cf4 100644
--- a/opengl/libs/EGL/BlobCache_test.cpp
+++ b/opengl/libs/EGL/BlobCache_test.cpp
@@ -97,7 +97,7 @@
TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
mBC->set("abcd", 4, "efgh", 4);
- ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, nullptr, 0));
}
TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
@@ -169,7 +169,7 @@
}
mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
- ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+ ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
}
TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
@@ -219,7 +219,7 @@
}
mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
- ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+ ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
}
TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
@@ -237,7 +237,7 @@
int numCached = 0;
for (int i = 0; i < 256; i++) {
uint8_t k = i;
- if (mBC->get(&k, 1, NULL, 0) == 1) {
+ if (mBC->get(&k, 1, nullptr, 0) == 1) {
numCached++;
}
}
@@ -260,7 +260,7 @@
int numCached = 0;
for (int i = 0; i < maxEntries+1; i++) {
uint8_t k = i;
- if (mBC->get(&k, 1, NULL, 0) == 1) {
+ if (mBC->get(&k, 1, nullptr, 0) == 1) {
numCached++;
}
}
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
index 7923715..cc42ac7 100644
--- a/opengl/libs/EGL/FileBlobCache.cpp
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -77,7 +77,7 @@
return;
}
- uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+ uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(nullptr, fileSize,
PROT_READ, MAP_PRIVATE, fd, 0));
if (buf == MAP_FAILED) {
ALOGE("error mmaping cache file: %s (%d)", strerror(errno),
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 91a3455..e954b4f 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -129,7 +129,7 @@
{
dso[0] = gles;
for (size_t i=1 ; i<NELEM(dso) ; i++)
- dso[i] = 0;
+ dso[i] = nullptr;
}
Loader::driver_t::~driver_t()
@@ -137,7 +137,7 @@
for (size_t i=0 ; i<NELEM(dso) ; i++) {
if (dso[i]) {
dlclose(dso[i]);
- dso[i] = 0;
+ dso[i] = nullptr;
}
}
}
@@ -163,7 +163,7 @@
// ----------------------------------------------------------------------------
Loader::Loader()
- : getProcAddress(NULL)
+ : getProcAddress(nullptr)
{
}
@@ -221,7 +221,7 @@
ATRACE_CALL();
void* dso;
- driver_t* hnd = 0;
+ driver_t* hnd = nullptr;
setEmulatorGlesValue();
@@ -272,11 +272,11 @@
char const * name = *api;
__eglMustCastToProperFunctionPointerType f =
(__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
- if (f == NULL) {
+ if (f == nullptr) {
// couldn't find the entry-point, use eglGetProcAddress()
f = getProcAddress(name);
}
- if (f == NULL) {
+ if (f == nullptr) {
// Try without the OES postfix
ssize_t index = ssize_t(strlen(name)) - 3;
if ((index>0 && (index<SIZE-1)) && (!strcmp(name+index, "OES"))) {
@@ -286,7 +286,7 @@
//ALOGD_IF(f, "found <%s> instead", scrap);
}
}
- if (f == NULL) {
+ if (f == nullptr) {
// Try with the OES postfix
ssize_t index = ssize_t(strlen(name)) - 3;
if (index>0 && strcmp(name+index, "OES")) {
@@ -295,7 +295,7 @@
//ALOGD_IF(f, "found <%s> instead", scrap);
}
}
- if (f == NULL) {
+ if (f == nullptr) {
//ALOGD("%s", name);
f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
@@ -406,9 +406,9 @@
}
DIR* d = opendir(search);
- if (d != NULL) {
+ if (d != nullptr) {
struct dirent* e;
- while ((e = readdir(d)) != NULL) {
+ while ((e = readdir(d)) != nullptr) {
if (e->d_type == DT_DIR) {
continue;
}
@@ -434,7 +434,7 @@
std::string absolutePath = MatchFile::find(kind);
if (absolutePath.empty()) {
// this happens often, we don't want to log an error
- return 0;
+ return nullptr;
}
const char* const driver_absolute_path = absolutePath.c_str();
@@ -444,10 +444,10 @@
// sphal namespace.
void* dso = do_android_load_sphal_library(driver_absolute_path,
RTLD_NOW | RTLD_LOCAL);
- if (dso == 0) {
+ if (dso == nullptr) {
const char* err = dlerror();
ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown");
- return 0;
+ return nullptr;
}
ALOGD("loaded %s", driver_absolute_path);
@@ -495,7 +495,7 @@
if (!dso) {
dso = load_system_driver(kind);
if (!dso)
- return NULL;
+ return nullptr;
}
if (mask & EGL) {
@@ -512,11 +512,11 @@
char const * name = *api;
__eglMustCastToProperFunctionPointerType f =
(__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
- if (f == NULL) {
+ if (f == nullptr) {
// couldn't find the entry-point, use eglGetProcAddress()
f = getProcAddress(name);
- if (f == NULL) {
- f = (__eglMustCastToProperFunctionPointerType)0;
+ if (f == nullptr) {
+ f = (__eglMustCastToProperFunctionPointerType)nullptr;
}
}
*curr++ = f;
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index f53cf3f..e292b80 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -89,22 +89,22 @@
egl_display_ptr validate_display(EGLDisplay dpy) {
egl_display_ptr dp = get_display(dpy);
if (!dp)
- return setError(EGL_BAD_DISPLAY, egl_display_ptr(NULL));
+ return setError(EGL_BAD_DISPLAY, egl_display_ptr(nullptr));
if (!dp->isReady())
- return setError(EGL_NOT_INITIALIZED, egl_display_ptr(NULL));
+ return setError(EGL_NOT_INITIALIZED, egl_display_ptr(nullptr));
return dp;
}
egl_display_ptr validate_display_connection(EGLDisplay dpy,
egl_connection_t*& cnx) {
- cnx = NULL;
+ cnx = nullptr;
egl_display_ptr dp = validate_display(dpy);
if (!dp)
return dp;
cnx = &gEGLImpl;
- if (cnx->dso == 0) {
- return setError(EGL_BAD_CONFIG, egl_display_ptr(NULL));
+ if (cnx->dso == nullptr) {
+ return setError(EGL_BAD_CONFIG, egl_display_ptr(nullptr));
}
return dp;
}
@@ -117,14 +117,14 @@
EGLContext context = egl_tls_t::getContext();
if (context == EGL_NO_CONTEXT)
- return NULL;
+ return nullptr;
egl_context_t const * const c = get_context(context);
- if (c == NULL) // this should never happen, by construction
- return NULL;
+ if (c == nullptr) // this should never happen, by construction
+ return nullptr;
if (name != GL_EXTENSIONS)
- return NULL;
+ return nullptr;
return (const GLubyte *)c->gl_extensions.c_str();
}
@@ -135,19 +135,19 @@
EGLContext context = egl_tls_t::getContext();
if (context == EGL_NO_CONTEXT)
- return NULL;
+ return nullptr;
egl_context_t const * const c = get_context(context);
- if (c == NULL) // this should never happen, by construction
- return NULL;
+ if (c == nullptr) // this should never happen, by construction
+ return nullptr;
if (name != GL_EXTENSIONS)
- return NULL;
+ return nullptr;
// if index is out of bounds, assume it will be in the default
// implementation too, so we don't have to generate a GL error here
if (index >= c->tokenized_gl_extensions.size())
- return NULL;
+ return nullptr;
return (const GLubyte *)c->tokenized_gl_extensions[index].c_str();
}
@@ -161,7 +161,7 @@
return -1;
egl_context_t const * const c = get_context(context);
- if (c == NULL) // this should never happen, by construction
+ if (c == nullptr) // this should never happen, by construction
return -1;
return (GLint)c->tokenized_gl_extensions.size();
@@ -184,7 +184,7 @@
// dynamically load our EGL implementation
egl_connection_t* cnx = &gEGLImpl;
- if (cnx->dso == 0) {
+ if (cnx->dso == nullptr) {
cnx->hooks[egl_connection_t::GLESv1_INDEX] =
&gHooks[egl_connection_t::GLESv1_INDEX];
cnx->hooks[egl_connection_t::GLESv2_INDEX] =
@@ -249,12 +249,12 @@
char const * const gl_names[] = {
#include "../entries.in"
- NULL
+ nullptr
};
char const * const egl_names[] = {
#include "egl_entries.in"
- NULL
+ nullptr
};
#undef GL_ENTRY
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 42049a4..c361ab0 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -136,7 +136,6 @@
// "EGL_IMG_hibernate_process " // optional
// "EGL_ANDROID_native_fence_sync " // strongly recommended
// "EGL_ANDROID_framebuffer_target " // mandatory for HWC 1.1
-// "EGL_ANDROID_image_crop " // optional
/*
* EGL Extensions entry-points exposed to 3rd party applications
@@ -258,7 +257,7 @@
return map[i].address;
}
}
- return NULL;
+ return nullptr;
}
// ----------------------------------------------------------------------------
@@ -341,7 +340,7 @@
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- if (num_config==0) {
+ if (num_config==nullptr) {
return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
}
@@ -366,7 +365,7 @@
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- if (num_config==0) {
+ if (num_config==nullptr) {
return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
}
@@ -385,8 +384,8 @@
// Only enable MSAA if the context is OpenGL ES 2.0 and
// if no caveat is requested
- const EGLint *attribRendererable = NULL;
- const EGLint *attribCaveat = NULL;
+ const EGLint *attribRendererable = nullptr;
+ const EGLint *attribCaveat = nullptr;
// Count the number of attributes and look for
// EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT
@@ -441,7 +440,7 @@
{
clearError();
- egl_connection_t* cnx = NULL;
+ egl_connection_t* cnx = nullptr;
const egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (!dp) return EGL_FALSE;
@@ -699,7 +698,7 @@
const EGLint *origAttribList = attrib_list;
clearError();
- egl_connection_t* cnx = NULL;
+ egl_connection_t* cnx = nullptr;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
if (!window) {
@@ -782,7 +781,7 @@
{
clearError();
- egl_connection_t* cnx = NULL;
+ egl_connection_t* cnx = nullptr;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
EGLDisplay iDpy = dp->disp.dpy;
@@ -803,7 +802,7 @@
dp->disp.dpy, config, pixmap, attrib_list);
if (surface != EGL_NO_SURFACE) {
egl_surface_t* s =
- new egl_surface_t(dp.get(), config, NULL, surface,
+ new egl_surface_t(dp.get(), config, nullptr, surface,
getReportedColorSpace(colorSpace), cnx);
return s;
}
@@ -816,7 +815,7 @@
{
clearError();
- egl_connection_t* cnx = NULL;
+ egl_connection_t* cnx = nullptr;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
EGLDisplay iDpy = dp->disp.dpy;
@@ -837,7 +836,7 @@
dp->disp.dpy, config, attrib_list);
if (surface != EGL_NO_SURFACE) {
egl_surface_t* s =
- new egl_surface_t(dp.get(), config, NULL, surface,
+ new egl_surface_t(dp.get(), config, nullptr, surface,
getReportedColorSpace(colorSpace), cnx);
return s;
}
@@ -911,7 +910,7 @@
{
clearError();
- egl_connection_t* cnx = NULL;
+ egl_connection_t* cnx = nullptr;
const egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
if (share_list != EGL_NO_CONTEXT) {
@@ -1000,9 +999,9 @@
EGLSurface impl_read = EGL_NO_SURFACE;
// these are our objects structs passed in
- egl_context_t * c = NULL;
- egl_surface_t const * d = NULL;
- egl_surface_t const * r = NULL;
+ egl_context_t * c = nullptr;
+ egl_surface_t const * d = nullptr;
+ egl_surface_t const * r = nullptr;
// these are the current objects structs
egl_context_t * cur_c = get_context(getContext());
@@ -1016,7 +1015,7 @@
// calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
return setError(EGL_BAD_MATCH, (EGLBoolean)EGL_FALSE);
}
- if (cur_c == NULL) {
+ if (cur_c == nullptr) {
// no current context
// not an error, there is just no current context.
return EGL_TRUE;
@@ -1164,7 +1163,7 @@
static __eglMustCastToProperFunctionPointerType findBuiltinWrapper(
const char* procname) {
const egl_connection_t* cnx = &gEGLImpl;
- void* proc = NULL;
+ void* proc = nullptr;
proc = dlsym(cnx->libEgl, procname);
if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
@@ -1175,7 +1174,7 @@
proc = dlsym(cnx->libGles1, procname);
if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
- return NULL;
+ return nullptr;
}
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
@@ -1188,11 +1187,11 @@
if (egl_init_drivers() == EGL_FALSE) {
setError(EGL_BAD_PARAMETER, NULL);
- return NULL;
+ return nullptr;
}
if (FILTER_EXTENSIONS(procname)) {
- return NULL;
+ return nullptr;
}
__eglMustCastToProperFunctionPointerType addr;
@@ -1347,7 +1346,7 @@
egl_surface_t* const s = get_surface(draw);
if (CC_UNLIKELY(dp->traceGpuCompletion)) {
- EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
if (sync != EGL_NO_SYNC_KHR) {
FrameCompletionThread::queueSync(sync);
}
@@ -1398,7 +1397,7 @@
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
{
- return eglSwapBuffersWithDamageKHR(dpy, surface, NULL, 0);
+ return eglSwapBuffersWithDamageKHR(dpy, surface, nullptr, 0);
}
EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
@@ -1429,10 +1428,10 @@
// If we want to support EGL_EXT_client_extensions later, we can return
// the client extension string here instead.
if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
- return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)0);
+ return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)nullptr);
const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return (const char *) NULL;
+ if (!dp) return (const char *) nullptr;
switch (name) {
case EGL_VENDOR:
@@ -1446,7 +1445,7 @@
default:
break;
}
- return setError(EGL_BAD_PARAMETER, (const char *)0);
+ return setError(EGL_BAD_PARAMETER, (const char *)nullptr);
}
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
@@ -1454,7 +1453,7 @@
clearError();
const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return (const char *) NULL;
+ if (!dp) return (const char *) nullptr;
switch (name) {
case EGL_VENDOR:
@@ -1468,7 +1467,7 @@
default:
break;
}
- return setError(EGL_BAD_PARAMETER, (const char *)0);
+ return setError(EGL_BAD_PARAMETER, (const char *)nullptr);
}
// ----------------------------------------------------------------------------
@@ -1650,7 +1649,7 @@
{
clearError();
- egl_connection_t* cnx = NULL;
+ egl_connection_t* cnx = nullptr;
const egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (!dp) return EGL_FALSE;
if (cnx->egl.eglCreatePbufferFromClientBuffer) {
@@ -1713,31 +1712,13 @@
ContextRef _c(dp.get(), ctx);
egl_context_t * const c = _c.get();
- // Temporary hack: eglImageCreateKHR should accept EGL_GL_COLORSPACE_LINEAR_KHR,
- // EGL_GL_COLORSPACE_SRGB_KHR and EGL_GL_COLORSPACE_DEFAULT_EXT if
- // EGL_EXT_image_gl_colorspace is supported, but some drivers don't like
- // the DEFAULT value and generate an error.
- std::vector<EGLint> strippedAttribList;
- for (const EGLint *attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
- if (attr[0] == EGL_GL_COLORSPACE_KHR &&
- dp->haveExtension("EGL_EXT_image_gl_colorspace")) {
- if (attr[1] != EGL_GL_COLORSPACE_LINEAR_KHR &&
- attr[1] != EGL_GL_COLORSPACE_SRGB_KHR) {
- continue;
- }
- }
- strippedAttribList.push_back(attr[0]);
- strippedAttribList.push_back(attr[1]);
- }
- strippedAttribList.push_back(EGL_NONE);
-
EGLImageKHR result = EGL_NO_IMAGE_KHR;
egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso && cnx->egl.eglCreateImageKHR) {
result = cnx->egl.eglCreateImageKHR(
dp->disp.dpy,
c ? c->context : EGL_NO_CONTEXT,
- target, buffer, strippedAttribList.data());
+ target, buffer, attrib_list);
}
return result;
}
@@ -1954,7 +1935,7 @@
EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR(
dp->disp.dpy, config, stream, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface,
+ egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface,
EGL_GL_COLORSPACE_LINEAR_KHR, cnx);
return s;
}
@@ -2110,10 +2091,10 @@
// this function cannot be implemented when this libEGL is built for
// vendors.
#ifndef __ANDROID_VNDK__
- if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
+ if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
#else
- return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
+ return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
#endif
}
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index ec548f3..bcf4961 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -95,7 +95,7 @@
reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
cnx->egl.eglGetProcAddress(
"eglSetBlobCacheFuncsANDROID"));
- if (eglSetBlobCacheFuncsANDROID == NULL) {
+ if (eglSetBlobCacheFuncsANDROID == nullptr) {
ALOGE("EGL_ANDROID_blob_cache advertised, "
"but unable to get eglSetBlobCacheFuncsANDROID");
return;
@@ -119,7 +119,7 @@
if (mBlobCache) {
mBlobCache->writeToFile();
}
- mBlobCache = NULL;
+ mBlobCache = nullptr;
}
void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize,
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 2aec249..d16d33a 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -116,7 +116,7 @@
EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
if (uintptr_t(disp) >= NUM_DISPLAYS)
- return NULL;
+ return nullptr;
return sDisplay[uintptr_t(disp)].getDisplay(disp);
}
@@ -135,7 +135,7 @@
disp.dpy = dpy;
if (dpy == EGL_NO_DISPLAY) {
loader.close(cnx->dso);
- cnx->dso = NULL;
+ cnx->dso = nullptr;
}
}
@@ -148,9 +148,9 @@
std::unique_lock<std::mutex> _l(refLock);
refs++;
if (refs > 1) {
- if (major != NULL)
+ if (major != nullptr)
*major = VERSION_MAJOR;
- if (minor != NULL)
+ if (minor != nullptr)
*minor = VERSION_MINOR;
while(!eglIsInitialized) {
refCond.wait(_l);
@@ -240,12 +240,6 @@
if (len) {
// NOTE: we could avoid the copy if we had strnstr.
const std::string ext(start, len);
- // Temporary hack: Adreno 530 driver exposes this extension under the draft
- // KHR name, but during Khronos review it was decided to demote it to EXT.
- if (ext == "EGL_EXT_image_gl_colorspace" &&
- findExtension(disp.queryString.extensions, "EGL_KHR_image_gl_colorspace")) {
- mExtensionString.append("EGL_EXT_image_gl_colorspace ");
- }
if (findExtension(disp.queryString.extensions, ext.c_str(), len)) {
mExtensionString.append(ext + " ");
}
@@ -268,9 +262,9 @@
traceGpuCompletion = true;
}
- if (major != NULL)
+ if (major != nullptr)
*major = VERSION_MAJOR;
- if (minor != NULL)
+ if (minor != nullptr)
*minor = VERSION_MINOR;
}
@@ -361,8 +355,8 @@
// by construction, these are either 0 or valid (possibly terminated)
// it should be impossible for these to be invalid
ContextRef _cur_c(cur_c);
- SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
- SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
+ SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : nullptr);
+ SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : nullptr);
{ // scope for the lock
std::lock_guard<std::mutex> _l(lock);
@@ -387,8 +381,8 @@
// by construction, these are either 0 or valid (possibly terminated)
// it should be impossible for these to be invalid
ContextRef _cur_c(cur_c);
- SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
- SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
+ SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : nullptr);
+ SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : nullptr);
{ // scope for the lock
std::lock_guard<std::mutex> _l(lock);
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 79a9f08..f764028 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -160,7 +160,7 @@
const egl_display_t* get() const { return mDpy; }
egl_display_t* get() { return mDpy; }
- operator bool() const { return mDpy != NULL; }
+ operator bool() const { return mDpy != nullptr; }
private:
egl_display_t* mDpy;
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index f879254..ff4fe2d 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -81,14 +81,14 @@
}
egl_surface_t::~egl_surface_t() {
- if (win != NULL) {
+ if (win != nullptr) {
disconnect();
win->decStrong(this);
}
}
void egl_surface_t::disconnect() {
- if (win != NULL && connected) {
+ if (win != nullptr && connected) {
native_window_set_buffers_format(win, 0);
if (native_window_api_disconnect(win, NATIVE_WINDOW_API_EGL)) {
ALOGW("EGLNativeWindowType %p disconnect failed", win);
@@ -281,12 +281,12 @@
egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
egl_connection_t const* cnx, int version) :
egl_object_t(get_display_nowake(dpy)), dpy(dpy), context(context),
- config(config), read(0), draw(0), cnx(cnx), version(version) {
+ config(config), read(nullptr), draw(nullptr), cnx(cnx), version(version) {
}
void egl_context_t::onLooseCurrent() {
- read = NULL;
- draw = NULL;
+ read = nullptr;
+ draw = nullptr;
}
void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) {
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 4e1de5c..fb2bdf4 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -67,7 +67,7 @@
public:
~LocalRef();
explicit LocalRef(egl_object_t* rhs);
- explicit LocalRef(egl_display_t const* display, T o) : ref(0) {
+ explicit LocalRef(egl_display_t const* display, T o) : ref(nullptr) {
egl_object_t* native = reinterpret_cast<N*>(o);
if (o && egl_object_t::get(display, native)) {
ref = native;
diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp
index 8508c5f..b57c357 100644
--- a/opengl/libs/EGL/egl_tls.cpp
+++ b/opengl/libs/EGL/egl_tls.cpp
@@ -28,7 +28,7 @@
pthread_once_t egl_tls_t::sOnceKey = PTHREAD_ONCE_INIT;
egl_tls_t::egl_tls_t()
- : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(true) {
+ : error(EGL_SUCCESS), ctx(nullptr), logCallWithNoContext(true) {
}
const char *egl_tls_t::egl_strerror(EGLint err) {
@@ -55,13 +55,38 @@
void egl_tls_t::validateTLSKey()
{
struct TlsKeyInitializer {
- static void create() {
- pthread_key_create(&sKey, (void (*)(void*))&eglReleaseThread);
- }
+ static void create() { pthread_key_create(&sKey, destructTLSData); }
};
pthread_once(&sOnceKey, TlsKeyInitializer::create);
}
+void egl_tls_t::destructTLSData(void* data) {
+ egl_tls_t* tls = static_cast<egl_tls_t*>(data);
+ if (!tls) return;
+
+ // Several things in the call tree of eglReleaseThread expect to be able to get the current
+ // thread state directly from TLS. That's a problem because Bionic has already cleared our
+ // TLS pointer before calling this function (pthread_getspecific(sKey) will return nullptr).
+ // Instead the data is passed as our parameter.
+ //
+ // Ideally we'd refactor this so we have thin wrappers that retrieve thread state from TLS and
+ // then pass it as a parameter (or 'this' pointer) to functions that do the real work without
+ // touching TLS. Then from here we could just call those implementation functions with the the
+ // TLS data we just received as a parameter.
+ //
+ // But that's a fairly invasive refactoring, so to do this robustly in the short term we just
+ // put the data *back* in TLS and call the top-level eglReleaseThread. It and it's call tree
+ // will retrieve the value from TLS, and then finally clear the TLS data. Bionic explicitly
+ // tolerates re-setting the value that it's currently trying to destruct (see
+ // pthread_key_clean_all()). Even if we forgot to clear the restored TLS data, bionic would
+ // call the destructor again, but eventually gives up and just leaks the data rather than
+ // enter an infinite loop.
+ pthread_setspecific(sKey, tls);
+ eglReleaseThread();
+ ALOGE_IF(pthread_getspecific(sKey) != nullptr,
+ "EGL TLS data still exists after eglReleaseThread");
+}
+
void egl_tls_t::setErrorEtcImpl(
const char* caller, int line, EGLint error, bool quiet) {
validateTLSKey();
@@ -92,7 +117,7 @@
egl_tls_t* egl_tls_t::getTLS() {
egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
- if (tls == 0) {
+ if (tls == nullptr) {
tls = new egl_tls_t;
pthread_setspecific(sKey, tls);
}
@@ -103,7 +128,7 @@
if (sKey != TLS_KEY_NOT_INITIALIZED) {
egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
if (tls) {
- pthread_setspecific(sKey, 0);
+ pthread_setspecific(sKey, nullptr);
delete tls;
}
}
diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h
index 9feae68..86a375c 100644
--- a/opengl/libs/EGL/egl_tls.h
+++ b/opengl/libs/EGL/egl_tls.h
@@ -38,6 +38,7 @@
egl_tls_t();
static void validateTLSKey();
+ static void destructTLSData(void* data);
static void setErrorEtcImpl(
const char* caller, int line, EGLint error, bool quiet);
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 9858276..299d8f7 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -37,7 +37,7 @@
GLESv2_INDEX = 1
};
- inline egl_connection_t() : dso(0) { }
+ inline egl_connection_t() : dso(nullptr) { }
void * dso;
gl_hooks_t * hooks[2];
EGLint major;
diff --git a/opengl/libs/tools/genfiles b/opengl/libs/tools/genfiles
deleted file mode 100755
index feef318..0000000
--- a/opengl/libs/tools/genfiles
+++ /dev/null
@@ -1,50 +0,0 @@
-#! /bin/sh
-#
-# Copyright (C) 2008 Google Inc.
-#
-# 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.
-
-# Force a specific locale for sorting to avoid irrelevant differences
-# in the generated files that could hide real differences.
-export LC_ALL=POSIX
-
-./glapigen ../../include/GLES/gl.h > ../GLES_CM/gl_api.in
-./glapigen ../../include/GLES/glext.h > ../GLES_CM/glext_api.in
-./glapigen ../../include/GLES3/gl3.h > ../GLES2/gl2_api.in
-./glapigen ../../include/GLES2/gl2ext.h > ../GLES2/gl2ext_api.in
-
-./glentrygen ../../include/GLES/gl.h > /tmp/gl_entries.in
-./glentrygen ../../include/GLES/glext.h > /tmp/glext_entries.in
-./glentrygen ../../include/GLES3/gl3.h > /tmp/gl2_entries.in
-./glentrygen ../../include/GLES2/gl2ext.h > /tmp/gl2ext_entries.in
-
-# The awk command removes lines with the same function name as an earlier
-# line, even if the rest of the line differs. Although signatures of
-# functions with the same name should be the same, the different versions
-# have some irrelevant whitespace and parameter name differences.
-cat /tmp/gl_entries.in \
- /tmp/glext_entries.in \
- /tmp/gl2_entries.in \
- /tmp/gl2ext_entries.in \
- | sort -t, -k2 \
- | awk -F, '!_[$2]++' \
- > ../entries.in
-
-cat ../../include/GLES/gl.h \
- ../../include/GLES/glext.h \
- ../../include/GLES2/gl2ext.h \
- ../../include/GLES3/gl3.h \
- | ./glenumsgen \
- | sort \
- > ../enums.in
-
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
deleted file mode 100755
index 4d8334f..0000000
--- a/opengl/libs/tools/glapigen
+++ /dev/null
@@ -1,76 +0,0 @@
-#! /usr/bin/perl
-#
-# Copyright (C) 2008 Google Inc.
-#
-# 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.
-
-use strict;
-
-sub rtrim($)
-{
- my $string = shift;
- $string =~ s/\s+$//;
- return $string;
-}
-
-while (my $line = <>) {
- next if $line =~ /^\//;
- next if $line =~ /^#/;
- next if $line =~ /^\s*$/;
- if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
- next;
- }
- my $type = rtrim($2);
- my $name = $3;
- my $args = $4;
-
- #printf("%s", $line);
-
- my $prefix = "";
- if ($name eq "glGetString") {
- $prefix = "__";
- }
-
- printf("%s API_ENTRY(%s%s)(%s)", $type, $prefix, $name, $args);
-
- printf(" {\n");
- if ($type eq "void") {
- printf(" CALL_GL_API(%s", $name);
- } else {
- printf(" CALL_GL_API_RETURN(%s", $name);
- }
- my @args = split ',', $args;
- my $len = scalar(@args);
- for (my $num = 0; $num < $len; $num++) {
- if ($args[$num] ne "void") {
- print ", ";
- #
- # extract the name from the parameter
- # type name
- # const type *name
- # type *name
- # type name[4]
- #
- if ($args[$num] =~ /(\S+\s)+\**\s*([\w]+)/) {
- printf("%s", $2);
- }
- }
- }
- printf(");\n");
- printf("}\n");
-}
-
-
-
-
-
diff --git a/opengl/libs/tools/glentrygen b/opengl/libs/tools/glentrygen
deleted file mode 100755
index 170f041..0000000
--- a/opengl/libs/tools/glentrygen
+++ /dev/null
@@ -1,38 +0,0 @@
-#! /usr/bin/perl
-#
-# Copyright (C) 2008 Google Inc.
-#
-# 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.
-
-use strict;
-
-sub rtrim($)
-{
- my $string = shift;
- $string =~ s/\s+$//;
- return $string;
-}
-
-while (my $line = <>) {
- next if $line =~ /^\//;
- next if $line =~ /^#/;
- next if $line =~ /^\s*$/;
- if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
- next;
- }
- my $type = rtrim($2);
- my $name = $3;
- my $args = $4;
-
- printf("GL_ENTRY(%s, %s, %s)\n", $type, $name, $args);
-}
diff --git a/opengl/libs/tools/glenumsgen b/opengl/libs/tools/glenumsgen
deleted file mode 100755
index 2ae5fbf..0000000
--- a/opengl/libs/tools/glenumsgen
+++ /dev/null
@@ -1,38 +0,0 @@
-#! /usr/bin/perl
-#
-# Copyright (C) 2010 Google Inc.
-#
-# 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.
-
-use strict;
-
-my %enumHash = ();
-
-while (my $line = <STDIN>) {
- next if $line =~ /^\//;
- # Skip bitfield definitions.
- next if $line =~ /_BIT(\d+_|\s+)/;
- if ($line !~ /^#define\s+(\S+)\s+(0x\S+)/) {
- next;
- }
- my $enumName = $1;
- my $enumValue = $2;
- next if exists($enumHash { $enumValue });
- $enumHash { $enumValue } = $enumName;
- printf("GL_ENUM(%s,%s)\n", $enumValue, $enumName);
-}
-
-
-
-
-
diff --git a/opengl/specs/README b/opengl/specs/README
index fdafb1b..6d597d5 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -19,10 +19,7 @@
0x3145 EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync)
0x3146 EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync)
0x3147 EGL_FRAMEBUFFER_TARGET_ANDROID (EGL_ANDROID_framebuffer_target)
-0x3148 EGL_IMAGE_CROP_LEFT_ANDROID (EGL_ANDROID_image_crop)
-0x3149 EGL_IMAGE_CROP_TOP_ANDROID (EGL_ANDROID_image_crop)
-0x314A EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
-0x314B EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
+0x3148 - 0x314B previously used by the undocumented, deprecated extension EGL_ANDROID_image_crop
0x314C EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
0x314D EGL_GL_COLORSPACE_DEFAULT_EXT (EGL_EXT_image_gl_colorspace)
0x314E - 0x314F (unused)
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index 2b76279..b06422a 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -57,7 +57,7 @@
sp<SurfaceControl> sc = surfaceComposerClient->createSurface(
String8("Benchmark"), width, height,
PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
- if (sc == NULL || !sc->isValid()) {
+ if (sc == nullptr || !sc->isValid()) {
fprintf(stderr, "Failed to create SurfaceControl\n");
return;
}
diff --git a/opengl/tests/lib/glTestLib.cpp b/opengl/tests/lib/glTestLib.cpp
index 213dffd..290d7a0 100644
--- a/opengl/tests/lib/glTestLib.cpp
+++ b/opengl/tests/lib/glTestLib.cpp
@@ -37,7 +37,7 @@
{
const char *v = (const char *) glGetString(s);
- if (v == NULL) {
+ if (v == nullptr) {
testPrintI("GL %s unknown", name);
} else {
testPrintI("GL %s = %s", name, v);
diff --git a/opengl/tests/lib/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h
index 9dc6bcf..eb9571d 100644
--- a/opengl/tests/lib/include/EGLUtils.h
+++ b/opengl/tests/lib/include/EGLUtils.h
@@ -100,11 +100,11 @@
if (!attrs)
return BAD_VALUE;
- if (outConfig == NULL)
+ if (outConfig == nullptr)
return BAD_VALUE;
// Get all the "potential match" configs...
- if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
+ if (eglGetConfigs(dpy, nullptr, 0, &numConfigs) == EGL_FALSE)
return BAD_VALUE;
std::vector<EGLConfig> configs(numConfigs);
@@ -113,7 +113,7 @@
}
int i;
- EGLConfig config = NULL;
+ EGLConfig config = nullptr;
for (i=0 ; i<n ; i++) {
EGLint nativeVisualId = 0;
eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
@@ -243,7 +243,7 @@
bool EGLUtils::printEGLConfigurations(EGLDisplay dpy, String8& msg) {
EGLint numConfig = 0;
- EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
+ EGLint returnVal = eglGetConfigs(dpy, nullptr, 0, &numConfig);
msg.append(checkEglError("eglGetConfigs", returnVal));
if (!returnVal) {
return false;
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index a9e5a43..45efb9f 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -15,6 +15,8 @@
cc_library_shared {
name: "libinputflinger",
+ cpp_std: "c++17",
+
srcs: [
"EventHub.cpp",
"InputApplication.cpp",
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 4d9a2a0..a964d29 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -76,16 +76,16 @@
return value ? "true" : "false";
}
-static String8 sha1(const String8& in) {
+static std::string sha1(const std::string& in) {
SHA_CTX ctx;
SHA1_Init(&ctx);
- SHA1_Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size());
+ SHA1_Update(&ctx, reinterpret_cast<const u_char*>(in.c_str()), in.size());
u_char digest[SHA_DIGEST_LENGTH];
SHA1_Final(digest, &ctx);
- String8 out;
+ std::string out;
for (size_t i = 0; i < SHA_DIGEST_LENGTH; i++) {
- out.appendFormat("%02x", digest[i]);
+ out += StringPrintf("%02x", digest[i]);
}
return out;
}
@@ -141,11 +141,11 @@
// --- EventHub::Device ---
-EventHub::Device::Device(int fd, int32_t id, const String8& path,
+EventHub::Device::Device(int fd, int32_t id, const std::string& path,
const InputDeviceIdentifier& identifier) :
- next(NULL),
+ next(nullptr),
fd(fd), id(id), path(path), identifier(identifier),
- classes(0), configuration(NULL), virtualKeyMap(NULL),
+ classes(0), configuration(nullptr), virtualKeyMap(nullptr),
ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true),
isVirtual(fd < 0) {
@@ -172,9 +172,9 @@
}
status_t EventHub::Device::enable() {
- fd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+ fd = open(path.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
if(fd < 0) {
- ALOGE("could not open %s, %s\n", path.string(), strerror(errno));
+ ALOGE("could not open %s, %s\n", path.c_str(), strerror(errno));
return -errno;
}
enabled = true;
@@ -200,7 +200,7 @@
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
- mOpeningDevices(0), mClosingDevices(0),
+ mOpeningDevices(nullptr), mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
@@ -267,21 +267,21 @@
InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device == NULL) return InputDeviceIdentifier();
+ if (device == nullptr) return InputDeviceIdentifier();
return device->identifier;
}
uint32_t EventHub::getDeviceClasses(int32_t deviceId) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device == NULL) return 0;
+ if (device == nullptr) return 0;
return device->classes;
}
int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device == NULL) return 0;
+ if (device == nullptr) return 0;
return device->controllerNumber;
}
@@ -307,7 +307,7 @@
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
- axis, device->identifier.name.string(), device->fd, errno);
+ axis, device->identifier.name.c_str(), device->fd, errno);
return -errno;
}
@@ -416,7 +416,7 @@
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
- axis, device->identifier.name.string(), device->fd, errno);
+ axis, device->identifier.name.c_str(), device->fd, errno);
return -errno;
}
@@ -465,7 +465,7 @@
if (device) {
// Check the key character map first.
sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
- if (kcm != NULL) {
+ if (kcm != nullptr) {
if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
*outFlags = 0;
status = NO_ERROR;
@@ -481,7 +481,7 @@
}
if (status == NO_ERROR) {
- if (kcm != NULL) {
+ if (kcm != nullptr) {
kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
} else {
*outMetaState = metaState;
@@ -512,7 +512,7 @@
return NAME_NOT_FOUND;
}
-void EventHub::setExcludedDevices(const Vector<String8>& devices) {
+void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
AutoMutex _l(mLock);
mExcludedDevices = devices;
@@ -581,7 +581,7 @@
if (device) {
return device->getKeyCharacterMap();
}
- return NULL;
+ return nullptr;
}
bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId,
@@ -599,16 +599,16 @@
return false;
}
-static String8 generateDescriptor(InputDeviceIdentifier& identifier) {
- String8 rawDescriptor;
- rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor,
+static std::string generateDescriptor(InputDeviceIdentifier& identifier) {
+ std::string rawDescriptor;
+ rawDescriptor += StringPrintf(":%04x:%04x:", identifier.vendor,
identifier.product);
// TODO add handling for USB devices to not uniqueify kbs that show up twice
- if (!identifier.uniqueId.isEmpty()) {
- rawDescriptor.append("uniqueId:");
- rawDescriptor.append(identifier.uniqueId);
+ if (!identifier.uniqueId.empty()) {
+ rawDescriptor += "uniqueId:";
+ rawDescriptor += identifier.uniqueId;
} else if (identifier.nonce != 0) {
- rawDescriptor.appendFormat("nonce:%04x", identifier.nonce);
+ rawDescriptor += StringPrintf("nonce:%04x", identifier.nonce);
}
if (identifier.vendor == 0 && identifier.product == 0) {
@@ -616,12 +616,12 @@
// built-in so we need to rely on other information to uniquely identify
// the input device. Usually we try to avoid relying on the device name or
// location but for built-in input device, they are unlikely to ever change.
- if (!identifier.name.isEmpty()) {
- rawDescriptor.append("name:");
- rawDescriptor.append(identifier.name);
- } else if (!identifier.location.isEmpty()) {
- rawDescriptor.append("location:");
- rawDescriptor.append(identifier.location);
+ if (!identifier.name.empty()) {
+ rawDescriptor += "name:";
+ rawDescriptor += identifier.name;
+ } else if (!identifier.location.empty()) {
+ rawDescriptor += "location:";
+ rawDescriptor += identifier.location;
}
}
identifier.descriptor = sha1(rawDescriptor);
@@ -637,17 +637,17 @@
// Ideally, we also want the descriptor to be short and relatively opaque.
identifier.nonce = 0;
- String8 rawDescriptor = generateDescriptor(identifier);
- if (identifier.uniqueId.isEmpty()) {
+ std::string rawDescriptor = generateDescriptor(identifier);
+ if (identifier.uniqueId.empty()) {
// If it didn't have a unique id check for conflicts and enforce
// uniqueness if necessary.
- while(getDeviceByDescriptorLocked(identifier.descriptor) != NULL) {
+ while(getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) {
identifier.nonce++;
rawDescriptor = generateDescriptor(identifier);
}
}
- ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.string(),
- identifier.descriptor.string());
+ ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.c_str(),
+ identifier.descriptor.c_str());
}
void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
@@ -664,7 +664,7 @@
effect.replay.delay = 0;
if (ioctl(device->fd, EVIOCSFF, &effect)) {
ALOGW("Could not upload force feedback effect to device %s due to error %d.",
- device->identifier.name.string(), errno);
+ device->identifier.name.c_str(), errno);
return;
}
device->ffEffectId = effect.id;
@@ -677,7 +677,7 @@
ev.value = 1;
if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
ALOGW("Could not start force feedback effect on device %s due to error %d.",
- device->identifier.name.string(), errno);
+ device->identifier.name.c_str(), errno);
return;
}
device->ffEffectPlaying = true;
@@ -699,22 +699,22 @@
ev.value = 0;
if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
ALOGW("Could not stop force feedback effect on device %s due to error %d.",
- device->identifier.name.string(), errno);
+ device->identifier.name.c_str(), errno);
return;
}
}
}
}
-EventHub::Device* EventHub::getDeviceByDescriptorLocked(String8& descriptor) const {
+EventHub::Device* EventHub::getDeviceByDescriptorLocked(const std::string& descriptor) const {
size_t size = mDevices.size();
for (size_t i = 0; i < size; i++) {
Device* device = mDevices.valueAt(i);
- if (descriptor.compare(device->identifier.descriptor) == 0) {
+ if (descriptor == device->identifier.descriptor) {
return device;
}
}
- return NULL;
+ return nullptr;
}
EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
@@ -732,7 +732,7 @@
return device;
}
}
- return NULL;
+ return nullptr;
}
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
@@ -763,7 +763,7 @@
while (mClosingDevices) {
Device* device = mClosingDevices;
ALOGV("Reporting device closed: id=%d, name=%s\n",
- device->id, device->path.string());
+ device->id, device->path.c_str());
mClosingDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
@@ -782,10 +782,10 @@
mNeedToSendFinishedDeviceScan = true;
}
- while (mOpeningDevices != NULL) {
+ while (mOpeningDevices != nullptr) {
Device* device = mOpeningDevices;
ALOGV("Reporting device opened: id=%d, name=%s\n",
- device->id, device->path.string());
+ device->id, device->path.c_str());
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
@@ -867,7 +867,7 @@
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",
- device->path.string(),
+ device->path.c_str(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
@@ -936,7 +936,7 @@
"event time %" PRId64 ", current time %" PRId64
", call time %" PRId64 ". "
"Using current time instead.",
- device->path.string(), event->when, time, now);
+ device->path.c_str(), event->when, time, now);
event->when = time;
} else {
ALOGV("Event time is ok but failed the fast path and required "
@@ -962,12 +962,12 @@
}
} else if (eventItem.events & EPOLLHUP) {
ALOGI("Removing device %s due to epoll hang-up event.",
- device->identifier.name.string());
+ device->identifier.name.c_str());
deviceChanged = true;
closeDeviceLocked(device);
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.",
- eventItem.events, device->identifier.name.string());
+ eventItem.events, device->identifier.name.c_str());
}
}
@@ -1099,7 +1099,7 @@
status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) {
if (device->hasValidFd()) {
- if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
+ if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, nullptr)) {
ALOGW("Could not remove device fd from epoll instance. errno=%d", errno);
return -errno;
}
@@ -1125,14 +1125,14 @@
//fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
- identifier.name.setTo(buffer);
+ identifier.name = buffer;
}
// Check to see if the device is on our excluded list
for (size_t i = 0; i < mExcludedDevices.size(); i++) {
- const String8& item = mExcludedDevices.itemAt(i);
+ const std::string& item = mExcludedDevices[i];
if (identifier.name == item) {
- ALOGI("ignoring event id %s driver %s\n", devicePath, item.string());
+ ALOGI("ignoring event id %s driver %s\n", devicePath, item.c_str());
close(fd);
return -1;
}
@@ -1163,7 +1163,7 @@
//fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
- identifier.location.setTo(buffer);
+ identifier.location = buffer;
}
// Get device unique id.
@@ -1171,7 +1171,7 @@
//fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
- identifier.uniqueId.setTo(buffer);
+ identifier.uniqueId = buffer;
}
// Fill in the descriptor.
@@ -1179,7 +1179,7 @@
// Allocate device. (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
- Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
+ Device* device = new Device(fd, deviceId, devicePath, identifier);
ALOGV("add device %d: %s\n", deviceId, devicePath);
ALOGV(" bus: %04x\n"
@@ -1187,10 +1187,10 @@
" product %04x\n"
" version %04x\n",
identifier.bus, identifier.vendor, identifier.product, identifier.version);
- ALOGV(" name: \"%s\"\n", identifier.name.string());
- ALOGV(" location: \"%s\"\n", identifier.location.string());
- ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.string());
- ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.string());
+ ALOGV(" name: \"%s\"\n", identifier.name.c_str());
+ ALOGV(" location: \"%s\"\n", identifier.location.c_str());
+ ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.c_str());
+ ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.c_str());
ALOGV(" driver: v%d.%d.%d\n",
driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
@@ -1343,7 +1343,7 @@
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
ALOGV("Dropping device: id=%d, path='%s', name='%s'",
- deviceId, devicePath, device->identifier.name.string());
+ deviceId, devicePath, device->identifier.name.c_str());
delete device;
return -1;
}
@@ -1374,11 +1374,11 @@
ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
- deviceId, fd, devicePath, device->identifier.name.string(),
+ deviceId, fd, devicePath, device->identifier.name.c_str(),
device->classes,
- device->configurationFile.string(),
- device->keyMap.keyLayoutFile.string(),
- device->keyMap.keyCharacterMapFile.string(),
+ device->configurationFile.c_str(),
+ device->keyMap.keyLayoutFile.c_str(),
+ device->keyMap.keyCharacterMapFile.c_str(),
toString(mBuiltInKeyboardId == deviceId));
addDeviceLocked(device);
@@ -1392,11 +1392,11 @@
unsigned int repeatRate[] = {0, 0};
if (ioctl(device->fd, EVIOCSREP, repeatRate)) {
ALOGW("Unable to disable kernel key repeat for %s: %s",
- device->path.string(), strerror(errno));
+ device->path.c_str(), strerror(errno));
}
}
- String8 wakeMechanism("EPOLLWAKEUP");
+ std::string wakeMechanism = "EPOLLWAKEUP";
if (!mUsingEpollWakeup) {
#ifndef EVIOCSSUSPENDBLOCK
// uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels
@@ -1416,14 +1416,14 @@
// clock.
int clockId = CLOCK_MONOTONIC;
bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId);
- ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.string(),
+ ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(),
toString(usingClockIoctl));
}
bool EventHub::isDeviceEnabled(int32_t deviceId) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device == NULL) {
+ if (device == nullptr) {
ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
return false;
}
@@ -1433,7 +1433,7 @@
status_t EventHub::enableDevice(int32_t deviceId) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device == NULL) {
+ if (device == nullptr) {
ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
return BAD_VALUE;
}
@@ -1455,7 +1455,7 @@
status_t EventHub::disableDevice(int32_t deviceId) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device == NULL) {
+ if (device == nullptr) {
ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
return BAD_VALUE;
}
@@ -1473,7 +1473,7 @@
identifier.uniqueId = "<virtual>";
assignDescriptorLocked(identifier);
- Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8("<virtual>"), identifier);
+ Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, "<virtual>", identifier);
device->classes = INPUT_DEVICE_CLASS_KEYBOARD
| INPUT_DEVICE_CLASS_ALPHAKEY
| INPUT_DEVICE_CLASS_DPAD
@@ -1491,26 +1491,26 @@
void EventHub::loadConfigurationLocked(Device* device) {
device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
- if (device->configurationFile.isEmpty()) {
+ if (device->configurationFile.empty()) {
ALOGD("No input device configuration file found for device '%s'.",
- device->identifier.name.string());
+ device->identifier.name.c_str());
} else {
- status_t status = PropertyMap::load(device->configurationFile,
+ status_t status = PropertyMap::load(String8(device->configurationFile.c_str()),
&device->configuration);
if (status) {
ALOGE("Error loading input device configuration file for device '%s'. "
"Using default configuration.",
- device->identifier.name.string());
+ device->identifier.name.c_str());
}
}
}
status_t EventHub::loadVirtualKeyMapLocked(Device* device) {
// The virtual key map is supplied by the kernel as a system board property file.
- String8 path;
- path.append("/sys/board_properties/virtualkeys.");
- path.append(device->identifier.name);
- if (access(path.string(), R_OK)) {
+ std::string path;
+ path += "/sys/board_properties/virtualkeys.";
+ path += device->identifier.name;
+ if (access(path.c_str(), R_OK)) {
return NAME_NOT_FOUND;
}
return VirtualKeyMap::load(path, &device->virtualKeyMap);
@@ -1543,7 +1543,7 @@
int32_t EventHub::getNextControllerNumberLocked(Device* device) {
if (mControllerNumbers.isFull()) {
ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
- device->identifier.name.string());
+ device->identifier.name.c_str());
return 0;
}
// Since the controller number 0 is reserved for non-controllers, translate all numbers up by
@@ -1617,12 +1617,12 @@
void EventHub::closeDeviceLocked(Device* device) {
ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
- device->path.string(), device->identifier.name.string(), device->id,
+ device->path.c_str(), device->identifier.name.c_str(), device->id,
device->fd, device->classes);
if (device->id == mBuiltInKeyboardId) {
ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
- device->path.string(), mBuiltInKeyboardId);
+ device->path.c_str(), mBuiltInKeyboardId);
mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
}
@@ -1634,9 +1634,9 @@
device->close();
// Unlink for opening devices list if it is present.
- Device* pred = NULL;
+ Device* pred = nullptr;
bool found = false;
- for (Device* entry = mOpeningDevices; entry != NULL; ) {
+ for (Device* entry = mOpeningDevices; entry != nullptr; ) {
if (entry == device) {
found = true;
break;
@@ -1648,7 +1648,7 @@
// Unlink the device from the opening devices list then delete it.
// We don't need to tell the client that the device was closed because
// it does not even know it was opened in the first place.
- ALOGI("Device %s was immediately closed after opening.", device->path.string());
+ ALOGI("Device %s was immediately closed after opening.", device->path.c_str());
if (pred) {
pred->next = device->next;
} else {
@@ -1712,7 +1712,7 @@
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
- if(dir == NULL)
+ if(dir == nullptr)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
@@ -1750,30 +1750,30 @@
const Device* device = mDevices.valueAt(i);
if (mBuiltInKeyboardId == device->id) {
dump += StringPrintf(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
- device->id, device->identifier.name.string());
+ device->id, device->identifier.name.c_str());
} else {
dump += StringPrintf(INDENT2 "%d: %s\n", device->id,
- device->identifier.name.string());
+ device->identifier.name.c_str());
}
dump += StringPrintf(INDENT3 "Classes: 0x%08x\n", device->classes);
- dump += StringPrintf(INDENT3 "Path: %s\n", device->path.string());
+ dump += StringPrintf(INDENT3 "Path: %s\n", device->path.c_str());
dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(device->enabled));
- dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
- dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.string());
+ dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.c_str());
+ dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.c_str());
dump += StringPrintf(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
- dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
+ dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.c_str());
dump += StringPrintf(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
"product=0x%04x, version=0x%04x\n",
device->identifier.bus, device->identifier.vendor,
device->identifier.product, device->identifier.version);
dump += StringPrintf(INDENT3 "KeyLayoutFile: %s\n",
- device->keyMap.keyLayoutFile.string());
+ device->keyMap.keyLayoutFile.c_str());
dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n",
- device->keyMap.keyCharacterMapFile.string());
+ device->keyMap.keyCharacterMapFile.c_str());
dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n",
- device->configurationFile.string());
+ device->configurationFile.c_str());
dump += StringPrintf(INDENT3 "HaveKeyboardLayoutOverlay: %s\n",
- toString(device->overlayKeyMap != NULL));
+ toString(device->overlayKeyMap != nullptr));
}
} // release lock
}
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 66bc294..ea663b7 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -18,6 +18,8 @@
#ifndef _RUNTIME_EVENT_HUB_H
#define _RUNTIME_EVENT_HUB_H
+#include <vector>
+
#include <input/Input.h>
#include <input/InputDevice.h>
#include <input/Keyboard.h>
@@ -29,7 +31,6 @@
#include <utils/List.h>
#include <utils/Errors.h>
#include <utils/PropertyMap.h>
-#include <utils/Vector.h>
#include <utils/KeyedVector.h>
#include <utils/BitSet.h>
@@ -207,7 +208,7 @@
// Sets devices that are excluded from opening.
// This can be used to ignore input devices for sensors.
- virtual void setExcludedDevices(const Vector<String8>& devices) = 0;
+ virtual void setExcludedDevices(const std::vector<std::string>& devices) = 0;
/*
* Wait for events to become available and returns them.
@@ -303,7 +304,7 @@
virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
AxisInfo* outAxisInfo) const;
- virtual void setExcludedDevices(const Vector<String8>& devices);
+ virtual void setExcludedDevices(const std::vector<std::string>& devices);
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
@@ -344,7 +345,7 @@
int fd; // may be -1 if device is closed
const int32_t id;
- const String8 path;
+ const std::string path;
const InputDeviceIdentifier identifier;
uint32_t classes;
@@ -357,7 +358,7 @@
uint8_t ffBitmask[(FF_MAX + 1) / 8];
uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
- String8 configurationFile;
+ std::string configurationFile;
PropertyMap* configuration;
VirtualKeyMap* virtualKeyMap;
KeyMap keyMap;
@@ -373,7 +374,8 @@
int32_t timestampOverrideSec;
int32_t timestampOverrideUsec;
- Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
+ Device(int fd, int32_t id, const std::string& path,
+ const InputDeviceIdentifier& identifier);
~Device();
void close();
@@ -385,7 +387,7 @@
const bool isVirtual; // set if fd < 0 is passed to constructor
const sp<KeyCharacterMap>& getKeyCharacterMap() const {
- if (combinedKeyMap != NULL) {
+ if (combinedKeyMap != nullptr) {
return combinedKeyMap;
}
return keyMap.keyCharacterMap;
@@ -413,7 +415,7 @@
void scanDevicesLocked();
status_t readNotifyLocked();
- Device* getDeviceByDescriptorLocked(String8& descriptor) const;
+ Device* getDeviceByDescriptorLocked(const std::string& descriptor) const;
Device* getDeviceLocked(int32_t deviceId) const;
Device* getDeviceByPathLocked(const char* devicePath) const;
@@ -457,7 +459,7 @@
bool mNeedToSendFinishedDeviceScan;
bool mNeedToReopenDevices;
bool mNeedToScanDevices;
- Vector<String8> mExcludedDevices;
+ std::vector<std::string> mExcludedDevices;
int mEpollFd;
int mINotifyFd;
diff --git a/services/inputflinger/InputApplication.cpp b/services/inputflinger/InputApplication.cpp
index 9e90631..c56dfe6 100644
--- a/services/inputflinger/InputApplication.cpp
+++ b/services/inputflinger/InputApplication.cpp
@@ -25,7 +25,7 @@
// --- InputApplicationHandle ---
InputApplicationHandle::InputApplicationHandle() :
- mInfo(NULL) {
+ mInfo(nullptr) {
}
InputApplicationHandle::~InputApplicationHandle() {
@@ -35,7 +35,7 @@
void InputApplicationHandle::releaseInfo() {
if (mInfo) {
delete mInfo;
- mInfo = NULL;
+ mInfo = nullptr;
}
}
diff --git a/services/inputflinger/InputApplication.h b/services/inputflinger/InputApplication.h
index 724fc2c..9b365b9 100644
--- a/services/inputflinger/InputApplication.h
+++ b/services/inputflinger/InputApplication.h
@@ -17,6 +17,8 @@
#ifndef _UI_INPUT_APPLICATION_H
#define _UI_INPUT_APPLICATION_H
+#include <string>
+
#include <input/Input.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 9a449fa..d609573 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -240,14 +240,14 @@
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
- mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
+ mPendingEvent(nullptr), mLastDropReason(DROP_REASON_NOT_DROPPED),
mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
- mNextUnblockedEvent(NULL),
+ mNextUnblockedEvent(nullptr),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);
- mKeyRepeatState.lastKeyEntry = NULL;
+ mKeyRepeatState.lastKeyEntry = nullptr;
policy->getDispatcherConfiguration(&mConfig);
}
@@ -360,7 +360,7 @@
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
- ALOG_ASSERT(mPendingEvent != NULL);
+ ALOG_ASSERT(mPendingEvent != nullptr);
bool done = false;
DropReason dropReason = DROP_REASON_NOT_DROPPED;
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
@@ -370,7 +370,7 @@
}
if (mNextUnblockedEvent == mPendingEvent) {
- mNextUnblockedEvent = NULL;
+ mNextUnblockedEvent = nullptr;
}
switch (mPendingEvent->type) {
@@ -481,14 +481,14 @@
if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
- && mInputTargetWaitApplicationHandle != NULL) {
+ && mInputTargetWaitApplicationHandle != nullptr) {
int32_t displayId = motionEntry->displayId;
int32_t x = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
- if (touchedWindowHandle != NULL
+ if (touchedWindowHandle != nullptr
&& touchedWindowHandle->inputApplicationHandle
!= mInputTargetWaitApplicationHandle) {
// User touched a different application than the one we are waiting on.
@@ -515,9 +515,10 @@
sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
int32_t x, int32_t y) {
// Traverse windows from front to back to find touched window.
- size_t numWindows = mWindowHandles.size();
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId == displayId) {
int32_t flags = windowInfo->layoutParamsFlags;
@@ -534,7 +535,7 @@
}
}
}
- return NULL;
+ return nullptr;
}
void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
@@ -663,7 +664,7 @@
if (mPendingEvent) {
resetANRTimeoutsLocked();
releaseInboundEventLocked(mPendingEvent);
- mPendingEvent = NULL;
+ mPendingEvent = nullptr;
}
}
@@ -676,7 +677,7 @@
setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
}
if (entry == mNextUnblockedEvent) {
- mNextUnblockedEvent = NULL;
+ mNextUnblockedEvent = nullptr;
}
addRecentEventLocked(entry);
entry->release();
@@ -685,7 +686,7 @@
void InputDispatcher::resetKeyRepeatLocked() {
if (mKeyRepeatState.lastKeyEntry) {
mKeyRepeatState.lastKeyEntry->release();
- mKeyRepeatState.lastKeyEntry = NULL;
+ mKeyRepeatState.lastKeyEntry = nullptr;
}
}
@@ -702,7 +703,7 @@
entry->repeatCount += 1;
} else {
KeyEntry* newEntry = new KeyEntry(currentTime,
- entry->deviceId, entry->source, policyFlags,
+ entry->deviceId, entry->source, entry->displayId, policyFlags,
entry->action, entry->flags, entry->keyCode, entry->scanCode,
entry->metaState, entry->repeatCount + 1, entry->downTime);
@@ -807,7 +808,7 @@
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
- if (mFocusedWindowHandle != NULL) {
+ if (mFocusedWindowHandle != nullptr) {
commandEntry->inputWindowHandle = mFocusedWindowHandle;
}
commandEntry->keyEntry = entry;
@@ -851,11 +852,11 @@
void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
- "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, "
- "repeatCount=%d, downTime=%" PRId64,
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
+ "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
+ "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
prefix,
- entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
+ entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags,
entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
entry->repeatCount, entry->downTime);
#endif
@@ -924,12 +925,13 @@
void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+ ", policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, "
"metaState=0x%x, buttonState=0x%x,"
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
prefix,
- entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
+ entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags,
entry->action, entry->actionButton, entry->flags,
entry->metaState, entry->buttonState,
entry->edgeFlags, entry->xPrecision, entry->yPrecision,
@@ -987,7 +989,7 @@
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime, const char* reason) {
- if (applicationHandle == NULL && windowHandle == NULL) {
+ if (applicationHandle == nullptr && windowHandle == nullptr) {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
#if DEBUG_FOCUS
ALOGD("Waiting for system to become ready for input. Reason: %s", reason);
@@ -1006,9 +1008,9 @@
reason);
#endif
nsecs_t timeout;
- if (windowHandle != NULL) {
+ if (windowHandle != nullptr) {
timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
- } else if (applicationHandle != NULL) {
+ } else if (applicationHandle != nullptr) {
timeout = applicationHandle->getDispatchingTimeout(
DEFAULT_INPUT_DISPATCHING_TIMEOUT);
} else {
@@ -1021,10 +1023,10 @@
mInputTargetWaitTimeoutExpired = false;
mInputTargetWaitApplicationHandle.clear();
- if (windowHandle != NULL) {
+ if (windowHandle != nullptr) {
mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
}
- if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
+ if (mInputTargetWaitApplicationHandle == nullptr && applicationHandle != nullptr) {
mInputTargetWaitApplicationHandle = applicationHandle;
}
}
@@ -1067,7 +1069,7 @@
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
sp<InputWindowHandle> windowHandle = connection->inputWindowHandle;
- if (windowHandle != NULL) {
+ if (windowHandle != nullptr) {
const InputWindowInfo* info = windowHandle->getInfo();
if (info) {
ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(info->displayId);
@@ -1113,10 +1115,10 @@
// If there is no currently focused window and no focused application
// then drop the event.
- if (mFocusedWindowHandle == NULL) {
- if (mFocusedApplicationHandle != NULL) {
+ if (mFocusedWindowHandle == nullptr) {
+ if (mFocusedApplicationHandle != nullptr) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplicationHandle, NULL, nextWakeupTime,
+ mFocusedApplicationHandle, nullptr, nextWakeupTime,
"Waiting because no window has focus but there is a "
"focused application that may eventually add a window "
"when it finishes starting up.");
@@ -1186,7 +1188,7 @@
// Copy current touch state into mTempTouchState.
// This state is always reset at the end of this function, so if we don't find state
// for the specified display then our initial state will be empty.
- const TouchState* oldState = NULL;
+ const TouchState* oldState = nullptr;
ssize_t oldStateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
if (oldStateIndex >= 0) {
oldState = &mTouchStatesByDisplay.valueAt(oldStateIndex);
@@ -1246,9 +1248,10 @@
bool isTouchModal = false;
// Traverse windows from front to back to find touched window and outside targets.
- size_t numWindows = mWindowHandles.size();
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId != displayId) {
continue; // wrong display
@@ -1274,21 +1277,21 @@
}
// Figure out whether splitting will be allowed for this window.
- if (newTouchedWindowHandle != NULL
+ if (newTouchedWindowHandle != nullptr
&& newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
// New window supports splitting.
isSplit = true;
} else if (isSplit) {
// New window does not support splitting but we have already split events.
// Ignore the new window.
- newTouchedWindowHandle = NULL;
+ newTouchedWindowHandle = nullptr;
}
// Handle the case where we did not find a window.
- if (newTouchedWindowHandle == NULL) {
+ if (newTouchedWindowHandle == nullptr) {
// Try to assign the pointer to the first foreground window we find, if there is one.
newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
- if (newTouchedWindowHandle == NULL) {
+ if (newTouchedWindowHandle == nullptr) {
ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y);
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
@@ -1345,7 +1348,7 @@
sp<InputWindowHandle> newTouchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y);
if (oldTouchedWindowHandle != newTouchedWindowHandle
- && newTouchedWindowHandle != NULL) {
+ && newTouchedWindowHandle != nullptr) {
#if DEBUG_FOCUS
ALOGD("Touch is slipping out of window %s into window %s.",
oldTouchedWindowHandle->getName().c_str(),
@@ -1380,7 +1383,7 @@
if (newHoverWindowHandle != mLastHoverWindowHandle) {
// Let the previous window know that the hover sequence is over.
- if (mLastHoverWindowHandle != NULL) {
+ if (mLastHoverWindowHandle != nullptr) {
#if DEBUG_HOVER
ALOGD("Sending hover exit event to window %s.",
mLastHoverWindowHandle->getName().c_str());
@@ -1390,7 +1393,7 @@
}
// Let the new window know that the hover sequence is starting.
- if (newHoverWindowHandle != NULL) {
+ if (newHoverWindowHandle != nullptr) {
#if DEBUG_HOVER
ALOGD("Sending hover enter event to window %s.",
newHoverWindowHandle->getName().c_str());
@@ -1455,7 +1458,7 @@
touchedWindow.windowHandle, entry, "touched");
if (!reason.empty()) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- NULL, touchedWindow.windowHandle, nextWakeupTime, reason.c_str());
+ nullptr, touchedWindow.windowHandle, nextWakeupTime, reason.c_str());
goto Unresponsive;
}
}
@@ -1471,8 +1474,10 @@
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
if (foregroundWindowHandle->getInfo()->hasWallpaper) {
- for (size_t i = 0; i < mWindowHandles.size(); i++) {
- sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ size_t numWindows = windowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
const InputWindowInfo* info = windowHandle->getInfo();
if (info->displayId == displayId
&& windowHandle->getInfo()->layoutParamsType
@@ -1503,7 +1508,7 @@
Failed:
// Check injection permission once and for all.
if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
- if (checkInjectionPermission(NULL, entry->injectionState)) {
+ if (checkInjectionPermission(nullptr, entry->injectionState)) {
injectionPermission = INJECTION_PERMISSION_GRANTED;
} else {
injectionPermission = INJECTION_PERMISSION_DENIED;
@@ -1636,10 +1641,10 @@
bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState) {
if (injectionState
- && (windowHandle == NULL
+ && (windowHandle == nullptr
|| windowHandle->getInfo()->ownerUid != injectionState->injectorUid)
&& !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
- if (windowHandle != NULL) {
+ if (windowHandle != nullptr) {
ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
"owned by uid %d",
injectionState->injectorPid, injectionState->injectorUid,
@@ -1657,9 +1662,10 @@
bool InputDispatcher::isWindowObscuredAtPointLocked(
const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
int32_t displayId = windowHandle->getInfo()->displayId;
- size_t numWindows = mWindowHandles.size();
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+ sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
if (otherHandle == windowHandle) {
break;
}
@@ -1677,10 +1683,11 @@
bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
int32_t displayId = windowHandle->getInfo()->displayId;
+ const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
- size_t numWindows = mWindowHandles.size();
+ size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+ sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
if (otherHandle == windowHandle) {
break;
}
@@ -1778,8 +1785,8 @@
std::string InputDispatcher::getApplicationWindowLabelLocked(
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle) {
- if (applicationHandle != NULL) {
- if (windowHandle != NULL) {
+ if (applicationHandle != nullptr) {
+ if (windowHandle != nullptr) {
std::string label(applicationHandle->getName());
label += " - ";
label += windowHandle->getName();
@@ -1787,7 +1794,7 @@
} else {
return applicationHandle->getName();
}
- } else if (windowHandle != NULL) {
+ } else if (windowHandle != nullptr) {
return windowHandle->getName();
} else {
return "<unknown application or window>";
@@ -1795,7 +1802,7 @@
}
void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
- if (mFocusedWindowHandle != NULL) {
+ if (mFocusedWindowHandle != nullptr) {
const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
#if DEBUG_DISPATCH_CYCLE
@@ -2017,7 +2024,7 @@
// Publish the key event.
status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
- keyEntry->deviceId, keyEntry->source,
+ keyEntry->deviceId, keyEntry->source, keyEntry->displayId,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
keyEntry->keyCode, keyEntry->scanCode,
keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
@@ -2291,7 +2298,7 @@
InputTarget target;
sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
- if (windowHandle != NULL) {
+ if (windowHandle != nullptr) {
const InputWindowInfo* windowInfo = windowHandle->getInfo();
target.xOffset = -windowInfo->frameLeft;
target.yOffset = -windowInfo->frameTop;
@@ -2349,7 +2356,7 @@
"we expected there to be %d pointers. This probably means we received "
"a broken sequence of pointer ids from the input device.",
splitPointerCount, pointerIds.count());
- return NULL;
+ return nullptr;
}
int32_t action = originalMotionEntry->action;
@@ -2384,6 +2391,7 @@
originalMotionEntry->eventTime,
originalMotionEntry->deviceId,
originalMotionEntry->source,
+ originalMotionEntry->displayId,
originalMotionEntry->policyFlags,
action,
originalMotionEntry->actionButton,
@@ -2394,7 +2402,6 @@
originalMotionEntry->xPrecision,
originalMotionEntry->yPrecision,
originalMotionEntry->downTime,
- originalMotionEntry->displayId,
splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
if (originalMotionEntry->injectionState) {
@@ -2423,12 +2430,49 @@
}
}
+/**
+ * If one of the meta shortcuts is detected, process them here:
+ * Meta + Backspace -> generate BACK
+ * Meta + Enter -> generate HOME
+ * This will potentially overwrite keyCode and metaState.
+ */
+void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int32_t action,
+ int32_t& keyCode, int32_t& metaState) {
+ if (metaState & AMETA_META_ON && action == AKEY_EVENT_ACTION_DOWN) {
+ int32_t newKeyCode = AKEYCODE_UNKNOWN;
+ if (keyCode == AKEYCODE_DEL) {
+ newKeyCode = AKEYCODE_BACK;
+ } else if (keyCode == AKEYCODE_ENTER) {
+ newKeyCode = AKEYCODE_HOME;
+ }
+ if (newKeyCode != AKEYCODE_UNKNOWN) {
+ AutoMutex _l(mLock);
+ struct KeyReplacement replacement = {keyCode, deviceId};
+ mReplacedKeys.add(replacement, newKeyCode);
+ keyCode = newKeyCode;
+ metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
+ }
+ } else if (action == AKEY_EVENT_ACTION_UP) {
+ // In order to maintain a consistent stream of up and down events, check to see if the key
+ // going up is one we've replaced in a down event and haven't yet replaced in an up event,
+ // even if the modifier was released between the down and the up events.
+ AutoMutex _l(mLock);
+ struct KeyReplacement replacement = {keyCode, deviceId};
+ ssize_t index = mReplacedKeys.indexOfKey(replacement);
+ if (index >= 0) {
+ keyCode = mReplacedKeys.valueAt(index);
+ mReplacedKeys.removeItemsAt(index);
+ metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
+ }
+ }
+}
+
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyKey - eventTime=%" PRId64
- ", deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
+ ", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
- args->eventTime, args->deviceId, args->source, args->policyFlags,
+ args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->flags, args->keyCode, args->scanCode,
args->metaState, args->downTime);
#endif
@@ -2450,36 +2494,10 @@
policyFlags |= POLICY_FLAG_TRUSTED;
int32_t keyCode = args->keyCode;
- if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) {
- int32_t newKeyCode = AKEYCODE_UNKNOWN;
- if (keyCode == AKEYCODE_DEL) {
- newKeyCode = AKEYCODE_BACK;
- } else if (keyCode == AKEYCODE_ENTER) {
- newKeyCode = AKEYCODE_HOME;
- }
- if (newKeyCode != AKEYCODE_UNKNOWN) {
- AutoMutex _l(mLock);
- struct KeyReplacement replacement = {keyCode, args->deviceId};
- mReplacedKeys.add(replacement, newKeyCode);
- keyCode = newKeyCode;
- metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
- }
- } else if (args->action == AKEY_EVENT_ACTION_UP) {
- // In order to maintain a consistent stream of up and down events, check to see if the key
- // going up is one we've replaced in a down event and haven't yet replaced in an up event,
- // even if the modifier was released between the down and the up events.
- AutoMutex _l(mLock);
- struct KeyReplacement replacement = {keyCode, args->deviceId};
- ssize_t index = mReplacedKeys.indexOfKey(replacement);
- if (index >= 0) {
- keyCode = mReplacedKeys.valueAt(index);
- mReplacedKeys.removeItemsAt(index);
- metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
- }
- }
+ accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState);
KeyEvent event;
- event.initialize(args->deviceId, args->source, args->action,
+ event.initialize(args->deviceId, args->source, args->displayId, args->action,
flags, keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
@@ -2507,7 +2525,7 @@
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
- args->deviceId, args->source, policyFlags,
+ args->deviceId, args->source, args->displayId, policyFlags,
args->action, flags, keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
@@ -2526,10 +2544,11 @@
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
+ ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+ ", policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
- args->eventTime, args->deviceId, args->source, args->policyFlags,
+ args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
for (uint32_t i = 0; i < args->pointerCount; i++) {
@@ -2573,7 +2592,8 @@
mLock.unlock();
MotionEvent event;
- event.initialize(args->deviceId, args->source, args->action, args->actionButton,
+ event.initialize(args->deviceId, args->source, args->displayId,
+ args->action, args->actionButton,
args->flags, args->edgeFlags, args->metaState, args->buttonState,
0, 0, args->xPrecision, args->yPrecision,
args->downTime, args->eventTime,
@@ -2589,11 +2609,10 @@
// Just enqueue a new motion event.
MotionEntry* newEntry = new MotionEntry(args->eventTime,
- args->deviceId, args->source, policyFlags,
+ args->deviceId, args->source, args->displayId, policyFlags,
args->action, args->actionButton, args->flags,
args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
- args->displayId,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
needWake = enqueueInboundEventLocked(newEntry);
@@ -2642,14 +2661,13 @@
}
}
-int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displayId,
+int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x, displayId=%d",
- event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags,
- displayId);
+ "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x",
+ event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags);
#endif
nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
@@ -2663,20 +2681,29 @@
EventEntry* lastInjectedEntry;
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
- const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
- int32_t action = keyEvent->getAction();
+ KeyEvent keyEvent;
+ keyEvent.initialize(*static_cast<const KeyEvent*>(event));
+ int32_t action = keyEvent.getAction();
if (! validateKeyEvent(action)) {
return INPUT_EVENT_INJECTION_FAILED;
}
- int32_t flags = keyEvent->getFlags();
+ int32_t flags = keyEvent.getFlags();
+ int32_t keyCode = keyEvent.getKeyCode();
+ int32_t metaState = keyEvent.getMetaState();
+ accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
+ /*byref*/ keyCode, /*byref*/ metaState);
+ keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
+ action, flags, keyCode, keyEvent.getScanCode(), metaState, 0,
+ keyEvent.getDownTime(), keyEvent.getEventTime());
+
if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
policyFlags |= POLICY_FLAG_VIRTUAL;
}
if (!(policyFlags & POLICY_FLAG_FILTERED)) {
android::base::Timer t;
- mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
+ mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
@@ -2684,11 +2711,11 @@
}
mLock.lock();
- firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),
- keyEvent->getDeviceId(), keyEvent->getSource(),
+ firstInjectedEntry = new KeyEntry(keyEvent.getEventTime(),
+ keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
policyFlags, action, flags,
- keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
- keyEvent->getRepeatCount(), keyEvent->getDownTime());
+ keyEvent.getKeyCode(), keyEvent.getScanCode(), keyEvent.getMetaState(),
+ keyEvent.getRepeatCount(), keyEvent.getDownTime());
lastInjectedEntry = firstInjectedEntry;
break;
}
@@ -2717,12 +2744,13 @@
const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
firstInjectedEntry = new MotionEntry(*sampleEventTimes,
- motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+ motionEvent->getDeviceId(), motionEvent->getSource(), motionEvent->getDisplayId(),
+ policyFlags,
action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
- motionEvent->getDownTime(), displayId,
+ motionEvent->getDownTime(),
uint32_t(pointerCount), pointerProperties, samplePointerCoords,
motionEvent->getXOffset(), motionEvent->getYOffset());
lastInjectedEntry = firstInjectedEntry;
@@ -2730,12 +2758,13 @@
sampleEventTimes += 1;
samplePointerCoords += pointerCount;
MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes,
- motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+ motionEvent->getDeviceId(), motionEvent->getSource(),
+ motionEvent->getDisplayId(), policyFlags,
action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
- motionEvent->getDownTime(), displayId,
+ motionEvent->getDownTime(),
uint32_t(pointerCount), pointerProperties, samplePointerCoords,
motionEvent->getXOffset(), motionEvent->getYOffset());
lastInjectedEntry->next = nextInjectedEntry;
@@ -2758,7 +2787,7 @@
lastInjectedEntry->injectionState = injectionState;
bool needWake = false;
- for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) {
+ for (EventEntry* entry = firstInjectedEntry; entry != nullptr; ) {
EventEntry* nextEntry = entry->next;
needWake |= enqueueInboundEventLocked(entry);
entry = nextEntry;
@@ -2886,74 +2915,133 @@
}
}
+Vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {
+ std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>>::const_iterator it =
+ mWindowHandlesByDisplay.find(displayId);
+ if(it != mWindowHandlesByDisplay.end()) {
+ return it->second;
+ }
+
+ // Return an empty one if nothing found.
+ return Vector<sp<InputWindowHandle>>();
+}
+
sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
const sp<InputChannel>& inputChannel) const {
- size_t numWindows = mWindowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- if (windowHandle->getInputChannel() == inputChannel) {
- return windowHandle;
+ for (auto& it : mWindowHandlesByDisplay) {
+ const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+ size_t numWindows = windowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ if (windowHandle->getInputChannel() == inputChannel) {
+ return windowHandle;
+ }
}
}
- return NULL;
+ return nullptr;
}
bool InputDispatcher::hasWindowHandleLocked(
const sp<InputWindowHandle>& windowHandle) const {
- size_t numWindows = mWindowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- if (mWindowHandles.itemAt(i) == windowHandle) {
- return true;
+ for (auto& it : mWindowHandlesByDisplay) {
+ const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+ size_t numWindows = windowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ if (windowHandles.itemAt(i) == windowHandle) {
+ if (windowHandle->getInfo()->displayId != it.first) {
+ ALOGE("Found window %s in display %d, but it should belong to display %d",
+ windowHandle->getName().c_str(), it.first,
+ windowHandle->getInfo()->displayId);
+ }
+ return true;
+ }
}
}
return false;
}
-void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
+/**
+ * Called from InputManagerService, update window handle list by displayId that can receive input.
+ * A window handle contains information about InputChannel, Touch Region, Types, Focused,...
+ * If set an empty list, remove all handles from the specific display.
+ * For focused handle, check if need to change and send a cancel event to previous one.
+ * For removed handle, check if need to send a cancel event if already in touch.
+ */
+void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
+ int32_t displayId) {
#if DEBUG_FOCUS
ALOGD("setInputWindows");
#endif
{ // acquire lock
AutoMutex _l(mLock);
- Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
- mWindowHandles = inputWindowHandles;
+ // Copy old handles for release if they are no longer present.
+ const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
- sp<InputWindowHandle> newFocusedWindowHandle;
+ // TODO(b/111361570): multi-display focus, one focus window per display.
+ sp<InputWindowHandle> newFocusedWindowHandle = mFocusedWindowHandle;
+ // Reset newFocusedWindowHandle to nullptr if current display own the focus window,
+ // that will be updated below when going through all window handles in current display.
+ // And if list of window handles becomes empty then it will be updated by other display.
+ if (mFocusedWindowHandle != nullptr) {
+ const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
+ if (info == nullptr || info->displayId == displayId) {
+ newFocusedWindowHandle = nullptr;
+ }
+ }
+
bool foundHoveredWindow = false;
- for (size_t i = 0; i < mWindowHandles.size(); i++) {
- const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {
- mWindowHandles.removeAt(i--);
- continue;
+
+ if (inputWindowHandles.isEmpty()) {
+ // Remove all handles on a display if there are no windows left.
+ mWindowHandlesByDisplay.erase(displayId);
+ } else {
+ size_t numWindows = inputWindowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ const sp<InputWindowHandle>& windowHandle = inputWindowHandles.itemAt(i);
+ if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
+ continue;
+ }
+
+ if (windowHandle->getInfo()->displayId != displayId) {
+ ALOGE("Window %s updated by wrong display %d, should belong to display %d",
+ windowHandle->getName().c_str(), displayId,
+ windowHandle->getInfo()->displayId);
+ continue;
+ }
+
+ if (windowHandle->getInfo()->hasFocus) {
+ newFocusedWindowHandle = windowHandle;
+ }
+ if (windowHandle == mLastHoverWindowHandle) {
+ foundHoveredWindow = true;
+ }
}
- if (windowHandle->getInfo()->hasFocus) {
- newFocusedWindowHandle = windowHandle;
- }
- if (windowHandle == mLastHoverWindowHandle) {
- foundHoveredWindow = true;
- }
+
+ // Insert or replace
+ mWindowHandlesByDisplay[displayId] = inputWindowHandles;
}
if (!foundHoveredWindow) {
- mLastHoverWindowHandle = NULL;
+ mLastHoverWindowHandle = nullptr;
}
+ // TODO(b/111361570): multi-display focus, one focus in all display in current.
if (mFocusedWindowHandle != newFocusedWindowHandle) {
- if (mFocusedWindowHandle != NULL) {
+ if (mFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
ALOGD("Focus left window: %s",
mFocusedWindowHandle->getName().c_str());
#endif
sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
- if (focusedInputChannel != NULL) {
+ if (focusedInputChannel != nullptr) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
synthesizeCancelationEventsForInputChannelLocked(
focusedInputChannel, options);
}
}
- if (newFocusedWindowHandle != NULL) {
+ if (newFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
ALOGD("Focus entered window: %s",
newFocusedWindowHandle->getName().c_str());
@@ -2962,8 +3050,9 @@
mFocusedWindowHandle = newFocusedWindowHandle;
}
- for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
- TouchState& state = mTouchStatesByDisplay.editValueAt(d);
+ ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
+ if (stateIndex >= 0) {
+ TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex);
for (size_t i = 0; i < state.windows.size(); ) {
TouchedWindow& touchedWindow = state.windows.editItemAt(i);
if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
@@ -2973,7 +3062,7 @@
#endif
sp<InputChannel> touchedInputChannel =
touchedWindow.windowHandle->getInputChannel();
- if (touchedInputChannel != NULL) {
+ if (touchedInputChannel != nullptr) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
synthesizeCancelationEventsForInputChannelLocked(
@@ -2990,7 +3079,8 @@
// This ensures that unused input channels are released promptly.
// Otherwise, they might stick around until the window handle is destroyed
// which might not happen until the next GC.
- for (size_t i = 0; i < oldWindowHandles.size(); i++) {
+ size_t numWindows = oldWindowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
if (!hasWindowHandleLocked(oldWindowHandle)) {
#if DEBUG_FOCUS
@@ -3013,15 +3103,15 @@
{ // acquire lock
AutoMutex _l(mLock);
- if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) {
+ if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) {
if (mFocusedApplicationHandle != inputApplicationHandle) {
- if (mFocusedApplicationHandle != NULL) {
+ if (mFocusedApplicationHandle != nullptr) {
resetANRTimeoutsLocked();
mFocusedApplicationHandle->releaseInfo();
}
mFocusedApplicationHandle = inputApplicationHandle;
}
- } else if (mFocusedApplicationHandle != NULL) {
+ } else if (mFocusedApplicationHandle != nullptr) {
resetANRTimeoutsLocked();
mFocusedApplicationHandle->releaseInfo();
mFocusedApplicationHandle.clear();
@@ -3103,7 +3193,7 @@
sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel);
sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel);
- if (fromWindowHandle == NULL || toWindowHandle == NULL) {
+ if (fromWindowHandle == nullptr || toWindowHandle == nullptr) {
#if DEBUG_FOCUS
ALOGD("Cannot transfer focus because from or to window not found.");
#endif
@@ -3208,7 +3298,7 @@
dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
- if (mFocusedApplicationHandle != NULL) {
+ if (mFocusedApplicationHandle != nullptr) {
dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
mFocusedApplicationHandle->getName().c_str(),
mFocusedApplicationHandle->getDispatchingTimeout(
@@ -3217,7 +3307,7 @@
dump += StringPrintf(INDENT "FocusedApplication: <null>\n");
}
dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n",
- mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().c_str() : "<null>");
+ mFocusedWindowHandle != nullptr ? mFocusedWindowHandle->getName().c_str() : "<null>");
if (!mTouchStatesByDisplay.isEmpty()) {
dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
@@ -3243,36 +3333,44 @@
dump += INDENT "TouchStates: <no displays touched>\n";
}
- if (!mWindowHandles.isEmpty()) {
- dump += INDENT "Windows:\n";
- for (size_t i = 0; i < mWindowHandles.size(); i++) {
- const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ if (!mWindowHandlesByDisplay.empty()) {
+ for (auto& it : mWindowHandlesByDisplay) {
+ const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+ dump += StringPrintf(INDENT "Display: %d\n", it.first);
+ if (!windowHandles.isEmpty()) {
+ dump += INDENT2 "Windows:\n";
+ for (size_t i = 0; i < windowHandles.size(); i++) {
+ const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
- dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, "
- "paused=%s, hasFocus=%s, hasWallpaper=%s, "
- "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
- "frame=[%d,%d][%d,%d], scale=%f, "
- "touchableRegion=",
- i, windowInfo->name.c_str(), windowInfo->displayId,
- toString(windowInfo->paused),
- toString(windowInfo->hasFocus),
- toString(windowInfo->hasWallpaper),
- toString(windowInfo->visible),
- toString(windowInfo->canReceiveKeys),
- windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
- windowInfo->layer,
- windowInfo->frameLeft, windowInfo->frameTop,
- windowInfo->frameRight, windowInfo->frameBottom,
- windowInfo->scaleFactor);
- dumpRegion(dump, windowInfo->touchableRegion);
- dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
- dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
- windowInfo->ownerPid, windowInfo->ownerUid,
- windowInfo->dispatchingTimeout / 1000000.0);
+ dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
+ "paused=%s, hasFocus=%s, hasWallpaper=%s, "
+ "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
+ "frame=[%d,%d][%d,%d], scale=%f, "
+ "touchableRegion=",
+ i, windowInfo->name.c_str(), windowInfo->displayId,
+ toString(windowInfo->paused),
+ toString(windowInfo->hasFocus),
+ toString(windowInfo->hasWallpaper),
+ toString(windowInfo->visible),
+ toString(windowInfo->canReceiveKeys),
+ windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
+ windowInfo->layer,
+ windowInfo->frameLeft, windowInfo->frameTop,
+ windowInfo->frameRight, windowInfo->frameBottom,
+ windowInfo->scaleFactor);
+ dumpRegion(dump, windowInfo->touchableRegion);
+ dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
+ dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
+ windowInfo->ownerPid, windowInfo->ownerUid,
+ windowInfo->dispatchingTimeout / 1000000.0);
+ }
+ } else {
+ dump += INDENT2 "Windows: <none>\n";
+ }
}
} else {
- dump += INDENT "Windows: <none>\n";
+ dump += INDENT "Displays: <none>\n";
}
if (!mMonitoringChannels.isEmpty()) {
@@ -3528,7 +3626,7 @@
dispatchLatency, waitDuration, reason);
// Capture a record of the InputDispatcher state at the time of the ANR.
- time_t t = time(NULL);
+ time_t t = time(nullptr);
struct tm tm;
localtime_r(&t, &tm);
char timestr[64];
@@ -3583,8 +3681,8 @@
mLock.lock();
resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
- commandEntry->inputWindowHandle != NULL
- ? commandEntry->inputWindowHandle->getInputChannel() : NULL);
+ commandEntry->inputWindowHandle != nullptr
+ ? commandEntry->inputWindowHandle->getInputChannel() : nullptr);
}
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -3817,6 +3915,7 @@
keyEntry->eventTime = event.getEventTime();
keyEntry->deviceId = event.getDeviceId();
keyEntry->source = event.getSource();
+ keyEntry->displayId = event.getDisplayId();
keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
keyEntry->keyCode = fallbackKeyCode;
keyEntry->scanCode = event.getScanCode();
@@ -3855,7 +3954,7 @@
}
void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) {
- event->initialize(entry->deviceId, entry->source, entry->action, entry->flags,
+ event->initialize(entry->deviceId, entry->source, entry->displayId, entry->action, entry->flags,
entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
entry->downTime, entry->eventTime);
}
@@ -3934,7 +4033,7 @@
InputDispatcher::EventEntry::EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags) :
refCount(1), type(type), eventTime(eventTime), policyFlags(policyFlags),
- injectionState(NULL), dispatchInProgress(false) {
+ injectionState(nullptr), dispatchInProgress(false) {
}
InputDispatcher::EventEntry::~EventEntry() {
@@ -3953,7 +4052,7 @@
void InputDispatcher::EventEntry::releaseInjectionState() {
if (injectionState) {
injectionState->release();
- injectionState = NULL;
+ injectionState = nullptr;
}
}
@@ -3991,11 +4090,11 @@
// --- InputDispatcher::KeyEntry ---
InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime,
- int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
+ int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
int32_t repeatCount, nsecs_t downTime) :
EventEntry(TYPE_KEY, eventTime, policyFlags),
- deviceId(deviceId), source(source), action(action), flags(flags),
+ deviceId(deviceId), source(source), displayId(displayId), action(action), flags(flags),
keyCode(keyCode), scanCode(scanCode), metaState(metaState),
repeatCount(repeatCount), downTime(downTime),
syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN),
@@ -4006,10 +4105,10 @@
}
void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const {
- msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, action=%s, "
+ msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, "
"flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
"repeatCount=%d), policyFlags=0x%08x",
- deviceId, source, keyActionToString(action).c_str(), flags, keyCode,
+ deviceId, source, displayId, keyActionToString(action).c_str(), flags, keyCode,
scanCode, metaState, repeatCount, policyFlags);
}
@@ -4026,18 +4125,19 @@
// --- InputDispatcher::MotionEntry ---
InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId,
- uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton,
+ uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
+ int32_t actionButton,
int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
float xPrecision, float yPrecision, nsecs_t downTime,
- int32_t displayId, uint32_t pointerCount,
+ uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset) :
EventEntry(TYPE_MOTION, eventTime, policyFlags),
eventTime(eventTime),
- deviceId(deviceId), source(source), action(action), actionButton(actionButton),
- flags(flags), metaState(metaState), buttonState(buttonState),
+ deviceId(deviceId), source(source), displayId(displayId), action(action),
+ actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState),
edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision),
- downTime(downTime), displayId(displayId), pointerCount(pointerCount) {
+ downTime(downTime), pointerCount(pointerCount) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
this->pointerCoords[i].copyFrom(pointerCoords[i]);
@@ -4051,11 +4151,12 @@
}
void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
- msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%s, actionButton=0x%08x, "
- "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
- "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
- deviceId, source, motionActionToString(action).c_str(), actionButton, flags, metaState,
- buttonState, edgeFlags, xPrecision, yPrecision, displayId);
+ msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
+ ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
+ "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[",
+ deviceId, source, displayId, motionActionToString(action).c_str(), actionButton, flags,
+ metaState, buttonState, edgeFlags, xPrecision, yPrecision);
+
for (uint32_t i = 0; i < pointerCount; i++) {
if (i) {
msg += ", ";
@@ -4184,8 +4285,8 @@
}
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
- "actionMasked=%d",
- entry->deviceId, entry->source, actionMasked);
+ "displayId=%" PRId32 ", actionMasked=%d",
+ entry->deviceId, entry->source, entry->displayId, actionMasked);
#endif
return false;
}
@@ -4237,8 +4338,8 @@
}
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Dropping inconsistent motion pointer up/down or move event: "
- "deviceId=%d, source=%08x, actionMasked=%d",
- entry->deviceId, entry->source, actionMasked);
+ "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
+ entry->deviceId, entry->source, entry->displayId, actionMasked);
#endif
return false;
}
@@ -4250,8 +4351,9 @@
return true;
}
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x",
- entry->deviceId, entry->source);
+ ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
+ "displayId=%" PRId32,
+ entry->deviceId, entry->source, entry->displayId);
#endif
return false;
}
@@ -4276,6 +4378,7 @@
const KeyMemento& memento = mKeyMementos.itemAt(i);
if (memento.deviceId == entry->deviceId
&& memento.source == entry->source
+ && memento.displayId == entry->displayId
&& memento.keyCode == entry->keyCode
&& memento.scanCode == entry->scanCode) {
return i;
@@ -4303,6 +4406,7 @@
KeyMemento& memento = mKeyMementos.editTop();
memento.deviceId = entry->deviceId;
memento.source = entry->source;
+ memento.displayId = entry->displayId;
memento.keyCode = entry->keyCode;
memento.scanCode = entry->scanCode;
memento.metaState = entry->metaState;
@@ -4317,11 +4421,11 @@
MotionMemento& memento = mMotionMementos.editTop();
memento.deviceId = entry->deviceId;
memento.source = entry->source;
+ memento.displayId = entry->displayId;
memento.flags = flags;
memento.xPrecision = entry->xPrecision;
memento.yPrecision = entry->yPrecision;
memento.downTime = entry->downTime;
- memento.displayId = entry->displayId;
memento.setPointers(entry);
memento.hovering = hovering;
memento.policyFlags = entry->policyFlags;
@@ -4341,7 +4445,7 @@
const KeyMemento& memento = mKeyMementos.itemAt(i);
if (shouldCancelKey(memento, options)) {
outEvents.push(new KeyEntry(currentTime,
- memento.deviceId, memento.source, memento.policyFlags,
+ memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED,
memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime));
}
@@ -4351,13 +4455,12 @@
const MotionMemento& memento = mMotionMementos.itemAt(i);
if (shouldCancelMotion(memento, options)) {
outEvents.push(new MotionEntry(currentTime,
- memento.deviceId, memento.source, memento.policyFlags,
+ memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
memento.hovering
? AMOTION_EVENT_ACTION_HOVER_EXIT
: AMOTION_EVENT_ACTION_CANCEL,
memento.flags, 0, 0, 0, 0,
memento.xPrecision, memento.yPrecision, memento.downTime,
- memento.displayId,
memento.pointerCount, memento.pointerProperties, memento.pointerCoords,
0, 0));
}
@@ -4461,7 +4564,7 @@
}
const std::string InputDispatcher::Connection::getWindowName() const {
- if (inputWindowHandle != NULL) {
+ if (inputWindowHandle != nullptr) {
return inputWindowHandle->getName();
}
if (monitor) {
@@ -4487,19 +4590,19 @@
}
InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
- for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) {
+ for (DispatchEntry* entry = waitQueue.head; entry != nullptr; entry = entry->next) {
if (entry->seq == seq) {
return entry;
}
}
- return NULL;
+ return nullptr;
}
// --- InputDispatcher::CommandEntry ---
InputDispatcher::CommandEntry::CommandEntry(Command command) :
- command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0),
+ command(command), eventTime(0), keyEntry(nullptr), userActivityEventType(0),
seq(0), handled(false) {
}
@@ -4510,7 +4613,7 @@
// --- InputDispatcher::TouchState ---
InputDispatcher::TouchState::TouchState() :
- down(false), split(false), deviceId(-1), source(0), displayId(-1) {
+ down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) {
}
InputDispatcher::TouchState::~TouchState() {
@@ -4521,7 +4624,7 @@
split = false;
deviceId = -1;
source = 0;
- displayId = -1;
+ displayId = ADISPLAY_ID_NONE;
windows.clear();
}
@@ -4590,7 +4693,7 @@
return window.windowHandle;
}
}
- return NULL;
+ return nullptr;
}
bool InputDispatcher::TouchState::isSlippery() const {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 8da8450..fdf75f6 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -31,6 +31,7 @@
#include <stddef.h>
#include <unistd.h>
#include <limits.h>
+#include <unordered_map>
#include "InputWindow.h"
#include "InputApplication.h"
@@ -299,7 +300,7 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId,
+ virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags) = 0;
@@ -307,7 +308,8 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0;
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+ int32_t displayId) = 0;
/* Sets the focused application.
*
@@ -383,11 +385,12 @@
virtual void notifySwitch(const NotifySwitchArgs* args);
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
- virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId,
+ virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags);
- virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+ int32_t displayId);
virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
virtual void setInputDispatchMode(bool enabled, bool frozen);
virtual void setInputFilterEnabled(bool enabled);
@@ -406,7 +409,7 @@
T* prev;
protected:
- inline Link() : next(NULL), prev(NULL) { }
+ inline Link() : next(nullptr), prev(nullptr) { }
};
struct InjectionState {
@@ -441,7 +444,7 @@
bool dispatchInProgress; // initially false, set to true while dispatching
- inline bool isInjected() const { return injectionState != NULL; }
+ inline bool isInjected() const { return injectionState != nullptr; }
void release();
@@ -474,6 +477,7 @@
struct KeyEntry : EventEntry {
int32_t deviceId;
uint32_t source;
+ int32_t displayId;
int32_t action;
int32_t flags;
int32_t keyCode;
@@ -494,8 +498,8 @@
nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER
KeyEntry(nsecs_t eventTime,
- int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
- int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
+ int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags,
+ int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
int32_t repeatCount, nsecs_t downTime);
virtual void appendDescription(std::string& msg) const;
void recycle();
@@ -508,6 +512,7 @@
nsecs_t eventTime;
int32_t deviceId;
uint32_t source;
+ int32_t displayId;
int32_t action;
int32_t actionButton;
int32_t flags;
@@ -517,17 +522,15 @@
float xPrecision;
float yPrecision;
nsecs_t downTime;
- int32_t displayId;
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
MotionEntry(nsecs_t eventTime,
- int32_t deviceId, uint32_t source, uint32_t policyFlags,
+ int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags,
int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState, int32_t edgeFlags,
- float xPrecision, float yPrecision, nsecs_t downTime,
- int32_t displayId, uint32_t pointerCount,
+ float xPrecision, float yPrecision, nsecs_t downTime, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset);
virtual void appendDescription(std::string& msg) const;
@@ -614,7 +617,7 @@
T* tail;
uint32_t entryCount;
- inline Queue() : head(NULL), tail(NULL), entryCount(0) {
+ inline Queue() : head(nullptr), tail(nullptr), entryCount(0) {
}
inline bool isEmpty() const {
@@ -629,7 +632,7 @@
} else {
head = entry;
}
- entry->next = NULL;
+ entry->next = nullptr;
tail = entry;
}
@@ -641,7 +644,7 @@
} else {
tail = entry;
}
- entry->prev = NULL;
+ entry->prev = nullptr;
head = entry;
}
@@ -664,9 +667,9 @@
T* entry = head;
head = entry->next;
if (head) {
- head->prev = NULL;
+ head->prev = nullptr;
} else {
- tail = NULL;
+ tail = nullptr;
}
return entry;
}
@@ -754,6 +757,7 @@
struct KeyMemento {
int32_t deviceId;
uint32_t source;
+ int32_t displayId;
int32_t keyCode;
int32_t scanCode;
int32_t metaState;
@@ -765,11 +769,11 @@
struct MotionMemento {
int32_t deviceId;
uint32_t source;
+ int32_t displayId;
int32_t flags;
float xPrecision;
float yPrecision;
nsecs_t downTime;
- int32_t displayId;
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
@@ -932,6 +936,9 @@
};
// Maps the key code replaced, device id tuple to the key code it was replaced with
KeyedVector<KeyReplacement, int32_t> mReplacedKeys;
+ // Process certain Meta + Key combinations
+ void accelerateMetaShortcuts(const int32_t deviceId, const int32_t action,
+ int32_t& keyCode, int32_t& metaState);
// Deferred command processing.
bool haveCommandsLocked() const;
@@ -952,8 +959,9 @@
bool mDispatchFrozen;
bool mInputFilterEnabled;
- Vector<sp<InputWindowHandle> > mWindowHandles;
-
+ std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay;
+ // Get window handles by display, return an empty vector if not found.
+ Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 520fea4..25a39a8 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -43,17 +43,18 @@
// --- NotifyKeyArgs ---
NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
- uint32_t policyFlags,
+ int32_t displayId, uint32_t policyFlags,
int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, nsecs_t downTime) :
- eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
+ eventTime(eventTime), deviceId(deviceId), source(source), displayId(displayId),
+ policyFlags(policyFlags),
action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
metaState(metaState), downTime(downTime) {
}
NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) :
eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
- policyFlags(other.policyFlags),
+ displayId(other.displayId), policyFlags(other.policyFlags),
action(other.action), flags(other.flags),
keyCode(other.keyCode), scanCode(other.scanCode),
metaState(other.metaState), downTime(other.downTime) {
@@ -67,16 +68,17 @@
// --- NotifyMotionArgs ---
NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
- uint32_t policyFlags,
+ int32_t displayId, uint32_t policyFlags,
int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
- int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t deviceTimestamp,
+ int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) :
- eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
+ eventTime(eventTime), deviceId(deviceId), source(source), displayId(displayId),
+ policyFlags(policyFlags),
action(action), actionButton(actionButton),
flags(flags), metaState(metaState), buttonState(buttonState),
- edgeFlags(edgeFlags), displayId(displayId), deviceTimestamp(deviceTimestamp),
+ edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
pointerCount(pointerCount),
xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
@@ -87,10 +89,10 @@
NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
- policyFlags(other.policyFlags),
+ displayId(other.displayId), policyFlags(other.policyFlags),
action(other.action), actionButton(other.actionButton), flags(other.flags),
metaState(other.metaState), buttonState(other.buttonState),
- edgeFlags(other.edgeFlags), displayId(other.displayId),
+ edgeFlags(other.edgeFlags),
deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h
index 77afb34..a3d919b 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -55,6 +55,7 @@
nsecs_t eventTime;
int32_t deviceId;
uint32_t source;
+ int32_t displayId;
uint32_t policyFlags;
int32_t action;
int32_t flags;
@@ -65,8 +66,8 @@
inline NotifyKeyArgs() { }
- NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
- int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
+ NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+ uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, nsecs_t downTime);
NotifyKeyArgs(const NotifyKeyArgs& other);
@@ -82,6 +83,7 @@
nsecs_t eventTime;
int32_t deviceId;
uint32_t source;
+ int32_t displayId;
uint32_t policyFlags;
int32_t action;
int32_t actionButton;
@@ -89,7 +91,6 @@
int32_t metaState;
int32_t buttonState;
int32_t edgeFlags;
- int32_t displayId;
/**
* A timestamp in the input device's time base, not the platform's.
* The units are microseconds since the last reset.
@@ -106,10 +107,11 @@
inline NotifyMotionArgs() { }
- NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
+ NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+ uint32_t policyFlags,
int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState,
- int32_t edgeFlags, int32_t displayId, uint32_t deviceTimestamp, uint32_t pointerCount,
+ int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime);
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index a213b2d..92e0af2 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -31,7 +31,6 @@
#include <utils/Vector.h>
#include <utils/Timers.h>
#include <utils/RefBase.h>
-#include <utils/String8.h>
namespace android {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 2df0090..8f12129 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -226,7 +226,7 @@
}
static void synthesizeButtonKey(InputReaderContext* context, int32_t action,
- nsecs_t when, int32_t deviceId, uint32_t source,
+ nsecs_t when, int32_t deviceId, uint32_t source, int32_t displayId,
uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState,
int32_t buttonState, int32_t keyCode) {
if (
@@ -236,19 +236,19 @@
|| (action == AKEY_EVENT_ACTION_UP
&& (lastButtonState & buttonState)
&& !(currentButtonState & buttonState))) {
- NotifyKeyArgs args(when, deviceId, source, policyFlags,
+ NotifyKeyArgs args(when, deviceId, source, displayId, policyFlags,
action, 0, keyCode, 0, context->getGlobalMetaState(), when);
context->getListener()->notifyKey(&args);
}
}
static void synthesizeButtonKeys(InputReaderContext* context, int32_t action,
- nsecs_t when, int32_t deviceId, uint32_t source,
+ nsecs_t when, int32_t deviceId, uint32_t source, int32_t displayId,
uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) {
- synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
+ synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags,
lastButtonState, currentButtonState,
AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK);
- synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
+ synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags,
lastButtonState, currentButtonState,
AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD);
}
@@ -257,11 +257,12 @@
// --- InputReaderConfiguration ---
bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
- const String8* uniqueDisplayId, DisplayViewport* outViewport) const {
- const DisplayViewport* viewport = NULL;
- if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != NULL) {
+ const std::string& uniqueDisplayId, DisplayViewport* outViewport) const {
+ const DisplayViewport* viewport = nullptr;
+ if (viewportType == ViewportType::VIEWPORT_VIRTUAL && !uniqueDisplayId.empty()) {
+
for (const DisplayViewport& currentViewport : mVirtualDisplays) {
- if (currentViewport.uniqueId == *uniqueDisplayId) {
+ if (currentViewport.uniqueId == uniqueDisplayId) {
viewport = ¤tViewport;
break;
}
@@ -272,7 +273,7 @@
viewport = &mInternalDisplay;
}
- if (viewport != NULL && viewport->displayId >= 0) {
+ if (viewport != nullptr && viewport->displayId >= 0) {
*outViewport = *viewport;
return true;
}
@@ -473,10 +474,10 @@
if (device->isIgnored()) {
ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
- identifier.name.string());
+ identifier.name.c_str());
} else {
ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
- identifier.name.string(), device->getSources());
+ identifier.name.c_str(), device->getSources());
}
mDevices.add(deviceId, device);
@@ -488,7 +489,7 @@
}
void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
- InputDevice* device = NULL;
+ InputDevice* device = nullptr;
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
@@ -501,10 +502,10 @@
if (device->isIgnored()) {
ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)",
- device->getId(), device->getName().string());
+ device->getId(), device->getName().c_str());
} else {
ALOGI("Device removed: id=%d, name='%s', sources=0x%08x",
- device->getId(), device->getName().string(), device->getSources());
+ device->getId(), device->getName().c_str(), device->getSources());
}
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
@@ -687,7 +688,7 @@
if (now < mDisableVirtualKeysTimeout) {
ALOGI("Dropping virtual key from device %s because virtual keys are "
"temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d",
- device->getName().string(),
+ device->getName().c_str(),
(mDisableVirtualKeysTimeout - now) * 0.000001,
keyCode, scanCode);
return true;
@@ -894,7 +895,7 @@
if (i != 0) {
dump += ", ";
}
- dump += mConfig.excludedDeviceNames.itemAt(i).string();
+ dump += mConfig.excludedDeviceNames[i];
}
dump += "]\n";
dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
@@ -1077,7 +1078,7 @@
getDeviceInfo(& deviceInfo);
dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
- deviceInfo.getDisplayName().string());
+ deviceInfo.getDisplayName().c_str());
dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration);
dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic));
@@ -1135,7 +1136,7 @@
if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) {
if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
- String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
+ std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
if (mAlias != alias) {
mAlias = alias;
bumpGeneration();
@@ -1196,7 +1197,7 @@
#endif
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
- ALOGI("Detected input event buffer overrun for device %s.", getName().string());
+ ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
@@ -1786,7 +1787,7 @@
// --- MultiTouchMotionAccumulator ---
MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() :
- mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false),
+ mCurrentSlot(-1), mSlots(nullptr), mSlotCount(0), mUsingSlotsProtocol(false),
mHaveStylus(false), mDeviceTimestamp(0) {
}
@@ -2240,8 +2241,7 @@
KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
uint32_t source, int32_t keyboardType) :
- InputMapper(device), mSource(source),
- mKeyboardType(keyboardType) {
+ InputMapper(device), mSource(source), mKeyboardType(keyboardType) {
}
KeyboardInputMapper::~KeyboardInputMapper() {
@@ -2251,6 +2251,20 @@
return mSource;
}
+int32_t KeyboardInputMapper::getOrientation() {
+ if (mViewport) {
+ return mViewport->orientation;
+ }
+ return DISPLAY_ORIENTATION_0;
+}
+
+int32_t KeyboardInputMapper::getDisplayId() {
+ if (mViewport) {
+ return mViewport->displayId;
+ }
+ return ADISPLAY_ID_NONE;
+}
+
void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
InputMapper::populateDeviceInfo(info);
@@ -2262,7 +2276,7 @@
dump += INDENT2 "Keyboard Input Mapper:\n";
dumpParameters(dump);
dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType);
- dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
+ dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation());
dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
@@ -2279,15 +2293,10 @@
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
- if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
- DisplayViewport v;
- if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
- mOrientation = v.orientation;
- } else {
- mOrientation = DISPLAY_ORIENTATION_0;
- }
- } else {
- mOrientation = DISPLAY_ORIENTATION_0;
+ if (mParameters.orientationAware) {
+ DisplayViewport dvp;
+ config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &dvp);
+ mViewport = dvp;
}
}
}
@@ -2310,10 +2319,7 @@
config.tryGetProperty(String8("keyboard.orientationAware"),
mParameters.orientationAware);
- mParameters.hasAssociatedDisplay = false;
if (mParameters.orientationAware) {
- mParameters.hasAssociatedDisplay = true;
-
mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary");
mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1");
mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2");
@@ -2327,8 +2333,6 @@
void KeyboardInputMapper::dumpParameters(std::string& dump) {
dump += INDENT3 "Parameters:\n";
- dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
- toString(mParameters.hasAssociatedDisplay));
dump += StringPrintf(INDENT4 "OrientationAware: %s\n",
toString(mParameters.orientationAware));
dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n",
@@ -2423,8 +2427,8 @@
if (down) {
// Rotate key codes according to orientation if needed.
- if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
- keyCode = rotateKeyCode(keyCode, mOrientation);
+ if (mParameters.orientationAware) {
+ keyCode = rotateKeyCode(keyCode, getOrientation());
}
// Add key down.
@@ -2461,7 +2465,7 @@
// key was not actually down
ALOGI("Dropping key up from device %s because the key was not down. "
"keyCode=%d, scanCode=%d",
- getDeviceName().string(), keyCode, scanCode);
+ getDeviceName().c_str(), keyCode, scanCode);
return;
}
}
@@ -2489,7 +2493,7 @@
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
- NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyKeyArgs args(when, getDeviceId(), mSource, getDisplayId(), policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);
@@ -2699,15 +2703,12 @@
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+ mOrientation = DISPLAY_ORIENTATION_0;
if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
DisplayViewport v;
- if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
+ if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
mOrientation = v.orientation;
- } else {
- mOrientation = DISPLAY_ORIENTATION_0;
}
- } else {
- mOrientation = DISPLAY_ORIENTATION_0;
}
bumpGeneration();
}
@@ -2826,8 +2827,8 @@
float hscroll = mCursorScrollAccumulator.getRelativeHWheel();
bool scrolled = vscroll != 0 || hscroll != 0;
- mWheelYVelocityControl.move(when, NULL, &vscroll);
- mWheelXVelocityControl.move(when, &hscroll, NULL);
+ mWheelYVelocityControl.move(when, nullptr, &vscroll);
+ mWheelXVelocityControl.move(when, &hscroll, nullptr);
mPointerVelocityControl.move(when, &deltaX, &deltaY);
@@ -2874,7 +2875,7 @@
// Synthesize key down from buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
- policyFlags, lastButtonState, currentButtonState);
+ displayId, policyFlags, lastButtonState, currentButtonState);
// Send motion event.
if (downChanged || moved || scrolled || buttonsChanged) {
@@ -2894,19 +2895,19 @@
while (!released.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
buttonState &= ~actionButton;
- NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+ /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&releaseArgs);
}
}
- NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
motionEventAction, 0, 0, metaState, currentButtonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+ /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&args);
@@ -2915,10 +2916,10 @@
while (!pressed.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
buttonState |= actionButton;
- NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+ /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&pressArgs);
}
@@ -2929,10 +2930,10 @@
// Send hover move after UP to tell the application that the mouse is hovering now.
if (motionEventAction == AMOTION_EVENT_ACTION_UP
&& (mSource == AINPUT_SOURCE_MOUSE)) {
- NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+ /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&hoverArgs);
}
@@ -2942,10 +2943,10 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+ /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&scrollArgs);
}
@@ -2953,7 +2954,7 @@
// Synthesize key up from buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
- policyFlags, lastButtonState, currentButtonState);
+ displayId, policyFlags, lastButtonState, currentButtonState);
mCursorMotionAccumulator.finishSync();
mCursorScrollAccumulator.finishSync();
@@ -2968,7 +2969,7 @@
}
void CursorInputMapper::fadePointer() {
- if (mPointerController != NULL) {
+ if (mPointerController != nullptr) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
}
}
@@ -3020,7 +3021,7 @@
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
DisplayViewport v;
- if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
+ if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
mOrientation = v.orientation;
} else {
mOrientation = DISPLAY_ORIENTATION_0;
@@ -3072,10 +3073,10 @@
int32_t metaState = mContext->getGlobalMetaState();
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
- NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+ /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
0, 0, 0);
getListener()->notifyMotion(&scrollArgs);
}
@@ -3394,8 +3395,10 @@
mParameters.hasAssociatedDisplay = true;
if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
mParameters.associatedDisplayIsExternal = getDevice()->isExternal();
+ String8 uniqueDisplayId;
getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"),
- mParameters.uniqueDisplayId);
+ uniqueDisplayId);
+ mParameters.uniqueDisplayId = uniqueDisplayId.c_str();
}
}
@@ -3506,7 +3509,7 @@
// Ensure we have valid X and Y axes.
if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis! "
- "The device will be inoperable.", getDeviceName().string());
+ "The device will be inoperable.", getDeviceName().c_str());
mDeviceMode = DEVICE_MODE_DISABLED;
return;
}
@@ -3518,15 +3521,15 @@
// Get associated display dimensions.
DisplayViewport newViewport;
if (mParameters.hasAssociatedDisplay) {
- const String8* uniqueDisplayId = NULL;
+ std::string uniqueDisplayId;
ViewportType viewportTypeToUse;
if (mParameters.associatedDisplayIsExternal) {
viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL;
- } else if (!mParameters.uniqueDisplayId.isEmpty()) {
+ } else if (!mParameters.uniqueDisplayId.empty()) {
// If the IDC file specified a unique display Id, then it expects to be linked to a
// virtual display with the same unique ID.
- uniqueDisplayId = &mParameters.uniqueDisplayId;
+ uniqueDisplayId = mParameters.uniqueDisplayId;
viewportTypeToUse = ViewportType::VIEWPORT_VIRTUAL;
} else {
viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
@@ -3536,7 +3539,7 @@
ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
"display. The device will be inoperable until the display size "
"becomes available.",
- getDeviceName().string());
+ getDeviceName().c_str());
mDeviceMode = DEVICE_MODE_DISABLED;
return;
}
@@ -3632,7 +3635,7 @@
// Create pointer controller if needed.
if (mDeviceMode == DEVICE_MODE_POINTER ||
(mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
- if (mPointerController == NULL) {
+ if (mPointerController == nullptr) {
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
}
} else {
@@ -3642,7 +3645,7 @@
if (viewportChanged || deviceModeChanged) {
ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
"display id %d",
- getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight,
+ getDeviceId(), getDeviceName().c_str(), mSurfaceWidth, mSurfaceHeight,
mSurfaceOrientation, mDeviceMode, mViewport.displayId);
// Configure X and Y factors.
@@ -4286,7 +4289,7 @@
mPointerSimple.reset();
resetExternalStylus();
- if (mPointerController != NULL) {
+ if (mPointerController != nullptr) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
mPointerController->clearSpots();
}
@@ -4448,7 +4451,8 @@
// Synthesize key down from raw buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
- policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
+ mViewport.displayId, policyFlags,
+ mLastCookedState.buttonState, mCurrentCookedState.buttonState);
// Dispatch the touches either directly or by translation through a pointer on screen.
if (mDeviceMode == DEVICE_MODE_POINTER) {
@@ -4495,7 +4499,7 @@
dispatchPointerUsage(when, policyFlags, pointerUsage);
} else {
if (mDeviceMode == DEVICE_MODE_DIRECT
- && mConfig.showTouches && mPointerController != NULL) {
+ && mConfig.showTouches && mPointerController != nullptr) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
@@ -4520,7 +4524,8 @@
// Synthesize key up from raw buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
- policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
+ mViewport.displayId, policyFlags,
+ mLastCookedState.buttonState, mCurrentCookedState.buttonState);
// Clear some transient state.
mCurrentRawState.rawVScroll = 0;
@@ -4735,8 +4740,8 @@
int32_t metaState = mContext->getGlobalMetaState();
policyFlags |= POLICY_FLAG_VIRTUAL;
- NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
- keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
+ NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, mViewport.displayId,
+ policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
getListener()->notifyKey(&args);
}
@@ -5428,10 +5433,10 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
- NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mViewport.displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+ /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
0, 0, mPointerGesture.downTime);
getListener()->notifyMotion(&args);
}
@@ -5473,7 +5478,7 @@
mPointerVelocityControl.reset();
// Remove any current spots.
- if (mPointerController != NULL) {
+ if (mPointerController != nullptr) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
mPointerController->clearSpots();
}
@@ -6336,7 +6341,7 @@
bool down, bool hovering) {
int32_t metaState = getContext()->getGlobalMetaState();
- if (mPointerController != NULL) {
+ if (mPointerController != nullptr) {
if (down || hovering) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
mPointerController->clearSpots();
@@ -6351,9 +6356,9 @@
mPointerSimple.down = false;
// Send up.
- NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
- mViewport.displayId, /* deviceTimestamp */ 0,
+ /* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6364,9 +6369,9 @@
mPointerSimple.hovering = false;
// Send hover exit.
- NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
- mViewport.displayId, /* deviceTimestamp */ 0,
+ /* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6379,9 +6384,9 @@
mPointerSimple.downTime = when;
// Send down.
- NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
- mViewport.displayId, /* deviceTimestamp */ 0,
+ /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6389,9 +6394,9 @@
}
// Send move.
- NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
- mViewport.displayId, /* deviceTimestamp */ 0,
+ /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6403,10 +6408,10 @@
mPointerSimple.hovering = true;
// Send hover enter.
- NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
mCurrentRawState.buttonState, 0,
- mViewport.displayId, /* deviceTimestamp */ 0,
+ /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6414,10 +6419,10 @@
}
// Send hover move.
- NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
mCurrentRawState.buttonState, 0,
- mViewport.displayId, /* deviceTimestamp */ 0,
+ /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6427,8 +6432,8 @@
if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
float vscroll = mCurrentRawState.rawVScroll;
float hscroll = mCurrentRawState.rawHScroll;
- mWheelYVelocityControl.move(when, NULL, &vscroll);
- mWheelXVelocityControl.move(when, &hscroll, NULL);
+ mWheelYVelocityControl.move(when, nullptr, &vscroll);
+ mWheelXVelocityControl.move(when, &hscroll, nullptr);
// Send scroll.
PointerCoords pointerCoords;
@@ -6436,9 +6441,9 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
- mViewport.displayId, /* deviceTimestamp */ 0,
+ /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &pointerCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6499,9 +6504,9 @@
}
}
- NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), source, mViewport.displayId, policyFlags,
action, actionButton, flags, metaState, buttonState, edgeFlags,
- mViewport.displayId, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
+ deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
}
@@ -6535,7 +6540,7 @@
}
void TouchInputMapper::fadePointer() {
- if (mPointerController != NULL) {
+ if (mPointerController != nullptr) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
}
}
@@ -6574,7 +6579,7 @@
}
}
- return NULL;
+ return nullptr;
}
void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) {
@@ -6923,7 +6928,7 @@
#if DEBUG_POINTERS
ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
"ignoring the rest.",
- getDeviceName().string(), MAX_POINTERS);
+ getDeviceName().c_str(), MAX_POINTERS);
#endif
break; // too many fingers!
}
@@ -7014,7 +7019,7 @@
if (slotCount > MAX_SLOTS) {
ALOGW("MultiTouch Device %s reported %zu slots but the framework "
"only supports a maximum of %zu slots at this time.",
- getDeviceName().string(), slotCount, MAX_SLOTS);
+ getDeviceName().c_str(), slotCount, MAX_SLOTS);
slotCount = MAX_SLOTS;
}
mMultiTouchMotionAccumulator.configure(getDevice(),
@@ -7257,7 +7262,7 @@
// Prefer to keep explicitly mapped axes.
if (mAxes.size() > PointerCoords::MAX_AXES) {
ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.",
- getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES);
+ getDeviceName().c_str(), mAxes.size(), PointerCoords::MAX_AXES);
pruneAxes(true);
pruneAxes(false);
}
@@ -7279,7 +7284,7 @@
} else {
ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
"have already been assigned to other axes.",
- getDeviceName().string(), mAxes.keyAt(i));
+ getDeviceName().c_str(), mAxes.keyAt(i));
mAxes.removeItemsAt(i--);
numAxes -= 1;
}
@@ -7308,7 +7313,7 @@
continue;
}
ALOGI("Discarding joystick '%s' axis %d because there are too many axes.",
- getDeviceName().string(), mAxes.keyAt(i));
+ getDeviceName().c_str(), mAxes.keyAt(i));
mAxes.removeItemsAt(i);
}
}
@@ -7423,9 +7428,10 @@
// TODO: Use the input device configuration to control this behavior more finely.
uint32_t policyFlags = 0;
- NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE,
+ policyFlags,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- ADISPLAY_ID_NONE, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+ /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
0, 0, 0);
getListener()->notifyMotion(&args);
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 2f98e69..c06168d 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -35,6 +35,7 @@
#include <utils/BitSet.h>
#include <utils/SortedVector.h>
+#include <optional>
#include <stddef.h>
#include <unistd.h>
@@ -100,7 +101,7 @@
// The excluded device names for the platform.
// Devices with these names will be ignored.
- Vector<String8> excludedDeviceNames;
+ std::vector<std::string> excludedDeviceNames;
// Velocity control parameters for mouse pointer movements.
VelocityControlParameters pointerVelocityControlParameters;
@@ -200,7 +201,7 @@
pointerGestureZoomSpeedRatio(0.3f),
showTouches(false) { }
- bool getDisplayViewport(ViewportType viewportType, const String8* displayId,
+ bool getDisplayViewport(ViewportType viewportType, const std::string& uniqueDisplayId,
DisplayViewport* outViewport) const;
void setPhysicalDisplayViewport(ViewportType viewportType, const DisplayViewport& viewport);
void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports);
@@ -273,11 +274,11 @@
const InputDeviceIdentifier& identifier) = 0;
/* Gets a user-supplied alias for a particular input device, or an empty string if none. */
- virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0;
+ virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier) = 0;
/* Gets the affine calibration associated with the specified device. */
virtual TouchAffineTransformation getTouchAffineTransformation(
- const String8& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
+ const std::string& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
};
@@ -552,8 +553,8 @@
inline int32_t getId() const { return mId; }
inline int32_t getControllerNumber() const { return mControllerNumber; }
inline int32_t getGeneration() const { return mGeneration; }
- inline const String8& getName() const { return mIdentifier.name; }
- inline const String8& getDescriptor() { return mIdentifier.descriptor; }
+ inline const std::string getName() const { return mIdentifier.name; }
+ inline const std::string getDescriptor() { return mIdentifier.descriptor; }
inline uint32_t getClasses() const { return mClasses; }
inline uint32_t getSources() const { return mSources; }
@@ -624,7 +625,7 @@
int32_t mGeneration;
int32_t mControllerNumber;
InputDeviceIdentifier mIdentifier;
- String8 mAlias;
+ std::string mAlias;
uint32_t mClasses;
Vector<InputMapper*> mMappers;
@@ -980,7 +981,7 @@
inline InputDevice* getDevice() { return mDevice; }
inline int32_t getDeviceId() { return mDevice->getId(); }
- inline const String8 getDeviceName() { return mDevice->getName(); }
+ inline const std::string getDeviceName() { return mDevice->getName(); }
inline InputReaderContext* getContext() { return mContext; }
inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); }
inline InputListenerInterface* getListener() { return mContext->getListener(); }
@@ -1094,6 +1095,9 @@
virtual void updateMetaState(int32_t keyCode);
private:
+ // The current viewport.
+ std::optional<DisplayViewport> mViewport;
+
struct KeyDown {
int32_t keyCode;
int32_t scanCode;
@@ -1102,8 +1106,6 @@
uint32_t mSource;
int32_t mKeyboardType;
- int32_t mOrientation; // orientation for dpad keys
-
Vector<KeyDown> mKeyDowns; // keys that are down
int32_t mMetaState;
nsecs_t mDownTime; // time of most recent key down
@@ -1120,7 +1122,6 @@
// Immutable configuration parameters.
struct Parameters {
- bool hasAssociatedDisplay;
bool orientationAware;
bool handlesKeyRepeat;
} mParameters;
@@ -1128,6 +1129,9 @@
void configureParameters();
void dumpParameters(std::string& dump);
+ int32_t getOrientation();
+ int32_t getDisplayId();
+
bool isKeyboardOrGamepadKey(int32_t scanCode);
bool isMediaKey(int32_t keyCode);
@@ -1305,7 +1309,7 @@
bool associatedDisplayIsExternal;
bool orientationAware;
bool hasButtonUnderPad;
- String8 uniqueDisplayId;
+ std::string uniqueDisplayId;
enum GestureMode {
GESTURE_MODE_SINGLE_TOUCH,
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index 3ae7972..0d1dfdd 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -66,7 +66,7 @@
// --- InputWindowHandle ---
InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- inputApplicationHandle(inputApplicationHandle), mInfo(NULL) {
+ inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) {
}
InputWindowHandle::~InputWindowHandle() {
@@ -76,7 +76,7 @@
void InputWindowHandle::releaseInfo() {
if (mInfo) {
delete mInfo;
- mInfo = NULL;
+ mInfo = nullptr;
}
}
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 5a48375..c481853 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -169,7 +169,7 @@
}
inline sp<InputChannel> getInputChannel() const {
- return mInfo ? mInfo->inputChannel : NULL;
+ return mInfo ? mInfo->inputChannel : nullptr;
}
inline std::string getName() const {
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index bd11d56..2f046c3 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -217,18 +217,18 @@
idi.product = id->productId;
idi.version = id->version;
- String8 configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
+ std::string configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
idi, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
- if (configFile.isEmpty()) {
+ if (configFile.empty()) {
ALOGD("No input device configuration file found for device '%s'.",
- idi.name.string());
+ idi.name.c_str());
} else {
auto propMap = new input_property_map_t();
- status_t status = PropertyMap::load(configFile, &propMap->propertyMap);
+ status_t status = PropertyMap::load(String8(configFile.c_str()), &propMap->propertyMap);
if (status) {
ALOGE("Error loading input device configuration file for device '%s'. "
"Using default configuration.",
- idi.name.string());
+ idi.name.c_str());
delete propMap;
return nullptr;
}
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index dd19800..517e639 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -2,11 +2,11 @@
cc_test {
name: "inputflinger_tests",
+ cpp_std: "c++17",
srcs: [
"InputReader_test.cpp",
"InputDispatcher_test.cpp",
],
- test_per_src: true,
cflags: [
"-Wall",
"-Werror",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index aa6df24..61dcdd9 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -28,7 +28,7 @@
static const int32_t DEVICE_ID = 1;
// An arbitrary display id.
-static const int32_t DISPLAY_ID = 0;
+static const int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
// An arbitrary injector pid / uid pair that has permission to inject events.
static const int32_t INJECTOR_PID = 999;
@@ -103,13 +103,20 @@
protected:
sp<FakeInputDispatcherPolicy> mFakePolicy;
sp<InputDispatcher> mDispatcher;
+ sp<InputDispatcherThread> mDispatcherThread;
virtual void SetUp() {
mFakePolicy = new FakeInputDispatcherPolicy();
mDispatcher = new InputDispatcher(mFakePolicy);
+ mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
+ //Start InputDispatcher thread
+ mDispatcherThread = new InputDispatcherThread(mDispatcher);
+ mDispatcherThread->run("InputDispatcherTest", PRIORITY_URGENT_DISPLAY);
}
virtual void TearDown() {
+ mDispatcherThread->requestExit();
+ mDispatcherThread.clear();
mFakePolicy.clear();
mDispatcher.clear();
}
@@ -120,20 +127,20 @@
KeyEvent event;
// Rejects undefined key actions.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
/*action*/ -1, 0,
AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject key events with undefined action.";
// Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
AKEY_EVENT_ACTION_MULTIPLE, 0,
AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject key events with ACTION_MULTIPLE.";
}
@@ -149,108 +156,401 @@
}
// Rejects undefined motion actions.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
/*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with undefined action.";
// Rejects pointer down with invalid index.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer down index too large.";
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer down index too small.";
// Rejects pointer up with invalid index.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer up index too large.";
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer up index too small.";
// Rejects motion events with invalid number of pointers.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with 0 pointers.";
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with more than MAX_POINTERS pointers.";
// Rejects motion events with invalid pointer ids.
pointerProperties[0].id = -1;
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer ids less than 0.";
pointerProperties[0].id = MAX_POINTER_ID + 1;
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
// Rejects motion events with duplicate pointer ids.
pointerProperties[0].id = 1;
pointerProperties[1].id = 1;
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event, DISPLAY_ID,
+ &event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with duplicate pointer ids.";
}
+// --- InputDispatcherTest SetInputWindowTest ---
+static const int32_t INJECT_EVENT_TIMEOUT = 500;
+static const int32_t DISPATCHING_TIMEOUT = 100;
+
+class FakeApplicationHandle : public InputApplicationHandle {
+public:
+ FakeApplicationHandle() {}
+ virtual ~FakeApplicationHandle() {}
+
+ virtual bool updateInfo() {
+ if (!mInfo) {
+ mInfo = new InputApplicationInfo();
+ }
+ mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+ return true;
+ }
+};
+
+class FakeWindowHandle : public InputWindowHandle {
+public:
+ static const int32_t WIDTH = 600;
+ static const int32_t HEIGHT = 800;
+
+ FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<InputDispatcher>& dispatcher, const std::string name) :
+ InputWindowHandle(inputApplicationHandle), mDispatcher(dispatcher),
+ mName(name), mFocused(false), mDisplayId(ADISPLAY_ID_DEFAULT) {
+ InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
+ mConsumer = new InputConsumer(mClientChannel);
+ mDispatcher->registerInputChannel(mServerChannel, this, false);
+ }
+
+ virtual ~FakeWindowHandle() {
+ mDispatcher->unregisterInputChannel(mServerChannel);
+ mServerChannel.clear();
+ mClientChannel.clear();
+ mDispatcher.clear();
+
+ if (mConsumer != nullptr) {
+ delete mConsumer;
+ }
+ }
+
+ virtual bool updateInfo() {
+ if (!mInfo) {
+ mInfo = new InputWindowInfo();
+ }
+ mInfo->inputChannel = mServerChannel;
+ mInfo->name = mName;
+ mInfo->layoutParamsFlags = 0;
+ mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+ mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo->frameLeft = 0;
+ mInfo->frameTop = 0;
+ mInfo->frameRight = WIDTH;
+ mInfo->frameBottom = HEIGHT;
+ mInfo->scaleFactor = 1.0;
+ mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
+ mInfo->visible = true;
+ mInfo->canReceiveKeys = true;
+ mInfo->hasFocus = mFocused;
+ mInfo->hasWallpaper = false;
+ mInfo->paused = false;
+ mInfo->layer = 0;
+ mInfo->ownerPid = INJECTOR_PID;
+ mInfo->ownerUid = INJECTOR_UID;
+ mInfo->inputFeatures = 0;
+ mInfo->displayId = mDisplayId;
+
+ return true;
+ }
+
+ void setFocus() {
+ mFocused = true;
+ }
+
+ void setDisplayId(int32_t displayId) {
+ mDisplayId = displayId;
+ }
+
+ void consumeEvent(int32_t expectedEventType, int32_t expectedDisplayId) {
+ uint32_t consumeSeq;
+ InputEvent* event;
+ status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
+ &consumeSeq, &event);
+
+ ASSERT_EQ(OK, status)
+ << mName.c_str() << ": consumer consume should return OK.";
+ ASSERT_TRUE(event != nullptr)
+ << mName.c_str() << ": consumer should have returned non-NULL event.";
+ ASSERT_EQ(expectedEventType, event->getType())
+ << mName.c_str() << ": consumer type should same as expected one.";
+
+ ASSERT_EQ(expectedDisplayId, event->getDisplayId())
+ << mName.c_str() << ": consumer displayId should same as expected one.";
+
+ status = mConsumer->sendFinishedSignal(consumeSeq, true /*handled*/);
+ ASSERT_EQ(OK, status)
+ << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
+ }
+
+ void assertNoEvents() {
+ uint32_t consumeSeq;
+ InputEvent* event;
+ status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
+ &consumeSeq, &event);
+ ASSERT_NE(OK, status)
+ << mName.c_str()
+ << ": should not have received any events, so consume(..) should not return OK.";
+ }
+
+ private:
+ sp<InputDispatcher> mDispatcher;
+ sp<InputChannel> mServerChannel, mClientChannel;
+ InputConsumer *mConsumer;
+ PreallocatedInputEventFactory mEventFactory;
+
+ std::string mName;
+ bool mFocused;
+ int32_t mDisplayId;
+};
+
+static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher) {
+ KeyEvent event;
+ nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // Define a valid key down event.
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+ AKEY_EVENT_ACTION_DOWN, /* flags */ 0,
+ AKEYCODE_A, KEY_A, AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime);
+
+ // Inject event until dispatch out.
+ return dispatcher->injectInputEvent(
+ &event,
+ INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
+ INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+}
+
+static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t displayId) {
+ MotionEvent event;
+ PointerProperties pointerProperties[1];
+ PointerCoords pointerCoords[1];
+
+ pointerProperties[0].clear();
+ pointerProperties[0].id = 0;
+ pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+ pointerCoords[0].clear();
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200);
+
+ nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ // Define a valid motion down event.
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, displayId,
+ AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
+ AMETA_NONE, /* buttonState */ 0, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
+ /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
+ pointerCoords);
+
+ // Inject event until dispatch out.
+ return dispatcher->injectInputEvent(
+ &event,
+ INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
+ INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+}
+
+TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window");
+
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.add(window);
+
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Window should receive motion event.
+ window->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+}
+
+// The foreground window should receive the first touch down event.
+TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.add(windowTop);
+ inputWindowHandles.add(windowSecond);
+
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Top window should receive the touch down event. Second window should not receive anything.
+ windowTop->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+ windowSecond->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+
+ // Set focus application.
+ mDispatcher->setFocusedApplication(application);
+
+ // Expect one focus window exist in display.
+ windowSecond->setFocus();
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.add(windowTop);
+ inputWindowHandles.add(windowSecond);
+
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Focused window should receive event.
+ windowTop->assertNoEvents();
+ windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+}
+
+TEST_F(InputDispatcherTest, SetInputWindow_MultiDisplayTouch) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
+ sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application, mDispatcher, "D_2");
+
+ // Test the primary display touch down.
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push(windowInPrimary);
+
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+ windowInSecondary->assertNoEvents();
+
+ // Test the second display touch down.
+ constexpr int32_t SECOND_DISPLAY_ID = 1;
+ windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
+ Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+ inputWindowHandles_Second.push(windowInSecondary);
+
+ mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, SECOND_DISPLAY_ID))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->assertNoEvents();
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
+}
+
+// TODO(b/111361570): multi-display focus, one focus window per display.
+TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
+ sp<FakeApplicationHandle> application2 = new FakeApplicationHandle();
+ sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2");
+
+ // Set focus to second display window.
+ mDispatcher->setFocusedApplication(application2);
+ windowInSecondary->setFocus();
+
+ // Update all windows per displays.
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push(windowInPrimary);
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+
+ constexpr int32_t SECOND_DISPLAY_ID = 1;
+ windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
+ Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+ inputWindowHandles_Second.push(windowInSecondary);
+ mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+
+ // Test inject a key down.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->assertNoEvents();
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+
+ // Remove secondary display.
+ inputWindowHandles_Second.clear();
+ mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+
+ // Expect old focus should receive a cancel event.
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+
+ // Test inject a key down, should timeout because of no target window.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+ windowInPrimary->assertNoEvents();
+ windowInSecondary->assertNoEvents();
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 22f15a0..9b985dc 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -142,7 +142,7 @@
}
void setDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
- const String8& uniqueId) {
+ const std::string& uniqueId) {
DisplayViewport v = createDisplayViewport(displayId, width, height, orientation, uniqueId);
// Set the size of both the internal and external display at the same time.
mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_INTERNAL, v);
@@ -150,14 +150,14 @@
}
void setVirtualDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
- const String8& uniqueId) {
+ const std::string& uniqueId) {
Vector<DisplayViewport> viewports;
viewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId));
mConfig.setVirtualDisplayViewports(viewports);
}
- void addExcludedDeviceName(const String8& deviceName) {
- mConfig.excludedDeviceNames.push(deviceName);
+ void addExcludedDeviceName(const std::string& deviceName) {
+ mConfig.excludedDeviceNames.push_back(deviceName);
}
void addDisabledDevice(int32_t deviceId) {
@@ -188,7 +188,7 @@
return mInputDevices;
}
- TouchAffineTransformation getTouchAffineTransformation(const String8& inputDeviceDescriptor,
+ TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
int32_t surfaceRotation) {
return transform;
}
@@ -203,7 +203,7 @@
private:
DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
- int32_t orientation, const String8& uniqueId) {
+ int32_t orientation, const std::string& uniqueId) {
bool isRotated = (orientation == DISPLAY_ORIENTATION_90
|| orientation == DISPLAY_ORIENTATION_270);
DisplayViewport v;
@@ -236,11 +236,11 @@
}
virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier&) {
- return NULL;
+ return nullptr;
}
- virtual String8 getDeviceAlias(const InputDeviceIdentifier&) {
- return String8::empty();
+ virtual std::string getDeviceAlias(const InputDeviceIdentifier&) {
+ return "";
}
};
@@ -263,7 +263,7 @@
}
void assertNotifyConfigurationChangedWasCalled(
- NotifyConfigurationChangedArgs* outEventArgs = NULL) {
+ NotifyConfigurationChangedArgs* outEventArgs = nullptr) {
ASSERT_FALSE(mNotifyConfigurationChangedArgsQueue.empty())
<< "Expected notifyConfigurationChanged() to have been called.";
if (outEventArgs) {
@@ -278,7 +278,7 @@
}
void assertNotifyDeviceResetWasCalled(
- NotifyDeviceResetArgs* outEventArgs = NULL) {
+ NotifyDeviceResetArgs* outEventArgs = nullptr) {
ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty())
<< "Expected notifyDeviceReset() to have been called.";
if (outEventArgs) {
@@ -292,7 +292,7 @@
<< "Expected notifyDeviceReset() to not have been called.";
}
- void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) {
+ void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = nullptr) {
ASSERT_FALSE(mNotifyKeyArgsQueue.empty())
<< "Expected notifyKey() to have been called.";
if (outEventArgs) {
@@ -306,7 +306,7 @@
<< "Expected notifyKey() to not have been called.";
}
- void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = NULL) {
+ void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = nullptr) {
ASSERT_FALSE(mNotifyMotionArgsQueue.empty())
<< "Expected notifyMotion() to have been called.";
if (outEventArgs) {
@@ -320,7 +320,7 @@
<< "Expected notifyMotion() to not have been called.";
}
- void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = NULL) {
+ void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr) {
ASSERT_FALSE(mNotifySwitchArgsQueue.empty())
<< "Expected notifySwitch() to have been called.";
if (outEventArgs) {
@@ -392,7 +392,7 @@
};
KeyedVector<int32_t, Device*> mDevices;
- Vector<String8> mExcludedDevices;
+ std::vector<std::string> mExcludedDevices;
List<RawEvent> mEvents;
protected:
@@ -405,7 +405,7 @@
public:
FakeEventHub() { }
- void addDevice(int32_t deviceId, const String8& name, uint32_t classes) {
+ void addDevice(int32_t deviceId, const std::string& name, uint32_t classes) {
Device* device = new Device(classes);
device->identifier.name = name;
mDevices.add(deviceId, device);
@@ -422,7 +422,7 @@
bool isDeviceEnabled(int32_t deviceId) {
Device* device = getDevice(deviceId);
- if (device == NULL) {
+ if (device == nullptr) {
ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
return false;
}
@@ -432,7 +432,7 @@
status_t enableDevice(int32_t deviceId) {
status_t result;
Device* device = getDevice(deviceId);
- if (device == NULL) {
+ if (device == nullptr) {
ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
return BAD_VALUE;
}
@@ -446,7 +446,7 @@
status_t disableDevice(int32_t deviceId) {
Device* device = getDevice(deviceId);
- if (device == NULL) {
+ if (device == nullptr) {
ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
return BAD_VALUE;
}
@@ -534,7 +534,7 @@
return device->leds.valueFor(led);
}
- Vector<String8>& getExcludedDevices() {
+ std::vector<std::string>& getExcludedDevices() {
return mExcludedDevices;
}
@@ -566,7 +566,7 @@
private:
Device* getDevice(int32_t deviceId) const {
ssize_t index = mDevices.indexOfKey(deviceId);
- return index >= 0 ? mDevices.valueAt(index) : NULL;
+ return index >= 0 ? mDevices.valueAt(index) : nullptr;
}
virtual uint32_t getDeviceClasses(int32_t deviceId) const {
@@ -651,14 +651,14 @@
return &device->keysByScanCode.valueAt(index);
}
}
- return NULL;
+ return nullptr;
}
virtual status_t mapAxis(int32_t, int32_t, AxisInfo*) const {
return NAME_NOT_FOUND;
}
- virtual void setExcludedDevices(const Vector<String8>& devices) {
+ virtual void setExcludedDevices(const std::vector<std::string>& devices) {
mExcludedDevices = devices;
}
@@ -781,7 +781,7 @@
}
virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t) const {
- return NULL;
+ return nullptr;
}
virtual bool setKeyboardLayoutOverlay(int32_t, const sp<KeyCharacterMap>&) {
@@ -940,7 +940,7 @@
mResetWasCalled = false;
}
- void assertProcessWasCalled(RawEvent* outLastEvent = NULL) {
+ void assertProcessWasCalled(RawEvent* outLastEvent = nullptr) {
ASSERT_TRUE(mProcessWasCalled)
<< "Expected process() to have been called.";
if (outLastEvent) {
@@ -1039,7 +1039,7 @@
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
InputReader(eventHub, policy, listener),
- mNextDevice(NULL) {
+ mNextDevice(nullptr) {
}
virtual ~InstrumentedInputReader() {
@@ -1052,7 +1052,7 @@
mNextDevice = device;
}
- InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const String8& name,
+ InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const std::string& name,
uint32_t classes) {
InputDeviceIdentifier identifier;
identifier.name = name;
@@ -1066,7 +1066,7 @@
const InputDeviceIdentifier& identifier, uint32_t classes) {
if (mNextDevice) {
InputDevice* device = mNextDevice;
- mNextDevice = NULL;
+ mNextDevice = nullptr;
return device;
}
return InputReader::createDeviceLocked(deviceId, controllerNumber, identifier, classes);
@@ -1101,7 +1101,7 @@
mFakeEventHub.clear();
}
- void addDevice(int32_t deviceId, const String8& name, uint32_t classes,
+ void addDevice(int32_t deviceId, const std::string& name, uint32_t classes,
const PropertyMap* configuration) {
mFakeEventHub->addDevice(deviceId, name, classes);
@@ -1129,7 +1129,7 @@
}
FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
- const String8& name, uint32_t classes, uint32_t sources,
+ const std::string& name, uint32_t classes, uint32_t sources,
const PropertyMap* configuration) {
InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes);
FakeInputMapper* mapper = new FakeInputMapper(device, sources);
@@ -1141,17 +1141,18 @@
};
TEST_F(InputReaderTest, GetInputDevices) {
- ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"),
- INPUT_DEVICE_CLASS_KEYBOARD, NULL));
- ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("ignored"),
- 0, NULL)); // no classes so device will be ignored
+ ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard",
+ INPUT_DEVICE_CLASS_KEYBOARD, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored",
+ 0, nullptr)); // no classes so device will be ignored
+
Vector<InputDeviceInfo> inputDevices;
mReader->getInputDevices(inputDevices);
ASSERT_EQ(1U, inputDevices.size());
ASSERT_EQ(1, inputDevices[0].getId());
- ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string());
+ ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
@@ -1160,7 +1161,7 @@
inputDevices = mFakePolicy->getInputDevices();
ASSERT_EQ(1U, inputDevices.size());
ASSERT_EQ(1, inputDevices[0].getId());
- ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string());
+ ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
@@ -1169,14 +1170,14 @@
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0, String8("fake"), deviceClass);
+ InputDevice* device = mReader->newDevice(deviceId, 0, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
mReader->setNextDevice(device);
- addDevice(deviceId, String8("fake"), deviceClass, NULL);
+ addDevice(deviceId, "fake", deviceClass, nullptr);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(NULL));
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(nullptr));
NotifyDeviceResetArgs resetArgs;
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
@@ -1207,9 +1208,9 @@
}
TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
- FakeInputMapper* mapper = NULL;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+ FakeInputMapper* mapper = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
+ INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0,
@@ -1234,9 +1235,9 @@
}
TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
- FakeInputMapper* mapper = NULL;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+ FakeInputMapper* mapper = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
+ INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN);
ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0,
@@ -1261,9 +1262,9 @@
}
TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
- FakeInputMapper* mapper = NULL;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+ FakeInputMapper* mapper = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
+ INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN);
ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0,
@@ -1288,9 +1289,10 @@
}
TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
- FakeInputMapper* mapper = NULL;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+ FakeInputMapper* mapper = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
+ INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
+
mapper->addSupportedKeyCode(AKEYCODE_A);
mapper->addSupportedKeyCode(AKEYCODE_B);
@@ -1323,7 +1325,7 @@
}
TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) {
- addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, NULL);
+ addDevice(1, "ignored", INPUT_DEVICE_CLASS_KEYBOARD, nullptr);
NotifyConfigurationChangedArgs args;
@@ -1332,9 +1334,9 @@
}
TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
- FakeInputMapper* mapper = NULL;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
- INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+ FakeInputMapper* mapper = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
+ INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1);
mReader->loopOnce();
@@ -1373,7 +1375,7 @@
mFakeListener = new FakeInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
- mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
+ mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0);
InputDeviceIdentifier identifier;
identifier.name = DEVICE_NAME;
mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
@@ -1399,7 +1401,7 @@
TEST_F(InputDeviceTest, ImmutableProperties) {
ASSERT_EQ(DEVICE_ID, mDevice->getId());
- ASSERT_STREQ(DEVICE_NAME, mDevice->getName());
+ ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str());
ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses());
}
@@ -1427,7 +1429,7 @@
InputDeviceInfo info;
mDevice->getDeviceInfo(&info);
ASSERT_EQ(DEVICE_ID, info.getId());
- ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string());
+ ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NONE, info.getKeyboardType());
ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, info.getSources());
@@ -1497,7 +1499,7 @@
InputDeviceInfo info;
mDevice->getDeviceInfo(&info);
ASSERT_EQ(DEVICE_ID, info.getId());
- ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string());
+ ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, info.getKeyboardType());
ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), info.getSources());
@@ -1570,7 +1572,7 @@
mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
- mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
+ mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0);
}
virtual void TearDown() {
@@ -1597,12 +1599,12 @@
void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
int32_t orientation) {
- mFakePolicy->setDisplayViewport(displayId, width, height, orientation, String8::empty());
+ mFakePolicy->setDisplayViewport(displayId, width, height, orientation, "");
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
}
void setVirtualDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
- int32_t orientation, const String8& uniqueId) {
+ int32_t orientation, const std::string& uniqueId) {
mFakePolicy->setVirtualDisplayViewport(displayId, width, height, orientation, uniqueId);
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
}
@@ -1621,7 +1623,7 @@
static void assertMotionRange(const InputDeviceInfo& info,
int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) {
const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
- ASSERT_TRUE(range != NULL) << "Axis: " << axis << " Source: " << source;
+ ASSERT_TRUE(range != nullptr) << "Axis: " << axis << " Source: " << source;
ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source;
ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source;
ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source;
@@ -1996,6 +1998,64 @@
ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
}
+TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware) {
+ // If the keyboard is not orientation aware,
+ // key events should not be associated with a specific display id
+ mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
+ AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ addMapperAndConfigure(mapper);
+ NotifyKeyArgs args;
+
+ // Display id should be ADISPLAY_ID_NONE without any display configuration.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(ADISPLAY_ID_NONE, args.displayId);
+
+ setDisplayInfoAndReconfigure(DISPLAY_ID,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(ADISPLAY_ID_NONE, args.displayId);
+}
+
+TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) {
+ // If the keyboard is orientation aware,
+ // key events should be associated with the internal viewport
+ mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
+ AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ addConfigurationProperty("keyboard.orientationAware", "1");
+ addMapperAndConfigure(mapper);
+ NotifyKeyArgs args;
+
+ // Display id should be ADISPLAY_ID_NONE without any display configuration.
+ // ^--- already checked by the previous test
+
+ setDisplayInfoAndReconfigure(DISPLAY_ID,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(DISPLAY_ID, args.displayId);
+
+ constexpr int32_t newDisplayId = 2;
+ setDisplayInfoAndReconfigure(newDisplayId,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(newDisplayId, args.displayId);
+}
+
TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
@@ -2174,8 +2234,8 @@
mapper->populateDeviceInfo(&info);
// Initially there may not be a valid motion range.
- ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
- ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
+ ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
+ ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
@@ -2990,7 +3050,7 @@
void TouchInputMapperTest::prepareVirtualDisplay(int32_t orientation) {
setVirtualDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
- VIRTUAL_DISPLAY_HEIGHT, orientation, String8(VIRTUAL_DISPLAY_UNIQUE_ID));
+ VIRTUAL_DISPLAY_HEIGHT, orientation, VIRTUAL_DISPLAY_UNIQUE_ID);
}
void TouchInputMapperTest::prepareVirtualKeys() {
diff --git a/services/media/arcvideobridge/Android.bp b/services/media/arcvideobridge/Android.bp
deleted file mode 100644
index ca5b896..0000000
--- a/services/media/arcvideobridge/Android.bp
+++ /dev/null
@@ -1,28 +0,0 @@
-cc_library_shared {
- name: "libarcvideobridge",
- product_variables: {
- arc: {
- srcs: [
- "IArcVideoBridge.cpp",
- ],
- shared_libs: [
- "libarcbridge",
- "libarcbridgeservice",
- "libbinder",
- "libchrome",
- "liblog",
- "libmojo",
- "libutils",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
- include_dirs: [
- "frameworks/native/include/media/arcvideobridge",
- ]
- }
- }
-}
diff --git a/services/media/arcvideobridge/IArcVideoBridge.cpp b/services/media/arcvideobridge/IArcVideoBridge.cpp
deleted file mode 100644
index 468b76b..0000000
--- a/services/media/arcvideobridge/IArcVideoBridge.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#define LOG_TAG "IArcVideoBridge"
-//#define LOG_NDEBUG 0
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "IArcVideoBridge.h"
-#include <binder/Parcel.h>
-#include <utils/Log.h>
-
-namespace android {
-
-enum {
- BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY = IBinder::FIRST_CALL_TRANSACTION,
- HOST_VERSION,
-};
-
-class BpArcVideoBridge : public BpInterface<IArcVideoBridge> {
-public:
- BpArcVideoBridge(const sp<IBinder>& impl) : BpInterface<IArcVideoBridge>(impl) { }
-
- virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() {
- Parcel data, reply;
- ALOGV("bootstrapVideoAcceleratorFactory");
- data.writeInterfaceToken(IArcVideoBridge::getInterfaceDescriptor());
- status_t status = remote()->transact(
- BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY, data, &reply, 0);
- if (status != 0) {
- ALOGE("transact failed: %d", status);
- return arc::MojoBootstrapResult();
- }
- return arc::MojoBootstrapResult::createFromParcel(reply);
- }
-
- virtual int32_t hostVersion() {
- Parcel data, reply;
- ALOGV("hostVersion");
- data.writeInterfaceToken(IArcVideoBridge::getInterfaceDescriptor());
- status_t status = remote()->transact(HOST_VERSION, data, &reply, 0);
- if (status != 0) {
- ALOGE("transact failed: %d", status);
- return false;
- }
- return reply.readInt32();
- }
-};
-
-IMPLEMENT_META_INTERFACE(ArcVideoBridge, "android.os.IArcVideoBridge");
-
-status_t BnArcVideoBridge::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
- switch(code) {
- case BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY: {
- ALOGV("BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY");
- CHECK_INTERFACE(IArcVideoBridge, data, reply);
- arc::MojoBootstrapResult result = bootstrapVideoAcceleratorFactory();
- return result.writeToParcel(reply);
- }
- case HOST_VERSION: {
- ALOGV("HOST_VERSION");
- CHECK_INTERFACE(IArcVideoBridge, data, reply);
- reply->writeInt32(hostVersion());
- return OK;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-} // namespace android
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index d8e5b29..14f9a12 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -94,7 +94,7 @@
bool BatteryService::checkService() {
if (mBatteryStatService == nullptr) {
const sp<IServiceManager> sm(defaultServiceManager());
- if (sm != NULL) {
+ if (sm != nullptr) {
const String16 name("batterystats");
mBatteryStatService = interface_cast<IBatteryStats>(sm->getService(name));
}
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index 7b00f4d..f2ea02e 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -94,7 +94,7 @@
return "GeoMag Rotation Vector Sensor";
default:
assert(0);
- return NULL;
+ return nullptr;
}
}
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 115a983..ae3f42f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -208,7 +208,7 @@
if(numHidlTransportErrors > 0) {
ALOGE("Saw %d Hidl transport failures", numHidlTransportErrors);
- HidlTransportErrorLog errLog(time(NULL), numHidlTransportErrors);
+ HidlTransportErrorLog errLog(time(nullptr), numHidlTransportErrors);
mHidlTransportErrors.add(errLog);
mTotalHidlTransportErrors++;
}
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 956844f..0fb4ac6 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -31,7 +31,7 @@
const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
const String16& opPackageName, bool hasSensorAccess)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
- mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
+ mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(nullptr),
mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
mDestroyed(false), mHasSensorAccess(hasSensorAccess) {
mChannel = new BitTube(mService->mSocketBufferSize);
@@ -55,8 +55,8 @@
}
mService->cleanupConnection(this);
- if (mEventCache != NULL) {
- delete mEventCache;
+ if (mEventCache != nullptr) {
+ delete[] mEventCache;
}
mDestroyed = true;
}
@@ -200,7 +200,7 @@
// Add the file descriptor to the Looper for receiving acknowledegments if the app has
// registered for wake-up sensors OR for sending events in the cache.
- int ret = looper->addFd(mChannel->getSendFd(), 0, looper_flags, this, NULL);
+ int ret = looper->addFd(mChannel->getSendFd(), 0, looper_flags, this, nullptr);
if (ret == 1) {
ALOGD_IF(DEBUG_CONNECTIONS, "%p addFd fd=%d", this, mChannel->getSendFd());
mHasLooperCallbacks = true;
@@ -224,7 +224,7 @@
wp<const SensorEventConnection> const * mapFlushEventsToConnections) {
// filter out events not for this connection
- sensors_event_t* sanitizedBuffer = nullptr;
+ std::unique_ptr<sensors_event_t[]> sanitizedBuffer;
int count = 0;
Mutex::Autolock _l(mConnectionLock);
@@ -293,7 +293,8 @@
scratch = const_cast<sensors_event_t *>(buffer);
count = numEvents;
} else {
- scratch = sanitizedBuffer = new sensors_event_t[numEvents];
+ sanitizedBuffer.reset(new sensors_event_t[numEvents]);
+ scratch = sanitizedBuffer.get();
for (size_t i = 0; i < numEvents; i++) {
if (buffer[i].type == SENSOR_TYPE_META_DATA) {
scratch[count++] = buffer[i++];
@@ -305,7 +306,6 @@
sendPendingFlushEventsLocked();
// Early return if there are no events for this connection.
if (count == 0) {
- delete sanitizedBuffer;
return status_t(NO_ERROR);
}
@@ -323,7 +323,6 @@
// the max cache size that is desired.
if (mCacheSize + count < computeMaxCacheSizeLocked()) {
reAllocateCacheLocked(scratch, count);
- delete sanitizedBuffer;
return status_t(NO_ERROR);
}
// Some events need to be dropped.
@@ -342,7 +341,6 @@
memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize,
numEventsDropped * sizeof(sensors_event_t));
}
- delete sanitizedBuffer;
return status_t(NO_ERROR);
}
@@ -373,7 +371,7 @@
--mTotalAcksNeeded;
#endif
}
- if (mEventCache == NULL) {
+ if (mEventCache == nullptr) {
mMaxCacheSize = computeMaxCacheSizeLocked();
mEventCache = new sensors_event_t[mMaxCacheSize];
mCacheSize = 0;
@@ -384,7 +382,6 @@
// Add this file descriptor to the looper to get a callback when this fd is available for
// writing.
updateLooperRegistrationLocked(mService->getLooper());
- delete sanitizedBuffer;
return size;
}
@@ -394,7 +391,6 @@
}
#endif
- delete sanitizedBuffer;
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
@@ -415,7 +411,7 @@
ALOGD_IF(DEBUG_CONNECTIONS, "reAllocateCacheLocked maxCacheSize=%d %d", mMaxCacheSize,
new_cache_size);
- delete mEventCache;
+ delete[] mEventCache;
mEventCache = eventCache_new;
mCacheSize += count;
mMaxCacheSize = new_cache_size;
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 032721e..40c21ff 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -53,7 +53,7 @@
bool hasSensorAccess);
status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
- wp<const SensorEventConnection> const * mapFlushEventsToConnections = NULL);
+ wp<const SensorEventConnection> const * mapFlushEventsToConnections = nullptr);
bool hasSensor(int32_t handle) const;
bool hasAnySensor() const;
bool hasOneShotSensors() const;
diff --git a/services/sensorservice/SensorRecord.cpp b/services/sensorservice/SensorRecord.cpp
index 53fb9de..7c4c6a2 100644
--- a/services/sensorservice/SensorRecord.cpp
+++ b/services/sensorservice/SensorRecord.cpp
@@ -71,7 +71,7 @@
if (mPendingFlushConnections.size() > 0) {
return mPendingFlushConnections[0];
}
- return NULL;
+ return nullptr;
}
void SensorService::SensorRecord::clearAllPendingFlushConnections() {
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index bba8372..5411515 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -47,7 +47,7 @@
mPid = (thread != nullptr) ? thread->getCallingPid() : -1;
mUid = (thread != nullptr) ? thread->getCallingUid() : -1;
- time_t rawtime = time(NULL);
+ time_t rawtime = time(nullptr);
struct tm * timeinfo = localtime(&rawtime);
mHour = static_cast<int8_t>(timeinfo->tm_hour);
mMin = static_cast<int8_t>(timeinfo->tm_min);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8e9e7fd..372b609 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -250,7 +250,7 @@
// it to maxSystemSocketBufferSize if necessary.
FILE *fp = fopen("/proc/sys/net/core/wmem_max", "r");
char line[128];
- if (fp != NULL && fgets(line, sizeof(line), fp) != NULL) {
+ if (fp != nullptr && fgets(line, sizeof(line), fp) != nullptr) {
line[sizeof(line) - 1] = '\0';
size_t maxSystemSocketBufferSize;
sscanf(line, "%zu", &maxSystemSocketBufferSize);
@@ -295,7 +295,7 @@
{
Mutex::Autolock _l(mLock);
for (size_t i = 0 ; i < activeConnections.size(); i++) {
- if (activeConnections[i] != 0 && activeConnections[i]->getUid() == uid) {
+ if (activeConnections[i] != nullptr && activeConnections[i]->getUid() == uid) {
activeConnections[i]->setSensorAccess(hasAccess);
}
}
@@ -475,7 +475,7 @@
result.appendFormat("%zd active connections\n", mActiveConnections.size());
for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != 0) {
+ if (connection != nullptr) {
result.appendFormat("Connection Number: %zu \n", i);
connection->dump(result);
}
@@ -722,11 +722,11 @@
// on the hardware sensor. mapFlushEventsToConnections[i] will be the
// SensorEventConnection mapped to the corresponding flush_complete_event in
// mSensorEventBuffer[i] if such a mapping exists (NULL otherwise).
- mMapFlushEventsToConnections[i] = NULL;
+ mMapFlushEventsToConnections[i] = nullptr;
if (mSensorEventBuffer[i].type == SENSOR_TYPE_META_DATA) {
const int sensor_handle = mSensorEventBuffer[i].meta_data.sensor;
SensorRecord* rec = mActiveSensors.valueFor(sensor_handle);
- if (rec != NULL) {
+ if (rec != nullptr) {
mMapFlushEventsToConnections[i] = rec->getFirstPendingFlushConnection();
rec->removeFirstPendingFlushConnection();
}
@@ -770,7 +770,7 @@
size_t numConnections = activeConnections.size();
for (size_t i=0 ; i < numConnections; ++i) {
- if (activeConnections[i] != NULL) {
+ if (activeConnections[i] != nullptr) {
activeConnections[i]->removeSensor(handle);
}
}
@@ -783,7 +783,7 @@
bool needsWakeLock = false;
size_t numConnections = activeConnections.size();
for (size_t i=0 ; i < numConnections; ++i) {
- if (activeConnections[i] != 0) {
+ if (activeConnections[i] != nullptr) {
activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
mMapFlushEventsToConnections);
needsWakeLock |= activeConnections[i]->needsWakeLock();
@@ -816,7 +816,7 @@
{
Mutex::Autolock _l(mLock);
for (size_t i=0 ; i < activeConnections.size(); ++i) {
- if (activeConnections[i] != 0) {
+ if (activeConnections[i] != nullptr) {
activeConnections[i]->resetWakeLockRefCount();
}
}
@@ -1021,15 +1021,15 @@
int requestedMode, const String16& opPackageName) {
// Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION.
if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {
- return NULL;
+ return nullptr;
}
Mutex::Autolock _l(mLock);
// To create a client in DATA_INJECTION mode to inject data, SensorService should already be
// operating in DI mode.
if (requestedMode == DATA_INJECTION) {
- if (mCurrentOperatingMode != DATA_INJECTION) return NULL;
- if (!isWhiteListedPackage(packageName)) return NULL;
+ if (mCurrentOperatingMode != DATA_INJECTION) return nullptr;
+ if (!isWhiteListedPackage(packageName)) return nullptr;
}
uid_t uid = IPCThreadState::self()->getCallingUid();
@@ -1325,7 +1325,7 @@
}
SensorRecord* rec = mActiveSensors.valueFor(handle);
- if (rec == 0) {
+ if (rec == nullptr) {
rec = new SensorRecord(connection);
mActiveSensors.add(handle, rec);
if (sensor->isVirtual()) {
@@ -1352,7 +1352,7 @@
if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
setWakeLockAcquiredLocked(true);
}
- connection->sendEvents(&event, 1, NULL);
+ connection->sendEvents(&event, 1, nullptr);
if (!connection->needsWakeLock() && mWakeLockAcquired) {
checkWakeLockStateLocked();
}
@@ -1534,7 +1534,7 @@
status_t err_flush = sensor->flush(connection.get(), handle);
if (err_flush == NO_ERROR) {
SensorRecord* rec = mActiveSensors.valueFor(handle);
- if (rec != NULL) rec->addPendingFlushConnection(connection);
+ if (rec != nullptr) rec->addPendingFlushConnection(connection);
}
err = (err_flush != NO_ERROR) ? err_flush : err;
}
@@ -1592,7 +1592,7 @@
bool releaseLock = true;
for (size_t i=0 ; i<mActiveConnections.size() ; i++) {
sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != 0) {
+ if (connection != nullptr) {
if (connection->needsWakeLock()) {
releaseLock = false;
break;
@@ -1617,7 +1617,7 @@
Mutex::Autolock _l(mLock);
for (size_t i=0 ; i < mActiveConnections.size(); ++i) {
sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != 0) {
+ if (connection != nullptr) {
activeConnections->add(connection);
}
}
diff --git a/services/sensorservice/hidl/EventQueue.cpp b/services/sensorservice/hidl/EventQueue.cpp
index ff20066..b781744 100644
--- a/services/sensorservice/hidl/EventQueue.cpp
+++ b/services/sensorservice/hidl/EventQueue.cpp
@@ -64,7 +64,7 @@
mInternalQueue(internalQueue) {
mLooper->addFd(internalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT,
- new EventQueueLooperCallback(internalQueue, callback), NULL /* data */);
+ new EventQueueLooperCallback(internalQueue, callback), nullptr /* data */);
}
void EventQueue::onLastStrongRef(const void *id) {
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index fee6da1..9380600 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -157,7 +157,7 @@
JavaVMAttachArgs args{
.version = JNI_VERSION_1_2,
.name = POLL_THREAD_NAME,
- .group = NULL
+ .group = nullptr
};
JNIEnv* env;
if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 320e11f..e72aaca 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -23,9 +23,11 @@
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.1",
+ "android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
"android.hardware.power@1.0",
"android.hardware.power@1.3",
"libbase",
@@ -53,6 +55,7 @@
"libvulkan",
],
static_libs: [
+ "librenderengine",
"libserviceutils",
"libtrace_proto",
"libvkjson",
@@ -62,14 +65,17 @@
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
],
export_static_lib_headers: [
+ "librenderengine",
"libserviceutils",
],
export_shared_lib_headers: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
"android.hardware.power@1.3",
"libhidlbase",
"libhidltransport",
@@ -89,48 +95,43 @@
srcs: [
"BufferLayer.cpp",
"BufferLayerConsumer.cpp",
+ "BufferQueueLayer.cpp",
+ "BufferStateLayer.cpp",
"Client.cpp",
"ColorLayer.cpp",
"ContainerLayer.cpp",
"DisplayDevice.cpp",
"DisplayHardware/ComposerHal.cpp",
+ "DisplayHardware/DisplayIdentification.cpp",
"DisplayHardware/FramebufferSurface.cpp",
"DisplayHardware/HWC2.cpp",
"DisplayHardware/HWComposer.cpp",
"DisplayHardware/HWComposerBufferCache.cpp",
"DisplayHardware/PowerAdvisor.cpp",
"DisplayHardware/VirtualDisplaySurface.cpp",
- "DispSync.cpp",
"Effects/Daltonizer.cpp",
- "EventControlThread.cpp",
"EventLog/EventLog.cpp",
- "EventThread.cpp",
"FrameTracker.cpp",
"GpuService.cpp",
"Layer.cpp",
+ "LayerBE.cpp",
"LayerProtoHelper.cpp",
"LayerRejecter.cpp",
"LayerStats.cpp",
"LayerVector.cpp",
- "MessageQueue.cpp",
"MonitoredProducer.cpp",
"RenderArea.cpp",
- "RenderEngine/Description.cpp",
- "RenderEngine/GLES20RenderEngine.cpp",
- "RenderEngine/GLExtensions.cpp",
- "RenderEngine/Image.cpp",
- "RenderEngine/Mesh.cpp",
- "RenderEngine/Program.cpp",
- "RenderEngine/ProgramCache.cpp",
- "RenderEngine/RenderEngine.cpp",
- "RenderEngine/Surface.cpp",
- "RenderEngine/Texture.cpp",
+ "Scheduler/DispSync.cpp",
+ "Scheduler/DispSyncSource.cpp",
+ "Scheduler/EventControlThread.cpp",
+ "Scheduler/EventThread.cpp",
+ "Scheduler/MessageQueue.cpp",
+ "Scheduler/Scheduler.cpp",
"StartPropertySetThread.cpp",
"SurfaceFlinger.cpp",
"SurfaceInterceptor.cpp",
"SurfaceTracing.cpp",
"TimeStats/TimeStats.cpp",
- "Transform.cpp",
],
}
@@ -169,6 +170,7 @@
"android.frameworks.displayservice@1.0",
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
+ "android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
"libbinder",
"libcutils",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f5b5eda..89394cd 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -23,9 +23,8 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "LayerRejecter.h"
-#include "clz.h"
-#include "RenderEngine/RenderEngine.h"
+#include <renderengine/RenderEngine.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
@@ -53,22 +52,18 @@
BufferLayer::BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
uint32_t w, uint32_t h, uint32_t flags)
: Layer(flinger, client, name, w, h, flags),
- mConsumer(nullptr),
- mTextureName(UINT32_MAX),
- mFormat(PIXEL_FORMAT_NONE),
+ mTextureName(mFlinger->getNewTexture()),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mBufferLatched(false),
- mPreviousFrameNumber(0),
- mUpdateTexImageFailed(false),
mRefreshPending(false) {
ALOGV("Creating Layer %s", name.string());
- mTextureName = mFlinger->getNewTexture();
- mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
+ mTexture.init(renderengine::Texture::TEXTURE_EXTERNAL, mTextureName);
- if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false;
+ mPremultipliedAlpha = !(flags & ISurfaceComposerClient::eNonPremultiplied);
- mCurrentState.requested = mCurrentState.active;
+ mPotentialCursor = flags & ISurfaceComposerClient::eCursorWindow;
+ mProtectedByApp = flags & ISurfaceComposerClient::eProtectedByApp;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -89,7 +84,7 @@
if (mFlinger->mForceFullDamage) {
surfaceDamageRegion = Region::INVALID_REGION;
} else {
- surfaceDamageRegion = mConsumer->getSurfaceDamage();
+ surfaceDamageRegion = getDrawingSurfaceDamage();
}
}
@@ -97,46 +92,27 @@
surfaceDamageRegion.clear();
}
-bool BufferLayer::isProtected() const {
- const sp<GraphicBuffer>& buffer(getBE().compositionInfo.mBuffer);
- return (buffer != 0) &&
- (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+bool BufferLayer::isOpaque(const Layer::State& s) const {
+ // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
+ // layer's opaque flag.
+ if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
+ return false;
+ }
+
+ // if the layer has the opaque flag, then we're always opaque,
+ // otherwise we use the current buffer's format.
+ return ((s.flags & layer_state_t::eLayerOpaque) != 0) || getOpacityForFormat(getPixelFormat());
}
bool BufferLayer::isVisible() const {
return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
- (getBE().compositionInfo.mBuffer != nullptr ||
- getBE().compositionInfo.hwc.sidebandStream != nullptr);
+ (mActiveBuffer != nullptr || getBE().compositionInfo.hwc.sidebandStream != nullptr);
}
bool BufferLayer::isFixedSize() const {
return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
}
-status_t BufferLayer::setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) {
- uint32_t const maxSurfaceDims =
- min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
-
- // never allow a surface larger than what our underlying GL implementation
- // can handle.
- if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
- ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
- return BAD_VALUE;
- }
-
- mFormat = format;
-
- mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
- mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
- mCurrentOpacity = getOpacityForFormat(format);
-
- mConsumer->setDefaultBufferSize(w, h);
- mConsumer->setDefaultBufferFormat(format);
- mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-
- return NO_ERROR;
-}
-
static constexpr mat4 inverseOrientation(uint32_t transform) {
const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
@@ -159,10 +135,10 @@
* onDraw will draw the current layer onto the presentable buffer
*/
void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) const {
+ bool useIdentityTransform) {
ATRACE_CALL();
- if (CC_UNLIKELY(getBE().compositionInfo.mBuffer == 0)) {
+ if (CC_UNLIKELY(mActiveBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
// SurfaceView because the WindowManager can't know when the client
@@ -191,7 +167,7 @@
// Bind the current buffer to the GL texture, and wait for it to be
// ready for us to draw into.
- status_t err = mConsumer->bindTextureImage();
+ status_t err = bindTextureImage();
if (err != NO_ERROR) {
ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
// Go ahead and draw the buffer anyway; no matter what we do the screen
@@ -204,12 +180,12 @@
if (!blackOutLayer) {
// TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize();
+ const bool useFiltering = needsFiltering(renderArea) || isFixedSize();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
- mConsumer->setFilteringEnabled(useFiltering);
- mConsumer->getTransformMatrix(textureMatrix);
+ setFilteringEnabled(useFiltering);
+ getDrawingTransformMatrix(textureMatrix);
if (getTransformToDisplayInverse()) {
/*
@@ -240,8 +216,7 @@
}
// Set things up for texturing.
- mTexture.setDimensions(getBE().compositionInfo.mBuffer->getWidth(),
- getBE().compositionInfo.mBuffer->getHeight());
+ mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
mTexture.setFiltering(useFiltering);
mTexture.setMatrix(textureMatrix);
@@ -253,54 +228,61 @@
engine.disableTexturing();
}
-void BufferLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
- mConsumer->setReleaseFence(releaseFence);
+bool BufferLayer::isHdrY410() const {
+ // pixel format is HDR Y410 masquerading as RGBA_1010102
+ return (mCurrentDataSpace == ui::Dataspace::BT2020_ITU_PQ &&
+ getDrawingApi() == NATIVE_WINDOW_API_MEDIA &&
+ getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
-void BufferLayer::abandon() {
- mConsumer->abandon();
-}
+void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
+ // Apply this display's projection's viewport to the visible region
+ // before giving it to the HWC HAL.
+ const ui::Transform& tr = display->getTransform();
+ const auto& viewport = display->getViewport();
+ Region visible = tr.transform(visibleRegion.intersect(viewport));
+ const auto displayId = display->getId();
+ getBE().compositionInfo.hwc.visibleRegion = visible;
+ getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
-bool BufferLayer::shouldPresentNow(const DispSync& dispSync) const {
- if (mSidebandStreamChanged || mAutoRefresh) {
- return true;
+ // Sideband layers
+ if (getBE().compositionInfo.hwc.sidebandStream.get()) {
+ setCompositionType(displayId, HWC2::Composition::Sideband);
+ getBE().compositionInfo.compositionType = HWC2::Composition::Sideband;
+ return;
}
- Mutex::Autolock lock(mQueueItemLock);
- if (mQueueItems.empty()) {
- return false;
+ if (getBE().compositionInfo.hwc.skipGeometry) {
+ // Device or Cursor layers
+ if (mPotentialCursor) {
+ ALOGV("[%s] Requesting Cursor composition", mName.string());
+ setCompositionType(displayId, HWC2::Composition::Cursor);
+ } else {
+ ALOGV("[%s] Requesting Device composition", mName.string());
+ setCompositionType(displayId, HWC2::Composition::Device);
+ }
}
- auto timestamp = mQueueItems[0].mTimestamp;
- nsecs_t expectedPresent = mConsumer->computeExpectedPresent(dispSync);
- // Ignore timestamps more than a second in the future
- bool isPlausible = timestamp < (expectedPresent + s2ns(1));
- ALOGW_IF(!isPlausible,
- "[%s] Timestamp %" PRId64 " seems implausible "
- "relative to expectedPresent %" PRId64,
- mName.string(), timestamp, expectedPresent);
+ getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
+ getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
+ getBE().compositionInfo.hwc.supportedPerFrameMetadata = display->getSupportedPerFrameMetadata();
- bool isDue = timestamp < expectedPresent;
- return isDue || !isPlausible;
-}
-
-void BufferLayer::setTransformHint(uint32_t orientation) const {
- mConsumer->setTransformHint(orientation);
+ setHwcLayerBuffer(display);
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
if (mBufferLatched) {
Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addPreComposition(mCurrentFrameNumber,
- refreshStartTime);
+ mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
}
mRefreshPending = false;
- return mQueuedFrames > 0 || mSidebandStreamChanged ||
- mAutoRefresh;
+ return hasReadyFrame();
}
+
bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) {
+
// mFrameLatencyNeeded is true when a new frame was latched for the
// composition.
if (!mFrameLatencyNeeded) return false;
@@ -308,18 +290,18 @@
// Update mFrameEventHistory.
{
Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence,
- presentFence, compositorTiming);
+ mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
+ compositorTiming);
}
// Update mFrameTracker.
- nsecs_t desiredPresentTime = mConsumer->getTimestamp();
+ nsecs_t desiredPresentTime = getDesiredPresentTime();
mFrameTracker.setDesiredPresentTime(desiredPresentTime);
const std::string layerName(getName().c_str());
mTimeStats.setDesiredTime(layerName, mCurrentFrameNumber, desiredPresentTime);
- std::shared_ptr<FenceTime> frameReadyFence = mConsumer->getCurrentFenceTime();
+ std::shared_ptr<FenceTime> frameReadyFence = getCurrentFenceTime();
if (frameReadyFence->isValid()) {
mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
} else {
@@ -331,7 +313,7 @@
if (presentFence->isValid()) {
mTimeStats.setPresentFence(layerName, mCurrentFrameNumber, presentFence);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
- } else {
+ } else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t actualPresentTime =
@@ -345,58 +327,19 @@
return true;
}
-std::vector<OccupancyTracker::Segment> BufferLayer::getOccupancyHistory(bool forceFlush) {
- std::vector<OccupancyTracker::Segment> history;
- status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
- if (result != NO_ERROR) {
- ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
- return {};
- }
- return history;
-}
-
-bool BufferLayer::getTransformToDisplayInverse() const {
- return mConsumer->getTransformToDisplayInverse();
-}
-
-void BufferLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
- if (!mConsumer->releasePendingBuffer()) {
- return;
- }
-
- auto releaseFenceTime =
- std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
- mReleaseTimeline.updateSignalTimes();
- mReleaseTimeline.push(releaseFenceTime);
-
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- if (mPreviousFrameNumber != 0) {
- mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
- std::move(releaseFenceTime));
- }
-}
-
Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
ATRACE_CALL();
- if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
- // mSidebandStreamChanged was true
- mSidebandStream = mConsumer->getSidebandStream();
- // replicated in LayerBE until FE/BE is ready to be synchronized
- getBE().compositionInfo.hwc.sidebandStream = mSidebandStream;
- if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
- setTransactionFlags(eTransactionNeeded);
- mFlinger->setTransactionFlags(eTraversalNeeded);
- }
- recomputeVisibleRegions = true;
+ std::optional<Region> sidebandStreamDirtyRegion = latchSidebandStream(recomputeVisibleRegions);
- const State& s(getDrawingState());
- return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
+ if (sidebandStreamDirtyRegion) {
+ return *sidebandStreamDirtyRegion;
}
- Region outDirtyRegion;
- if (mQueuedFrames <= 0 && !mAutoRefresh) {
- return outDirtyRegion;
+ Region dirtyRegion;
+
+ if (!hasReadyFrame()) {
+ return dirtyRegion;
}
// if we've already called updateTexImage() without going through
@@ -405,119 +348,41 @@
// compositionComplete() call.
// we'll trigger an update in onPreComposition().
if (mRefreshPending) {
- return outDirtyRegion;
+ return dirtyRegion;
}
// If the head buffer's acquire fence hasn't signaled yet, return and
// try again later
- if (!headFenceHasSignaled()) {
+ if (!fenceHasSignaled()) {
mFlinger->signalLayerUpdate();
- return outDirtyRegion;
+ return dirtyRegion;
}
// Capture the old state of the layer for comparisons later
const State& s(getDrawingState());
const bool oldOpacity = isOpaque(s);
- sp<GraphicBuffer> oldBuffer = getBE().compositionInfo.mBuffer;
+ sp<GraphicBuffer> oldBuffer = mActiveBuffer;
if (!allTransactionsSignaled()) {
mFlinger->signalLayerUpdate();
- return outDirtyRegion;
+ return dirtyRegion;
}
- // This boolean is used to make sure that SurfaceFlinger's shadow copy
- // of the buffer queue isn't modified when the buffer queue is returning
- // BufferItem's that weren't actually queued. This can happen in shared
- // buffer mode.
- bool queuedBuffer = false;
- LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
- getProducerStickyTransform() != 0, mName.string(),
- mOverrideScalingMode, mFreezeGeometryUpdates);
- status_t updateResult =
- mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
- &mAutoRefresh, &queuedBuffer,
- mLastFrameNumberReceived);
- if (updateResult == BufferQueue::PRESENT_LATER) {
- // Producer doesn't want buffer to be displayed yet. Signal a
- // layer update so we check again at the next opportunity.
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
- // If the buffer has been rejected, remove it from the shadow queue
- // and return early
- if (queuedBuffer) {
- Mutex::Autolock lock(mQueueItemLock);
- mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
- mQueueItems.removeAt(0);
- android_atomic_dec(&mQueuedFrames);
- }
- return outDirtyRegion;
- } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
- // This can occur if something goes wrong when trying to create the
- // EGLImage for this buffer. If this happens, the buffer has already
- // been released, so we need to clean up the queue and bug out
- // early.
- if (queuedBuffer) {
- Mutex::Autolock lock(mQueueItemLock);
- mQueueItems.clear();
- android_atomic_and(0, &mQueuedFrames);
- mTimeStats.clearLayerRecord(getName().c_str());
- }
-
- // Once we have hit this state, the shadow queue may no longer
- // correctly reflect the incoming BufferQueue's contents, so even if
- // updateTexImage starts working, the only safe course of action is
- // to continue to ignore updates.
- mUpdateTexImageFailed = true;
-
- return outDirtyRegion;
+ status_t err = updateTexImage(recomputeVisibleRegions, latchTime);
+ if (err != NO_ERROR) {
+ return dirtyRegion;
}
- if (queuedBuffer) {
- // Autolock scope
- auto currentFrameNumber = mConsumer->getFrameNumber();
-
- Mutex::Autolock lock(mQueueItemLock);
-
- // Remove any stale buffers that have been dropped during
- // updateTexImage
- while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
- mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
- mQueueItems.removeAt(0);
- android_atomic_dec(&mQueuedFrames);
- }
-
- const std::string layerName(getName().c_str());
- mTimeStats.setAcquireFence(layerName, currentFrameNumber, mQueueItems[0].mFenceTime);
- mTimeStats.setLatchTime(layerName, currentFrameNumber, latchTime);
-
- mQueueItems.removeAt(0);
- }
-
- // Decrement the queued-frames count. Signal another event if we
- // have more frames pending.
- if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) ||
- mAutoRefresh) {
- mFlinger->signalLayerUpdate();
- }
-
- // update the active buffer
- getBE().compositionInfo.mBuffer =
- mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
- // replicated in LayerBE until FE/BE is ready to be synchronized
- mActiveBuffer = getBE().compositionInfo.mBuffer;
- if (getBE().compositionInfo.mBuffer == nullptr) {
- // this can only happen if the very first buffer was rejected.
- return outDirtyRegion;
+ err = updateActiveBuffer();
+ if (err != NO_ERROR) {
+ return dirtyRegion;
}
mBufferLatched = true;
- mPreviousFrameNumber = mCurrentFrameNumber;
- mCurrentFrameNumber = mConsumer->getFrameNumber();
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+ err = updateFrameNumber(latchTime);
+ if (err != NO_ERROR) {
+ return dirtyRegion;
}
mRefreshPending = true;
@@ -528,7 +393,7 @@
recomputeVisibleRegions = true;
}
- ui::Dataspace dataSpace = mConsumer->getCurrentDataSpace();
+ ui::Dataspace dataSpace = getDrawingDataSpace();
// treat modern dataspaces as legacy dataspaces whenever possible, until
// we can trust the buffer producers
switch (dataSpace) {
@@ -555,11 +420,10 @@
}
mCurrentDataSpace = dataSpace;
- Rect crop(mConsumer->getCurrentCrop());
- const uint32_t transform(mConsumer->getCurrentTransform());
- const uint32_t scalingMode(mConsumer->getCurrentScalingMode());
- if ((crop != mCurrentCrop) ||
- (transform != mCurrentTransform) ||
+ Rect crop(getDrawingCrop());
+ const uint32_t transform(getDrawingTransform());
+ const uint32_t scalingMode(getDrawingScalingMode());
+ if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
(scalingMode != mCurrentScalingMode)) {
mCurrentCrop = crop;
mCurrentTransform = transform;
@@ -568,15 +432,13 @@
}
if (oldBuffer != nullptr) {
- uint32_t bufWidth = getBE().compositionInfo.mBuffer->getWidth();
- uint32_t bufHeight = getBE().compositionInfo.mBuffer->getHeight();
- if (bufWidth != uint32_t(oldBuffer->width) ||
- bufHeight != uint32_t(oldBuffer->height)) {
+ uint32_t bufWidth = mActiveBuffer->getWidth();
+ uint32_t bufHeight = mActiveBuffer->getHeight();
+ if (bufWidth != uint32_t(oldBuffer->width) || bufHeight != uint32_t(oldBuffer->height)) {
recomputeVisibleRegions = true;
}
}
- mCurrentOpacity = getOpacityForFormat(getBE().compositionInfo.mBuffer->format);
if (oldOpacity != isOpaque(s)) {
recomputeVisibleRegions = true;
}
@@ -603,306 +465,37 @@
}
// FIXME: postedRegion should be dirty & bounds
- Region dirtyRegion(Rect(s.active.w, s.active.h));
-
// transform the dirty region to window-manager space
- outDirtyRegion = (getTransform().transform(dirtyRegion));
-
- return outDirtyRegion;
+ return getTransform().transform(Region(Rect(getActiveWidth(s), getActiveHeight(s))));
}
-void BufferLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
- mConsumer->setDefaultBufferSize(w, h);
-}
-
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
- // Apply this display's projection's viewport to the visible region
- // before giving it to the HWC HAL.
- const Transform& tr = displayDevice->getTransform();
- const auto& viewport = displayDevice->getViewport();
- Region visible = tr.transform(visibleRegion.intersect(viewport));
- auto hwcId = displayDevice->getHwcDisplayId();
- if (!hasHwcLayer(hwcId)) {
- return;
- }
- auto& hwcInfo = getBE().mHwcLayers[hwcId];
- auto& hwcLayer = hwcInfo.layer;
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
-
- // Sideband layers
- if (getBE().compositionInfo.hwc.sidebandStream.get()) {
- setCompositionType(hwcId, HWC2::Composition::Sideband);
- ALOGV("[%s] Requesting Sideband composition", mName.string());
- error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
- getBE().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- return;
- }
-
- // Device or Cursor layers
- if (mPotentialCursor) {
- ALOGV("[%s] Requesting Cursor composition", mName.string());
- setCompositionType(hwcId, HWC2::Composition::Cursor);
- } else {
- ALOGV("[%s] Requesting Device composition", mName.string());
- setCompositionType(hwcId, HWC2::Composition::Device);
- }
-
- ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
- error = hwcLayer->setDataspace(mCurrentDataSpace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- const HdrMetadata& metadata = mConsumer->getCurrentHdrMetadata();
- error = hwcLayer->setPerFrameMetadata(displayDevice->getSupportedPerFrameMetadata(), metadata);
- if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
- ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- uint32_t hwcSlot = 0;
- sp<GraphicBuffer> hwcBuffer;
- hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot,
- getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer);
-
- auto acquireFence = mConsumer->getCurrentFence();
- error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
- getBE().compositionInfo.mBuffer->handle, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-}
-
-bool BufferLayer::isOpaque(const Layer::State& s) const {
- // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
- // layer's opaque flag.
- if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (getBE().compositionInfo.mBuffer == nullptr)) {
- return false;
- }
-
- // if the layer has the opaque flag, then we're always opaque,
- // otherwise we use the current buffer's format.
- return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
-}
-
-void BufferLayer::onFirstRef() {
- Layer::onFirstRef();
-
- // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer, true);
- mProducer = new MonitoredProducer(producer, mFlinger, this);
- {
- // Grab the SF state lock during this since it's the only safe way to access RenderEngine
- Mutex::Autolock lock(mFlinger->mStateLock);
- mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName,
- this);
- }
- mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
- mConsumer->setContentsChangedListener(this);
- mConsumer->setName(mName);
-
- if (mFlinger->isLayerTripleBufferingDisabled()) {
- mProducer->setMaxDequeuedBufferCount(2);
- }
-
- const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
- updateTransformHint(hw);
-}
-
-// ---------------------------------------------------------------------------
-// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
-// ---------------------------------------------------------------------------
-
-void BufferLayer::onFrameAvailable(const BufferItem& item) {
- // Add this buffer from our internal queue tracker
- { // Autolock scope
- Mutex::Autolock lock(mQueueItemLock);
- mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
- item.mGraphicBuffer->getHeight(),
- item.mFrameNumber);
- // Reset the frame number tracker when we receive the first buffer after
- // a frame number reset
- if (item.mFrameNumber == 1) {
- mLastFrameNumberReceived = 0;
- }
-
- // Ensure that callbacks are handled in order
- while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
- status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
- ms2ns(500));
- if (result != NO_ERROR) {
- ALOGE("[%s] Timed out waiting on callback", mName.string());
- }
- }
-
- mQueueItems.push_back(item);
- android_atomic_inc(&mQueuedFrames);
-
- // Wake up any pending callbacks
- mLastFrameNumberReceived = item.mFrameNumber;
- mQueueItemCondition.broadcast();
- }
-
- mFlinger->signalLayerUpdate();
-}
-
-void BufferLayer::onFrameReplaced(const BufferItem& item) {
- { // Autolock scope
- Mutex::Autolock lock(mQueueItemLock);
-
- // Ensure that callbacks are handled in order
- while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
- status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
- ms2ns(500));
- if (result != NO_ERROR) {
- ALOGE("[%s] Timed out waiting on callback", mName.string());
- }
- }
-
- if (mQueueItems.empty()) {
- ALOGE("Can't replace a frame on an empty queue");
- return;
- }
- mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
-
- // Wake up any pending callbacks
- mLastFrameNumberReceived = item.mFrameNumber;
- mQueueItemCondition.broadcast();
- }
-}
-
-void BufferLayer::onSidebandStreamChanged() {
- if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
- // mSidebandStreamChanged was false
- mFlinger->signalLayerUpdate();
- }
-}
-
-bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
- return mNeedsFiltering || renderArea.needsFiltering();
-}
-
-// As documented in libhardware header, formats in the range
-// 0x100 - 0x1FF are specific to the HAL implementation, and
-// are known to have no alpha channel
-// TODO: move definition for device-specific range into
-// hardware.h, instead of using hard-coded values here.
-#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
-
-bool BufferLayer::getOpacityForFormat(uint32_t format) {
- if (HARDWARE_IS_DEVICE_FORMAT(format)) {
- return true;
- }
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- case HAL_PIXEL_FORMAT_RGBA_FP16:
- case HAL_PIXEL_FORMAT_RGBA_1010102:
- return false;
- }
- // in all other case, we have no blending (also for unknown formats)
- return true;
-}
-
-bool BufferLayer::isHdrY410() const {
- // pixel format is HDR Y410 masquerading as RGBA_1010102
- return (mCurrentDataSpace == ui::Dataspace::BT2020_ITU_PQ &&
- mConsumer->getCurrentApi() == NATIVE_WINDOW_API_MEDIA &&
- getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
-}
-
-void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
- ATRACE_CALL();
- const State& s(getDrawingState());
-
- computeGeometry(renderArea, getBE().mMesh, useIdentityTransform);
-
- /*
- * NOTE: the way we compute the texture coordinates here produces
- * different results than when we take the HWC path -- in the later case
- * the "source crop" is rounded to texel boundaries.
- * This can produce significantly different results when the texture
- * is scaled by a large amount.
- *
- * The GL code below is more logical (imho), and the difference with
- * HWC is due to a limitation of the HWC API to integers -- a question
- * is suspend is whether we should ignore this problem or revert to
- * GL composition when a buffer scaling is applied (maybe with some
- * minimal value)? Or, we could make GL behave like HWC -- but this feel
- * like more of a hack.
- */
- const Rect bounds{computeBounds()}; // Rounds from FloatRect
-
- Transform t = getTransform();
- Rect win = bounds;
- if (!s.finalCrop.isEmpty()) {
- win = t.transform(win);
- if (!win.intersect(s.finalCrop, &win)) {
- win.clear();
- }
- win = t.inverse().transform(win);
- if (!win.intersect(bounds, &win)) {
- win.clear();
+// transaction
+void BufferLayer::notifyAvailableFrames() {
+ auto headFrameNumber = getHeadFrameNumber();
+ bool headFenceSignaled = fenceHasSignaled();
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+ for (auto& point : mLocalSyncPoints) {
+ if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
+ point->setFrameAvailable();
}
}
-
- float left = float(win.left) / float(s.active.w);
- float top = float(win.top) / float(s.active.h);
- float right = float(win.right) / float(s.active.w);
- float bottom = float(win.bottom) / float(s.active.h);
-
- // TODO: we probably want to generate the texture coords with the mesh
- // here we assume that we only have 4 vertices
- Mesh::VertexArray<vec2> texCoords(getBE().mMesh.getTexCoordArray<vec2>());
- texCoords[0] = vec2(left, 1.0f - top);
- texCoords[1] = vec2(left, 1.0f - bottom);
- texCoords[2] = vec2(right, 1.0f - bottom);
- texCoords[3] = vec2(right, 1.0f - top);
-
- auto& engine(mFlinger->getRenderEngine());
- engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
- getColor());
- engine.setSourceDataSpace(mCurrentDataSpace);
-
- if (isHdrY410()) {
- engine.setSourceY410BT2020(true);
- }
-
- engine.drawMesh(getBE().mMesh);
- engine.disableBlending();
-
- engine.setSourceY410BT2020(false);
}
-uint32_t BufferLayer::getProducerStickyTransform() const {
- int producerStickyTransform = 0;
- int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
- if (ret != OK) {
- ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
- strerror(-ret), ret);
- return 0;
+bool BufferLayer::hasReadyFrame() const {
+ return hasDrawingBuffer() || getSidebandStreamChanged() || getAutoRefresh();
+}
+
+uint32_t BufferLayer::getEffectiveScalingMode() const {
+ if (mOverrideScalingMode >= 0) {
+ return mOverrideScalingMode;
}
- return static_cast<uint32_t>(producerStickyTransform);
+
+ return mCurrentScalingMode;
+}
+
+bool BufferLayer::isProtected() const {
+ const sp<GraphicBuffer>& buffer(mActiveBuffer);
+ return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
bool BufferLayer::latchUnsignaledBuffers() {
@@ -919,65 +512,7 @@
return latch;
}
-uint64_t BufferLayer::getHeadFrameNumber() const {
- Mutex::Autolock lock(mQueueItemLock);
- if (!mQueueItems.empty()) {
- return mQueueItems[0].mFrameNumber;
- } else {
- return mCurrentFrameNumber;
- }
-}
-
-bool BufferLayer::headFenceHasSignaled() const {
- if (latchUnsignaledBuffers()) {
- return true;
- }
-
- Mutex::Autolock lock(mQueueItemLock);
- if (mQueueItems.empty()) {
- return true;
- }
- if (mQueueItems[0].mIsDroppable) {
- // Even though this buffer's fence may not have signaled yet, it could
- // be replaced by another buffer before it has a chance to, which means
- // that it's possible to get into a situation where a buffer is never
- // able to be latched. To avoid this, grab this buffer anyway.
- return true;
- }
- return mQueueItems[0].mFenceTime->getSignalTime() !=
- Fence::SIGNAL_TIME_PENDING;
-}
-
-uint32_t BufferLayer::getEffectiveScalingMode() const {
- if (mOverrideScalingMode >= 0) {
- return mOverrideScalingMode;
- }
- return mCurrentScalingMode;
-}
-
-// ----------------------------------------------------------------------------
-// transaction
-// ----------------------------------------------------------------------------
-
-void BufferLayer::notifyAvailableFrames() {
- auto headFrameNumber = getHeadFrameNumber();
- bool headFenceSignaled = headFenceHasSignaled();
- Mutex::Autolock lock(mLocalSyncPointMutex);
- for (auto& point : mLocalSyncPoints) {
- if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
- point->setFrameAvailable();
- }
- }
-}
-
-sp<IGraphicBufferProducer> BufferLayer::getProducer() const {
- return mProducer;
-}
-
-// ---------------------------------------------------------------------------
// h/w composer set-up
-// ---------------------------------------------------------------------------
-
bool BufferLayer::allTransactionsSignaled() {
auto headFrameNumber = getHeadFrameNumber();
bool matchingFramesFound = false;
@@ -1004,6 +539,94 @@
return !matchingFramesFound || allTransactionsApplied;
}
+// As documented in libhardware header, formats in the range
+// 0x100 - 0x1FF are specific to the HAL implementation, and
+// are known to have no alpha channel
+// TODO: move definition for device-specific range into
+// hardware.h, instead of using hard-coded values here.
+#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
+
+bool BufferLayer::getOpacityForFormat(uint32_t format) {
+ if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+ return true;
+ }
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ return false;
+ }
+ // in all other case, we have no blending (also for unknown formats)
+ return true;
+}
+
+bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
+ return mNeedsFiltering || renderArea.needsFiltering();
+}
+
+void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
+ ATRACE_CALL();
+ const State& s(getDrawingState());
+
+ computeGeometry(renderArea, getBE().mMesh, useIdentityTransform);
+
+ /*
+ * NOTE: the way we compute the texture coordinates here produces
+ * different results than when we take the HWC path -- in the later case
+ * the "source crop" is rounded to texel boundaries.
+ * This can produce significantly different results when the texture
+ * is scaled by a large amount.
+ *
+ * The GL code below is more logical (imho), and the difference with
+ * HWC is due to a limitation of the HWC API to integers -- a question
+ * is suspend is whether we should ignore this problem or revert to
+ * GL composition when a buffer scaling is applied (maybe with some
+ * minimal value)? Or, we could make GL behave like HWC -- but this feel
+ * like more of a hack.
+ */
+ const Rect bounds{computeBounds()}; // Rounds from FloatRect
+
+ ui::Transform t = getTransform();
+ Rect win = bounds;
+
+ float left = float(win.left) / float(getActiveWidth(s));
+ float top = float(win.top) / float(getActiveHeight(s));
+ float right = float(win.right) / float(getActiveWidth(s));
+ float bottom = float(win.bottom) / float(getActiveHeight(s));
+
+ // TODO: we probably want to generate the texture coords with the mesh
+ // here we assume that we only have 4 vertices
+ renderengine::Mesh::VertexArray<vec2> texCoords(getBE().mMesh.getTexCoordArray<vec2>());
+ // flip texcoords vertically because BufferLayerConsumer expects them to be in GL convention
+ texCoords[0] = vec2(left, 1.0f - top);
+ texCoords[1] = vec2(left, 1.0f - bottom);
+ texCoords[2] = vec2(right, 1.0f - bottom);
+ texCoords[3] = vec2(right, 1.0f - top);
+
+ auto& engine(mFlinger->getRenderEngine());
+ engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
+ getColor());
+ engine.setSourceDataSpace(mCurrentDataSpace);
+
+ if (isHdrY410()) {
+ engine.setSourceY410BT2020(true);
+ }
+
+ engine.drawMesh(getBE().mMesh);
+ engine.disableBlending();
+
+ engine.setSourceY410BT2020(false);
+}
+
+uint64_t BufferLayer::getHeadFrameNumber() const {
+ if (hasDrawingBuffer()) {
+ return getFrameNumber();
+ } else {
+ return mCurrentFrameNumber;
+ }
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index bf0ca69..45906ff 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -24,14 +24,12 @@
#include "FrameTracker.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
-#include "RenderEngine/Mesh.h"
-#include "RenderEngine/Texture.h"
#include "SurfaceFlinger.h"
-#include "Transform.h"
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
-
+#include <renderengine/Mesh.h>
+#include <renderengine/Texture.h>
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
@@ -47,151 +45,141 @@
namespace android {
-/*
- * A new BufferQueue and a new BufferLayerConsumer are created when the
- * BufferLayer is first referenced.
- *
- * This also implements onFrameAvailable(), which notifies SurfaceFlinger
- * that new data has arrived.
- */
-class BufferLayer : public Layer, public BufferLayerConsumer::ContentsChangedListener {
+class BufferLayer : public Layer {
public:
BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
uint32_t h, uint32_t flags);
~BufferLayer() override;
- // If we have received a new buffer this frame, we will pass its surface
- // damage down to hardware composer. Otherwise, we must send a region with
- // one empty rect.
- void useSurfaceDamage();
- void useEmptyDamage();
-
// -----------------------------------------------------------------------
// Overriden from Layer
// -----------------------------------------------------------------------
+public:
+ // If we have received a new buffer this frame, we will pass its surface
+ // damage down to hardware composer. Otherwise, we must send a region with
+ // one empty rect.
+ void useSurfaceDamage() override;
+ void useEmptyDamage() override;
- /*
- * getTypeId - Provide unique string for each class type in the Layer
- * hierarchy
- */
+ // getTypeId - Provide unique string for each class type in the Layer
+ // hierarchy
const char* getTypeId() const override { return "BufferLayer"; }
- /*
- * isProtected - true if the layer may contain protected content in the
- * GRALLOC_USAGE_PROTECTED sense.
- */
- bool isProtected() const;
+ bool isOpaque(const Layer::State& s) const override;
- /*
- * isVisible - true if this layer is visible, false otherwise
- */
+ // isVisible - true if this layer is visible, false otherwise
bool isVisible() const override;
- /*
- * isFixedSize - true if content has a fixed size
- */
+ // isFixedSize - true if content has a fixed size
bool isFixedSize() const override;
- // the this layer's size and format
- status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
-
- /*
- * onDraw - draws the surface.
- */
+ // onDraw - draws the surface.
void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) const override;
-
- void onLayerDisplayed(const sp<Fence>& releaseFence) override;
-
- void abandon() override;
- bool shouldPresentNow(const DispSync& dispSync) const override;
- void setTransformHint(uint32_t orientation) const override;
- bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
- const std::shared_ptr<FenceTime>& presentFence,
- const CompositorTiming& compositorTiming) override;
- std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
- bool getTransformToDisplayInverse() const override;
-
-public:
- bool onPreComposition(nsecs_t refreshStartTime) override;
-
- // If a buffer was replaced this frame, release the former buffer
- void releasePendingBuffer(nsecs_t dequeueReadyTime);
-
- /*
- * latchBuffer - called each time the screen is redrawn and returns whether
- * the visible regions need to be recomputed (this is a fairly heavy
- * operation, so this should be set only if needed). Typically this is used
- * to figure out if the content or size of a surface has changed.
- */
- Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
- bool isBufferLatched() const override { return mRefreshPending; }
- void setDefaultBufferSize(uint32_t w, uint32_t h) override;
+ bool useIdentityTransform) override;
bool isHdrY410() const override;
void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
- bool isOpaque(const Layer::State& s) const override;
+ bool onPreComposition(nsecs_t refreshStartTime) override;
+ bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+ const std::shared_ptr<FenceTime>& presentFence,
+ const CompositorTiming& compositorTiming) override;
-private:
- void onFirstRef() override;
+ // latchBuffer - called each time the screen is redrawn and returns whether
+ // the visible regions need to be recomputed (this is a fairly heavy
+ // operation, so this should be set only if needed). Typically this is used
+ // to figure out if the content or size of a surface has changed.
+ Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
- // Interface implementation for
- // BufferLayerConsumer::ContentsChangedListener
- void onFrameAvailable(const BufferItem& item) override;
- void onFrameReplaced(const BufferItem& item) override;
- void onSidebandStreamChanged() override;
+ bool isBufferLatched() const override { return mRefreshPending; }
- // needsLinearFiltering - true if this surface's state requires filtering
- bool needsFiltering(const RenderArea& renderArea) const;
+ void notifyAvailableFrames() override;
- static bool getOpacityForFormat(uint32_t format);
-
- // drawing
- void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
-
- // Temporary - Used only for LEGACY camera mode.
- uint32_t getProducerStickyTransform() const;
-
- // Loads the corresponding system property once per process
- static bool latchUnsignaledBuffers();
-
- uint64_t getHeadFrameNumber() const;
- bool headFenceHasSignaled() const;
+ bool hasReadyFrame() const override;
// Returns the current scaling mode, unless mOverrideScalingMode
// is set, in which case, it returns mOverrideScalingMode
uint32_t getEffectiveScalingMode() const override;
+ // -----------------------------------------------------------------------
+
+ // -----------------------------------------------------------------------
+ // Functions that must be implemented by derived classes
+ // -----------------------------------------------------------------------
+private:
+ virtual bool fenceHasSignaled() const = 0;
+
+ virtual nsecs_t getDesiredPresentTime() = 0;
+ virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
+
+ virtual void getDrawingTransformMatrix(float *matrix) = 0;
+ virtual uint32_t getDrawingTransform() const = 0;
+ virtual ui::Dataspace getDrawingDataSpace() const = 0;
+ virtual Rect getDrawingCrop() const = 0;
+ virtual uint32_t getDrawingScalingMode() const = 0;
+ virtual Region getDrawingSurfaceDamage() const = 0;
+ virtual const HdrMetadata& getDrawingHdrMetadata() const = 0;
+ virtual int getDrawingApi() const = 0;
+ virtual PixelFormat getPixelFormat() const = 0;
+
+ virtual uint64_t getFrameNumber() const = 0;
+
+ virtual bool getAutoRefresh() const = 0;
+ virtual bool getSidebandStreamChanged() const = 0;
+
+ virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
+
+ virtual bool hasDrawingBuffer() const = 0;
+
+ virtual void setFilteringEnabled(bool enabled) = 0;
+
+ virtual status_t bindTextureImage() const = 0;
+ virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
+
+ virtual status_t updateActiveBuffer() = 0;
+ virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
+
+ virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& display) = 0;
+
+ // -----------------------------------------------------------------------
public:
- void notifyAvailableFrames() override;
+ // isProtected - true if the layer may contain protected content in the
+ // GRALLOC_USAGE_PROTECTED sense.
+ bool isProtected() const;
- PixelFormat getPixelFormat() const override { return mFormat; }
- sp<IGraphicBufferProducer> getProducer() const;
-
-private:
- sp<BufferLayerConsumer> mConsumer;
+protected:
+ // Loads the corresponding system property once per process
+ static bool latchUnsignaledBuffers();
// Check all of the local sync points to ensure that all transactions
// which need to have been applied prior to the frame which is about to
// be latched have signaled
bool allTransactionsSignaled();
- sp<IGraphicBufferProducer> mProducer;
- // constants
- uint32_t mTextureName; // from GLES
- PixelFormat mFormat;
+ static bool getOpacityForFormat(uint32_t format);
- // main thread
+ // from GLES
+ const uint32_t mTextureName;
+
+private:
+ // needsLinearFiltering - true if this surface's state requires filtering
+ bool needsFiltering(const RenderArea& renderArea) const;
+
+ // drawing
+ void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
+
+ uint64_t getHeadFrameNumber() const;
+
uint32_t mCurrentScalingMode;
- bool mBufferLatched = false; // TODO: Use mActiveBuffer?
- uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
- // The texture used to draw the layer in GLES composition mode
- mutable Texture mTexture;
- bool mUpdateTexImageFailed; // This is only accessed on the main thread.
+ // main thread.
+ bool mBufferLatched; // TODO: Use mActiveBuffer?
+
+ // The texture used to draw the layer in GLES composition mode
+ mutable renderengine::Texture mTexture;
+
bool mRefreshPending;
};
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 87333d0..fa181ad 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -20,11 +20,8 @@
//#define LOG_NDEBUG 0
#include "BufferLayerConsumer.h"
-
-#include "DispSync.h"
#include "Layer.h"
-#include "RenderEngine/Image.h"
-#include "RenderEngine/RenderEngine.h"
+#include "Scheduler/DispSync.h"
#include <inttypes.h>
@@ -38,10 +35,9 @@
#include <gui/GLConsumer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
-
#include <private/gui/ComposerService.h>
-#include <private/gui/SyncFeatures.h>
-
+#include <renderengine/Image.h>
+#include <renderengine/RenderEngine.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/Trace.h>
@@ -58,7 +54,8 @@
static const mat4 mtxIdentity;
BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq,
- RE::RenderEngine& engine, uint32_t tex, Layer* layer)
+ renderengine::RenderEngine& engine, uint32_t tex,
+ Layer* layer)
: ConsumerBase(bq, false),
mCurrentCrop(Rect::EMPTY_RECT),
mCurrentTransform(0),
@@ -206,7 +203,7 @@
return err;
}
- if (!SyncFeatures::getInstance().useNativeFenceSync()) {
+ if (mRE.useNativeFenceSync()) {
// Bind the new buffer to the GL texture.
//
// Older devices require the "implicit" synchronization provided
@@ -280,14 +277,6 @@
return NO_ERROR;
}
-bool BufferLayerConsumer::canUseImageCrop(const Rect& crop) const {
- // If the crop rect is not at the origin, we can't set the crop on the
- // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
- // extension. In the future we can add a layered extension that
- // removes this restriction if there is hardware that can support it.
- return mRE.supportsImageCrop() && crop.left == 0 && crop.top == 0;
-}
-
status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
PendingRelease* pendingRelease) {
status_t err = NO_ERROR;
@@ -365,8 +354,7 @@
return NO_INIT;
}
- const Rect& imageCrop = canUseImageCrop(mCurrentCrop) ? mCurrentCrop : Rect::EMPTY_RECT;
- status_t err = mCurrentTextureImage->createIfNeeded(imageCrop);
+ status_t err = mCurrentTextureImage->createIfNeeded();
if (err != NO_ERROR) {
BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
@@ -383,7 +371,7 @@
BLC_LOGV("syncForReleaseLocked");
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- if (SyncFeatures::getInstance().useNativeFenceSync()) {
+ if (mRE.useNativeFenceSync()) {
base::unique_fd fenceFd = mRE.flush();
if (fenceFd == -1) {
BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
@@ -435,9 +423,8 @@
BLC_LOGD("computeCurrentTransformMatrixLocked: "
"mCurrentTextureImage is nullptr");
}
- const Rect& cropRect = canUseImageCrop(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop;
- GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, cropRect, mCurrentTransform,
- mFilteringEnabled);
+ GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
+ mCurrentTransform, mFilteringEnabled);
}
nsecs_t BufferLayerConsumer::getTimestamp() {
@@ -522,7 +509,7 @@
}
if (mCurrentFence->isValid()) {
- if (SyncFeatures::getInstance().useWaitSync()) {
+ if (mRE.useWaitSync()) {
base::unique_fd fenceFd(mCurrentFence->dup());
if (fenceFd == -1) {
BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno);
@@ -606,7 +593,8 @@
ConsumerBase::dumpLocked(result, prefix);
}
-BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer, RE::RenderEngine& engine)
+BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer,
+ renderengine::RenderEngine& engine)
: mGraphicBuffer(graphicBuffer),
mImage{engine.createImage()},
mCreated(false),
@@ -615,23 +603,12 @@
BufferLayerConsumer::Image::~Image() = default;
-status_t BufferLayerConsumer::Image::createIfNeeded(const Rect& imageCrop) {
- const int32_t cropWidth = imageCrop.width();
- const int32_t cropHeight = imageCrop.height();
- if (mCreated && mCropWidth == cropWidth && mCropHeight == cropHeight) {
- return OK;
- }
+status_t BufferLayerConsumer::Image::createIfNeeded() {
+ if (mCreated) return OK;
mCreated = mImage->setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
- mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED,
- cropWidth, cropHeight);
- if (mCreated) {
- mCropWidth = cropWidth;
- mCropHeight = cropHeight;
- } else {
- mCropWidth = 0;
- mCropHeight = 0;
-
+ mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+ if (!mCreated) {
const sp<GraphicBuffer>& buffer = mGraphicBuffer;
ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index f81cdb1..257a4e5 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -37,10 +37,10 @@
class Layer;
class String8;
-namespace RE {
+namespace renderengine {
class RenderEngine;
class Image;
-} // namespace RE
+} // namespace renderengine
/*
* BufferLayerConsumer consumes buffers of graphics data from a BufferQueue,
@@ -73,7 +73,7 @@
// BufferLayerConsumer constructs a new BufferLayerConsumer object. The
// tex parameter indicates the name of the RenderEngine texture to which
// images are to be streamed.
- BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RE::RenderEngine& engine,
+ BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, renderengine::RenderEngine& engine,
uint32_t tex, Layer* layer);
// Sets the contents changed listener. This should be used instead of
@@ -216,28 +216,27 @@
status_t bindTextureImageLocked();
private:
- // Image is a utility class for tracking and creating RE::Images. There
+ // Image is a utility class for tracking and creating renderengine::Images. There
// is primarily just one image per slot, but there is also special cases:
// - After freeBuffer, we must still keep the current image/buffer
- // Reference counting RE::Images lets us handle all these cases easily while
- // also only creating new RE::Images from buffers when required.
+ // Reference counting renderengine::Images lets us handle all these cases easily while
+ // also only creating new renderengine::Images from buffers when required.
class Image : public LightRefBase<Image> {
public:
- Image(sp<GraphicBuffer> graphicBuffer, RE::RenderEngine& engine);
+ Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine);
Image(const Image& rhs) = delete;
Image& operator=(const Image& rhs) = delete;
- // createIfNeeded creates an RE::Image if required (we haven't created
- // one yet, or the crop-rect has changed).
- status_t createIfNeeded(const Rect& imageCrop);
+ // createIfNeeded creates an renderengine::Image if we haven't created one yet.
+ status_t createIfNeeded();
const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
const native_handle* graphicBufferHandle() {
return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
}
- const RE::Image& image() const { return *mImage; }
+ const renderengine::Image& image() const { return *mImage; }
private:
// Only allow instantiation using ref counting.
@@ -248,7 +247,7 @@
sp<GraphicBuffer> mGraphicBuffer;
// mImage is the image created from mGraphicBuffer.
- std::unique_ptr<RE::Image> mImage;
+ std::unique_ptr<renderengine::Image> mImage;
bool mCreated;
int32_t mCropWidth;
int32_t mCropHeight;
@@ -256,7 +255,7 @@
// freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in
- // that slot and destroy the RE::Image in that slot. Otherwise it has no
+ // that slot and destroy the renderengine::Image in that slot. Otherwise it has no
// effect.
//
// This method must be called with mMutex locked.
@@ -352,7 +351,7 @@
// setFilteringEnabled().
bool mFilteringEnabled;
- RE::RenderEngine& mRE;
+ renderengine::RenderEngine& mRE;
// mTexName is the name of the RenderEngine texture to which streamed
// images will be bound when bindTexImage is called. It is set at
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
new file mode 100644
index 0000000..4839bfb
--- /dev/null
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2018 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 "BufferQueueLayer.h"
+#include "LayerRejecter.h"
+
+#include <system/window.h>
+
+namespace android {
+
+BufferQueueLayer::BufferQueueLayer(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags)
+ : BufferLayer(flinger, client, name, w, h, flags),
+ mConsumer(nullptr),
+ mProducer(nullptr),
+ mFormat(PIXEL_FORMAT_NONE),
+ mPreviousFrameNumber(0),
+ mUpdateTexImageFailed(false),
+ mQueueItemLock(),
+ mQueueItemCondition(),
+ mQueueItems(),
+ mLastFrameNumberReceived(0),
+ mAutoRefresh(false),
+ mActiveBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mQueuedFrames(0),
+ mSidebandStreamChanged(false) {
+ mCurrentState.requested_legacy = mCurrentState.active_legacy;
+}
+
+// -----------------------------------------------------------------------
+// Interface implementation for Layer
+// -----------------------------------------------------------------------
+
+void BufferQueueLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+ mConsumer->setReleaseFence(releaseFence);
+}
+
+void BufferQueueLayer::abandon() {
+ mConsumer->abandon();
+}
+
+void BufferQueueLayer::setTransformHint(uint32_t orientation) const {
+ mConsumer->setTransformHint(orientation);
+}
+
+std::vector<OccupancyTracker::Segment> BufferQueueLayer::getOccupancyHistory(bool forceFlush) {
+ std::vector<OccupancyTracker::Segment> history;
+ status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
+ if (result != NO_ERROR) {
+ ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
+ return {};
+ }
+ return history;
+}
+
+bool BufferQueueLayer::getTransformToDisplayInverse() const {
+ return mConsumer->getTransformToDisplayInverse();
+}
+
+void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
+ if (!mConsumer->releasePendingBuffer()) {
+ return;
+ }
+
+ auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
+ mReleaseTimeline.updateSignalTimes();
+ mReleaseTimeline.push(releaseFenceTime);
+
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
+ std::move(releaseFenceTime));
+ }
+}
+
+void BufferQueueLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
+ mConsumer->setDefaultBufferSize(w, h);
+}
+
+int32_t BufferQueueLayer::getQueuedFrameCount() const {
+ return mQueuedFrames;
+}
+
+bool BufferQueueLayer::shouldPresentNow(const DispSync& dispSync) const {
+ if (getSidebandStreamChanged() || getAutoRefresh()) {
+ return true;
+ }
+
+ if (!hasDrawingBuffer()) {
+ return false;
+ }
+
+ Mutex::Autolock lock(mQueueItemLock);
+
+ const int64_t addedTime = mQueueItems[0].mTimestamp;
+ const nsecs_t expectedPresentTime = mConsumer->computeExpectedPresent(dispSync);
+
+ // Ignore timestamps more than a second in the future
+ const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1));
+ ALOGW_IF(!isPlausible,
+ "[%s] Timestamp %" PRId64 " seems implausible "
+ "relative to expectedPresent %" PRId64,
+ mName.string(), addedTime, expectedPresentTime);
+
+ const bool isDue = addedTime < expectedPresentTime;
+ return isDue || !isPlausible;
+}
+
+// -----------------------------------------------------------------------
+// Interface implementation for BufferLayer
+// -----------------------------------------------------------------------
+
+bool BufferQueueLayer::fenceHasSignaled() const {
+ if (latchUnsignaledBuffers()) {
+ return true;
+ }
+
+ if (!hasDrawingBuffer()) {
+ return true;
+ }
+
+ Mutex::Autolock lock(mQueueItemLock);
+ if (mQueueItems[0].mIsDroppable) {
+ // Even though this buffer's fence may not have signaled yet, it could
+ // be replaced by another buffer before it has a chance to, which means
+ // that it's possible to get into a situation where a buffer is never
+ // able to be latched. To avoid this, grab this buffer anyway.
+ return true;
+ }
+ return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+}
+
+nsecs_t BufferQueueLayer::getDesiredPresentTime() {
+ return mConsumer->getTimestamp();
+}
+
+std::shared_ptr<FenceTime> BufferQueueLayer::getCurrentFenceTime() const {
+ return mConsumer->getCurrentFenceTime();
+}
+
+void BufferQueueLayer::getDrawingTransformMatrix(float *matrix) {
+ return mConsumer->getTransformMatrix(matrix);
+}
+
+// NOTE: SurfaceFlinger's definitions of "Current" and "Drawing" do not neatly map to BufferQueue's
+// These functions get the fields for the frame that is currently in SurfaceFlinger's Drawing state
+// so the functions start with "getDrawing". The data is retrieved from the BufferQueueConsumer's
+// current buffer so the consumer functions start with "getCurrent".
+//
+// This results in the rather confusing functions below.
+uint32_t BufferQueueLayer::getDrawingTransform() const {
+ return mConsumer->getCurrentTransform();
+}
+
+ui::Dataspace BufferQueueLayer::getDrawingDataSpace() const {
+ return mConsumer->getCurrentDataSpace();
+}
+
+Rect BufferQueueLayer::getDrawingCrop() const {
+ return mConsumer->getCurrentCrop();
+}
+
+uint32_t BufferQueueLayer::getDrawingScalingMode() const {
+ return mConsumer->getCurrentScalingMode();
+}
+
+Region BufferQueueLayer::getDrawingSurfaceDamage() const {
+ return mConsumer->getSurfaceDamage();
+}
+
+const HdrMetadata& BufferQueueLayer::getDrawingHdrMetadata() const {
+ return mConsumer->getCurrentHdrMetadata();
+}
+
+int BufferQueueLayer::getDrawingApi() const {
+ return mConsumer->getCurrentApi();
+}
+
+PixelFormat BufferQueueLayer::getPixelFormat() const {
+ return mFormat;
+}
+
+uint64_t BufferQueueLayer::getFrameNumber() const {
+ Mutex::Autolock lock(mQueueItemLock);
+ return mQueueItems[0].mFrameNumber;
+}
+
+bool BufferQueueLayer::getAutoRefresh() const {
+ return mAutoRefresh;
+}
+
+bool BufferQueueLayer::getSidebandStreamChanged() const {
+ return mSidebandStreamChanged;
+}
+
+std::optional<Region> BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+ if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
+ // mSidebandStreamChanged was true
+ // replicated in LayerBE until FE/BE is ready to be synchronized
+ getBE().compositionInfo.hwc.sidebandStream = mConsumer->getSidebandStream();
+ if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
+ setTransactionFlags(eTransactionNeeded);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
+ recomputeVisibleRegions = true;
+
+ const State& s(getDrawingState());
+ return getTransform().transform(Region(Rect(s.active_legacy.w, s.active_legacy.h)));
+ }
+ return {};
+}
+
+bool BufferQueueLayer::hasDrawingBuffer() const {
+ return mQueuedFrames > 0;
+}
+
+void BufferQueueLayer::setFilteringEnabled(bool enabled) {
+ return mConsumer->setFilteringEnabled(enabled);
+}
+
+status_t BufferQueueLayer::bindTextureImage() const {
+ return mConsumer->bindTextureImage();
+}
+
+status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+ // This boolean is used to make sure that SurfaceFlinger's shadow copy
+ // of the buffer queue isn't modified when the buffer queue is returning
+ // BufferItem's that weren't actually queued. This can happen in shared
+ // buffer mode.
+ bool queuedBuffer = false;
+ LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
+ getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
+ getTransformToDisplayInverse(), mFreezeGeometryUpdates);
+ status_t updateResult =
+ mConsumer->updateTexImage(&r, *mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
+ mLastFrameNumberReceived);
+ if (updateResult == BufferQueue::PRESENT_LATER) {
+ // Producer doesn't want buffer to be displayed yet. Signal a
+ // layer update so we check again at the next opportunity.
+ mFlinger->signalLayerUpdate();
+ return BAD_VALUE;
+ } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
+ // If the buffer has been rejected, remove it from the shadow queue
+ // and return early
+ if (queuedBuffer) {
+ Mutex::Autolock lock(mQueueItemLock);
+ mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+ return BAD_VALUE;
+ } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
+ // This can occur if something goes wrong when trying to create the
+ // EGLImage for this buffer. If this happens, the buffer has already
+ // been released, so we need to clean up the queue and bug out
+ // early.
+ if (queuedBuffer) {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.clear();
+ android_atomic_and(0, &mQueuedFrames);
+ mTimeStats.clearLayerRecord(getName().c_str());
+ }
+
+ // Once we have hit this state, the shadow queue may no longer
+ // correctly reflect the incoming BufferQueue's contents, so even if
+ // updateTexImage starts working, the only safe course of action is
+ // to continue to ignore updates.
+ mUpdateTexImageFailed = true;
+
+ return BAD_VALUE;
+ }
+
+ if (queuedBuffer) {
+ // Autolock scope
+ auto currentFrameNumber = mConsumer->getFrameNumber();
+
+ Mutex::Autolock lock(mQueueItemLock);
+
+ // Remove any stale buffers that have been dropped during
+ // updateTexImage
+ while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+
+ const std::string layerName(getName().c_str());
+ mTimeStats.setAcquireFence(layerName, currentFrameNumber, mQueueItems[0].mFenceTime);
+ mTimeStats.setLatchTime(layerName, currentFrameNumber, latchTime);
+
+ mQueueItems.removeAt(0);
+ }
+
+ // Decrement the queued-frames count. Signal another event if we
+ // have more frames pending.
+ if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || mAutoRefresh) {
+ mFlinger->signalLayerUpdate();
+ }
+
+ return NO_ERROR;
+}
+
+status_t BufferQueueLayer::updateActiveBuffer() {
+ // update the active buffer
+ mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot);
+ getBE().compositionInfo.mBuffer = mActiveBuffer;
+ getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
+
+ if (mActiveBuffer == nullptr) {
+ // this can only happen if the very first buffer was rejected.
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
+status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
+ mPreviousFrameNumber = mCurrentFrameNumber;
+ mCurrentFrameNumber = mConsumer->getFrameNumber();
+
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+ }
+ return NO_ERROR;
+}
+
+void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>&) {
+ auto acquireFence = mConsumer->getCurrentFence();
+ getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
+ getBE().compositionInfo.mBuffer = mActiveBuffer;
+ getBE().compositionInfo.hwc.fence = acquireFence;
+}
+
+// -----------------------------------------------------------------------
+// Interface implementation for BufferLayerConsumer::ContentsChangedListener
+// -----------------------------------------------------------------------
+
+void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
+ // Add this buffer from our internal queue tracker
+ { // Autolock scope
+ Mutex::Autolock lock(mQueueItemLock);
+ // Reset the frame number tracker when we receive the first buffer after
+ // a frame number reset
+ if (item.mFrameNumber == 1) {
+ mLastFrameNumberReceived = 0;
+ }
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
+ mQueueItems.push_back(item);
+ android_atomic_inc(&mQueuedFrames);
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
+ }
+
+ mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
+ item.mGraphicBuffer->getHeight(), item.mFrameNumber);
+ mFlinger->signalLayerUpdate();
+}
+
+void BufferQueueLayer::onFrameReplaced(const BufferItem& item) {
+ { // Autolock scope
+ Mutex::Autolock lock(mQueueItemLock);
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
+ if (!hasDrawingBuffer()) {
+ ALOGE("Can't replace a frame on an empty queue");
+ return;
+ }
+ mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
+ }
+}
+
+void BufferQueueLayer::onSidebandStreamChanged() {
+ if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
+ // mSidebandStreamChanged was false
+ mFlinger->signalLayerUpdate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void BufferQueueLayer::onFirstRef() {
+ BufferLayer::onFirstRef();
+
+ // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer, true);
+ mProducer = new MonitoredProducer(producer, mFlinger, this);
+ {
+ // Grab the SF state lock during this since it's the only safe way to access RenderEngine
+ Mutex::Autolock lock(mFlinger->mStateLock);
+ mConsumer =
+ new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
+ }
+ mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+ mConsumer->setContentsChangedListener(this);
+ mConsumer->setName(mName);
+
+ if (mFlinger->isLayerTripleBufferingDisabled()) {
+ mProducer->setMaxDequeuedBufferCount(2);
+ }
+
+ if (const auto display = mFlinger->getDefaultDisplayDevice()) {
+ updateTransformHint(display);
+ }
+}
+
+status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
+ uint32_t const maxSurfaceDims =
+ std::min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
+
+ // never allow a surface larger than what our underlying GL implementation
+ // can handle.
+ if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
+ ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
+ return BAD_VALUE;
+ }
+
+ mFormat = format;
+
+ setDefaultBufferSize(w, h);
+ mConsumer->setDefaultBufferFormat(format);
+ mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+
+ return NO_ERROR;
+}
+
+sp<IGraphicBufferProducer> BufferQueueLayer::getProducer() const {
+ return mProducer;
+}
+
+uint32_t BufferQueueLayer::getProducerStickyTransform() const {
+ int producerStickyTransform = 0;
+ int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
+ if (ret != OK) {
+ ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
+ strerror(-ret), ret);
+ return 0;
+ }
+ return static_cast<uint32_t>(producerStickyTransform);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
new file mode 100644
index 0000000..579ed81
--- /dev/null
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 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 "BufferLayer.h"
+
+#include <utils/String8.h>
+
+namespace android {
+
+/*
+ * A new BufferQueue and a new BufferLayerConsumer are created when the
+ * BufferLayer is first referenced.
+ *
+ * This also implements onFrameAvailable(), which notifies SurfaceFlinger
+ * that new data has arrived.
+ */
+class BufferQueueLayer : public BufferLayer, public BufferLayerConsumer::ContentsChangedListener {
+public:
+ BufferQueueLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags);
+
+ // -----------------------------------------------------------------------
+ // Interface implementation for Layer
+ // -----------------------------------------------------------------------
+public:
+ void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+
+ void abandon() override;
+
+ void setTransformHint(uint32_t orientation) const override;
+
+ std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
+
+ bool getTransformToDisplayInverse() const override;
+
+ // If a buffer was replaced this frame, release the former buffer
+ void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
+
+ void setDefaultBufferSize(uint32_t w, uint32_t h) override;
+
+ int32_t getQueuedFrameCount() const override;
+
+ bool shouldPresentNow(const DispSync& dispSync) const override;
+ // -----------------------------------------------------------------------
+
+ // -----------------------------------------------------------------------
+ // Interface implementation for BufferLayer
+ // -----------------------------------------------------------------------
+public:
+ bool fenceHasSignaled() const override;
+
+private:
+ nsecs_t getDesiredPresentTime() override;
+ std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
+
+ void getDrawingTransformMatrix(float *matrix) override;
+ uint32_t getDrawingTransform() const override;
+ ui::Dataspace getDrawingDataSpace() const override;
+ Rect getDrawingCrop() const override;
+ uint32_t getDrawingScalingMode() const override;
+ Region getDrawingSurfaceDamage() const override;
+ const HdrMetadata& getDrawingHdrMetadata() const override;
+ int getDrawingApi() const override;
+ PixelFormat getPixelFormat() const override;
+
+ uint64_t getFrameNumber() const override;
+
+ bool getAutoRefresh() const override;
+ bool getSidebandStreamChanged() const override;
+
+ std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+
+ bool hasDrawingBuffer() const override;
+
+ void setFilteringEnabled(bool enabled) override;
+
+ status_t bindTextureImage() const override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+
+ status_t updateActiveBuffer() override;
+ status_t updateFrameNumber(nsecs_t latchTime) override;
+
+ void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
+ // -----------------------------------------------------------------------
+
+ // -----------------------------------------------------------------------
+ // Interface implementation for BufferLayerConsumer::ContentsChangedListener
+ // -----------------------------------------------------------------------
+protected:
+ void onFrameAvailable(const BufferItem& item) override;
+ void onFrameReplaced(const BufferItem& item) override;
+ void onSidebandStreamChanged() override;
+ // -----------------------------------------------------------------------
+
+public:
+ status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format);
+
+ sp<IGraphicBufferProducer> getProducer() const;
+
+private:
+ // Temporary - Used only for LEGACY camera mode.
+ uint32_t getProducerStickyTransform() const;
+
+ void onFirstRef() override;
+
+ sp<BufferLayerConsumer> mConsumer;
+ sp<IGraphicBufferProducer> mProducer;
+
+ PixelFormat mFormat;
+
+ // Only accessed on the main thread.
+ uint64_t mPreviousFrameNumber;
+ bool mUpdateTexImageFailed;
+
+ // Local copy of the queued contents of the incoming BufferQueue
+ mutable Mutex mQueueItemLock;
+ Condition mQueueItemCondition;
+ Vector<BufferItem> mQueueItems;
+ std::atomic<uint64_t> mLastFrameNumberReceived;
+
+ bool mAutoRefresh;
+ int mActiveBufferSlot;
+
+ // thread-safe
+ volatile int32_t mQueuedFrames;
+ volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
new file mode 100644
index 0000000..da9dcfb
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "BufferStateLayer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BufferStateLayer.h"
+
+#include <private/gui/SyncFeatures.h>
+#include <renderengine/Image.h>
+
+namespace android {
+
+static const std::array<float, 16> IDENTITY_MATRIX{1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1};
+
+BufferStateLayer::BufferStateLayer(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags)
+ : BufferLayer(flinger, client, name, w, h, flags),
+ mSidebandStreamChanged(false),
+ mFrameNumber(0) {
+ mTransformMatrix = IDENTITY_MATRIX;
+}
+
+// -----------------------------------------------------------------------
+// Interface implementation for Layer
+// -----------------------------------------------------------------------
+void BufferStateLayer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {
+ // TODO(marissaw): send the release fence back to buffer owner
+ return;
+}
+
+void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
+ // TODO(marissaw): send the transform hint to buffer owner
+ return;
+}
+
+void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
+ // TODO(marissaw): use this to signal the buffer owner
+ return;
+}
+
+bool BufferStateLayer::shouldPresentNow(const DispSync& /*dispSync*/) const {
+ if (getSidebandStreamChanged() || getAutoRefresh()) {
+ return true;
+ }
+
+ return hasDrawingBuffer();
+}
+
+bool BufferStateLayer::getTransformToDisplayInverse() const {
+ return mCurrentState.transformToDisplayInverse;
+}
+
+void BufferStateLayer::pushPendingState() {
+ if (!mCurrentState.modified) {
+ return;
+ }
+ mPendingStates.push_back(mCurrentState);
+ ATRACE_INT(mTransactionName.string(), mPendingStates.size());
+}
+
+bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
+ const bool stateUpdateAvailable = !mPendingStates.empty();
+ while (!mPendingStates.empty()) {
+ popPendingState(stateToCommit);
+ }
+ mCurrentState.modified = false;
+ return stateUpdateAvailable;
+}
+
+Rect BufferStateLayer::getCrop(const Layer::State& s) const {
+ return (getEffectiveScalingMode() == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
+ ? GLConsumer::scaleDownCrop(s.crop, s.active.w, s.active.h)
+ : s.crop;
+}
+
+bool BufferStateLayer::setTransform(uint32_t transform) {
+ if (mCurrentState.transform == transform) return false;
+ mCurrentState.sequence++;
+ mCurrentState.transform = transform;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInverse) {
+ if (mCurrentState.transformToDisplayInverse == transformToDisplayInverse) return false;
+ mCurrentState.sequence++;
+ mCurrentState.transformToDisplayInverse = transformToDisplayInverse;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setCrop(const Rect& crop) {
+ if (mCurrentState.crop == crop) return false;
+ mCurrentState.sequence++;
+ mCurrentState.crop = crop;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setBuffer(sp<GraphicBuffer> buffer) {
+ mCurrentState.sequence++;
+ mCurrentState.buffer = buffer;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
+ mCurrentState.acquireFence = fence;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setDataspace(ui::Dataspace dataspace) {
+ if (mCurrentState.dataspace == dataspace) return false;
+ mCurrentState.sequence++;
+ mCurrentState.dataspace = dataspace;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
+ if (mCurrentState.hdrMetadata == hdrMetadata) return false;
+ mCurrentState.sequence++;
+ mCurrentState.hdrMetadata = hdrMetadata;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setSurfaceDamageRegion(const Region& surfaceDamage) {
+ mCurrentState.sequence++;
+ mCurrentState.surfaceDamageRegion = surfaceDamage;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setApi(int32_t api) {
+ if (mCurrentState.api == api) return false;
+ mCurrentState.sequence++;
+ mCurrentState.api = api;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setSidebandStream(const sp<NativeHandle>& sidebandStream) {
+ if (mCurrentState.sidebandStream == sidebandStream) return false;
+ mCurrentState.sequence++;
+ mCurrentState.sidebandStream = sidebandStream;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+
+ if (!mSidebandStreamChanged.exchange(true)) {
+ // mSidebandStreamChanged was false
+ mFlinger->signalLayerUpdate();
+ }
+ return true;
+}
+
+bool BufferStateLayer::setSize(uint32_t w, uint32_t h) {
+ if (mCurrentState.active.w == w && mCurrentState.active.h == h) return false;
+ mCurrentState.active.w = w;
+ mCurrentState.active.h = h;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setPosition(float x, float y, bool /*immediate*/) {
+ if (mCurrentState.active.transform.tx() == x && mCurrentState.active.transform.ty() == y)
+ return false;
+
+ mCurrentState.active.transform.set(x, y);
+
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
+ mCurrentState.transparentRegionHint = transparent;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix,
+ bool allowNonRectPreservingTransforms) {
+ ui::Transform t;
+ t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+
+ if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
+ ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER ignored");
+ return false;
+ }
+
+ mCurrentState.sequence++;
+ mCurrentState.active.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+// -----------------------------------------------------------------------
+
+// -----------------------------------------------------------------------
+// Interface implementation for BufferLayer
+// -----------------------------------------------------------------------
+bool BufferStateLayer::fenceHasSignaled() const {
+ if (latchUnsignaledBuffers()) {
+ return true;
+ }
+
+ return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
+}
+
+nsecs_t BufferStateLayer::getDesiredPresentTime() {
+ // TODO(marissaw): support an equivalent to desiredPresentTime for timestats metrics
+ return 0;
+}
+
+std::shared_ptr<FenceTime> BufferStateLayer::getCurrentFenceTime() const {
+ return std::make_shared<FenceTime>(getDrawingState().acquireFence);
+}
+
+void BufferStateLayer::getDrawingTransformMatrix(float *matrix) {
+ std::copy(std::begin(mTransformMatrix), std::end(mTransformMatrix), matrix);
+}
+
+uint32_t BufferStateLayer::getDrawingTransform() const {
+ return getDrawingState().transform;
+}
+
+ui::Dataspace BufferStateLayer::getDrawingDataSpace() const {
+ return getDrawingState().dataspace;
+}
+
+Rect BufferStateLayer::getDrawingCrop() const {
+ return Rect::INVALID_RECT;
+}
+
+uint32_t BufferStateLayer::getDrawingScalingMode() const {
+ return NATIVE_WINDOW_SCALING_MODE_FREEZE;
+}
+
+Region BufferStateLayer::getDrawingSurfaceDamage() const {
+ return getDrawingState().surfaceDamageRegion;
+}
+
+const HdrMetadata& BufferStateLayer::getDrawingHdrMetadata() const {
+ return getDrawingState().hdrMetadata;
+}
+
+int BufferStateLayer::getDrawingApi() const {
+ return getDrawingState().api;
+}
+
+PixelFormat BufferStateLayer::getPixelFormat() const {
+ return mActiveBuffer->format;
+}
+
+uint64_t BufferStateLayer::getFrameNumber() const {
+ return mFrameNumber;
+}
+
+bool BufferStateLayer::getAutoRefresh() const {
+ // TODO(marissaw): support shared buffer mode
+ return false;
+}
+
+bool BufferStateLayer::getSidebandStreamChanged() const {
+ return mSidebandStreamChanged.load();
+}
+
+std::optional<Region> BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+ if (mSidebandStreamChanged.exchange(false)) {
+ const State& s(getDrawingState());
+ // mSidebandStreamChanged was true
+ // replicated in LayerBE until FE/BE is ready to be synchronized
+ getBE().compositionInfo.hwc.sidebandStream = s.sidebandStream;
+ if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
+ setTransactionFlags(eTransactionNeeded);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
+ recomputeVisibleRegions = true;
+
+ return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
+ }
+ return {};
+}
+
+bool BufferStateLayer::hasDrawingBuffer() const {
+ return getDrawingState().buffer != nullptr;
+}
+
+void BufferStateLayer::setFilteringEnabled(bool enabled) {
+ GLConsumer::computeTransformMatrix(mTransformMatrix.data(), mActiveBuffer, mCurrentCrop,
+ mCurrentTransform, enabled);
+}
+
+status_t BufferStateLayer::bindTextureImage() const {
+ const State& s(getDrawingState());
+ auto& engine(mFlinger->getRenderEngine());
+
+ if (!engine.isCurrent()) {
+ ALOGE("RenderEngine is not current");
+ return INVALID_OPERATION;
+ }
+
+ engine.checkErrors();
+
+ if (!mTextureImage) {
+ ALOGE("no currently-bound texture");
+ engine.bindExternalTextureImage(mTextureName, *engine.createImage());
+ return NO_INIT;
+ }
+
+ bool created =
+ mTextureImage->setNativeWindowBuffer(s.buffer->getNativeBuffer(),
+ s.buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+ if (!created) {
+ ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
+ s.buffer->getWidth(), s.buffer->getHeight(), s.buffer->getStride(),
+ s.buffer->getUsage(), s.buffer->getPixelFormat());
+ engine.bindExternalTextureImage(mTextureName, *engine.createImage());
+ return NO_INIT;
+ }
+
+ engine.bindExternalTextureImage(mTextureName, *mTextureImage);
+
+ // Wait for the new buffer to be ready.
+ if (s.acquireFence->isValid()) {
+ if (SyncFeatures::getInstance().useWaitSync()) {
+ base::unique_fd fenceFd(s.acquireFence->dup());
+ if (fenceFd == -1) {
+ ALOGE("error dup'ing fence fd: %d", errno);
+ return -errno;
+ }
+ if (!engine.waitFence(std::move(fenceFd))) {
+ ALOGE("failed to wait on fence fd");
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ status_t err = s.acquireFence->waitForever("BufferStateLayer::bindTextureImage");
+ if (err != NO_ERROR) {
+ ALOGE("error waiting for fence: %d", err);
+ return err;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
+ const State& s(getDrawingState());
+
+ if (!s.buffer) {
+ return NO_ERROR;
+ }
+
+ auto& engine(mFlinger->getRenderEngine());
+ if (!engine.isCurrent()) {
+ ALOGE("RenderEngine is not current");
+ return INVALID_OPERATION;
+ }
+ engine.checkErrors();
+
+ // TODO(marissaw): once buffers are cached, don't create a new image everytime
+ mTextureImage = engine.createImage();
+
+ // Reject if the layer is invalid
+ uint32_t bufferWidth = s.buffer->width;
+ uint32_t bufferHeight = s.buffer->height;
+
+ if (s.transform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+
+ if (s.transformToDisplayInverse) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+ }
+
+ if (mOverrideScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE &&
+ (s.active.w != bufferWidth || s.active.h != bufferHeight)) {
+ ALOGE("[%s] rejecting buffer: "
+ "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
+ mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
+ mTimeStats.removeTimeRecord(getName().c_str(), getFrameNumber());
+ return BAD_VALUE;
+ }
+
+ // Handle sync fences
+ if (SyncFeatures::getInstance().useNativeFenceSync()) {
+ base::unique_fd fenceFd = engine.flush();
+ if (fenceFd == -1) {
+ ALOGE("failed to flush RenderEngine");
+ mTimeStats.clearLayerRecord(getName().c_str());
+ return UNKNOWN_ERROR;
+ }
+
+ sp<Fence> fence(new Fence(std::move(fenceFd)));
+
+ // Check status of fences first because merging is expensive.
+ // Merging an invalid fence with any other fence results in an
+ // invalid fence.
+ auto currentStatus = s.acquireFence->getStatus();
+ if (currentStatus == Fence::Status::Invalid) {
+ ALOGE("Existing fence has invalid state");
+ mTimeStats.clearLayerRecord(getName().c_str());
+ return BAD_VALUE;
+ }
+
+ auto incomingStatus = fence->getStatus();
+ if (incomingStatus == Fence::Status::Invalid) {
+ ALOGE("New fence has invalid state");
+ mDrawingState.acquireFence = fence;
+ mTimeStats.clearLayerRecord(getName().c_str());
+ return BAD_VALUE;
+ }
+
+ // If both fences are signaled or both are unsignaled, we need to merge
+ // them to get an accurate timestamp.
+ if (currentStatus == incomingStatus) {
+ char fenceName[32] = {};
+ snprintf(fenceName, 32, "%.28s:%d", mName.string(), mFrameNumber);
+ sp<Fence> mergedFence = Fence::merge(fenceName, mDrawingState.acquireFence, fence);
+ if (!mergedFence.get()) {
+ ALOGE("failed to merge release fences");
+ // synchronization is broken, the best we can do is hope fences
+ // signal in order so the new fence will act like a union
+ mDrawingState.acquireFence = fence;
+ mTimeStats.clearLayerRecord(getName().c_str());
+ return BAD_VALUE;
+ }
+ mDrawingState.acquireFence = mergedFence;
+ } else if (incomingStatus == Fence::Status::Unsignaled) {
+ // If one fence has signaled and the other hasn't, the unsignaled
+ // fence will approximately correspond with the correct timestamp.
+ // There's a small race if both fences signal at about the same time
+ // and their statuses are retrieved with unfortunate timing. However,
+ // by this point, they will have both signaled and only the timestamp
+ // will be slightly off; any dependencies after this point will
+ // already have been met.
+ mDrawingState.acquireFence = fence;
+ }
+ } else {
+ // Bind the new buffer to the GL texture.
+ //
+ // Older devices require the "implicit" synchronization provided
+ // by glEGLImageTargetTexture2DOES, which this method calls. Newer
+ // devices will either call this in Layer::onDraw, or (if it's not
+ // a GL-composited layer) not at all.
+ status_t err = bindTextureImage();
+ if (err != NO_ERROR) {
+ mTimeStats.clearLayerRecord(getName().c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ // TODO(marissaw): properly support mTimeStats
+ const std::string layerName(getName().c_str());
+ mTimeStats.setPostTime(getName().c_str(), getFrameNumber(), latchTime);
+ mTimeStats.setAcquireFence(layerName, getFrameNumber(), getCurrentFenceTime());
+ mTimeStats.setLatchTime(layerName, getFrameNumber(), latchTime);
+
+ return NO_ERROR;
+}
+
+status_t BufferStateLayer::updateActiveBuffer() {
+ const State& s(getDrawingState());
+
+ if (s.buffer == nullptr) {
+ return BAD_VALUE;
+ }
+
+ mActiveBuffer = s.buffer;
+ getBE().compositionInfo.mBuffer = mActiveBuffer;
+ getBE().compositionInfo.mBufferSlot = 0;
+
+ return NO_ERROR;
+}
+
+status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
+ // TODO(marissaw): support frame history events
+ mCurrentFrameNumber = mFrameNumber;
+ return NO_ERROR;
+}
+
+void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
+ const auto displayId = display->getId();
+ auto& hwcInfo = getBE().mHwcLayers[displayId];
+ auto& hwcLayer = hwcInfo.layer;
+
+ const State& s(getDrawingState());
+
+ // TODO(marissaw): support more than one slot
+ uint32_t hwcSlot = 0;
+
+ auto error = hwcLayer->setBuffer(hwcSlot, s.buffer, s.acquireFence);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
+ s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ mFrameNumber++;
+}
+
+void BufferStateLayer::onFirstRef() {
+ BufferLayer::onFirstRef();
+
+ if (const auto display = mFlinger->getDefaultDisplayDevice()) {
+ updateTransformHint(display);
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
new file mode 100644
index 0000000..ac3aad1
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 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 "BufferLayer.h"
+#include "Layer.h"
+
+#include <gui/GLConsumer.h>
+#include <renderengine/Image.h>
+#include <renderengine/RenderEngine.h>
+#include <system/window.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class BufferStateLayer : public BufferLayer {
+public:
+ BufferStateLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags);
+
+ // -----------------------------------------------------------------------
+ // Interface implementation for Layer
+ // -----------------------------------------------------------------------
+ void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+ void setTransformHint(uint32_t orientation) const override;
+ void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
+
+ bool shouldPresentNow(const DispSync& dispSync) const override;
+
+ bool getTransformToDisplayInverse() const override;
+
+ uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
+ return flags;
+ }
+ void pushPendingState() override;
+ bool applyPendingStates(Layer::State* stateToCommit) override;
+
+ uint32_t getActiveWidth(const Layer::State& s) const override { return s.active.w; }
+ uint32_t getActiveHeight(const Layer::State& s) const override { return s.active.h; }
+ ui::Transform getActiveTransform(const Layer::State& s) const override {
+ return s.active.transform;
+ }
+ Region getActiveTransparentRegion(const Layer::State& s) const override {
+ return s.transparentRegionHint;
+ }
+ Rect getCrop(const Layer::State& s) const;
+
+ bool setTransform(uint32_t transform) override;
+ bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
+ bool setCrop(const Rect& crop) override;
+ bool setBuffer(sp<GraphicBuffer> buffer) override;
+ bool setAcquireFence(const sp<Fence>& fence) override;
+ bool setDataspace(ui::Dataspace dataspace) override;
+ bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
+ bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
+ bool setApi(int32_t api) override;
+ bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
+
+ bool setSize(uint32_t w, uint32_t h) override;
+ bool setPosition(float x, float y, bool immediate) override;
+ bool setTransparentRegionHint(const Region& transparent) override;
+ bool setMatrix(const layer_state_t::matrix22_t& matrix,
+ bool allowNonRectPreservingTransforms) override;
+
+ // Override to ignore legacy layer state properties that are not used by BufferStateLayer
+ bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; };
+ void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
+ uint64_t /*frameNumber*/) override {}
+ void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
+ uint64_t /*frameNumber*/) override {}
+ // -----------------------------------------------------------------------
+
+ // -----------------------------------------------------------------------
+ // Interface implementation for BufferLayer
+ // -----------------------------------------------------------------------
+ bool fenceHasSignaled() const override;
+
+private:
+ nsecs_t getDesiredPresentTime() override;
+ std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
+
+ void getDrawingTransformMatrix(float *matrix) override;
+ uint32_t getDrawingTransform() const override;
+ ui::Dataspace getDrawingDataSpace() const override;
+ Rect getDrawingCrop() const override;
+ uint32_t getDrawingScalingMode() const override;
+ Region getDrawingSurfaceDamage() const override;
+ const HdrMetadata& getDrawingHdrMetadata() const override;
+ int getDrawingApi() const override;
+ PixelFormat getPixelFormat() const override;
+
+ uint64_t getFrameNumber() const override;
+
+ bool getAutoRefresh() const override;
+ bool getSidebandStreamChanged() const override;
+
+ std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+
+ bool hasDrawingBuffer() const override;
+
+ void setFilteringEnabled(bool enabled) override;
+
+ status_t bindTextureImage() const override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+
+ status_t updateActiveBuffer() override;
+ status_t updateFrameNumber(nsecs_t latchTime) override;
+
+ void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
+ // -----------------------------------------------------------------------
+private:
+ void onFirstRef() override;
+
+ std::unique_ptr<renderengine::Image> mTextureImage;
+
+ std::array<float, 16> mTransformMatrix;
+
+ std::atomic<bool> mSidebandStreamChanged;
+
+ uint32_t mFrameNumber;
+
+ // TODO(marissaw): support sticky transform for LEGACY camera mode
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index ff957c0..9bf75e8 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -22,14 +22,13 @@
#include <stdlib.h>
#include <sys/types.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <ui/GraphicBuffer.h>
-
#include "ColorLayer.h"
#include "DisplayDevice.h"
-#include "RenderEngine/RenderEngine.h"
#include "SurfaceFlinger.h"
namespace android {
@@ -43,64 +42,42 @@
}
void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
- bool useIdentityTransform) const {
+ bool useIdentityTransform) {
half4 color = getColor();
if (color.a > 0) {
- Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
+ renderengine::Mesh mesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2);
computeGeometry(renderArea, mesh, useIdentityTransform);
auto& engine(mFlinger->getRenderEngine());
engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
true /* disableTexture */, color);
+ engine.setSourceDataSpace(mCurrentDataSpace);
engine.drawMesh(mesh);
engine.disableBlending();
}
}
bool ColorLayer::isVisible() const {
- const Layer::State& s(getDrawingState());
- return !isHiddenByPolicy() && s.color.a;
+ return !isHiddenByPolicy() && getAlpha() > 0.0f;
}
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
- const Transform& tr = displayDevice->getTransform();
- const auto& viewport = displayDevice->getViewport();
+void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
+ const ui::Transform& tr = display->getTransform();
+ const auto& viewport = display->getViewport();
Region visible = tr.transform(visibleRegion.intersect(viewport));
- auto hwcId = displayDevice->getHwcDisplayId();
- if (!hasHwcLayer(hwcId)) {
- return;
- }
- auto& hwcInfo = getBE().mHwcLayers[hwcId];
- auto& hwcLayer = hwcInfo.layer;
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
+ const auto displayId = display->getId();
+ getBE().compositionInfo.hwc.visibleRegion = visible;
+ getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
- setCompositionType(hwcId, HWC2::Composition::SolidColor);
-
- error = hwcLayer->setDataspace(mCurrentDataSpace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
+ setCompositionType(displayId, HWC2::Composition::SolidColor);
+ getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
half4 color = getColor();
- error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ getBE().compositionInfo.hwc.color = { static_cast<uint8_t>(std::round(255.0f * color.r)),
+ static_cast<uint8_t>(std::round(255.0f * color.g)),
+ static_cast<uint8_t>(std::round(255.0f * color.b)), 255 };
// Clear out the transform, because it doesn't make sense absent a source buffer
- error = hwcLayer->setTransform(HWC2::Transform::None);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ getBE().compositionInfo.hwc.transform = HWC2::Transform::None;
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 0cde398..aa6b049 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -31,10 +31,13 @@
virtual const char* getTypeId() const { return "ColorLayer"; }
virtual void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) const;
+ bool useIdentityTransform);
bool isVisible() const override;
- void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+ void setPerFrameData(const sp<const DisplayDevice>& display) override;
+
+protected:
+ FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
};
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index f259d93..e9f3059 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -28,7 +28,7 @@
mDrawingState = mCurrentState;
}
-void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) const {}
+void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) {}
bool ContainerLayer::isVisible() const {
return !isHiddenByPolicy();
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index b352b96..0b4a181 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -31,10 +31,10 @@
const char* getTypeId() const override { return "ContainerLayer"; }
void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) const override;
+ bool useIdentityTransform) override;
bool isVisible() const override;
- void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+ void setPerFrameData(const sp<const DisplayDevice>& display) override;
bool isCreatedFromMainThread() const override { return true; }
};
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index db095a5..3eb0a92 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -18,6 +18,8 @@
#undef LOG_TAG
#define LOG_TAG "DisplayDevice"
+#include "DisplayDevice.h"
+
#include <array>
#include <unordered_set>
@@ -26,32 +28,24 @@
#include <string.h>
#include <math.h>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
#include <cutils/properties.h>
-
-#include <utils/RefBase.h>
-#include <utils/Log.h>
-
+#include <gui/Surface.h>
+#include <hardware/gralloc.h>
+#include <renderengine/RenderEngine.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
-
-#include <gui/Surface.h>
-
-#include <hardware/gralloc.h>
+#include <utils/RefBase.h>
+#include <utils/Log.h>
#include "DisplayHardware/DisplaySurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWC2.h"
-#include "RenderEngine/RenderEngine.h"
-
-#include "clz.h"
-#include "DisplayDevice.h"
#include "SurfaceFlinger.h"
#include "Layer.h"
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <configstore/Utils.h>
-
namespace android {
// retrieve triple buffer setting from configstore
@@ -216,14 +210,15 @@
DisplayDevice::DisplayDevice(
const sp<SurfaceFlinger>& flinger,
DisplayType type,
- int32_t hwcId,
+ int32_t id,
bool isSecure,
const wp<IBinder>& displayToken,
const sp<ANativeWindow>& nativeWindow,
const sp<DisplaySurface>& displaySurface,
- std::unique_ptr<RE::Surface> renderSurface,
+ std::unique_ptr<renderengine::Surface> renderSurface,
int displayWidth,
int displayHeight,
+ int displayInstallOrientation,
bool hasWideColorGamut,
const HdrCapabilities& hdrCapabilities,
const int32_t supportedPerFrameMetadata,
@@ -232,13 +227,14 @@
: lastCompositionHadVisibleLayers(false),
mFlinger(flinger),
mType(type),
- mHwcDisplayId(hwcId),
+ mId(id),
mDisplayToken(displayToken),
mNativeWindow(nativeWindow),
mDisplaySurface(displaySurface),
mSurface{std::move(renderSurface)},
mDisplayWidth(displayWidth),
mDisplayHeight(displayHeight),
+ mDisplayInstallOrientation(displayInstallOrientation),
mPageFlipCount(0),
mIsSecure(isSecure),
mLayerStack(NO_LAYER_STACK),
@@ -301,9 +297,9 @@
DisplayDevice::~DisplayDevice() = default;
void DisplayDevice::disconnect(HWComposer& hwc) {
- if (mHwcDisplayId >= 0) {
- hwc.disconnectDisplay(mHwcDisplayId);
- mHwcDisplayId = -1;
+ if (mId >= 0) {
+ hwc.disconnectDisplay(mId);
+ mId = -1;
}
}
@@ -319,8 +315,8 @@
return mDisplayHeight;
}
-void DisplayDevice::setDisplayName(const String8& displayName) {
- if (!displayName.isEmpty()) {
+void DisplayDevice::setDisplayName(const std::string& displayName) {
+ if (!displayName.empty()) {
// never override the name with an empty name
mDisplayName = displayName;
}
@@ -340,15 +336,16 @@
return mDisplaySurface->beginFrame(mustRecompose);
}
-status_t DisplayDevice::prepareFrame(HWComposer& hwc) {
- status_t error = hwc.prepare(*this);
+status_t DisplayDevice::prepareFrame(HWComposer& hwc,
+ std::vector<CompositionInfo>& compositionData) {
+ status_t error = hwc.prepare(*this, compositionData);
if (error != NO_ERROR) {
return error;
}
DisplaySurface::CompositionType compositionType;
- bool hasClient = hwc.hasClientComposition(mHwcDisplayId);
- bool hasDevice = hwc.hasDeviceComposition(mHwcDisplayId);
+ bool hasClient = hwc.hasClientComposition(mId);
+ bool hasDevice = hwc.hasDeviceComposition(mId);
if (hasClient && hasDevice) {
compositionType = DisplaySurface::COMPOSITION_MIXED;
} else if (hasClient) {
@@ -365,14 +362,13 @@
}
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
- if (hwc.hasClientComposition(mHwcDisplayId) || hwc.hasFlipClientTargetRequest(mHwcDisplayId)) {
+ if (hwc.hasClientComposition(mId) || hwc.hasFlipClientTargetRequest(mId)) {
mSurface->swapBuffers();
}
status_t result = mDisplaySurface->advanceFrame();
if (result != NO_ERROR) {
- ALOGE("[%s] failed pushing new frame to HWC: %d",
- mDisplayName.string(), result);
+ ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplayName.c_str(), result);
}
}
@@ -390,8 +386,7 @@
size_t w = mDisplayWidth;
size_t h = mDisplayHeight;
Rect sourceCrop(0, 0, w, h);
- mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, h,
- false, Transform::ROT_0);
+ mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, ui::Transform::ROT_0);
}
const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
@@ -421,7 +416,7 @@
if (repaintEverything) {
dirty.set(getBounds());
} else {
- const Transform& planeTransform(mGlobalTransform);
+ const ui::Transform& planeTransform(mGlobalTransform);
dirty = planeTransform.transform(this->dirtyRegion);
dirty.andSelf(getBounds());
}
@@ -437,8 +432,8 @@
return mPowerMode;
}
-bool DisplayDevice::isDisplayOn() const {
- return (mPowerMode != HWC_POWER_MODE_OFF);
+bool DisplayDevice::isPoweredOn() const {
+ return mPowerMode != HWC_POWER_MODE_OFF;
}
// ----------------------------------------------------------------------------
@@ -500,37 +495,37 @@
uint32_t transform = 0;
switch (mOrientation) {
case DisplayState::eOrientationDefault:
- transform = Transform::ROT_0;
+ transform = ui::Transform::ROT_0;
break;
case DisplayState::eOrientation90:
- transform = Transform::ROT_90;
+ transform = ui::Transform::ROT_90;
break;
case DisplayState::eOrientation180:
- transform = Transform::ROT_180;
+ transform = ui::Transform::ROT_180;
break;
case DisplayState::eOrientation270:
- transform = Transform::ROT_270;
+ transform = ui::Transform::ROT_270;
break;
}
return transform;
}
status_t DisplayDevice::orientationToTransfrom(
- int orientation, int w, int h, Transform* tr)
+ int orientation, int w, int h, ui::Transform* tr)
{
uint32_t flags = 0;
switch (orientation) {
case DisplayState::eOrientationDefault:
- flags = Transform::ROT_0;
+ flags = ui::Transform::ROT_0;
break;
case DisplayState::eOrientation90:
- flags = Transform::ROT_90;
+ flags = ui::Transform::ROT_90;
break;
case DisplayState::eOrientation180:
- flags = Transform::ROT_180;
+ flags = ui::Transform::ROT_180;
break;
case DisplayState::eOrientation270:
- flags = Transform::ROT_270;
+ flags = ui::Transform::ROT_270;
break;
default:
return BAD_VALUE;
@@ -565,7 +560,7 @@
const int w = mDisplayWidth;
const int h = mDisplayHeight;
- Transform R;
+ ui::Transform R;
DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
if (!frame.isValid()) {
@@ -580,16 +575,16 @@
// it's also invalid to have an empty viewport, so we handle that
// case in the same way.
viewport = Rect(w, h);
- if (R.getOrientation() & Transform::ROT_90) {
+ if (R.getOrientation() & ui::Transform::ROT_90) {
// viewport is always specified in the logical orientation
// of the display (ie: post-rotation).
- swap(viewport.right, viewport.bottom);
+ std::swap(viewport.right, viewport.bottom);
}
}
dirtyRegion.set(getBounds());
- Transform TL, TP, S;
+ ui::Transform TL, TP, S;
float src_width = viewport.width();
float src_height = viewport.height();
float dst_width = frame.width();
@@ -610,9 +605,8 @@
// need to take care of primary display rotation for mGlobalTransform
// for case if the panel is not installed aligned with device orientation
if (mType == DisplayType::DISPLAY_PRIMARY) {
- int primaryDisplayOrientation = mFlinger->getPrimaryDisplayOrientation();
DisplayDevice::orientationToTransfrom(
- (orientation + primaryDisplayOrientation) % (DisplayState::eOrientation270 + 1),
+ (orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1),
w, h, &R);
}
@@ -623,7 +617,7 @@
const uint8_t type = mGlobalTransform.getType();
mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
- (type >= Transform::SCALE));
+ (type >= ui::Transform::SCALE));
mScissor = mGlobalTransform.transform(viewport);
if (mScissor.isEmpty()) {
@@ -631,20 +625,20 @@
}
mOrientation = orientation;
- if (mType == DisplayType::DISPLAY_PRIMARY) {
+ if (isPrimary()) {
uint32_t transform = 0;
switch (mOrientation) {
case DisplayState::eOrientationDefault:
- transform = Transform::ROT_0;
+ transform = ui::Transform::ROT_0;
break;
case DisplayState::eOrientation90:
- transform = Transform::ROT_90;
+ transform = ui::Transform::ROT_90;
break;
case DisplayState::eOrientation180:
- transform = Transform::ROT_180;
+ transform = ui::Transform::ROT_180;
break;
case DisplayState::eOrientation270:
- transform = Transform::ROT_270;
+ transform = ui::Transform::ROT_270;
break;
}
sPrimaryDisplayOrientation = transform;
@@ -658,13 +652,13 @@
}
void DisplayDevice::dump(String8& result) const {
- const Transform& tr(mGlobalTransform);
+ const ui::Transform& tr(mGlobalTransform);
ANativeWindow* const window = mNativeWindow.get();
- result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string());
- result.appendFormat(" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
+ result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.c_str());
+ result.appendFormat(" type=%x, ID=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
"(%d:%d:%d:%d), orient=%2d (type=%08x), "
"flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
- mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
+ mType, mId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
mSurface->queryRedSize(), mSurface->queryGreenSize(),
mSurface->queryBlueSize(), mSurface->queryAlphaSize(), mOrientation,
tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
@@ -704,7 +698,7 @@
const Dataspace dataspace = colorModeToDataspace(mode);
const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
- ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mHwcDisplayId,
+ ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mId,
dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
decodeRenderIntent(intent).c_str(),
dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
@@ -791,18 +785,6 @@
}
}
-std::atomic<int32_t> DisplayDeviceState::nextDisplayId(1);
-
-DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure)
- : type(type),
- layerStack(DisplayDevice::NO_LAYER_STACK),
- orientation(0),
- width(0),
- height(0),
- isSecure(isSecure)
-{
- viewport.makeInvalid();
- frame.makeInvalid();
-}
+std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 6c3bd91..ed73671 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -17,28 +17,27 @@
#ifndef ANDROID_DISPLAY_DEVICE_H
#define ANDROID_DISPLAY_DEVICE_H
-#include "Transform.h"
-
#include <stdlib.h>
+
+#include <memory>
+#include <string>
#include <unordered_map>
-#include <math/mat4.h>
-
#include <binder/IBinder.h>
-#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
#include <hardware/hwcomposer_defs.h>
+#include <math/mat4.h>
+#include <renderengine/Surface.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
+#include <ui/Transform.h>
#include <utils/RefBase.h>
#include <utils/Mutex.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include "RenderArea.h"
-#include "RenderEngine/Surface.h"
-
-#include <memory>
struct ANativeWindow;
@@ -51,6 +50,7 @@
class Layer;
class SurfaceFlinger;
class HWComposer;
+struct CompositionInfo;
class DisplayDevice : public LightRefBase<DisplayDevice>
{
@@ -80,14 +80,15 @@
DisplayDevice(
const sp<SurfaceFlinger>& flinger,
DisplayType type,
- int32_t hwcId,
+ int32_t id,
bool isSecure,
const wp<IBinder>& displayToken,
const sp<ANativeWindow>& nativeWindow,
const sp<DisplaySurface>& displaySurface,
- std::unique_ptr<RE::Surface> renderSurface,
+ std::unique_ptr<renderengine::Surface> renderSurface,
int displayWidth,
int displayHeight,
+ int displayInstallOrientation,
bool hasWideColorGamut,
const HdrCapabilities& hdrCapabilities,
const int32_t supportedPerFrameMetadata,
@@ -111,6 +112,7 @@
int getWidth() const;
int getHeight() const;
+ int getInstallOrientation() const { return mDisplayInstallOrientation; }
void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
@@ -125,7 +127,7 @@
int getOrientation() const { return mOrientation; }
uint32_t getOrientationTransform() const;
static uint32_t getPrimaryDisplayOrientationTransform();
- const Transform& getTransform() const { return mGlobalTransform; }
+ const ui::Transform& getTransform() const { return mGlobalTransform; }
const Rect getViewport() const { return mViewport; }
const Rect getFrame() const { return mFrame; }
const Rect& getScissor() const { return mScissor; }
@@ -134,7 +136,8 @@
uint32_t getLayerStack() const { return mLayerStack; }
int32_t getDisplayType() const { return mType; }
bool isPrimary() const { return mType == DISPLAY_PRIMARY; }
- int32_t getHwcDisplayId() const { return mHwcDisplayId; }
+ bool isVirtual() const { return mType == DISPLAY_VIRTUAL; }
+ int32_t getId() const { return mId; }
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
@@ -142,7 +145,7 @@
// We pass in mustRecompose so we can keep VirtualDisplaySurface's state
// machine happy without actually queueing a buffer if nothing has changed
status_t beginFrame(bool mustRecompose) const;
- status_t prepareFrame(HWComposer& hwc);
+ status_t prepareFrame(HWComposer& hwc, std::vector<CompositionInfo>& compositionInfo);
bool hasWideColorGamut() const { return mHasWideColorGamut; }
// Whether h/w composer has native support for specific HDR type.
@@ -179,8 +182,8 @@
}
inline Rect bounds() const { return getBounds(); }
- void setDisplayName(const String8& displayName);
- const String8& getDisplayName() const { return mDisplayName; }
+ void setDisplayName(const std::string& displayName);
+ const std::string& getDisplayName() const { return mDisplayName; }
bool makeCurrent() const;
void setViewportAndProjection() const;
@@ -192,7 +195,7 @@
*/
int getPowerMode() const;
void setPowerMode(int mode);
- bool isDisplayOn() const;
+ bool isPoweredOn() const;
ui::ColorMode getActiveColorMode() const;
void setActiveColorMode(ui::ColorMode mode);
@@ -224,18 +227,19 @@
*/
sp<SurfaceFlinger> mFlinger;
DisplayType mType;
- int32_t mHwcDisplayId;
+ int32_t mId;
wp<IBinder> mDisplayToken;
// ANativeWindow this display is rendering into
sp<ANativeWindow> mNativeWindow;
sp<DisplaySurface> mDisplaySurface;
- std::unique_ptr<RE::Surface> mSurface;
+ std::unique_ptr<renderengine::Surface> mSurface;
int mDisplayWidth;
int mDisplayHeight;
+ const int mDisplayInstallOrientation;
mutable uint32_t mPageFlipCount;
- String8 mDisplayName;
+ std::string mDisplayName;
bool mIsSecure;
/*
@@ -252,7 +256,7 @@
* Transaction state
*/
static status_t orientationToTransfrom(int orientation,
- int w, int h, Transform* tr);
+ int w, int h, ui::Transform* tr);
// The identifier of the active layer stack for this display. Several displays
// can use the same layer stack: A z-ordered group of layers (sometimes called
@@ -267,7 +271,7 @@
Rect mFrame;
// pre-computed scissor to apply to the display
Rect mScissor;
- Transform mGlobalTransform;
+ ui::Transform mGlobalTransform;
bool mNeedsFiltering;
// Current power mode
int mPowerMode;
@@ -313,15 +317,9 @@
};
struct DisplayDeviceState {
- DisplayDeviceState() = default;
- DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure);
+ bool isVirtual() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
- bool isValid() const { return type >= 0; }
- bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; }
- bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
-
- static std::atomic<int32_t> nextDisplayId;
- int32_t displayId = nextDisplayId++;
+ int32_t sequenceId = sNextSequenceId++;
DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_ID_INVALID;
sp<IGraphicBufferProducer> surface;
uint32_t layerStack = DisplayDevice::NO_LAYER_STACK;
@@ -330,30 +328,118 @@
uint8_t orientation = 0;
uint32_t width = 0;
uint32_t height = 0;
- String8 displayName;
+ std::string displayName;
bool isSecure = false;
+
+private:
+ static std::atomic<int32_t> sNextSequenceId;
};
class DisplayRenderArea : public RenderArea {
public:
DisplayRenderArea(const sp<const DisplayDevice> device,
- ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
- : DisplayRenderArea(device, device->getBounds(), device->getHeight(), device->getWidth(),
+ ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
+ : DisplayRenderArea(device, device->getBounds(), device->getWidth(), device->getHeight(),
rotation) {}
- DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqHeight,
- uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
- : RenderArea(reqHeight, reqWidth, CaptureFill::OPAQUE, rotation), mDevice(device),
- mSourceCrop(sourceCrop) {}
+ DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
+ uint32_t reqHeight, ui::Transform::orientation_flags rotation)
+ : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE,
+ getDisplayRotation(rotation, device->getInstallOrientation())),
+ mDevice(device),
+ mSourceCrop(sourceCrop) {}
- const Transform& getTransform() const override { return mDevice->getTransform(); }
+ const ui::Transform& getTransform() const override { return mDevice->getTransform(); }
Rect getBounds() const override { return mDevice->getBounds(); }
int getHeight() const override { return mDevice->getHeight(); }
int getWidth() const override { return mDevice->getWidth(); }
bool isSecure() const override { return mDevice->isSecure(); }
- bool needsFiltering() const override { return mDevice->needsFiltering(); }
- Rect getSourceCrop() const override { return mSourceCrop; }
+
+ bool needsFiltering() const override {
+ // check if the projection from the logical display to the physical
+ // display needs filtering
+ if (mDevice->needsFiltering()) {
+ return true;
+ }
+
+ // check if the projection from the logical render area (i.e., the
+ // physical display) to the physical render area requires filtering
+ const Rect sourceCrop = getSourceCrop();
+ int width = sourceCrop.width();
+ int height = sourceCrop.height();
+ if (getRotationFlags() & ui::Transform::ROT_90) {
+ std::swap(width, height);
+ }
+ return width != getReqWidth() || height != getReqHeight();
+ }
+
+ Rect getSourceCrop() const override {
+ // use the (projected) logical display viewport by default
+ if (mSourceCrop.isEmpty()) {
+ return mDevice->getScissor();
+ }
+
+ const int orientation = mDevice->getInstallOrientation();
+ if (orientation == DisplayState::eOrientationDefault) {
+ return mSourceCrop;
+ }
+
+ // Install orientation is transparent to the callers. Apply it now.
+ uint32_t flags = 0x00;
+ switch (orientation) {
+ case DisplayState::eOrientation90:
+ flags = ui::Transform::ROT_90;
+ break;
+ case DisplayState::eOrientation180:
+ flags = ui::Transform::ROT_180;
+ break;
+ case DisplayState::eOrientation270:
+ flags = ui::Transform::ROT_270;
+ break;
+ }
+ ui::Transform tr;
+ tr.set(flags, getWidth(), getHeight());
+ return tr.transform(mSourceCrop);
+ }
private:
+ // Install orientation is transparent to the callers. We need to cancel
+ // it out by modifying rotation flags.
+ static ui::Transform::orientation_flags getDisplayRotation(
+ ui::Transform::orientation_flags rotation, int orientation) {
+ if (orientation == DisplayState::eOrientationDefault) {
+ return rotation;
+ }
+
+ // convert hw orientation into flag presentation
+ // here inverse transform needed
+ uint8_t hw_rot_90 = 0x00;
+ uint8_t hw_flip_hv = 0x00;
+ switch (orientation) {
+ case DisplayState::eOrientation90:
+ hw_rot_90 = ui::Transform::ROT_90;
+ hw_flip_hv = ui::Transform::ROT_180;
+ break;
+ case DisplayState::eOrientation180:
+ hw_flip_hv = ui::Transform::ROT_180;
+ break;
+ case DisplayState::eOrientation270:
+ hw_rot_90 = ui::Transform::ROT_90;
+ break;
+ }
+
+ // transform flags operation
+ // 1) flip H V if both have ROT_90 flag
+ // 2) XOR these flags
+ uint8_t rotation_rot_90 = rotation & ui::Transform::ROT_90;
+ uint8_t rotation_flip_hv = rotation & ui::Transform::ROT_180;
+ if (rotation_rot_90 & hw_rot_90) {
+ rotation_flip_hv = (~rotation_flip_hv) & ui::Transform::ROT_180;
+ }
+
+ return static_cast<ui::Transform::orientation_flags>(
+ (rotation_rot_90 ^ hw_rot_90) | (rotation_flip_hv ^ hw_flip_hv));
+ }
+
const sp<const DisplayDevice> mDevice;
const Rect mSourceCrop;
};
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 37ba433..163b26c 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -22,7 +22,6 @@
#include "ComposerHal.h"
-#include <android/hardware/graphics/composer/2.2/IComposer.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <gui/BufferQueue.h>
#include <hidl/HidlTransportUtils.h>
@@ -172,22 +171,31 @@
LOG_ALWAYS_FATAL("failed to get hwcomposer service");
}
- mComposer->createClient(
- [&](const auto& tmpError, const auto& tmpClient)
- {
- if (tmpError == Error::NONE) {
- mClient = tmpClient;
- }
- });
- if (mClient == nullptr) {
- LOG_ALWAYS_FATAL("failed to create composer client");
+ if (sp<IComposer> composer_2_3 = IComposer::castFrom(mComposer)) {
+ composer_2_3->createClient_2_3([&](const auto& tmpError, const auto& tmpClient) {
+ if (tmpError == Error::NONE) {
+ mClient = tmpClient;
+ mClient_2_2 = tmpClient;
+ mClient_2_3 = tmpClient;
+ }
+ });
+ } else {
+ mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ mClient = tmpClient;
+ if (sp<V2_2::IComposer> composer_2_2 = V2_2::IComposer::castFrom(mComposer)) {
+ mClient_2_2 = V2_2::IComposerClient::castFrom(mClient);
+ LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr,
+ "IComposer 2.2 did not return IComposerClient 2.2");
+ }
+ });
}
- // 2.2 support is optional
- sp<IComposer> composer_2_2 = IComposer::castFrom(mComposer);
- if (composer_2_2 != nullptr) {
- mClient_2_2 = IComposerClient::castFrom(mClient);
- LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr, "IComposer 2.2 did not return IComposerClient 2.2");
+ if (mClient == nullptr) {
+ LOG_ALWAYS_FATAL("failed to create composer client");
}
if (mIsUsingVrComposer) {
@@ -897,23 +905,25 @@
return Error::NONE;
}
-Error Composer::getPerFrameMetadataKeys(
- Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) {
+std::vector<IComposerClient::PerFrameMetadataKey> Composer::getPerFrameMetadataKeys(
+ Display display) {
+ std::vector<IComposerClient::PerFrameMetadataKey> keys;
if (!mClient_2_2) {
- return Error::UNSUPPORTED;
+ return keys;
}
Error error = kDefaultError;
mClient_2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
error = tmpError;
if (error != Error::NONE) {
+ ALOGW("getPerFrameMetadataKeys failed with %d", tmpError);
return;
}
- *outKeys = tmpKeys;
+ keys = tmpKeys;
});
- return error;
+ return keys;
}
Error Composer::getRenderIntents(Display display, ColorMode colorMode,
@@ -957,6 +967,42 @@
return error;
}
+// Composer HAL 2.3
+
+Error Composer::getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) {
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+
+ Error error = kDefaultError;
+ mClient_2_3->getDisplayIdentificationData(display,
+ [&](const auto& tmpError, const auto& tmpPort,
+ const auto& tmpData) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outPort = tmpPort;
+ *outData = tmpData;
+ });
+
+ return error;
+}
+
+Error Composer::setLayerColorTransform(Display display, Layer layer, const float* matrix)
+{
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerColorTransform(matrix);
+ return Error::NONE;
+}
+
CommandReader::~CommandReader()
{
resetData();
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index beee539..94be6e9 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -25,9 +25,9 @@
#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
#include <android/hardware/graphics/common/1.1/types.h>
-#include <android/hardware/graphics/composer/2.2/IComposer.h>
-#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
-#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/GraphicBuffer.h>
@@ -43,6 +43,7 @@
namespace V2_1 = hardware::graphics::composer::V2_1;
namespace V2_2 = hardware::graphics::composer::V2_2;
+namespace V2_3 = hardware::graphics::composer::V2_3;
using types::V1_0::ColorTransform;
using types::V1_0::Hdr;
@@ -59,10 +60,11 @@
using V2_1::IComposerCallback;
using V2_1::Layer;
-using V2_2::CommandReaderBase;
-using V2_2::CommandWriterBase;
-using V2_2::IComposer;
-using V2_2::IComposerClient;
+using V2_3::CommandReaderBase;
+using V2_3::CommandWriterBase;
+
+using V2_3::IComposer;
+using V2_3::IComposerClient;
using PerFrameMetadata = IComposerClient::PerFrameMetadata;
using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
@@ -180,11 +182,17 @@
virtual Error setLayerPerFrameMetadata(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) = 0;
- virtual Error getPerFrameMetadataKeys(
- Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) = 0;
+ virtual std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(
+ Display display) = 0;
virtual Error getRenderIntents(Display display, ColorMode colorMode,
std::vector<RenderIntent>* outRenderIntents) = 0;
virtual Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) = 0;
+
+ // Composer HAL 2.3
+ virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) = 0;
+ virtual Error setLayerColorTransform(Display display, Layer layer,
+ const float* matrix) = 0;
};
namespace impl {
@@ -374,12 +382,17 @@
Error setLayerPerFrameMetadata(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) override;
- Error getPerFrameMetadataKeys(
- Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override;
+ std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(
+ Display display) override;
Error getRenderIntents(Display display, ColorMode colorMode,
std::vector<RenderIntent>* outRenderIntents) override;
Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) override;
+ // Composer HAL 2.3
+ Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) override;
+ Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override;
+
private:
class CommandWriter : public CommandWriterBase {
public:
@@ -405,7 +418,8 @@
sp<V2_1::IComposer> mComposer;
sp<V2_1::IComposerClient> mClient;
- sp<IComposerClient> mClient_2_2;
+ sp<V2_2::IComposerClient> mClient_2_2;
+ sp<IComposerClient> mClient_2_3;
// 64KiB minus a small space for metadata such as read/write pointers
static constexpr size_t kWriterInitialSize =
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
new file mode 100644
index 0000000..dcc4138
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2018 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 "DisplayIdentification"
+
+#include <algorithm>
+#include <cctype>
+#include <numeric>
+#include <optional>
+
+#include <log/log.h>
+
+#include "DisplayIdentification.h"
+
+namespace android {
+namespace {
+
+using byte_view = std::basic_string_view<uint8_t>;
+
+constexpr size_t kEdidHeaderLength = 5;
+
+std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) {
+ if (view.size() < kEdidHeaderLength || view[0] || view[1] || view[2] || view[4]) {
+ return {};
+ }
+
+ return view[3];
+}
+
+std::string_view parseEdidText(const byte_view& view) {
+ std::string_view text(reinterpret_cast<const char*>(view.data()), view.size());
+ text = text.substr(0, text.find('\n'));
+
+ if (!std::all_of(text.begin(), text.end(), ::isprint)) {
+ ALOGW("Invalid EDID: ASCII text is not printable.");
+ return {};
+ }
+
+ return text;
+}
+
+// Big-endian 16-bit value encodes three 5-bit letters where A is 0b00001.
+template <size_t I>
+char getPnpLetter(uint16_t id) {
+ static_assert(I < 3);
+ const char letter = 'A' + (static_cast<uint8_t>(id >> ((2 - I) * 5)) & 0b00011111) - 1;
+ return letter < 'A' || letter > 'Z' ? '\0' : letter;
+}
+
+DisplayId getEdidDisplayId(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) {
+ return (static_cast<DisplayId>(manufacturerId) << 40) |
+ (static_cast<DisplayId>(displayNameHash) << 8) | port;
+}
+
+} // namespace
+
+bool isEdid(const DisplayIdentificationData& data) {
+ const uint8_t kMagic[] = {0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0};
+ return data.size() >= sizeof(kMagic) &&
+ std::equal(std::begin(kMagic), std::end(kMagic), data.begin());
+}
+
+std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) {
+ constexpr size_t kMinLength = 128;
+ if (edid.size() < kMinLength) {
+ ALOGW("Invalid EDID: structure is truncated.");
+ // Attempt parsing even if EDID is malformed.
+ } else {
+ ALOGW_IF(edid[126] != 0, "EDID extensions are currently unsupported.");
+ ALOGW_IF(std::accumulate(edid.begin(), edid.begin() + kMinLength, static_cast<uint8_t>(0)),
+ "Invalid EDID: structure does not checksum.");
+ }
+
+ constexpr size_t kManufacturerOffset = 8;
+ if (edid.size() < kManufacturerOffset + sizeof(uint16_t)) {
+ ALOGE("Invalid EDID: manufacturer ID is truncated.");
+ return {};
+ }
+
+ // Plug and play ID encoded as big-endian 16-bit value.
+ const uint16_t manufacturerId =
+ (edid[kManufacturerOffset] << 8) | edid[kManufacturerOffset + 1];
+
+ const auto pnpId = getPnpId(manufacturerId);
+ if (!pnpId) {
+ ALOGE("Invalid EDID: manufacturer ID is not a valid PnP ID.");
+ return {};
+ }
+
+ constexpr size_t kDescriptorOffset = 54;
+ if (edid.size() < kDescriptorOffset) {
+ ALOGE("Invalid EDID: descriptors are missing.");
+ return {};
+ }
+
+ byte_view view(edid.data(), edid.size());
+ view.remove_prefix(kDescriptorOffset);
+
+ std::string_view displayName;
+ std::string_view serialNumber;
+ std::string_view asciiText;
+
+ constexpr size_t kDescriptorCount = 4;
+ constexpr size_t kDescriptorLength = 18;
+
+ for (size_t i = 0; i < kDescriptorCount; i++) {
+ if (view.size() < kDescriptorLength) {
+ break;
+ }
+
+ if (const auto type = getEdidDescriptorType(view)) {
+ byte_view descriptor(view.data(), kDescriptorLength);
+ descriptor.remove_prefix(kEdidHeaderLength);
+
+ switch (*type) {
+ case 0xfc:
+ displayName = parseEdidText(descriptor);
+ break;
+ case 0xfe:
+ asciiText = parseEdidText(descriptor);
+ break;
+ case 0xff:
+ serialNumber = parseEdidText(descriptor);
+ break;
+ }
+ }
+
+ view.remove_prefix(kDescriptorLength);
+ }
+
+ if (displayName.empty()) {
+ ALOGW("Invalid EDID: falling back to serial number due to missing display name.");
+ displayName = serialNumber;
+ }
+ if (displayName.empty()) {
+ ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number.");
+ displayName = asciiText;
+ }
+ if (displayName.empty()) {
+ ALOGE("Invalid EDID: display name and fallback descriptors are missing.");
+ return {};
+ }
+
+ return Edid{manufacturerId, *pnpId, displayName};
+}
+
+std::optional<PnpId> getPnpId(uint16_t manufacturerId) {
+ const char a = getPnpLetter<0>(manufacturerId);
+ const char b = getPnpLetter<1>(manufacturerId);
+ const char c = getPnpLetter<2>(manufacturerId);
+ return a && b && c ? std::make_optional(PnpId{a, b, c}) : std::nullopt;
+}
+
+std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData& data) {
+ if (!isEdid(data)) {
+ ALOGE("Display identification data has unknown format.");
+ return {};
+ }
+
+ const auto edid = parseEdid(data);
+ if (!edid) {
+ return {};
+ }
+
+ // Hash display name instead of using product code or serial number, since the latter have been
+ // observed to change on some displays with multiple inputs.
+ const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
+ return getEdidDisplayId(port, edid->manufacturerId, hash);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
new file mode 100644
index 0000000..379f2d3
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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 <array>
+#include <cstdint>
+#include <optional>
+#include <string_view>
+#include <vector>
+
+namespace android {
+
+using DisplayId = uint64_t;
+using DisplayIdentificationData = std::vector<uint8_t>;
+
+// NUL-terminated plug and play ID.
+using PnpId = std::array<char, 4>;
+
+struct Edid {
+ uint16_t manufacturerId;
+ PnpId pnpId;
+ std::string_view displayName;
+};
+
+bool isEdid(const DisplayIdentificationData&);
+std::optional<Edid> parseEdid(const DisplayIdentificationData&);
+std::optional<PnpId> getPnpId(uint16_t manufacturerId);
+
+std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData&);
+
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 1a60c83..3a40648 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -124,6 +124,12 @@
return mComposer->getMaxVirtualDisplayCount();
}
+Error Device::getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+ std::vector<uint8_t>* outData) const {
+ auto intError = mComposer->getDisplayIdentificationData(hwcDisplayId, outPort, outData);
+ return static_cast<Error>(intError);
+}
+
Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
PixelFormat* format, Display** outDisplay)
{
@@ -178,6 +184,7 @@
auto newDisplay = std::make_unique<Display>(
*mComposer.get(), mPowerAdvisor, mCapabilities, displayId, displayType);
+ newDisplay->setFrequencyScaleParameters(mFrequencyScaler);
newDisplay->setConnected(true);
mDisplays.emplace(displayId, std::move(newDisplay));
} else if (connection == Connection::Disconnected) {
@@ -217,6 +224,14 @@
return static_cast<Error>(mComposer->executeCommands());
}
+void Device::setDisplayFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler) {
+ mFrequencyScaler = frequencyScaler;
+}
+
+Device::FrequencyScaler Device::getDisplayFrequencyScaleParameters() {
+ return mFrequencyScaler;
+}
+
// Display methods
Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
@@ -256,6 +271,7 @@
mWidth(-1),
mHeight(-1),
mVsyncPeriod(-1),
+ mFrequencyScaler(display.mFrequencyScaler),
mDpiX(-1),
mDpiY(-1) {}
@@ -403,21 +419,17 @@
return static_cast<Error>(intError);
}
-Error Display::getSupportedPerFrameMetadata(int32_t* outSupportedPerFrameMetadata) const
+int32_t Display::getSupportedPerFrameMetadata() const
{
- *outSupportedPerFrameMetadata = 0;
- std::vector<Hwc2::PerFrameMetadataKey> tmpKeys;
- auto intError = mComposer.getPerFrameMetadataKeys(mId, &tmpKeys);
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- return error;
- }
+ int32_t supportedPerFrameMetadata = 0;
+
+ std::vector<Hwc2::PerFrameMetadataKey> tmpKeys = mComposer.getPerFrameMetadataKeys(mId);
+ std::set<Hwc2::PerFrameMetadataKey> keys(tmpKeys.begin(), tmpKeys.end());
// Check whether a specific metadata type is supported. A metadata type is considered
// supported if and only if all required fields are supported.
// SMPTE2086
- std::set<Hwc2::PerFrameMetadataKey> keys(tmpKeys.begin(), tmpKeys.end());
if (hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X) &&
hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y) &&
hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X) &&
@@ -428,15 +440,15 @@
hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::WHITE_POINT_Y) &&
hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MAX_LUMINANCE) &&
hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MIN_LUMINANCE)) {
- *outSupportedPerFrameMetadata |= HdrMetadata::Type::SMPTE2086;
+ supportedPerFrameMetadata |= HdrMetadata::Type::SMPTE2086;
}
// CTA861_3
if (hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL) &&
hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL)) {
- *outSupportedPerFrameMetadata |= HdrMetadata::Type::CTA861_3;
+ supportedPerFrameMetadata |= HdrMetadata::Type::CTA861_3;
}
- return Error::None;
+ return supportedPerFrameMetadata;
}
Error Display::getRenderIntents(ColorMode colorMode,
@@ -699,6 +711,10 @@
mIsConnected = connected;
}
+void Display::setFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler) {
+ mFrequencyScaler = frequencyScaler;
+}
+
int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
{
int32_t value = 0;
@@ -765,7 +781,8 @@
: mComposer(composer),
mCapabilities(capabilities),
mDisplayId(displayId),
- mId(layerId)
+ mId(layerId),
+ mColorMatrix(android::mat4())
{
ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId);
}
@@ -972,4 +989,14 @@
return static_cast<Error>(intError);
}
+// Composer HAL 2.3
+Error Layer::setColorTransform(const android::mat4& matrix) {
+ if (matrix == mColorMatrix) {
+ return Error::None;
+ }
+ mColorMatrix = matrix;
+ auto intError = mComposer.setLayerColorTransform(mDisplayId, mId, matrix.asArray());
+ return static_cast<Error>(intError);
+}
+
} // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e423167..363adb5 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,6 +23,7 @@
#undef HWC2_INCLUDE_STRINGIFICATION
#undef HWC2_USE_CPP11
+#include <cutils/properties.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/GraphicTypes.h>
@@ -84,6 +85,11 @@
public:
explicit Device(std::unique_ptr<android::Hwc2::Composer> composer);
+ struct FrequencyScaler {
+ int32_t multiplier = 1;
+ int32_t divisor = 1;
+ };
+
void registerCallback(ComposerCallback* callback, int32_t sequenceId);
// Required by HWC2
@@ -95,6 +101,9 @@
};
uint32_t getMaxVirtualDisplayCount() const;
+ Error getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+ std::vector<uint8_t>* outData) const;
+
Error createVirtualDisplay(uint32_t width, uint32_t height,
android::ui::PixelFormat* format, Display** outDisplay);
void destroyDisplay(hwc2_display_t displayId);
@@ -112,6 +121,9 @@
// This method provides an explicit way to flush state changes to HWC.
Error flushCommands();
+ void setDisplayFrequencyScaleParameters(FrequencyScaler frequecyScaler);
+ FrequencyScaler getDisplayFrequencyScaleParameters();
+
private:
// Initialization methods
@@ -122,6 +134,7 @@
std::unordered_set<Capability> mCapabilities;
std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
android::Hwc2::impl::PowerAdvisor mPowerAdvisor;
+ FrequencyScaler mFrequencyScaler;
bool mRegisteredCallback = false;
};
@@ -186,7 +199,8 @@
int32_t getWidth() const { return mWidth; }
int32_t getHeight() const { return mHeight; }
- nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
+ nsecs_t getVsyncPeriod() const {
+ return mVsyncPeriod * mFrequencyScaler.multiplier / mFrequencyScaler.divisor; }
float getDpiX() const { return mDpiX; }
float getDpiY() const { return mDpiY; }
@@ -199,6 +213,7 @@
int32_t mWidth;
int32_t mHeight;
nsecs_t mVsyncPeriod;
+ Device::FrequencyScaler mFrequencyScaler;
float mDpiX;
float mDpiY;
};
@@ -215,10 +230,8 @@
std::unordered_map<Layer*, Composition>* outTypes);
[[clang::warn_unused_result]] Error getColorModes(
std::vector<android::ui::ColorMode>* outModes) const;
- // outSupportedPerFrameMetadata is an opaque bitmask to the callers
- // but contains HdrMetadata::Type::*.
- [[clang::warn_unused_result]] Error getSupportedPerFrameMetadata(
- int32_t* outSupportedPerFrameMetadata) const;
+ // Returns a bitmask which contains HdrMetadata::Type::*.
+ [[clang::warn_unused_result]] int32_t getSupportedPerFrameMetadata() const;
[[clang::warn_unused_result]] Error getRenderIntents(
android::ui::ColorMode colorMode,
std::vector<android::ui::RenderIntent>* outRenderIntents) const;
@@ -268,6 +281,7 @@
hwc2_display_t getId() const { return mId; }
bool isConnected() const { return mIsConnected; }
void setConnected(bool connected); // For use by Device only
+ void setFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler);
private:
int32_t getAttribute(hwc2_config_t configId, Attribute attribute);
@@ -292,6 +306,7 @@
hwc2_display_t mId;
bool mIsConnected;
DisplayType mType;
+ Device::FrequencyScaler mFrequencyScaler;
std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
};
@@ -340,6 +355,9 @@
[[clang::warn_unused_result]] Error setZOrder(uint32_t z);
[[clang::warn_unused_result]] Error setInfo(uint32_t type, uint32_t appId);
+ // Composer HAL 2.3
+ [[clang::warn_unused_result]] Error setColorTransform(const android::mat4& matrix);
+
private:
// These are references to data owned by HWC2::Device, which will outlive
// this HWC2::Layer, so these references are guaranteed to be valid for
@@ -352,6 +370,7 @@
android::ui::Dataspace mDataSpace = android::ui::Dataspace::UNKNOWN;
android::HdrMetadata mHdrMetadata;
std::function<void(Layer*)> mLayerDestroyedListener;
+ android::mat4 mColorMatrix;
};
} // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f5f7a82..6b56ca4 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -54,6 +54,9 @@
#include "../Layer.h" // needed only for debugging
#include "../SurfaceFlinger.h"
+#define LOG_HWC_DISPLAY_ERROR(hwcDisplayId, msg) \
+ ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
+
#define LOG_DISPLAY_ERROR(displayId, msg) \
ALOGE("%s failed for display %d: %s", __FUNCTION__, displayId, msg)
@@ -96,6 +99,18 @@
mHwcDevice->registerCallback(callback, sequenceId);
}
+bool HWComposer::getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+ DisplayIdentificationData* outData) const {
+ const auto error = mHwcDevice->getDisplayIdentificationData(hwcDisplayId, outPort, outData);
+ if (error != HWC2::Error::None) {
+ if (error != HWC2::Error::Unsupported) {
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, to_string(error).c_str());
+ }
+ return false;
+ }
+ return true;
+}
+
bool HWComposer::hasCapability(HWC2::Capability capability) const
{
return mHwcDevice->getCapabilities().count(capability) > 0;
@@ -131,53 +146,55 @@
}
}
-void HWComposer::onHotplug(hwc2_display_t displayId, int32_t displayType,
- HWC2::Connection connection) {
+std::optional<DisplayId> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
+ HWC2::Connection connection) {
if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
ALOGE("Invalid display type of %d", displayType);
- return;
+ return {};
}
- ALOGV("hotplug: %" PRIu64 ", %s %s", displayId,
- displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
- to_string(connection).c_str());
- mHwcDevice->onHotplug(displayId, connection);
+ ALOGV("hotplug: %" PRIu64 ", %s %s", hwcDisplayId,
+ displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
+ to_string(connection).c_str());
+ mHwcDevice->onHotplug(hwcDisplayId, connection);
+
+ std::optional<DisplayId> displayId;
+
+ if (connection == HWC2::Connection::Connected) {
+ uint8_t port;
+ DisplayIdentificationData data;
+ if (getDisplayIdentificationData(hwcDisplayId, &port, &data)) {
+ displayId = generateDisplayId(port, data);
+ ALOGE_IF(!displayId, "Failed to generate stable ID for display %" PRIu64, hwcDisplayId);
+ }
+ }
+
// Disconnect is handled through HWComposer::disconnectDisplay via
// SurfaceFlinger's onHotplugReceived callback handling
if (connection == HWC2::Connection::Connected) {
- mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(displayId);
- mHwcDisplaySlots[displayId] = displayType;
+ mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
+ mHwcDisplaySlots[hwcDisplayId] = displayType;
}
+
+ return displayId;
}
-bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp,
- int32_t* outDisplay) {
- auto display = mHwcDevice->getDisplayById(displayId);
- if (!display) {
- ALOGE("onVsync Failed to find display %" PRIu64, displayId);
- return false;
- }
- auto displayType = HWC2::DisplayType::Invalid;
- auto error = display->getType(&displayType);
- if (error != HWC2::Error::None) {
- ALOGE("onVsync: Failed to determine type of display %" PRIu64,
- display->getId());
+bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplayId) {
+ const auto it = mHwcDisplaySlots.find(hwcDisplayId);
+ if (it == mHwcDisplaySlots.end()) {
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid display");
return false;
}
- if (displayType == HWC2::DisplayType::Virtual) {
- ALOGE("Virtual display %" PRIu64 " passed to vsync callback",
- display->getId());
+ const int32_t displayId = it->second;
+ RETURN_IF_INVALID_DISPLAY(displayId, false);
+
+ const auto& displayData = mDisplayData[displayId];
+ if (displayData.isVirtual) {
+ LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
return false;
}
- if (mHwcDisplaySlots.count(display->getId()) == 0) {
- ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback",
- display->getId());
- return false;
- }
-
- int32_t disp = mHwcDisplaySlots[display->getId()];
{
Mutex::Autolock _l(mLock);
@@ -185,22 +202,22 @@
// with the same timestamp when turning the display off and on. This
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
- if (timestamp == mLastHwVSync[disp]) {
+ if (timestamp == mLastHwVSync[displayId]) {
ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
timestamp);
return false;
}
- mLastHwVSync[disp] = timestamp;
+ mLastHwVSync[displayId] = timestamp;
}
- if (outDisplay) {
- *outDisplay = disp;
+ if (outDisplayId) {
+ *outDisplayId = displayId;
}
char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
- ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
+ snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", displayId);
+ ATRACE_INT(tag, ++mVSyncCounts[displayId] & 1);
return true;
}
@@ -208,16 +225,15 @@
status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
ui::PixelFormat* format, int32_t *outId) {
if (mRemainingHwcVirtualDisplays == 0) {
- ALOGE("allocateVirtualDisplay: No remaining virtual displays");
+ ALOGE("%s: No remaining virtual displays", __FUNCTION__);
return NO_MEMORY;
}
if (SurfaceFlinger::maxVirtualDisplaySize != 0 &&
(width > SurfaceFlinger::maxVirtualDisplaySize ||
height > SurfaceFlinger::maxVirtualDisplaySize)) {
- ALOGE("createVirtualDisplay: Can't create a virtual display with"
- " a dimension > %" PRIu64 " (tried %u x %u)",
- SurfaceFlinger::maxVirtualDisplaySize, width, height);
+ ALOGE("%s: Display size %ux%u exceeds maximum dimension of %" PRIu64, __FUNCTION__, width,
+ height, SurfaceFlinger::maxVirtualDisplaySize);
return INVALID_OPERATION;
}
@@ -225,7 +241,7 @@
auto error = mHwcDevice->createVirtualDisplay(width, height, format,
&display);
if (error != HWC2::Error::None) {
- ALOGE("allocateVirtualDisplay: Failed to create HWC virtual display");
+ ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__);
return NO_MEMORY;
}
@@ -238,11 +254,13 @@
displaySlot = mDisplayData.size();
mDisplayData.resize(displaySlot + 1);
} else {
- ALOGE("allocateVirtualDisplay: Unable to allocate a display slot");
+ ALOGE("%s: Unable to allocate a display slot", __FUNCTION__);
return NO_MEMORY;
}
- mDisplayData[displaySlot].hwcDisplay = display;
+ auto& displayData = mDisplayData[displaySlot];
+ displayData.hwcDisplay = display;
+ displayData.isVirtual = true;
--mRemainingHwcVirtualDisplays;
*outId = static_cast<int32_t>(displaySlot);
@@ -319,21 +337,19 @@
}
int HWComposer::getActiveConfigIndex(int32_t displayId) const {
- if (!isValidDisplay(displayId)) {
- ALOGV("getActiveConfigIndex: Attempted to access invalid display %d", displayId);
- return -1;
- }
+ RETURN_IF_INVALID_DISPLAY(displayId, -1);
+
int index;
auto error = mDisplayData[displayId].hwcDisplay->getActiveConfigIndex(&index);
if (error == HWC2::Error::BadConfig) {
- ALOGE("getActiveConfigIndex: No config active, returning -1");
+ LOG_DISPLAY_ERROR(displayId, "No active config");
return -1;
- } else if (error != HWC2::Error::None) {
- ALOGE("getActiveConfigIndex failed for display %d: %s (%d)", displayId,
- to_string(error).c_str(), static_cast<int32_t>(error));
- return -1;
- } else if (index < 0) {
- ALOGE("getActiveConfigIndex returned an unknown config for display %d", displayId);
+ }
+
+ RETURN_IF_HWC_ERROR(error, displayId, -1);
+
+ if (index < 0) {
+ LOG_DISPLAY_ERROR(displayId, "Unknown config");
return -1;
}
@@ -365,19 +381,19 @@
void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
- if (displayId < 0 || displayId >= HWC_DISPLAY_VIRTUAL) {
- ALOGD("setVsyncEnabled: Ignoring for virtual display %d", displayId);
+ RETURN_IF_INVALID_DISPLAY(displayId);
+ auto& displayData = mDisplayData[displayId];
+
+ if (displayData.isVirtual) {
+ LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
return;
}
- RETURN_IF_INVALID_DISPLAY(displayId);
-
// NOTE: we use our own internal lock here because we have to call
// into the HWC with the lock held, and we want to make sure
// that even if HWC blocks (which it shouldn't), it won't
// affect other threads.
Mutex::Autolock _l(mVsyncLock);
- auto& displayData = mDisplayData[displayId];
if (enabled != displayData.vsyncEnabled) {
ATRACE_CALL();
auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
@@ -403,11 +419,12 @@
return NO_ERROR;
}
-status_t HWComposer::prepare(DisplayDevice& displayDevice) {
+status_t HWComposer::prepare(DisplayDevice& display,
+ std::vector<CompositionInfo>& compositionData) {
ATRACE_CALL();
Mutex::Autolock _l(mDisplayLock);
- auto displayId = displayDevice.getHwcDisplayId();
+ const auto displayId = display.getId();
if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
ALOGV("Skipping HWComposer prepare for non-HWC display");
return NO_ERROR;
@@ -474,18 +491,20 @@
displayData.hasClientComposition = false;
displayData.hasDeviceComposition = false;
- for (auto& layer : displayDevice.getVisibleLayersSortedByZ()) {
- auto hwcLayer = layer->getHwcLayer(displayId);
+ for (auto& compositionInfo : compositionData) {
+ auto hwcLayer = compositionInfo.hwc.hwcLayer;
- if (changedTypes.count(hwcLayer) != 0) {
+ if (changedTypes.count(&*hwcLayer) != 0) {
// We pass false so we only update our state and don't call back
// into the HWC device
- validateChange(layer->getCompositionType(displayId),
- changedTypes[hwcLayer]);
- layer->setCompositionType(displayId, changedTypes[hwcLayer], false);
+ validateChange(compositionInfo.compositionType,
+ changedTypes[&*hwcLayer]);
+ compositionInfo.compositionType = changedTypes[&*hwcLayer];
+ compositionInfo.layer->mLayer->setCompositionType(displayId,
+ compositionInfo.compositionType, false);
}
- switch (layer->getCompositionType(displayId)) {
+ switch (compositionInfo.compositionType) {
case HWC2::Composition::Client:
displayData.hasClientComposition = true;
break;
@@ -499,17 +518,19 @@
break;
}
- if (layerRequests.count(hwcLayer) != 0 &&
- layerRequests[hwcLayer] ==
+ if (layerRequests.count(&*hwcLayer) != 0 &&
+ layerRequests[&*hwcLayer] ==
HWC2::LayerRequest::ClearClientTarget) {
- layer->setClearClientTarget(displayId, true);
+ compositionInfo.hwc.clearClientTarget = true;
+ compositionInfo.layer->mLayer->setClearClientTarget(displayId, true);
} else {
- if (layerRequests.count(hwcLayer) != 0) {
+ if (layerRequests.count(&*hwcLayer) != 0) {
LOG_DISPLAY_ERROR(displayId,
- ("Unknown layer request " + to_string(layerRequests[hwcLayer]))
+ ("Unknown layer request " + to_string(layerRequests[&*hwcLayer]))
.c_str());
}
- layer->setClearClientTarget(displayId, false);
+ compositionInfo.hwc.clearClientTarget = false;
+ compositionInfo.layer->mLayer->setClearClientTarget(displayId, false);
}
}
@@ -601,7 +622,8 @@
ALOGV("setPowerMode(%d, %d)", displayId, intMode);
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- if (displayId >= VIRTUAL_DISPLAY_ID_BASE) {
+ const auto& displayData = mDisplayData[displayId];
+ if (displayData.isVirtual) {
LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
return INVALID_OPERATION;
}
@@ -611,7 +633,7 @@
setVsyncEnabled(displayId, HWC2::Vsync::Disable);
}
- auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
+ auto& hwcDisplay = displayData.hwcDisplay;
switch (mode) {
case HWC2::PowerMode::Off:
case HWC2::PowerMode::On:
@@ -680,43 +702,35 @@
return NO_ERROR;
}
-void HWComposer::disconnectDisplay(int displayId) {
- LOG_ALWAYS_FATAL_IF(displayId < 0);
+void HWComposer::disconnectDisplay(int32_t displayId) {
+ RETURN_IF_INVALID_DISPLAY(displayId);
auto& displayData = mDisplayData[displayId];
- auto displayType = HWC2::DisplayType::Invalid;
- auto error = displayData.hwcDisplay->getType(&displayType);
- RETURN_IF_HWC_ERROR_FOR("getType", error, displayId);
-
// If this was a virtual display, add its slot back for reuse by future
// virtual displays
- if (displayType == HWC2::DisplayType::Virtual) {
+ if (displayData.isVirtual) {
mFreeDisplaySlots.insert(displayId);
++mRemainingHwcVirtualDisplays;
}
- auto hwcId = displayData.hwcDisplay->getId();
- mHwcDisplaySlots.erase(hwcId);
- displayData.reset();
+ const auto hwcDisplayId = displayData.hwcDisplay->getId();
+ mHwcDisplaySlots.erase(hwcDisplayId);
+ displayData = DisplayData();
- mHwcDevice->destroyDisplay(hwcId);
+ mHwcDevice->destroyDisplay(hwcDisplayId);
}
status_t HWComposer::setOutputBuffer(int32_t displayId,
const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto& displayData = mDisplayData[displayId];
- auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
- auto displayType = HWC2::DisplayType::Invalid;
- auto error = hwcDisplay->getType(&displayType);
- RETURN_IF_HWC_ERROR_FOR("getType", error, displayId, NAME_NOT_FOUND);
-
- if (displayType != HWC2::DisplayType::Virtual) {
+ if (!displayData.isVirtual) {
LOG_DISPLAY_ERROR(displayId, "Invalid operation on physical display");
return INVALID_OPERATION;
}
- error = hwcDisplay->setOutputBuffer(buffer, acquireFence);
+ auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence);
RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
return NO_ERROR;
}
@@ -738,12 +752,7 @@
int32_t HWComposer::getSupportedPerFrameMetadata(int32_t displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, 0);
-
- int32_t supportedMetadata;
- auto error = mDisplayData[displayId].hwcDisplay->getSupportedPerFrameMetadata(
- &supportedMetadata);
- RETURN_IF_HWC_ERROR(error, displayId, 0);
- return supportedMetadata;
+ return mDisplayData[displayId].hwcDisplay->getSupportedPerFrameMetadata();
}
std::vector<ui::RenderIntent> HWComposer::getRenderIntents(int32_t displayId,
@@ -805,26 +814,15 @@
return mDisplayData[displayId].hwcDisplay->getId();
}
-// ---------------------------------------------------------------------------
-
-HWComposer::DisplayData::DisplayData()
- : hasClientComposition(false),
- hasDeviceComposition(false),
- hwcDisplay(nullptr),
- lastPresentFence(Fence::NO_FENCE),
- outbufHandle(nullptr),
- outbufAcquireFence(Fence::NO_FENCE),
- vsyncEnabled(HWC2::Vsync::Disable) {
- ALOGV("Created new DisplayData");
+void HWComposer::setDisplayFrequencyScaleParameters(
+ HWC2::Device::FrequencyScaler frequencyScaler)
+{
+ mHwcDevice->setDisplayFrequencyScaleParameters(frequencyScaler);
}
-HWComposer::DisplayData::~DisplayData() {
+HWC2::Device::FrequencyScaler HWComposer::getDisplayFrequencyScaleParameters()
+{
+ return mHwcDevice->getDisplayFrequencyScaleParameters();
}
-void HWComposer::DisplayData::reset() {
- ALOGV("DisplayData reset");
- *this = DisplayData();
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index f968948..cca1f3b 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -37,6 +37,8 @@
#include <set>
#include <vector>
+#include "DisplayIdentification.h"
+
extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
struct timespec *remain);
@@ -59,6 +61,7 @@
class Region;
class String8;
class TestableSurfaceFlinger;
+struct CompositionInfo;
namespace Hwc2 {
class Composer;
@@ -74,6 +77,9 @@
void registerCallback(HWC2::ComposerCallback* callback,
int32_t sequenceId);
+ bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+ DisplayIdentificationData* outData) const;
+
bool hasCapability(HWC2::Capability capability) const;
// Attempts to allocate a virtual display. If the virtual display is created
@@ -87,7 +93,8 @@
void destroyLayer(int32_t displayId, HWC2::Layer* layer);
// Asks the HAL what it can do
- status_t prepare(DisplayDevice& displayDevice);
+ status_t prepare(DisplayDevice& display,
+ std::vector<CompositionInfo>& compositionData);
status_t setClientTarget(int32_t displayId, uint32_t slot,
const sp<Fence>& acquireFence,
@@ -147,9 +154,9 @@
// Returns true if successful, false otherwise. The
// DisplayDevice::DisplayType of the display is returned as an output param.
- bool onVsync(hwc2_display_t displayId, int64_t timestamp,
- int32_t* outDisplay);
- void onHotplug(hwc2_display_t displayId, int32_t displayType, HWC2::Connection connection);
+ bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplay);
+ std::optional<DisplayId> onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
+ HWC2::Connection connection);
void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
@@ -179,35 +186,38 @@
android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
std::optional<hwc2_display_t> getHwcDisplayId(int32_t displayId) const;
+
+ // ------------------------------------------------------------------------
+ // These functions set and get the frequencyScaler. The frequencyScaler holds
+ // a multiplier and divisor for virtually scaling the panel frequency in
+ // software. This is used to simulate different panel frequencies when
+ // panel hardware is not available.
+ void setDisplayFrequencyScaleParameters(HWC2::Device::FrequencyScaler frequencyScaler);
+ HWC2::Device::FrequencyScaler getDisplayFrequencyScaleParameters();
private:
// For unit tests
friend TestableSurfaceFlinger;
- static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2;
-
bool isValidDisplay(int32_t displayId) const;
static void validateChange(HWC2::Composition from, HWC2::Composition to);
struct cb_context;
struct DisplayData {
- DisplayData();
- ~DisplayData();
- void reset();
-
- bool hasClientComposition;
- bool hasDeviceComposition;
- HWC2::Display* hwcDisplay;
+ bool isVirtual = false;
+ bool hasClientComposition = false;
+ bool hasDeviceComposition = false;
+ HWC2::Display* hwcDisplay = nullptr;
HWC2::DisplayRequest displayRequests;
- sp<Fence> lastPresentFence; // signals when the last set op retires
+ sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
- buffer_handle_t outbufHandle;
- sp<Fence> outbufAcquireFence;
+ buffer_handle_t outbufHandle = nullptr;
+ sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
mutable std::unordered_map<int32_t,
std::shared_ptr<const HWC2::Display::Config>> configMap;
// protected by mVsyncLock
- HWC2::Vsync vsyncEnabled;
+ HWC2::Vsync vsyncEnabled = HWC2::Vsync::Disable;
bool validateWasSkipped;
HWC2::Error presentError;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
deleted file mode 100644
index fe7944f..0000000
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef ANDROID_SF_HWCOMPOSER_HWC1_H
-#define ANDROID_SF_HWCOMPOSER_HWC1_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <hardware/hwcomposer_defs.h>
-
-#include <system/graphics.h>
-
-#include <ui/Fence.h>
-
-#include <utils/BitSet.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-#include <utils/StrongPointer.h>
-#include <utils/Thread.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
- const struct timespec *request,
- struct timespec *remain);
-
-struct hwc_composer_device_1;
-struct hwc_display_contents_1;
-struct hwc_layer_1;
-struct hwc_procs;
-struct framebuffer_device_t;
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Fence;
-class FloatRect;
-class GraphicBuffer;
-class NativeHandle;
-class Region;
-class String8;
-class SurfaceFlinger;
-
-class HWComposer
-{
-public:
- class EventHandler {
- friend class HWComposer;
- virtual void onVSyncReceived(
- HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
- virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected) = 0;
- virtual void onInvalidateReceived(HWComposer* composer) = 0;
- protected:
- virtual ~EventHandler() {}
- };
-
- enum {
- NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
- MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES,
- VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL,
- };
-
- HWComposer(
- const sp<SurfaceFlinger>& flinger,
- EventHandler& handler);
-
- ~HWComposer();
-
- status_t initCheck() const;
-
- // Returns a display ID starting at VIRTUAL_DISPLAY_ID_BASE, this ID is to
- // be used with createWorkList (and all other methods requiring an ID
- // below).
- // IDs below NUM_BUILTIN_DISPLAYS are pre-defined and therefore are
- // always valid.
- // Returns -1 if an ID cannot be allocated
- int32_t allocateDisplayId();
-
- // Recycles the given virtual display ID and frees the associated worklist.
- // IDs below NUM_BUILTIN_DISPLAYS are not recycled.
- status_t freeDisplayId(int32_t id);
-
-
- // Asks the HAL what it can do
- status_t prepare();
-
- // commits the list
- status_t commit();
-
- // set power mode
- status_t setPowerMode(int disp, int mode);
-
- // set active config
- status_t setActiveConfig(int disp, int mode);
-
- // reset state when an external, non-virtual display is disconnected
- void disconnectDisplay(int disp);
-
- // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
- status_t createWorkList(int32_t id, size_t numLayers);
-
- bool supportsFramebufferTarget() const;
-
- // does this display have layers handled by HWC
- bool hasHwcComposition(int32_t id) const;
-
- // does this display have layers handled by GLES
- bool hasGlesComposition(int32_t id) const;
-
- // get the releaseFence file descriptor for a display's framebuffer layer.
- // the release fence is only valid after commit()
- sp<Fence> getAndResetReleaseFence(int32_t id);
-
- // needed forward declarations
- class LayerListIterator;
-
- // return the visual id to be used to find a suitable EGLConfig for
- // *ALL* displays.
- int getVisualID() const;
-
- // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
- int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
- int fbCompositionComplete();
- void fbDump(String8& result);
-
- // Set the output buffer and acquire fence for a virtual display.
- // Returns INVALID_OPERATION if id is not a virtual display.
- status_t setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& buf);
-
- // Get the retire fence for the last committed frame. This fence will
- // signal when the h/w composer is completely finished with the frame.
- // For physical displays, it is no longer being displayed. For virtual
- // displays, writes to the output buffer are complete.
- sp<Fence> getLastRetireFence(int32_t id) const;
-
- status_t setCursorPositionAsync(int32_t id, const Rect &pos);
-
- /*
- * Interface to hardware composer's layers functionality.
- * This abstracts the HAL interface to layers which can evolve in
- * incompatible ways from one release to another.
- * The idea is that we could extend this interface as we add
- * features to h/w composer.
- */
- class HWCLayerInterface {
- protected:
- virtual ~HWCLayerInterface() { }
- public:
- virtual int32_t getCompositionType() const = 0;
- virtual uint32_t getHints() const = 0;
- virtual sp<Fence> getAndResetReleaseFence() = 0;
- virtual void setDefaultState() = 0;
- virtual void setSkip(bool skip) = 0;
- virtual void setIsCursorLayerHint(bool isCursor = true) = 0;
- virtual void setBlending(uint32_t blending) = 0;
- virtual void setTransform(uint32_t transform) = 0;
- virtual void setFrame(const Rect& frame) = 0;
- virtual void setCrop(const FloatRect& crop) = 0;
- virtual void setVisibleRegionScreen(const Region& reg) = 0;
- virtual void setSurfaceDamage(const Region& reg) = 0;
- virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
- virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
- virtual void setAcquireFenceFd(int fenceFd) = 0;
- virtual void setPlaneAlpha(uint8_t alpha) = 0;
- virtual void onDisplayed() = 0;
- };
-
- /*
- * Interface used to implement an iterator to a list
- * of HWCLayer.
- */
- class HWCLayer : public HWCLayerInterface {
- friend class LayerListIterator;
- // select the layer at the given index
- virtual status_t setLayer(size_t index) = 0;
- virtual HWCLayer* dup() = 0;
- static HWCLayer* copy(HWCLayer *rhs) {
- return rhs ? rhs->dup() : nullptr;
- }
- protected:
- virtual ~HWCLayer() { }
- };
-
- /*
- * Iterator through a HWCLayer list.
- * This behaves more or less like a forward iterator.
- */
- class LayerListIterator {
- friend class HWComposer;
- HWCLayer* const mLayerList;
- size_t mIndex;
-
- LayerListIterator() : mLayerList(nullptr), mIndex(0) { }
-
- LayerListIterator(HWCLayer* layer, size_t index)
- : mLayerList(layer), mIndex(index) { }
-
- // we don't allow assignment, because we don't need it for now
- LayerListIterator& operator = (const LayerListIterator& rhs);
-
- public:
- // copy operators
- LayerListIterator(const LayerListIterator& rhs)
- : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) {
- }
-
- ~LayerListIterator() { delete mLayerList; }
-
- // pre-increment
- LayerListIterator& operator++() {
- mLayerList->setLayer(++mIndex);
- return *this;
- }
-
- // dereference
- HWCLayerInterface& operator * () { return *mLayerList; }
- HWCLayerInterface* operator -> () { return mLayerList; }
-
- // comparison
- bool operator == (const LayerListIterator& rhs) const {
- return mIndex == rhs.mIndex;
- }
- bool operator != (const LayerListIterator& rhs) const {
- return !operator==(rhs);
- }
- };
-
- // Returns an iterator to the beginning of the layer list
- LayerListIterator begin(int32_t id);
-
- // Returns an iterator to the end of the layer list
- LayerListIterator end(int32_t id);
-
-
- // Events handling ---------------------------------------------------------
-
- enum {
- EVENT_VSYNC = HWC_EVENT_VSYNC
- };
-
- void eventControl(int disp, int event, int enabled);
-
- struct DisplayConfig {
- uint32_t width;
- uint32_t height;
- float xdpi;
- float ydpi;
- nsecs_t refresh;
- android_color_mode_t colorMode;
- bool operator==(const DisplayConfig& rhs) const {
- return width == rhs.width &&
- height == rhs.height &&
- xdpi == rhs.xdpi &&
- ydpi == rhs.ydpi &&
- refresh == rhs.refresh &&
- colorMode == rhs.colorMode;
- }
- };
-
- // Query display parameters. Pass in a display index (e.g.
- // HWC_DISPLAY_PRIMARY).
- nsecs_t getRefreshTimestamp(int disp) const;
- sp<Fence> getDisplayFence(int disp) const;
- uint32_t getFormat(int disp) const;
- bool isConnected(int disp) const;
-
- // These return the values for the current config of a given display index.
- // To get the values for all configs, use getConfigs below.
- uint32_t getWidth(int disp) const;
- uint32_t getHeight(int disp) const;
- float getDpiX(int disp) const;
- float getDpiY(int disp) const;
- nsecs_t getRefreshPeriod(int disp) const;
- android_color_mode_t getColorMode(int disp) const;
-
- const Vector<DisplayConfig>& getConfigs(int disp) const;
- size_t getCurrentConfig(int disp) const;
-
- status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h,
- uint32_t format);
-
- // this class is only used to fake the VSync event on systems that don't
- // have it.
- class VSyncThread : public Thread {
- HWComposer& mHwc;
- mutable Mutex mLock;
- Condition mCondition;
- bool mEnabled;
- mutable nsecs_t mNextFakeVSync;
- nsecs_t mRefreshPeriod;
- virtual void onFirstRef();
- virtual bool threadLoop();
- public:
- VSyncThread(HWComposer& hwc);
- void setEnabled(bool enabled);
- };
-
- friend class VSyncThread;
-
- // for debugging ----------------------------------------------------------
- void dump(String8& out) const;
-
-private:
- void loadHwcModule();
- int loadFbHalModule();
-
- LayerListIterator getLayerIterator(int32_t id, size_t index);
-
- struct cb_context;
-
- static void hook_invalidate(const struct hwc_procs* procs);
- static void hook_vsync(const struct hwc_procs* procs, int disp,
- int64_t timestamp);
- static void hook_hotplug(const struct hwc_procs* procs, int disp,
- int connected);
-
- inline void invalidate();
- inline void vsync(int disp, int64_t timestamp);
- inline void hotplug(int disp, int connected);
-
- status_t queryDisplayProperties(int disp);
-
- status_t setFramebufferTarget(int32_t id,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
-
- struct DisplayData {
- DisplayData();
- ~DisplayData();
- Vector<DisplayConfig> configs;
- size_t currentConfig;
- uint32_t format; // pixel format from FB hal, for pre-hwc-1.1
- bool connected;
- bool hasFbComp;
- bool hasOvComp;
- size_t capacity;
- hwc_display_contents_1* list;
- hwc_layer_1* framebufferTarget;
- buffer_handle_t fbTargetHandle;
- sp<Fence> lastRetireFence; // signals when the last set op retires
- sp<Fence> lastDisplayFence; // signals when the last set op takes
- // effect on screen
- buffer_handle_t outbufHandle;
- sp<Fence> outbufAcquireFence;
-
- // protected by mEventControlLock
- int32_t events;
-
- // We need to hold "copies" of these for memory management purposes. The
- // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
- // internally doesn't copy the memory unless one of the copies is
- // modified.
- Vector<Region> visibleRegions;
- Vector<Region> surfaceDamageRegions;
- };
-
- sp<SurfaceFlinger> mFlinger;
- framebuffer_device_t* mFbDev;
- struct hwc_composer_device_1* mHwc;
- // invariant: mLists[0] != nullptr iff mHwc != nullptr
- // mLists[i>0] can be nullptr. that display is to be ignored
- struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS];
- DisplayData mDisplayData[MAX_HWC_DISPLAYS];
- // protect mDisplayData from races between prepare and dump
- mutable Mutex mDisplayLock;
- size_t mNumDisplays;
-
- cb_context* mCBContext;
- EventHandler& mEventHandler;
- size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
- sp<VSyncThread> mVSyncThread;
- bool mDebugForceFakeVSync;
- BitSet32 mAllocatedDisplayIDs;
-
- // protected by mLock
- mutable Mutex mLock;
- mutable nsecs_t mLastHwVSync[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
-
- // thread-safe
- mutable Mutex mEventControlLock;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 9a2817d..c111a27 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -32,11 +32,11 @@
// ---------------------------------------------------------------------------
#define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \
- mDisplayName.string(), ##__VA_ARGS__)
+ mDisplayName.c_str(), ##__VA_ARGS__)
#define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \
- mDisplayName.string(), ##__VA_ARGS__)
+ mDisplayName.c_str(), ##__VA_ARGS__)
#define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \
- mDisplayName.string(), ##__VA_ARGS__)
+ mDisplayName.c_str(), ##__VA_ARGS__)
static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
switch (type) {
@@ -52,7 +52,7 @@
const sp<IGraphicBufferProducer>& sink,
const sp<IGraphicBufferProducer>& bqProducer,
const sp<IGraphicBufferConsumer>& bqConsumer,
- const String8& name)
+ const std::string& name)
: ConsumerBase(bqConsumer),
mHwc(hwc),
mDisplayId(dispId),
@@ -102,7 +102,7 @@
}
mOutputFormat = mDefaultOutputFormat;
- ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string());
+ ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.c_str());
mConsumer->setConsumerName(ConsumerBase::mName);
mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 5c8acea..4bd4d0f 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
+#include <string>
+
#include "DisplaySurface.h"
#include "HWComposerBufferCache.h"
@@ -77,7 +79,7 @@
const sp<IGraphicBufferProducer>& sink,
const sp<IGraphicBufferProducer>& bqProducer,
const sp<IGraphicBufferConsumer>& bqConsumer,
- const String8& name);
+ const std::string& name);
//
// DisplaySurface interface
@@ -153,7 +155,7 @@
//
HWComposer& mHwc;
const int32_t mDisplayId;
- const String8 mDisplayName;
+ const std::string mDisplayName;
sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_*
uint32_t mDefaultOutputFormat;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 90e0e9e..03b63bd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -50,11 +50,10 @@
#include "LayerRejecter.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
-#include "clz.h"
#include "DisplayHardware/HWComposer.h"
-#include "RenderEngine/RenderEngine.h"
+#include <renderengine/RenderEngine.h>
#include <mutex>
#include "LayerProtoHelper.h"
@@ -63,11 +62,6 @@
namespace android {
-LayerBE::LayerBE()
- : mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
-}
-
-
int32_t Layer::sSequence = 1;
Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
@@ -80,27 +74,19 @@
mTransactionFlags(0),
mPendingStateMutex(),
mPendingStates(),
- mQueuedFrames(0),
- mSidebandStreamChanged(false),
- mActiveBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
mCurrentTransform(0),
mOverrideScalingMode(-1),
- mCurrentOpacity(true),
mCurrentFrameNumber(0),
mFrameLatencyNeeded(false),
- mFiltering(false),
mNeedsFiltering(false),
mProtectedByApp(false),
mClientRef(client),
mPotentialCursor(false),
- mQueueItemLock(),
- mQueueItemCondition(),
- mQueueItems(),
- mLastFrameNumberReceived(0),
- mAutoRefresh(false),
mFreezeGeometryUpdates(false),
mCurrentChildren(LayerVector::StateSet::Current),
- mDrawingChildren(LayerVector::StateSet::Drawing) {
+ mDrawingChildren(LayerVector::StateSet::Drawing),
+ mBE{this, name.string()} {
+
mCurrentCrop.makeInvalid();
uint32_t layerFlags = 0;
@@ -111,21 +97,30 @@
mName = name;
mTransactionName = String8("TX - ") + mName;
- mCurrentState.active.w = w;
- mCurrentState.active.h = h;
+ mCurrentState.active_legacy.w = w;
+ mCurrentState.active_legacy.h = h;
mCurrentState.flags = layerFlags;
- mCurrentState.active.transform.set(0, 0);
- mCurrentState.crop.makeInvalid();
- mCurrentState.finalCrop.makeInvalid();
- mCurrentState.requestedFinalCrop = mCurrentState.finalCrop;
- mCurrentState.requestedCrop = mCurrentState.crop;
+ mCurrentState.active_legacy.transform.set(0, 0);
+ mCurrentState.crop_legacy.makeInvalid();
+ mCurrentState.requestedCrop_legacy = mCurrentState.crop_legacy;
mCurrentState.z = 0;
mCurrentState.color.a = 1.0f;
mCurrentState.layerStack = 0;
mCurrentState.sequence = 0;
- mCurrentState.requested = mCurrentState.active;
+ mCurrentState.requested_legacy = mCurrentState.active_legacy;
mCurrentState.appId = 0;
mCurrentState.type = 0;
+ mCurrentState.active.w = 0;
+ mCurrentState.active.h = 0;
+ mCurrentState.active.transform.set(0, 0);
+ mCurrentState.transform = 0;
+ mCurrentState.transformToDisplayInverse = false;
+ mCurrentState.crop.makeInvalid();
+ mCurrentState.acquireFence = new Fence(-1);
+ mCurrentState.dataspace = ui::Dataspace::UNKNOWN;
+ mCurrentState.hdrMetadata.validTypes = 0;
+ mCurrentState.surfaceDamageRegion.clear();
+ mCurrentState.api = -1;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -133,22 +128,7 @@
CompositorTiming compositorTiming;
flinger->getCompositorTiming(&compositorTiming);
mFrameEventHistory.initializeCompositorTiming(compositorTiming);
-}
-
-void Layer::onFirstRef() NO_THREAD_SAFETY_ANALYSIS {
- if (!isCreatedFromMainThread()) {
- // Grab the SF state lock during this since it's the only way to safely access HWC
- mFlinger->mStateLock.lock();
- }
-
- const auto& hwc = mFlinger->getHwComposer();
- const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY);
- nsecs_t displayPeriod = activeConfig->getVsyncPeriod();
- mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
-
- if (!isCreatedFromMainThread()) {
- mFlinger->mStateLock.unlock();
- }
+ mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
}
Layer::~Layer() {
@@ -228,33 +208,33 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) {
- LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(hwcId) != 0,
- "Already have a layer for hwcId %d", hwcId);
- HWC2::Layer* layer = hwc->createLayer(hwcId);
+bool Layer::createHwcLayer(HWComposer* hwc, int32_t displayId) {
+ LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(displayId) != 0,
+ "Already have a layer for display %d", displayId);
+ auto layer = std::shared_ptr<HWC2::Layer>(
+ hwc->createLayer(displayId),
+ [hwc, displayId](HWC2::Layer* layer) {
+ hwc->destroyLayer(displayId, layer); });
if (!layer) {
return false;
}
- LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers[hwcId];
+ LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers[displayId];
hwcInfo.hwc = hwc;
hwcInfo.layer = layer;
layer->setLayerDestroyedListener(
- [this, hwcId](HWC2::Layer* /*layer*/) { getBE().mHwcLayers.erase(hwcId); });
+ [this, displayId](HWC2::Layer* /*layer*/) { getBE().mHwcLayers.erase(displayId); });
return true;
}
-bool Layer::destroyHwcLayer(int32_t hwcId) {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
+bool Layer::destroyHwcLayer(int32_t displayId) {
+ if (getBE().mHwcLayers.count(displayId) == 0) {
return false;
}
- auto& hwcInfo = getBE().mHwcLayers[hwcId];
+ auto& hwcInfo = getBE().mHwcLayers[displayId];
LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, "Attempt to destroy null layer");
LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer");
- hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer);
- // The layer destroyed listener should have cleared the entry from
- // mHwcLayers. Verify that.
- LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(hwcId) != 0,
- "Stale layer entry in getBE().mHwcLayers");
+ hwcInfo.layer = nullptr;
+
return true;
}
@@ -304,20 +284,17 @@
}
Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
- const Layer::State& s(getDrawingState());
- Rect win(s.active.w, s.active.h);
+ const State& s(getDrawingState());
+ Rect win(getActiveWidth(s), getActiveHeight(s));
- if (!s.crop.isEmpty()) {
- win.intersect(s.crop, &win);
+ Rect crop = getCrop(s);
+ if (!crop.isEmpty()) {
+ win.intersect(crop, &win);
}
- Transform t = getTransform();
+ ui::Transform t = getTransform();
win = t.transform(win);
- if (!s.finalCrop.isEmpty()) {
- win.intersect(s.finalCrop, &win);
- }
-
const sp<Layer>& p = mDrawingParent.promote();
// Now we need to calculate the parent bounds, so we can clip ourselves to those.
// When calculating the parent bounds for purposes of clipping,
@@ -334,7 +311,7 @@
}
if (reduceTransparentRegion) {
- auto const screenTransparentRegion = t.transform(s.activeTransparentRegion);
+ auto const screenTransparentRegion = t.transform(getActiveTransparentRegion(s));
win = reduce(win, screenTransparentRegion);
}
@@ -342,16 +319,17 @@
}
FloatRect Layer::computeBounds() const {
- const Layer::State& s(getDrawingState());
- return computeBounds(s.activeTransparentRegion);
+ const State& s(getDrawingState());
+ return computeBounds(getActiveTransparentRegion(s));
}
FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
- const Layer::State& s(getDrawingState());
- Rect win(s.active.w, s.active.h);
+ const State& s(getDrawingState());
+ Rect win(getActiveWidth(s), getActiveHeight(s));
- if (!s.crop.isEmpty()) {
- win.intersect(s.crop, &win);
+ Rect crop = getCrop(s);
+ if (!crop.isEmpty()) {
+ win.intersect(crop, &win);
}
const auto& p = mDrawingParent.promote();
@@ -363,16 +341,11 @@
parentBounds = p->computeBounds(Region());
}
- Transform t = s.active.transform;
+ ui::Transform t = s.active_legacy.transform;
-
- if (p != nullptr || !s.finalCrop.isEmpty()) {
+ if (p != nullptr) {
floatWin = t.transform(floatWin);
floatWin = floatWin.intersect(parentBounds);
-
- if (!s.finalCrop.isEmpty()) {
- floatWin = floatWin.intersect(s.finalCrop.toFloatRect());
- }
floatWin = t.inverse().transform(floatWin);
}
@@ -380,7 +353,7 @@
return reduce(floatWin, activeTransparentRegion);
}
-Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& hw) const {
+Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& display) const {
// the crop is the area of the window that gets cropped, but not
// scaled in any ways.
const State& s(getDrawingState());
@@ -392,32 +365,28 @@
// FIXME: the 3 lines below can produce slightly incorrect clipping when we have
// a viewport clipping and a window transform. we should use floating point to fix this.
- Rect activeCrop(s.active.w, s.active.h);
- if (!s.crop.isEmpty()) {
- activeCrop.intersect(s.crop, &activeCrop);
+ Rect activeCrop(getActiveWidth(s), getActiveHeight(s));
+ Rect crop = getCrop(s);
+ if (!crop.isEmpty()) {
+ activeCrop.intersect(crop, &activeCrop);
}
- Transform t = getTransform();
+ ui::Transform t = getTransform();
activeCrop = t.transform(activeCrop);
- if (!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
+ if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
activeCrop.clear();
}
- if (!s.finalCrop.isEmpty()) {
- if (!activeCrop.intersect(s.finalCrop, &activeCrop)) {
- activeCrop.clear();
- }
- }
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
- auto parentCrop = p->computeInitialCrop(hw);
+ auto parentCrop = p->computeInitialCrop(display);
activeCrop.intersect(parentCrop, &activeCrop);
}
return activeCrop;
}
-FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
+FloatRect Layer::computeCrop(const sp<const DisplayDevice>& display) const {
// the content crop is the area of the content that gets scaled to the
// layer's size. This is in buffer space.
FloatRect crop = getContentCrop().toFloatRect();
@@ -426,8 +395,8 @@
const State& s(getDrawingState());
// Screen space to make reduction to parent crop clearer.
- Rect activeCrop = computeInitialCrop(hw);
- Transform t = getTransform();
+ Rect activeCrop = computeInitialCrop(display);
+ ui::Transform t = getTransform();
// Back to layer space to work with the content crop.
activeCrop = t.inverse().transform(activeCrop);
@@ -437,12 +406,12 @@
// transform.inverse().transform(transform.transform(Rect)) != Rect
// in which case we need to make sure the final rect is clipped to the
// display bounds.
- if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+ if (!activeCrop.intersect(Rect(getActiveWidth(s), getActiveHeight(s)), &activeCrop)) {
activeCrop.clear();
}
// subtract the transparent region and snap to the bounds
- activeCrop = reduce(activeCrop, s.activeTransparentRegion);
+ activeCrop = reduce(activeCrop, getActiveTransparentRegion(s));
// Transform the window crop to match the buffer coordinate system,
// which means using the inverse of the current transform set on the
@@ -459,11 +428,12 @@
invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
// and apply to the current transform
- invTransform = (Transform(invTransformOrient) * Transform(invTransform)).getOrientation();
+ invTransform = (ui::Transform(invTransformOrient) *
+ ui::Transform(invTransform)).getOrientation();
}
- int winWidth = s.active.w;
- int winHeight = s.active.h;
+ int winWidth = getActiveWidth(s);
+ int winHeight = getActiveHeight(s);
if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
// If the activeCrop has been rotate the ends are rotated but not
// the space itself so when transforming ends back we can't rely on
@@ -475,10 +445,10 @@
if (is_h_flipped == is_v_flipped) {
invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
- winWidth = s.active.h;
- winHeight = s.active.w;
+ winWidth = getActiveHeight(s);
+ winHeight = getActiveWidth(s);
}
- const Rect winCrop = activeCrop.transform(invTransform, s.active.w, s.active.h);
+ const Rect winCrop = activeCrop.transform(invTransform, getActiveWidth(s), getActiveHeight(s));
// below, crop is intersected with winCrop expressed in crop's coordinate space
float xScale = crop.getWidth() / float(winWidth);
@@ -497,23 +467,34 @@
return crop;
}
-void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z)
-{
- const auto hwcId = displayDevice->getHwcDisplayId();
- if (!hasHwcLayer(hwcId)) {
+void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
+ const auto displayId = display->getId();
+ if (!hasHwcLayer(displayId)) {
+ ALOGE("[%s] failed to setGeometry: no HWC layer found (%d)",
+ mName.string(), displayId);
return;
}
- auto& hwcInfo = getBE().mHwcLayers[hwcId];
+ auto& hwcInfo = getBE().mHwcLayers[displayId];
+
+ // Device or Cursor layers
+ if (mPotentialCursor) {
+ ALOGV("[%s] Requesting Cursor composition", mName.string());
+ setCompositionType(displayId, HWC2::Composition::Cursor);
+ } else {
+ ALOGV("[%s] Requesting Device composition", mName.string());
+ setCompositionType(displayId, HWC2::Composition::Device);
+ }
+
+ // Need to program geometry parts
+ getBE().compositionInfo.hwc.skipGeometry = false;
// enable this layer
hwcInfo.forceClientComposition = false;
- if (isSecure() && !displayDevice->isSecure()) {
+ if (isSecure() && !display->isSecure()) {
hwcInfo.forceClientComposition = true;
}
- auto& hwcLayer = hwcInfo.layer;
-
// this gives us only the "orientation" component of the transform
const State& s(getDrawingState());
auto blendMode = HWC2::BlendMode::None;
@@ -521,21 +502,16 @@
blendMode =
mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
}
- auto error = hwcLayer->setBlendMode(blendMode);
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set blend mode %s:"
- " %s (%d)",
- mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
+ getBE().compositionInfo.hwc.blendMode = blendMode;
// apply the layer's transform, followed by the display's global transform
// here we're guaranteed that the layer's transform preserves rects
- Region activeTransparentRegion(s.activeTransparentRegion);
- Transform t = getTransform();
- if (!s.crop.isEmpty()) {
- Rect activeCrop(s.crop);
+ Region activeTransparentRegion(getActiveTransparentRegion(s));
+ ui::Transform t = getTransform();
+ Rect activeCrop = getCrop(s);
+ if (!activeCrop.isEmpty()) {
activeCrop = t.transform(activeCrop);
- if (!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) {
+ if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
activeCrop.clear();
}
activeCrop = t.inverse().transform(activeCrop, true);
@@ -545,60 +521,35 @@
// transform.inverse().transform(transform.transform(Rect)) != Rect
// in which case we need to make sure the final rect is clipped to the
// display bounds.
- if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+ if (!activeCrop.intersect(Rect(getActiveWidth(s), getActiveHeight(s)), &activeCrop)) {
activeCrop.clear();
}
// mark regions outside the crop as transparent
- activeTransparentRegion.orSelf(Rect(0, 0, s.active.w, activeCrop.top));
- activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom, s.active.w, s.active.h));
+ activeTransparentRegion.orSelf(Rect(0, 0, getActiveWidth(s), activeCrop.top));
+ activeTransparentRegion.orSelf(
+ Rect(0, activeCrop.bottom, getActiveWidth(s), getActiveHeight(s)));
activeTransparentRegion.orSelf(Rect(0, activeCrop.top, activeCrop.left, activeCrop.bottom));
activeTransparentRegion.orSelf(
- Rect(activeCrop.right, activeCrop.top, s.active.w, activeCrop.bottom));
+ Rect(activeCrop.right, activeCrop.top, getActiveWidth(s), activeCrop.bottom));
}
// computeBounds returns a FloatRect to provide more accuracy during the
// transformation. We then round upon constructing 'frame'.
Rect frame{t.transform(computeBounds(activeTransparentRegion))};
- if (!s.finalCrop.isEmpty()) {
- if (!frame.intersect(s.finalCrop, &frame)) {
- frame.clear();
- }
- }
- if (!frame.intersect(displayDevice->getViewport(), &frame)) {
+ if (!frame.intersect(display->getViewport(), &frame)) {
frame.clear();
}
- const Transform& tr(displayDevice->getTransform());
+ const ui::Transform& tr = display->getTransform();
Rect transformedFrame = tr.transform(frame);
- error = hwcLayer->setDisplayFrame(transformedFrame);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", mName.string(),
- transformedFrame.left, transformedFrame.top, transformedFrame.right,
- transformedFrame.bottom, to_string(error).c_str(), static_cast<int32_t>(error));
- } else {
- hwcInfo.displayFrame = transformedFrame;
- }
+ getBE().compositionInfo.hwc.displayFrame = transformedFrame;
- FloatRect sourceCrop = computeCrop(displayDevice);
- error = hwcLayer->setSourceCrop(sourceCrop);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
- "%s (%d)",
- mName.string(), sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom,
- to_string(error).c_str(), static_cast<int32_t>(error));
- } else {
- hwcInfo.sourceCrop = sourceCrop;
- }
+ FloatRect sourceCrop = computeCrop(display);
+ getBE().compositionInfo.hwc.sourceCrop = sourceCrop;
float alpha = static_cast<float>(getAlpha());
- error = hwcLayer->setPlaneAlpha(alpha);
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set plane alpha %.3f: "
- "%s (%d)",
- mName.string(), alpha, to_string(error).c_str(), static_cast<int32_t>(error));
+ getBE().compositionInfo.hwc.alpha = alpha;
- error = hwcLayer->setZOrder(z);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), z,
- to_string(error).c_str(), static_cast<int32_t>(error));
+ getBE().compositionInfo.hwc.z = z;
int type = s.type;
int appId = s.appId;
@@ -611,9 +562,8 @@
}
}
- error = hwcLayer->setInfo(type, appId);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", mName.string(),
- static_cast<int32_t>(error));
+ getBE().compositionInfo.hwc.type = type;
+ getBE().compositionInfo.hwc.appId = appId;
/*
* Transformations are applied in this order:
@@ -623,8 +573,8 @@
* (NOTE: the matrices are multiplied in reverse order)
*/
- const Transform bufferOrientation(mCurrentTransform);
- Transform transform(tr * t * bufferOrientation);
+ const ui::Transform bufferOrientation(mCurrentTransform);
+ ui::Transform transform(tr * t * bufferOrientation);
if (getTransformToDisplayInverse()) {
/*
@@ -643,48 +593,43 @@
* computation so it's enough to just omit it in the composition.
* See comment in onDraw with ref to b/36727915 for why.
*/
- transform = Transform(invTransform) * tr * bufferOrientation;
+ transform = ui::Transform(invTransform) * tr * bufferOrientation;
}
// this gives us only the "orientation" component of the transform
const uint32_t orientation = transform.getOrientation();
- if (orientation & Transform::ROT_INVALID) {
+ if (orientation & ui::Transform::ROT_INVALID) {
// we can only handle simple transformation
hwcInfo.forceClientComposition = true;
} else {
auto transform = static_cast<HWC2::Transform>(orientation);
hwcInfo.transform = transform;
- auto error = hwcLayer->setTransform(transform);
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set transform %s: "
- "%s (%d)",
- mName.string(), to_string(transform).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
+ getBE().compositionInfo.hwc.transform = transform;
}
}
-void Layer::forceClientComposition(int32_t hwcId) {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
- ALOGE("forceClientComposition: no HWC layer found (%d)", hwcId);
+void Layer::forceClientComposition(int32_t displayId) {
+ if (getBE().mHwcLayers.count(displayId) == 0) {
+ ALOGE("forceClientComposition: no HWC layer found (%d)", displayId);
return;
}
- getBE().mHwcLayers[hwcId].forceClientComposition = true;
+ getBE().mHwcLayers[displayId].forceClientComposition = true;
}
-bool Layer::getForceClientComposition(int32_t hwcId) {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
- ALOGE("getForceClientComposition: no HWC layer found (%d)", hwcId);
+bool Layer::getForceClientComposition(int32_t displayId) {
+ if (getBE().mHwcLayers.count(displayId) == 0) {
+ ALOGE("getForceClientComposition: no HWC layer found (%d)", displayId);
return false;
}
- return getBE().mHwcLayers[hwcId].forceClientComposition;
+ return getBE().mHwcLayers[displayId].forceClientComposition;
}
-void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) {
- auto hwcId = displayDevice->getHwcDisplayId();
- if (getBE().mHwcLayers.count(hwcId) == 0 ||
- getCompositionType(hwcId) != HWC2::Composition::Cursor) {
+void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
+ const auto displayId = display->getId();
+ if (getBE().mHwcLayers.count(displayId) == 0 ||
+ getCompositionType(displayId) != HWC2::Composition::Cursor) {
return;
}
@@ -693,22 +638,21 @@
// Apply the layer's transform, followed by the display's global transform
// Here we're guaranteed that the layer's transform preserves rects
- Rect win(s.active.w, s.active.h);
- if (!s.crop.isEmpty()) {
- win.intersect(s.crop, &win);
+ Rect win(getActiveWidth(s), getActiveHeight(s));
+ Rect crop = getCrop(s);
+ if (!crop.isEmpty()) {
+ win.intersect(crop, &win);
}
// Subtract the transparent region and snap to the bounds
- Rect bounds = reduce(win, s.activeTransparentRegion);
+ Rect bounds = reduce(win, getActiveTransparentRegion(s));
Rect frame(getTransform().transform(bounds));
- frame.intersect(displayDevice->getViewport(), &frame);
- if (!s.finalCrop.isEmpty()) {
- frame.intersect(s.finalCrop, &frame);
- }
- auto& displayTransform(displayDevice->getTransform());
+ frame.intersect(display->getViewport(), &frame);
+ auto& displayTransform = display->getTransform();
auto position = displayTransform.transform(frame);
- auto error = getBE().mHwcLayers[hwcId].layer->setCursorPosition(position.left,
- position.top);
+ auto error =
+ (getBE().mHwcLayers[displayId].layer)->setCursorPosition(
+ position.left, position.top);
ALOGE_IF(error != HWC2::Error::None,
"[%s] Failed to set cursor position "
"to (%d, %d): %s (%d)",
@@ -720,18 +664,14 @@
// drawing...
// ---------------------------------------------------------------------------
-void Layer::draw(const RenderArea& renderArea, const Region& clip) const {
+void Layer::draw(const RenderArea& renderArea, const Region& clip) {
onDraw(renderArea, clip, false);
}
-void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) const {
+void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) {
onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform);
}
-void Layer::draw(const RenderArea& renderArea) const {
- onDraw(renderArea, Region(renderArea.getBounds()), false);
-}
-
void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue,
float alpha) const {
auto& engine(mFlinger->getRenderEngine());
@@ -744,56 +684,43 @@
clearWithOpenGL(renderArea, 0, 0, 0, 0);
}
-void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc) {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
+void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool /*callIntoHwc*/) {
+ if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setCompositionType called without a valid HWC layer");
return;
- }
- auto& hwcInfo = getBE().mHwcLayers[hwcId];
- auto& hwcLayer = hwcInfo.layer;
- ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(), to_string(type).c_str(),
- static_cast<int>(callIntoHwc));
- if (hwcInfo.compositionType != type) {
- ALOGV(" actually setting");
- hwcInfo.compositionType = type;
- if (callIntoHwc) {
- auto error = hwcLayer->setCompositionType(type);
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set "
- "composition type %s: %s (%d)",
- mName.string(), to_string(type).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
+ } else {
+ if (getBE().mHwcLayers[displayId].compositionType != type) {
+ ALOGV("setCompositionType: Changing compositionType from %s to %s",
+ to_string(getBE().mHwcLayers[displayId].compositionType).c_str(),
+ to_string(type).c_str());
+ getBE().mHwcLayers[displayId].compositionType = type;
}
}
}
-HWC2::Composition Layer::getCompositionType(int32_t hwcId) const {
- if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+HWC2::Composition Layer::getCompositionType(int32_t displayId) const {
+ if (getBE().mHwcLayers.count(displayId) == 0) {
// If we're querying the composition type for a display that does not
// have a HWC counterpart, then it will always be Client
return HWC2::Composition::Client;
}
- if (getBE().mHwcLayers.count(hwcId) == 0) {
- ALOGE("getCompositionType called with an invalid HWC layer");
- return HWC2::Composition::Invalid;
- }
- return getBE().mHwcLayers.at(hwcId).compositionType;
+ return getBE().mHwcLayers[displayId].compositionType;
}
-void Layer::setClearClientTarget(int32_t hwcId, bool clear) {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
+void Layer::setClearClientTarget(int32_t displayId, bool clear) {
+ if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setClearClientTarget called without a valid HWC layer");
return;
}
- getBE().mHwcLayers[hwcId].clearClientTarget = clear;
+ getBE().mHwcLayers[displayId].clearClientTarget = clear;
}
-bool Layer::getClearClientTarget(int32_t hwcId) const {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
+bool Layer::getClearClientTarget(int32_t displayId) const {
+ if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("getClearClientTarget called without a valid HWC layer");
return false;
}
- return getBE().mHwcLayers.at(hwcId).clearClientTarget;
+ return getBE().mHwcLayers.at(displayId).clearClientTarget;
}
bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
@@ -808,38 +735,14 @@
return true;
}
-void Layer::setFiltering(bool filtering) {
- mFiltering = filtering;
-}
-
-bool Layer::getFiltering() const {
- return mFiltering;
-}
-
// ----------------------------------------------------------------------------
// local state
// ----------------------------------------------------------------------------
-static void boundPoint(vec2* point, const Rect& crop) {
- if (point->x < crop.left) {
- point->x = crop.left;
- }
- if (point->x > crop.right) {
- point->x = crop.right;
- }
- if (point->y < crop.top) {
- point->y = crop.top;
- }
- if (point->y > crop.bottom) {
- point->y = crop.bottom;
- }
-}
-
-void Layer::computeGeometry(const RenderArea& renderArea, Mesh& mesh,
+void Layer::computeGeometry(const RenderArea& renderArea,
+ renderengine::Mesh& mesh,
bool useIdentityTransform) const {
- const Layer::State& s(getDrawingState());
- const Transform renderAreaTransform(renderArea.getTransform());
- const uint32_t height = renderArea.getHeight();
+ const ui::Transform renderAreaTransform(renderArea.getTransform());
FloatRect win = computeBounds();
vec2 lt = vec2(win.left, win.top);
@@ -847,7 +750,7 @@
vec2 rb = vec2(win.right, win.bottom);
vec2 rt = vec2(win.right, win.top);
- Transform layerTransform = getTransform();
+ ui::Transform layerTransform = getTransform();
if (!useIdentityTransform) {
lt = layerTransform.transform(lt);
lb = layerTransform.transform(lb);
@@ -855,25 +758,15 @@
rt = layerTransform.transform(rt);
}
- if (!s.finalCrop.isEmpty()) {
- boundPoint(<, s.finalCrop);
- boundPoint(&lb, s.finalCrop);
- boundPoint(&rb, s.finalCrop);
- boundPoint(&rt, s.finalCrop);
- }
-
- Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+ renderengine::Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
position[0] = renderAreaTransform.transform(lt);
position[1] = renderAreaTransform.transform(lb);
position[2] = renderAreaTransform.transform(rb);
position[3] = renderAreaTransform.transform(rt);
- for (size_t i = 0; i < 4; i++) {
- position[i].y = height - position[i].y;
- }
}
bool Layer::isSecure() const {
- const Layer::State& s(mDrawingState);
+ const State& s(mDrawingState);
return (s.flags & layer_state_t::eLayerSecure);
}
@@ -909,22 +802,22 @@
// If this transaction is waiting on the receipt of a frame, generate a sync
// point and send it to the remote layer.
- if (mCurrentState.barrierLayer != nullptr) {
- sp<Layer> barrierLayer = mCurrentState.barrierLayer.promote();
+ if (mCurrentState.barrierLayer_legacy != nullptr) {
+ sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote();
if (barrierLayer == nullptr) {
ALOGE("[%s] Unable to promote barrier Layer.", mName.string());
// If we can't promote the layer we are intended to wait on,
// then it is expired or otherwise invalid. Allow this transaction
// to be applied as per normal (no synchronization).
- mCurrentState.barrierLayer = nullptr;
+ mCurrentState.barrierLayer_legacy = nullptr;
} else {
- auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber);
+ auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy);
if (barrierLayer->addSyncPoint(syncPoint)) {
mRemoteSyncPoints.push_back(std::move(syncPoint));
} else {
// We already missed the frame we're supposed to synchronize
// on, so go ahead and apply the state update
- mCurrentState.barrierLayer = nullptr;
+ mCurrentState.barrierLayer_legacy = nullptr;
}
}
@@ -946,7 +839,7 @@
bool Layer::applyPendingStates(State* stateToCommit) {
bool stateUpdateAvailable = false;
while (!mPendingStates.empty()) {
- if (mPendingStates[0].barrierLayer != nullptr) {
+ if (mPendingStates[0].barrierLayer_legacy != nullptr) {
if (mRemoteSyncPoints.empty()) {
// If we don't have a sync point for this, apply it anyway. It
// will be visually wrong, but it should keep us from getting
@@ -957,7 +850,8 @@
continue;
}
- if (mRemoteSyncPoints.front()->getFrameNumber() != mPendingStates[0].frameNumber) {
+ if (mRemoteSyncPoints.front()->getFrameNumber() !=
+ mPendingStates[0].frameNumber_legacy) {
ALOGE("[%s] Unexpected sync point frame number found", mName.string());
// Signal our end of the sync point and then dispose of it
@@ -994,18 +888,11 @@
return stateUpdateAvailable;
}
-uint32_t Layer::doTransaction(uint32_t flags) {
- ATRACE_CALL();
+uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) {
+ const State& s(getDrawingState());
- pushPendingState();
- Layer::State c = getCurrentState();
- if (!applyPendingStates(&c)) {
- return 0;
- }
-
- const Layer::State& s(getDrawingState());
-
- const bool sizeChanged = (c.requested.w != s.requested.w) || (c.requested.h != s.requested.h);
+ const bool sizeChanged = (stateToCommit->requested_legacy.w != s.requested_legacy.w) ||
+ (stateToCommit->requested_legacy.h != s.requested_legacy.h);
if (sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
@@ -1015,16 +902,15 @@
" requested={ wh={%4u,%4u} }}\n"
" drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} }}\n",
- this, getName().string(), mCurrentTransform,
- getEffectiveScalingMode(), c.active.w, c.active.h, c.crop.left, c.crop.top,
- c.crop.right, c.crop.bottom, c.crop.getWidth(), c.crop.getHeight(), c.requested.w,
- c.requested.h, s.active.w, s.active.h, s.crop.left, s.crop.top, s.crop.right,
- s.crop.bottom, s.crop.getWidth(), s.crop.getHeight(), s.requested.w,
- s.requested.h);
-
- // record the new size, form this point on, when the client request
- // a buffer, it'll get the new size.
- setDefaultBufferSize(c.requested.w, c.requested.h);
+ this, getName().string(), mCurrentTransform, getEffectiveScalingMode(),
+ stateToCommit->active_legacy.w, stateToCommit->active_legacy.h,
+ stateToCommit->crop_legacy.left, stateToCommit->crop_legacy.top,
+ stateToCommit->crop_legacy.right, stateToCommit->crop_legacy.bottom,
+ stateToCommit->crop_legacy.getWidth(), stateToCommit->crop_legacy.getHeight(),
+ stateToCommit->requested_legacy.w, stateToCommit->requested_legacy.h,
+ s.active_legacy.w, s.active_legacy.h, s.crop_legacy.left, s.crop_legacy.top,
+ s.crop_legacy.right, s.crop_legacy.bottom, s.crop_legacy.getWidth(),
+ s.crop_legacy.getHeight(), s.requested_legacy.w, s.requested_legacy.h);
}
// Don't let Layer::doTransaction update the drawing state
@@ -1045,7 +931,9 @@
// resizePending state is to avoid applying the state of the new buffer
// to the old buffer. However in the state where we don't have an old buffer
// there is no such concern but we may still be being used as a parent layer.
- const bool resizePending = ((c.requested.w != c.active.w) || (c.requested.h != c.active.h)) &&
+ const bool resizePending =
+ ((stateToCommit->requested_legacy.w != stateToCommit->active_legacy.w) ||
+ (stateToCommit->requested_legacy.h != stateToCommit->active_legacy.h)) &&
(getBE().compositionInfo.mBuffer != nullptr);
if (!isFixedSize()) {
if (resizePending && getBE().compositionInfo.hwc.sidebandStream == nullptr) {
@@ -1057,7 +945,7 @@
// latching configuration. See Layer.h for a detailed discussion of
// how geometry latching is controlled.
if (!(flags & eDontUpdateGeometryState)) {
- Layer::State& editCurrentState(getCurrentState());
+ State& editCurrentState(getCurrentState());
// If mFreezeGeometryUpdates is true we are in the setGeometryAppliesWithResize
// mode, which causes attributes which normally latch regardless of scaling mode,
@@ -1069,21 +957,37 @@
// being stored in the same data structure while having different latching rules.
// b/38182305
//
- // Careful that "c" and editCurrentState may not begin as equivalent due to
+ // Careful that "stateToCommit" and editCurrentState may not begin as equivalent due to
// applyPendingStates in the presence of deferred transactions.
if (mFreezeGeometryUpdates) {
- float tx = c.active.transform.tx();
- float ty = c.active.transform.ty();
- c.active = c.requested;
- c.active.transform.set(tx, ty);
- editCurrentState.active = c.active;
+ float tx = stateToCommit->active_legacy.transform.tx();
+ float ty = stateToCommit->active_legacy.transform.ty();
+ stateToCommit->active_legacy = stateToCommit->requested_legacy;
+ stateToCommit->active_legacy.transform.set(tx, ty);
+ editCurrentState.active_legacy = stateToCommit->active_legacy;
} else {
- editCurrentState.active = editCurrentState.requested;
- c.active = c.requested;
+ editCurrentState.active_legacy = editCurrentState.requested_legacy;
+ stateToCommit->active_legacy = stateToCommit->requested_legacy;
}
}
- if (s.active != c.active) {
+ return flags;
+}
+
+uint32_t Layer::doTransaction(uint32_t flags) {
+ ATRACE_CALL();
+
+ pushPendingState();
+ State c = getCurrentState();
+ if (!applyPendingStates(&c)) {
+ return 0;
+ }
+
+ flags = doTransactionResize(flags, &c);
+
+ const State& s(getDrawingState());
+
+ if (getActiveGeometry(c) != getActiveGeometry(s)) {
// invalidate and recompute the visible regions if needed
flags |= Layer::eVisibleRegion;
}
@@ -1094,8 +998,8 @@
this->contentDirty = true;
// we may use linear filtering, if the matrix scales us
- const uint8_t type = c.active.transform.getType();
- mNeedsFiltering = (!c.active.transform.preserveRects() || (type >= Transform::SCALE));
+ const uint8_t type = getActiveTransform(c).getType();
+ mNeedsFiltering = (!getActiveTransform(c).preserveRects() || type >= ui::Transform::SCALE);
}
// If the layer is hidden, signal and clear out all local sync points so
@@ -1123,20 +1027,21 @@
}
bool Layer::setPosition(float x, float y, bool immediate) {
- if (mCurrentState.requested.transform.tx() == x && mCurrentState.requested.transform.ty() == y)
+ if (mCurrentState.requested_legacy.transform.tx() == x &&
+ mCurrentState.requested_legacy.transform.ty() == y)
return false;
mCurrentState.sequence++;
// We update the requested and active position simultaneously because
// we want to apply the position portion of the transform matrix immediately,
// but still delay scaling when resizing a SCALING_MODE_FREEZE layer.
- mCurrentState.requested.transform.set(x, y);
+ mCurrentState.requested_legacy.transform.set(x, y);
if (immediate && !mFreezeGeometryUpdates) {
// Here we directly update the active state
// unlike other setters, because we store it within
// the transform, but use different latching rules.
// b/38182305
- mCurrentState.active.transform.set(x, y);
+ mCurrentState.active_legacy.transform.set(x, y);
}
mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
@@ -1236,11 +1141,16 @@
}
bool Layer::setSize(uint32_t w, uint32_t h) {
- if (mCurrentState.requested.w == w && mCurrentState.requested.h == h) return false;
- mCurrentState.requested.w = w;
- mCurrentState.requested.h = h;
+ if (mCurrentState.requested_legacy.w == w && mCurrentState.requested_legacy.h == h)
+ return false;
+ mCurrentState.requested_legacy.w = w;
+ mCurrentState.requested_legacy.h = h;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
+
+ // record the new size, from this point on, when the client request
+ // a buffer, it'll get the new size.
+ setDefaultBufferSize(mCurrentState.requested_legacy.w, mCurrentState.requested_legacy.h);
return true;
}
bool Layer::setAlpha(float alpha) {
@@ -1268,7 +1178,7 @@
bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix,
bool allowNonRectPreservingTransforms) {
- Transform t;
+ ui::Transform t;
t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
@@ -1276,13 +1186,15 @@
return false;
}
mCurrentState.sequence++;
- mCurrentState.requested.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+ mCurrentState.requested_legacy.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx,
+ matrix.dsdy);
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
+
bool Layer::setTransparentRegionHint(const Region& transparent) {
- mCurrentState.requestedTransparentRegion = transparent;
+ mCurrentState.requestedTransparentRegion_legacy = transparent;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
@@ -1297,26 +1209,12 @@
return true;
}
-bool Layer::setCrop(const Rect& crop, bool immediate) {
- if (mCurrentState.requestedCrop == crop) return false;
+bool Layer::setCrop_legacy(const Rect& crop, bool immediate) {
+ if (mCurrentState.requestedCrop_legacy == crop) return false;
mCurrentState.sequence++;
- mCurrentState.requestedCrop = crop;
+ mCurrentState.requestedCrop_legacy = crop;
if (immediate && !mFreezeGeometryUpdates) {
- mCurrentState.crop = crop;
- }
- mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
-
- mCurrentState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setFinalCrop(const Rect& crop, bool immediate) {
- if (mCurrentState.requestedFinalCrop == crop) return false;
- mCurrentState.sequence++;
- mCurrentState.requestedFinalCrop = crop;
- if (immediate && !mFreezeGeometryUpdates) {
- mCurrentState.finalCrop = crop;
+ mCurrentState.crop_legacy = crop;
}
mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
@@ -1356,30 +1254,29 @@
return p->getLayerStack();
}
-void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
- mCurrentState.barrierLayer = barrierLayer;
- mCurrentState.frameNumber = frameNumber;
+void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
+ mCurrentState.barrierLayer_legacy = barrierLayer;
+ mCurrentState.frameNumber_legacy = frameNumber;
// We don't set eTransactionNeeded, because just receiving a deferral
// request without any other state updates shouldn't actually induce a delay
mCurrentState.modified = true;
pushPendingState();
- mCurrentState.barrierLayer = nullptr;
- mCurrentState.frameNumber = 0;
+ mCurrentState.barrierLayer_legacy = nullptr;
+ mCurrentState.frameNumber_legacy = 0;
mCurrentState.modified = false;
}
-void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber) {
+void Layer::deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle, uint64_t frameNumber) {
sp<Handle> handle = static_cast<Handle*>(barrierHandle.get());
- deferTransactionUntil(handle->owner.promote(), frameNumber);
+ deferTransactionUntil_legacy(handle->owner.promote(), frameNumber);
}
-
// ----------------------------------------------------------------------------
// pageflip handling...
// ----------------------------------------------------------------------------
bool Layer::isHiddenByPolicy() const {
- const Layer::State& s(mDrawingState);
+ const State& s(mDrawingState);
const auto& parent = mDrawingParent.promote();
if (parent != nullptr && parent->isHiddenByPolicy()) {
return true;
@@ -1400,15 +1297,15 @@
return usage;
}
-void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {
+void Layer::updateTransformHint(const sp<const DisplayDevice>& display) const {
uint32_t orientation = 0;
if (!mFlinger->mDebugDisableTransformHint) {
// The transform hint is used to improve performance, but we can
// only have a single transform hint, it cannot
// apply to all displays.
- const Transform& planeTransform(hw->getTransform());
+ const ui::Transform& planeTransform = display->getTransform();
orientation = planeTransform.getOrientation();
- if (orientation & Transform::ROT_INVALID) {
+ if (orientation & ui::Transform::ROT_INVALID) {
orientation = 0;
}
}
@@ -1419,34 +1316,34 @@
// debugging
// ----------------------------------------------------------------------------
+// TODO(marissaw): add new layer state info to layer debugging
LayerDebugInfo Layer::getLayerDebugInfo() const {
LayerDebugInfo info;
- const Layer::State& ds = getDrawingState();
+ const State& ds = getDrawingState();
info.mName = getName();
sp<Layer> parent = getParent();
info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
info.mType = String8(getTypeId());
- info.mTransparentRegion = ds.activeTransparentRegion;
+ info.mTransparentRegion = ds.activeTransparentRegion_legacy;
info.mVisibleRegion = visibleRegion;
info.mSurfaceDamageRegion = surfaceDamageRegion;
info.mLayerStack = getLayerStack();
- info.mX = ds.active.transform.tx();
- info.mY = ds.active.transform.ty();
+ info.mX = ds.active_legacy.transform.tx();
+ info.mY = ds.active_legacy.transform.ty();
info.mZ = ds.z;
- info.mWidth = ds.active.w;
- info.mHeight = ds.active.h;
- info.mCrop = ds.crop;
- info.mFinalCrop = ds.finalCrop;
+ info.mWidth = ds.active_legacy.w;
+ info.mHeight = ds.active_legacy.h;
+ info.mCrop = ds.crop_legacy;
info.mColor = ds.color;
info.mFlags = ds.flags;
info.mPixelFormat = getPixelFormat();
info.mDataSpace = static_cast<android_dataspace>(mCurrentDataSpace);
- info.mMatrix[0][0] = ds.active.transform[0][0];
- info.mMatrix[0][1] = ds.active.transform[0][1];
- info.mMatrix[1][0] = ds.active.transform[1][0];
- info.mMatrix[1][1] = ds.active.transform[1][1];
+ info.mMatrix[0][0] = ds.active_legacy.transform[0][0];
+ info.mMatrix[0][1] = ds.active_legacy.transform[0][1];
+ info.mMatrix[1][0] = ds.active_legacy.transform[1][0];
+ info.mMatrix[1][1] = ds.active_legacy.transform[1][1];
{
- sp<const GraphicBuffer> buffer = getBE().compositionInfo.mBuffer;
+ sp<const GraphicBuffer> buffer = mActiveBuffer;
if (buffer != 0) {
info.mActiveBufferWidth = buffer->getWidth();
info.mActiveBufferHeight = buffer->getHeight();
@@ -1467,19 +1364,22 @@
}
void Layer::miniDumpHeader(String8& result) {
- result.append("----------------------------------------");
- result.append("---------------------------------------\n");
+ result.append("-------------------------------");
+ result.append("-------------------------------");
+ result.append("-----------------------------\n");
result.append(" Layer name\n");
result.append(" Z | ");
result.append(" Comp Type | ");
+ result.append(" Transform | ");
result.append(" Disp Frame (LTRB) | ");
result.append(" Source Crop (LTRB)\n");
- result.append("----------------------------------------");
- result.append("---------------------------------------\n");
+ result.append("-------------------------------");
+ result.append("-------------------------------");
+ result.append("-----------------------------\n");
}
-void Layer::miniDump(String8& result, int32_t hwcId) const {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
+void Layer::miniDump(String8& result, int32_t displayId) const {
+ if (getBE().mHwcLayers.count(displayId) == 0) {
return;
}
@@ -1496,21 +1396,29 @@
result.appendFormat(" %s\n", name.string());
- const Layer::State& layerState(getDrawingState());
- const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(hwcId);
+ const State& layerState(getDrawingState());
+ const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(displayId);
if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
result.appendFormat(" rel %6d | ", layerState.z);
} else {
result.appendFormat(" %10d | ", layerState.z);
}
- result.appendFormat("%10s | ", to_string(getCompositionType(hwcId)).c_str());
+ result.appendFormat("%10s | ", to_string(getCompositionType(displayId)).c_str());
+ result.appendFormat("%10s | ", to_string(hwcInfo.transform).c_str());
const Rect& frame = hwcInfo.displayFrame;
result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
const FloatRect& crop = hwcInfo.sourceCrop;
result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right, crop.bottom);
- result.append("- - - - - - - - - - - - - - - - - - - - ");
- result.append("- - - - - - - - - - - - - - - - - - - -\n");
+ result.append("- - - - - - - - - - - - - - - -\n");
+
+ std::string compositionInfoStr;
+ getBE().compositionInfo.dump(compositionInfoStr, "compositionInfo");
+ result.append(compositionInfoStr.c_str());
+
+ result.append("- - - - - - - - - - - - - - - -");
+ result.append("- - - - - - - - - - - - - - - -");
+ result.append("- - - - - - - - - - - - - - -\n");
}
void Layer::dumpFrameStats(String8& result) const {
@@ -1867,8 +1775,8 @@
traverseChildrenInZOrderInner(layersInTree, stateSet, visitor);
}
-Transform Layer::getTransform() const {
- Transform t;
+ui::Transform Layer::getTransform() const {
+ ui::Transform t;
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
t = p->getTransform();
@@ -1888,14 +1796,14 @@
bufferHeight = p->getBE().compositionInfo.mBuffer->getWidth();
bufferWidth = p->getBE().compositionInfo.mBuffer->getHeight();
}
- float sx = p->getDrawingState().active.w / static_cast<float>(bufferWidth);
- float sy = p->getDrawingState().active.h / static_cast<float>(bufferHeight);
- Transform extraParentScaling;
+ float sx = p->getActiveWidth(p->getDrawingState()) / static_cast<float>(bufferWidth);
+ float sy = p->getActiveHeight(p->getDrawingState()) / static_cast<float>(bufferHeight);
+ ui::Transform extraParentScaling;
extraParentScaling.set(sx, 0, 0, sy);
t = t * extraParentScaling;
}
}
- return t * getDrawingState().active.transform;
+ return t * getActiveTransform(getDrawingState());
}
half Layer::getAlpha() const {
@@ -1924,8 +1832,8 @@
const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
const State& state = useDrawing ? mDrawingState : mCurrentState;
- Transform requestedTransform = state.active.transform;
- Transform transform = getTransform();
+ ui::Transform requestedTransform = state.active_legacy.transform;
+ ui::Transform transform = getTransform();
layerInfo->set_id(sequence);
layerInfo->set_name(getName().c_str());
@@ -1942,7 +1850,7 @@
}
}
- LayerProtoHelper::writeToProto(state.activeTransparentRegion,
+ LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
layerInfo->mutable_transparent_region());
LayerProtoHelper::writeToProto(visibleRegion, layerInfo->mutable_visible_region());
LayerProtoHelper::writeToProto(surfaceDamageRegion, layerInfo->mutable_damage_region());
@@ -1959,11 +1867,10 @@
requestedPosition->set_y(requestedTransform.ty());
SizeProto* size = layerInfo->mutable_size();
- size->set_w(state.active.w);
- size->set_h(state.active.h);
+ size->set_w(state.active_legacy.w);
+ size->set_h(state.active_legacy.h);
- LayerProtoHelper::writeToProto(state.crop, layerInfo->mutable_crop());
- LayerProtoHelper::writeToProto(state.finalCrop, layerInfo->mutable_final_crop());
+ LayerProtoHelper::writeToProto(state.crop_legacy, layerInfo->mutable_crop());
layerInfo->set_is_opaque(isOpaque(state));
layerInfo->set_invalidate(contentDirty);
@@ -1993,6 +1900,8 @@
auto buffer = getBE().compositionInfo.mBuffer;
if (buffer != nullptr) {
LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
+ LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
+ layerInfo->mutable_buffer_transform());
}
layerInfo->set_queued_frames(getQueuedFrameCount());
@@ -2002,22 +1911,23 @@
layerInfo->set_curr_frame(mCurrentFrameNumber);
for (const auto& pendingState : mPendingStates) {
- auto barrierLayer = pendingState.barrierLayer.promote();
+ auto barrierLayer = pendingState.barrierLayer_legacy.promote();
if (barrierLayer != nullptr) {
BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
barrierLayerProto->set_id(barrierLayer->sequence);
- barrierLayerProto->set_frame_number(pendingState.frameNumber);
+ barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
}
}
}
-void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) {
- if (!hasHwcLayer(hwcId)) {
+void Layer::writeToProto(LayerProto* layerInfo, int32_t displayId) {
+ if (!hasHwcLayer(displayId)) {
return;
}
+
writeToProto(layerInfo, LayerVector::StateSet::Drawing);
- const auto& hwcInfo = getBE().mHwcLayers.at(hwcId);
+ const auto& hwcInfo = getBE().mHwcLayers.at(displayId);
const Rect& frame = hwcInfo.displayFrame;
LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2239679..3845b22 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -19,40 +19,38 @@
#include <sys/types.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/Timers.h>
-
+#include <gui/BufferQueue.h>
+#include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
+#include <layerproto/LayerProtoHeader.h>
+#include <math/vec4.h>
+#include <renderengine/Mesh.h>
+#include <renderengine/Texture.h>
#include <ui/FloatRect.h>
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
+#include <ui/Transform.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
-#include <gui/ISurfaceComposerClient.h>
-#include <gui/LayerState.h>
-#include <gui/BufferQueue.h>
-
-#include <list>
#include <cstdint>
+#include <list>
+#include <vector>
#include "Client.h"
#include "FrameTracker.h"
+#include "LayerBE.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
-#include "Transform.h"
-#include <layerproto/LayerProtoHeader.h>
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWComposerBufferCache.h"
#include "RenderArea.h"
-#include "RenderEngine/Mesh.h"
-#include "RenderEngine/Texture.h"
-
-#include <math/vec4.h>
-#include <vector>
using namespace android::surfaceflinger;
@@ -74,74 +72,11 @@
// ---------------------------------------------------------------------------
-struct CompositionInfo {
- HWC2::Composition compositionType;
- sp<GraphicBuffer> mBuffer = nullptr;
- int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
- struct {
- HWComposer* hwc;
- sp<Fence> fence;
- HWC2::BlendMode blendMode;
- Rect displayFrame;
- float alpha;
- FloatRect sourceCrop;
- HWC2::Transform transform;
- int z;
- int type;
- int appId;
- Region visibleRegion;
- Region surfaceDamage;
- sp<NativeHandle> sidebandStream;
- android_dataspace dataspace;
- hwc_color_t color;
- } hwc;
- struct {
- RE::RenderEngine* renderEngine;
- Mesh* mesh;
- } renderEngine;
-};
-
-class LayerBE {
-public:
- LayerBE();
-
- // The mesh used to draw the layer in GLES composition mode
- Mesh mMesh;
-
- // HWC items, accessed from the main thread
- struct HWCInfo {
- HWCInfo()
- : hwc(nullptr),
- layer(nullptr),
- forceClientComposition(false),
- compositionType(HWC2::Composition::Invalid),
- clearClientTarget(false),
- transform(HWC2::Transform::None) {}
-
- HWComposer* hwc;
- HWC2::Layer* layer;
- bool forceClientComposition;
- HWC2::Composition compositionType;
- bool clearClientTarget;
- Rect displayFrame;
- FloatRect sourceCrop;
- HWComposerBufferCache bufferCache;
- HWC2::Transform transform;
- };
-
- // A layer can be attached to multiple displays when operating in mirror mode
- // (a.k.a: when several displays are attached with equal layerStack). In this
- // case we need to keep track. In non-mirror mode, a layer will have only one
- // HWCInfo. This map key is a display layerStack.
- std::unordered_map<int32_t, HWCInfo> mHwcLayers;
-
- CompositionInfo compositionInfo;
-};
-
class Layer : public virtual RefBase {
static int32_t sSequence;
public:
+ friend class LayerBE;
LayerBE& getBE() { return mBE; }
LayerBE& getBE() const { return mBE; }
mutable bool contentDirty;
@@ -164,7 +99,7 @@
struct Geometry {
uint32_t w;
uint32_t h;
- Transform transform;
+ ui::Transform transform;
inline bool operator==(const Geometry& rhs) const {
return (w == rhs.w && h == rhs.h) && (transform.tx() == rhs.transform.tx()) &&
@@ -174,8 +109,8 @@
};
struct State {
- Geometry active;
- Geometry requested;
+ Geometry active_legacy;
+ Geometry requested_legacy;
int32_t z;
// The identifier of the layer stack this layer belongs to. A layer can
@@ -191,23 +126,19 @@
bool modified;
// Crop is expressed in layer space coordinate.
- Rect crop;
- Rect requestedCrop;
-
- // finalCrop is expressed in display space coordinate.
- Rect finalCrop;
- Rect requestedFinalCrop;
+ Rect crop_legacy;
+ Rect requestedCrop_legacy;
// If set, defers this state update until the identified Layer
// receives a frame with the given frameNumber
- wp<Layer> barrierLayer;
- uint64_t frameNumber;
+ wp<Layer> barrierLayer_legacy;
+ uint64_t frameNumber_legacy;
// the transparentRegion hint is a bit special, it's latched only
// when we receive a buffer -- this is because it's "content"
// dependent.
- Region activeTransparentRegion;
- Region requestedTransparentRegion;
+ Region activeTransparentRegion_legacy;
+ Region requestedTransparentRegion_legacy;
int32_t appId;
int32_t type;
@@ -219,6 +150,24 @@
SortedVector<wp<Layer>> zOrderRelatives;
half4 color;
+
+ // The fields below this point are only used by BufferStateLayer
+ Geometry active;
+
+ uint32_t transform;
+ bool transformToDisplayInverse;
+
+ Rect crop;
+ Region transparentRegionHint;
+
+ sp<GraphicBuffer> buffer;
+ sp<Fence> acquireFence;
+ ui::Dataspace dataspace;
+ HdrMetadata hdrMetadata;
+ Region surfaceDamageRegion;
+ int32_t api;
+
+ sp<NativeHandle> sidebandStream;
};
Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
@@ -254,11 +203,12 @@
// also the rendered size of the layer prior to any transformations. Parent
// or local matrix transformations will not affect the size of the buffer,
// but may affect it's on-screen size or clipping.
- bool setSize(uint32_t w, uint32_t h);
+ virtual bool setSize(uint32_t w, uint32_t h);
// Set a 2x2 transformation matrix on the layer. This transform
// will be applied after parent transforms, but before any final
// producer specified transform.
- bool setMatrix(const layer_state_t::matrix22_t& matrix, bool allowNonRectPreservingTransforms);
+ virtual bool setMatrix(const layer_state_t::matrix22_t& matrix,
+ bool allowNonRectPreservingTransforms);
// This second set of geometry attributes are controlled by
// setGeometryAppliesWithResize, and their default mode is to be
@@ -268,32 +218,43 @@
// setPosition operates in parent buffer space (pre parent-transform) or display
// space for top-level layers.
- bool setPosition(float x, float y, bool immediate);
+ virtual bool setPosition(float x, float y, bool immediate);
// Buffer space
- bool setCrop(const Rect& crop, bool immediate);
- // Parent buffer space/display space
- bool setFinalCrop(const Rect& crop, bool immediate);
+ virtual bool setCrop_legacy(const Rect& crop, bool immediate);
// TODO(b/38182121): Could we eliminate the various latching modes by
// using the layer hierarchy?
// -----------------------------------------------------------------------
- bool setLayer(int32_t z);
- bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
+ virtual bool setLayer(int32_t z);
+ virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
- bool setAlpha(float alpha);
- bool setColor(const half3& color);
- bool setTransparentRegionHint(const Region& transparent);
- bool setFlags(uint8_t flags, uint8_t mask);
- bool setLayerStack(uint32_t layerStack);
- uint32_t getLayerStack() const;
- void deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber);
- void deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber);
- bool setOverrideScalingMode(int32_t overrideScalingMode);
- void setInfo(int32_t type, int32_t appId);
- bool reparentChildren(const sp<IBinder>& layer);
- void setChildrenDrawingParent(const sp<Layer>& layer);
- bool reparent(const sp<IBinder>& newParentHandle);
- bool detachChildren();
+ virtual bool setAlpha(float alpha);
+ virtual bool setColor(const half3& color);
+ virtual bool setTransparentRegionHint(const Region& transparent);
+ virtual bool setFlags(uint8_t flags, uint8_t mask);
+ virtual bool setLayerStack(uint32_t layerStack);
+ virtual uint32_t getLayerStack() const;
+ virtual void deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle,
+ uint64_t frameNumber);
+ virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
+ virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
+ virtual void setInfo(int32_t type, int32_t appId);
+ virtual bool reparentChildren(const sp<IBinder>& layer);
+ virtual void setChildrenDrawingParent(const sp<Layer>& layer);
+ virtual bool reparent(const sp<IBinder>& newParentHandle);
+ virtual bool detachChildren();
+
+ // Used only to set BufferStateLayer state
+ virtual bool setTransform(uint32_t /*transform*/) { return false; };
+ virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
+ virtual bool setCrop(const Rect& /*crop*/) { return false; };
+ virtual bool setBuffer(sp<GraphicBuffer> /*buffer*/) { return false; };
+ virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
+ virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
+ virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
+ virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
+ virtual bool setApi(int32_t /*api*/) { return false; };
+ virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
@@ -317,7 +278,8 @@
return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
}
- void computeGeometry(const RenderArea& renderArea, Mesh& mesh, bool useIdentityTransform) const;
+ void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh,
+ bool useIdentityTransform) const;
FloatRect computeBounds(const Region& activeTransparentRegion) const;
FloatRect computeBounds() const;
@@ -371,32 +333,43 @@
void writeToProto(LayerProto* layerInfo,
LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
- void writeToProto(LayerProto* layerInfo, int32_t hwcId);
+ void writeToProto(LayerProto* layerInfo, int32_t displayId);
+
+ virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
+ virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
+ virtual uint32_t getActiveHeight(const Layer::State& s) const { return s.active_legacy.h; }
+ virtual ui::Transform getActiveTransform(const Layer::State& s) const {
+ return s.active_legacy.transform;
+ }
+ virtual Region getActiveTransparentRegion(const Layer::State& s) const {
+ return s.activeTransparentRegion_legacy;
+ }
+ virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
protected:
/*
* onDraw - draws the surface.
*/
virtual void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) const = 0;
+ bool useIdentityTransform) = 0;
public:
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
virtual bool isHdrY410() const { return false; }
- void setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z);
- void forceClientComposition(int32_t hwcId);
- bool getForceClientComposition(int32_t hwcId);
- virtual void setPerFrameData(const sp<const DisplayDevice>& displayDevice) = 0;
+ void setGeometry(const sp<const DisplayDevice>& display, uint32_t z);
+ void forceClientComposition(int32_t displayId);
+ bool getForceClientComposition(int32_t displayId);
+ virtual void setPerFrameData(const sp<const DisplayDevice>& display) = 0;
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc = true);
- HWC2::Composition getCompositionType(int32_t hwcId) const;
- void setClearClientTarget(int32_t hwcId, bool clear);
- bool getClearClientTarget(int32_t hwcId) const;
- void updateCursorPosition(const sp<const DisplayDevice>& hw);
+ void setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc = true);
+ HWC2::Composition getCompositionType(int32_t displayId) const;
+ void setClearClientTarget(int32_t displayId, bool clear);
+ bool getClearClientTarget(int32_t displayId) const;
+ void updateCursorPosition(const sp<const DisplayDevice>& display);
/*
* called after page-flip
@@ -432,9 +405,8 @@
* draw - performs some global clipping optimizations
* and calls onDraw().
*/
- void draw(const RenderArea& renderArea, const Region& clip) const;
- void draw(const RenderArea& renderArea, bool useIdentityTransform) const;
- void draw(const RenderArea& renderArea) const;
+ void draw(const RenderArea& renderArea, const Region& clip);
+ void draw(const RenderArea& renderArea, bool useIdentityTransform);
/*
* doTransaction - process the transaction. This is a good place to figure
@@ -478,7 +450,6 @@
virtual bool isBufferLatched() const { return false; }
- bool isPotentialCursor() const { return mPotentialCursor; }
/*
* called with the state lock from a binder thread when the layer is
* removed from the current list to the pending removal list
@@ -493,7 +464,7 @@
// Updates the transform hint in our SurfaceFlingerConsumer to match
// the current orientation of the display device.
- void updateTransformHint(const sp<const DisplayDevice>& hw) const;
+ void updateTransformHint(const sp<const DisplayDevice>& display) const;
/*
* returns the rectangle that crops the content of the layer and scales it
@@ -502,37 +473,37 @@
Rect getContentCrop() const;
/*
- * Returns if a frame is queued.
+ * Returns if a frame is ready
*/
- bool hasQueuedFrame() const {
- return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
- }
+ virtual bool hasReadyFrame() const { return false; }
- int32_t getQueuedFrameCount() const { return mQueuedFrames; }
+ virtual int32_t getQueuedFrameCount() const { return 0; }
// -----------------------------------------------------------------------
- bool createHwcLayer(HWComposer* hwc, int32_t hwcId);
- bool destroyHwcLayer(int32_t hwcId);
+ bool createHwcLayer(HWComposer* hwc, int32_t displayId);
+ bool destroyHwcLayer(int32_t displayId);
void destroyAllHwcLayers();
- bool hasHwcLayer(int32_t hwcId) {
- return getBE().mHwcLayers.count(hwcId) > 0;
- }
+ bool hasHwcLayer(int32_t displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
- HWC2::Layer* getHwcLayer(int32_t hwcId) {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
+ HWC2::Layer* getHwcLayer(int32_t displayId) {
+ if (getBE().mHwcLayers.count(displayId) == 0) {
return nullptr;
}
- return getBE().mHwcLayers[hwcId].layer;
+ return getBE().mHwcLayers[displayId].layer.get();
+ }
+
+ bool setHwcLayer(int32_t hwcId) {
+ if (getBE().mHwcLayers.count(hwcId) == 0) {
+ return false;
+ }
+ getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[hwcId].layer;
+ return true;
}
// -----------------------------------------------------------------------
-
void clearWithOpenGL(const RenderArea& renderArea) const;
- void setFiltering(bool filtering);
- bool getFiltering() const;
-
inline const State& getDrawingState() const { return mDrawingState; }
inline const State& getCurrentState() const { return mCurrentState; }
@@ -542,7 +513,7 @@
/* always call base class first */
static void miniDumpHeader(String8& result);
- void miniDump(String8& result, int32_t hwcId) const;
+ void miniDump(String8& result, int32_t displayId) const;
void dumpFrameStats(String8& result) const;
void dumpFrameEvents(String8& result);
void clearFrameStats();
@@ -559,7 +530,7 @@
virtual bool getTransformToDisplayInverse() const { return false; }
- Transform getTransform() const;
+ ui::Transform getTransform() const;
// Returns the Alpha of the Surface, accounting for the Alpha
// of parent Surfaces in the hierarchy (alpha's will be multiplied
@@ -594,7 +565,7 @@
// SurfaceFlinger to complete a transaction.
void commitChildList();
int32_t getZ() const;
- void pushPendingState();
+ virtual void pushPendingState();
protected:
// constant
@@ -618,20 +589,21 @@
: mFlinger(flinger), mLayer(layer) {}
};
- virtual void onFirstRef();
-
friend class impl::SurfaceInterceptor;
+ // For unit tests
+ friend class TestableSurfaceFlinger;
+
void commitTransaction(const State& stateToCommit);
uint32_t getEffectiveUsage(uint32_t usage) const;
- FloatRect computeCrop(const sp<const DisplayDevice>& hw) const;
+ virtual FloatRect computeCrop(const sp<const DisplayDevice>& display) const;
// Compute the initial crop as specified by parent layers and the
// SurfaceControl for this layer. Does not include buffer crop from the
// IGraphicBufferProducer client, as that should not affect child clipping.
// Returns in screen space.
- Rect computeInitialCrop(const sp<const DisplayDevice>& hw) const;
+ Rect computeInitialCrop(const sp<const DisplayDevice>& display) const;
// drawing
void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b,
@@ -678,7 +650,8 @@
bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
void popPendingState(State* stateToCommit);
- bool applyPendingStates(State* stateToCommit);
+ virtual bool applyPendingStates(State* stateToCommit);
+ virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
void clearSyncPoints();
@@ -729,10 +702,6 @@
Mutex mPendingStateMutex;
Vector<State> mPendingStates;
- // thread-safe
- volatile int32_t mQueuedFrames;
- volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
-
// Timestamp history for UIAutomation. Thread safe.
FrameTracker mFrameTracker;
@@ -746,19 +715,14 @@
TimeStats& mTimeStats = TimeStats::getInstance();
// main thread
- int mActiveBufferSlot;
sp<GraphicBuffer> mActiveBuffer;
- sp<NativeHandle> mSidebandStream;
ui::Dataspace mCurrentDataSpace = ui::Dataspace::UNKNOWN;
Rect mCurrentCrop;
uint32_t mCurrentTransform;
// We encode unset as -1.
int32_t mOverrideScalingMode;
- bool mCurrentOpacity;
std::atomic<uint64_t> mCurrentFrameNumber;
bool mFrameLatencyNeeded;
- // Whether filtering is forced on or not
- bool mFiltering;
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering;
@@ -775,12 +739,6 @@
// This layer can be a cursor on some displays.
bool mPotentialCursor;
- // Local copy of the queued contents of the incoming BufferQueue
- mutable Mutex mQueueItemLock;
- Condition mQueueItemCondition;
- Vector<BufferItem> mQueueItems;
- std::atomic<uint64_t> mLastFrameNumberReceived;
- bool mAutoRefresh;
bool mFreezeGeometryUpdates;
// Child list about to be committed/used for editing.
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
new file mode 100644
index 0000000..ef017aa
--- /dev/null
+++ b/services/surfaceflinger/LayerBE.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "LayerBE"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "Layer.h"
+
+#include <android-base/stringprintf.h>
+#include <renderengine/RenderEngine.h>
+
+#include <string>
+
+namespace {
+
+const char* getCompositionName(HWC2::Composition compositionType) {
+ switch (compositionType) {
+ case HWC2::Composition::Invalid:
+ return "Invalid";
+ case HWC2::Composition::Client:
+ return "Client";
+ case HWC2::Composition::Device:
+ return "Device";
+ case HWC2::Composition::SolidColor:
+ return "Solid Color";
+ case HWC2::Composition::Cursor:
+ return "Cursor";
+ case HWC2::Composition::Sideband:
+ return "Sideband";
+ }
+ return "Invalid";
+}
+
+} // namespace anonymous
+
+namespace android {
+
+LayerBE::LayerBE(Layer* layer, std::string layerName)
+ : mLayer(layer),
+ mMesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2) {
+ compositionInfo.layer = std::make_shared<LayerBE>(*this);
+ compositionInfo.layerName = layerName;
+}
+
+LayerBE::LayerBE(const LayerBE& layer)
+ : mLayer(layer.mLayer),
+ mMesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2) {
+ compositionInfo.layer = layer.compositionInfo.layer;
+ compositionInfo.layerName = layer.mLayer->getName().string();
+}
+
+void LayerBE::onLayerDisplayed(const sp<Fence>& releaseFence) {
+ if (mLayer) {
+ mLayer->onLayerDisplayed(releaseFence);
+ }
+}
+
+void LayerBE::clear(renderengine::RenderEngine& engine) {
+ engine.setupFillWithColor(0, 0, 0, 0);
+ engine.drawMesh(mMesh);
+}
+
+void CompositionInfo::dump(const char* tag) const
+{
+ std::string logString;
+ dump(logString, tag);
+ ALOGV("%s", logString.c_str());
+}
+
+void CompositionInfo::dumpHwc(std::string& result, const char* tag) const {
+ if (tag == nullptr) {
+ result += base::StringPrintf("HWC parameters\n");
+ } else {
+ result += base::StringPrintf("[%s]HWC parameters\n", tag);
+ }
+
+ result += base::StringPrintf("\thwcLayer=%p\n", static_cast<HWC2::Layer*>(&*hwc.hwcLayer));
+ result += base::StringPrintf("\tfence=%p\n", hwc.fence.get());
+ result += base::StringPrintf("\tblendMode=%d\n", hwc.blendMode);
+ result += base::StringPrintf("\ttransform=%d\n", hwc.transform);
+ result += base::StringPrintf("\tz=%d\n", hwc.z);
+ result += base::StringPrintf("\ttype=%d\n", hwc.type);
+ result += base::StringPrintf("\tappId=%d\n", hwc.appId);
+ result += base::StringPrintf("\tdisplayFrame=%4d %4d %4d %4d\n", hwc.displayFrame.left,
+ hwc.displayFrame.top, hwc.displayFrame.right,
+ hwc.displayFrame.bottom);
+ result += base::StringPrintf("\talpha=%.3f", hwc.alpha);
+ result += base::StringPrintf("\tsourceCrop=%6.1f %6.1f %6.1f %6.1f\n", hwc.sourceCrop.left,
+ hwc.sourceCrop.top, hwc.sourceCrop.right, hwc.sourceCrop.bottom);
+
+ {
+ //
+ // Keep a conversion from std::string to String8 and back until Region can use std::string
+ //
+ String8 regionString;
+ hwc.visibleRegion.dump(regionString, "visibleRegion");
+ hwc.surfaceDamage.dump(regionString, "surfaceDamage");
+ result += regionString.string();
+ }
+}
+
+void CompositionInfo::dumpRe(std::string& result, const char* tag) const {
+ if (tag == nullptr) {
+ result += base::StringPrintf("RenderEngine parameters:\n");
+ } else {
+ result += base::StringPrintf("[%s]RenderEngine parameters:\n", tag);
+ }
+
+ result += base::StringPrintf("\tblackoutLayer=%d\n", re.blackoutLayer);
+ result += base::StringPrintf("\tclearArea=%d\n", re.clearArea);
+ result += base::StringPrintf("\tpreMultipliedAlpha=%d\n", re.preMultipliedAlpha);
+ result += base::StringPrintf("\topaque=%d\n", re.opaque);
+ result += base::StringPrintf("\tdisableTexture=%d\n", re.disableTexture);
+ result += base::StringPrintf("\tuseIdentityTransform=%d\n", re.useIdentityTransform);
+}
+
+void CompositionInfo::dump(std::string& result, const char* tag) const
+{
+ if (tag == nullptr) {
+ result += base::StringPrintf("CompositionInfo\n");
+ } else {
+ result += base::StringPrintf("[%s]CompositionInfo\n", tag);
+ }
+ result += base::StringPrintf("\tLayerName: %s\n", layerName.c_str());
+ result += base::StringPrintf("\tCompositionType: %s\n",
+ getCompositionName(compositionType));
+ result += base::StringPrintf("\tmBuffer = %p\n", mBuffer.get());
+ result += base::StringPrintf("\tmBufferSlot=%d\n", mBufferSlot);
+ result += base::StringPrintf("\tdisplayFrame=%4d %4d %4d %4d\n", hwc.displayFrame.left,
+ hwc.displayFrame.top, hwc.displayFrame.right,
+ hwc.displayFrame.bottom);
+ result += base::StringPrintf("\talpha=%f\n", hwc.alpha);
+ result += base::StringPrintf("\tsourceCrop=%6.1f %6.1f %6.1f %6.1f\n", hwc.sourceCrop.left,
+ hwc.sourceCrop.top, hwc.sourceCrop.right, hwc.sourceCrop.bottom);
+
+ switch (compositionType) {
+ case HWC2::Composition::Device:
+ dumpHwc(result, tag);
+ break;
+ case HWC2::Composition::Client:
+ dumpRe(result, tag);
+ break;
+ default:
+ break;
+ }
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
new file mode 100644
index 0000000..2722b01
--- /dev/null
+++ b/services/surfaceflinger/LayerBE.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 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 <stdint.h>
+#include <sys/types.h>
+
+#include <renderengine/Mesh.h>
+#include <renderengine/RenderEngine.h>
+#include <renderengine/Texture.h>
+#include <ui/Region.h>
+
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/HWComposerBufferCache.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+class LayerBE;
+
+struct CompositionInfo {
+ std::string layerName;
+ HWC2::Composition compositionType = HWC2::Composition::Invalid;
+ bool firstClear = false;
+ sp<GraphicBuffer> mBuffer = nullptr;
+ int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+ std::shared_ptr<LayerBE> layer;
+ struct {
+ std::shared_ptr<HWC2::Layer> hwcLayer;
+ bool skipGeometry = true;
+ int32_t displayId = -1;
+ sp<Fence> fence;
+ HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
+ Rect displayFrame;
+ float alpha;
+ FloatRect sourceCrop;
+ HWC2::Transform transform = HWC2::Transform::None;
+ int z;
+ int type;
+ int appId;
+ Region visibleRegion;
+ Region surfaceDamage;
+ sp<NativeHandle> sidebandStream;
+ ui::Dataspace dataspace;
+ hwc_color_t color;
+ bool clearClientTarget = false;
+ bool supportedPerFrameMetadata = false;
+ HdrMetadata hdrMetadata;
+ } hwc;
+ struct {
+ bool blackoutLayer = false;
+ bool clearArea = false;
+ bool preMultipliedAlpha = false;
+ bool opaque = false;
+ bool disableTexture = false;
+ half4 color;
+ bool useIdentityTransform = false;
+ bool Y410BT2020 = false;
+ } re;
+
+ void dump(const char* tag) const;
+ void dump(std::string& result, const char* tag = nullptr) const;
+ void dumpHwc(std::string& result, const char* tag = nullptr) const;
+ void dumpRe(std::string& result, const char* tag = nullptr) const;
+};
+
+class LayerBE {
+public:
+ friend class Layer;
+ friend class BufferLayer;
+ friend class BufferQueueLayer;
+ friend class BufferStateLayer;
+ friend class ColorLayer;
+ friend class SurfaceFlinger;
+
+ // For unit tests
+ friend class TestableSurfaceFlinger;
+
+ LayerBE(Layer* layer, std::string layerName);
+ explicit LayerBE(const LayerBE& layer);
+
+ void onLayerDisplayed(const sp<Fence>& releaseFence);
+ void clear(renderengine::RenderEngine& renderEngine);
+ renderengine::Mesh& getMesh() { return mMesh; }
+
+ Layer*const mLayer;
+private:
+ // The mesh used to draw the layer in GLES composition mode
+ renderengine::Mesh mMesh;
+
+ // HWC items, accessed from the main thread
+ struct HWCInfo {
+ HWCInfo()
+ : hwc(nullptr),
+ layer(nullptr),
+ forceClientComposition(false),
+ compositionType(HWC2::Composition::Invalid),
+ clearClientTarget(false),
+ transform(HWC2::Transform::None) {}
+
+ HWComposer* hwc;
+ std::shared_ptr<HWC2::Layer> layer;
+ bool forceClientComposition;
+ HWC2::Composition compositionType;
+ bool clearClientTarget;
+ Rect displayFrame;
+ FloatRect sourceCrop;
+ HWComposerBufferCache bufferCache;
+ HWC2::Transform transform;
+ };
+
+
+ // A layer can be attached to multiple displays when operating in mirror mode
+ // (a.k.a: when several displays are attached with equal layerStack). In this
+ // case we need to keep track. In non-mirror mode, a layer will have only one
+ // HWCInfo. This map key is a display layerStack.
+ std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+
+ CompositionInfo compositionInfo;
+};
+
+}; // namespace android
+
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index cc39550..3289e8f 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -51,7 +51,8 @@
colorProto->set_a(color.a);
}
-void LayerProtoHelper::writeToProto(const Transform& transform, TransformProto* transformProto) {
+void LayerProtoHelper::writeToProto(const ui::Transform& transform,
+ TransformProto* transformProto) {
transformProto->set_dsdx(transform[0][0]);
transformProto->set_dtdx(transform[0][1]);
transformProto->set_dsdy(transform[1][0]);
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 860da63..6df5aea 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -16,13 +16,11 @@
#include <layerproto/LayerProtoHeader.h>
+#include <math/vec4.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
#include <ui/Region.h>
-
-#include <Transform.h>
-
-#include <math/vec4.h>
+#include <ui/Transform.h>
namespace android {
namespace surfaceflinger {
@@ -32,7 +30,7 @@
static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
static void writeToProto(const Region& region, RegionProto* regionProto);
static void writeToProto(const half4 color, ColorProto* colorProto);
- static void writeToProto(const Transform& transform, TransformProto* transformProto);
+ static void writeToProto(const ui::Transform& transform, TransformProto* transformProto);
static void writeToProto(const sp<GraphicBuffer>& buffer, ActiveBufferProto* activeBufferProto);
};
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index a5f0b98..72abea8 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -19,8 +19,6 @@
#include <gui/BufferItem.h>
#include <system/window.h>
-#include "clz.h"
-
#define DEBUG_RESIZE 0
namespace android {
@@ -31,6 +29,7 @@
bool stickySet,
const char* name,
int32_t overrideScalingMode,
+ bool transformToDisplayInverse,
bool& freezePositionUpdates)
: mFront(front),
mCurrent(current),
@@ -38,6 +37,7 @@
mStickyTransformSet(stickySet),
mName(name),
mOverrideScalingMode(overrideScalingMode),
+ mTransformToDisplayInverse(transformToDisplayInverse),
mFreezeGeometryUpdates(freezePositionUpdates) {}
bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) {
@@ -50,26 +50,34 @@
// check that we received a buffer of the right size
// (Take the buffer's orientation into account)
- if (item.mTransform & Transform::ROT_90) {
- swap(bufWidth, bufHeight);
+ if (item.mTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+
+ if (mTransformToDisplayInverse) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
}
int actualScalingMode = mOverrideScalingMode >= 0 ? mOverrideScalingMode : item.mScalingMode;
bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
- if (mFront.active != mFront.requested) {
- if (isFixedSize || (bufWidth == mFront.requested.w && bufHeight == mFront.requested.h)) {
+ if (mFront.active_legacy != mFront.requested_legacy) {
+ if (isFixedSize ||
+ (bufWidth == mFront.requested_legacy.w && bufHeight == mFront.requested_legacy.h)) {
// Here we pretend the transaction happened by updating the
// current and drawing states. Drawing state is only accessed
// in this thread, no need to have it locked
- mFront.active = mFront.requested;
+ mFront.active_legacy = mFront.requested_legacy;
// We also need to update the current state so that
// we don't end-up overwriting the drawing state with
// this stale current state during the next transaction
//
// NOTE: We don't need to hold the transaction lock here
- // because State::active is only accessed from this thread.
- mCurrent.active = mFront.active;
+ // because State::active_legacy is only accessed from this thread.
+ mCurrent.active_legacy = mFront.active_legacy;
mCurrent.modified = true;
// recompute visible region
@@ -77,35 +85,32 @@
mFreezeGeometryUpdates = false;
- if (mFront.crop != mFront.requestedCrop) {
- mFront.crop = mFront.requestedCrop;
- mCurrent.crop = mFront.requestedCrop;
- mRecomputeVisibleRegions = true;
- }
- if (mFront.finalCrop != mFront.requestedFinalCrop) {
- mFront.finalCrop = mFront.requestedFinalCrop;
- mCurrent.finalCrop = mFront.requestedFinalCrop;
+ if (mFront.crop_legacy != mFront.requestedCrop_legacy) {
+ mFront.crop_legacy = mFront.requestedCrop_legacy;
+ mCurrent.crop_legacy = mFront.requestedCrop_legacy;
mRecomputeVisibleRegions = true;
}
}
ALOGD_IF(DEBUG_RESIZE,
"[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
- " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) "
+ " drawing={ active_legacy ={ wh={%4u,%4u} crop_legacy={%4d,%4d,%4d,%4d} "
+ "(%4d,%4d) "
"}\n"
- " requested={ wh={%4u,%4u} }}\n",
- mName, bufWidth, bufHeight, item.mTransform, item.mScalingMode, mFront.active.w,
- mFront.active.h, mFront.crop.left, mFront.crop.top, mFront.crop.right,
- mFront.crop.bottom, mFront.crop.getWidth(), mFront.crop.getHeight(),
- mFront.requested.w, mFront.requested.h);
+ " requested_legacy={ wh={%4u,%4u} }}\n",
+ mName, bufWidth, bufHeight, item.mTransform, item.mScalingMode,
+ mFront.active_legacy.w, mFront.active_legacy.h, mFront.crop_legacy.left,
+ mFront.crop_legacy.top, mFront.crop_legacy.right, mFront.crop_legacy.bottom,
+ mFront.crop_legacy.getWidth(), mFront.crop_legacy.getHeight(),
+ mFront.requested_legacy.w, mFront.requested_legacy.h);
}
if (!isFixedSize && !mStickyTransformSet) {
- if (mFront.active.w != bufWidth || mFront.active.h != bufHeight) {
+ if (mFront.active_legacy.w != bufWidth || mFront.active_legacy.h != bufHeight) {
// reject this buffer
ALOGE("[%s] rejecting buffer: "
- "bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}",
- mName, bufWidth, bufHeight, mFront.active.w, mFront.active.h);
+ "bufWidth=%d, bufHeight=%d, front.active_legacy.{w=%d, h=%d}",
+ mName, bufWidth, bufHeight, mFront.active_legacy.w, mFront.active_legacy.h);
return true;
}
}
@@ -118,16 +123,17 @@
// We latch the transparent region here, instead of above where we latch
// the rest of the geometry because it is only content but not necessarily
// resize dependent.
- if (!mFront.activeTransparentRegion.isTriviallyEqual(mFront.requestedTransparentRegion)) {
- mFront.activeTransparentRegion = mFront.requestedTransparentRegion;
+ if (!mFront.activeTransparentRegion_legacy.isTriviallyEqual(
+ mFront.requestedTransparentRegion_legacy)) {
+ mFront.activeTransparentRegion_legacy = mFront.requestedTransparentRegion_legacy;
// We also need to update the current state so that
// we don't end-up overwriting the drawing state with
// this stale current state during the next transaction
//
// NOTE: We don't need to hold the transaction lock here
- // because State::active is only accessed from this thread.
- mCurrent.activeTransparentRegion = mFront.activeTransparentRegion;
+ // because State::active_legacy is only accessed from this thread.
+ mCurrent.activeTransparentRegion_legacy = mFront.activeTransparentRegion_legacy;
// recompute visible region
mRecomputeVisibleRegions = true;
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
index 40972aa..63d51de 100644
--- a/services/surfaceflinger/LayerRejecter.h
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -29,6 +29,7 @@
bool stickySet,
const char *name,
int32_t overrideScalingMode,
+ bool transformToDisplayInverse,
bool &freezePositionUpdates);
virtual bool reject(const sp<GraphicBuffer> &buf, const BufferItem &item);
@@ -40,6 +41,7 @@
bool mStickyTransformSet;
const char *mName;
int32_t mOverrideScalingMode;
+ bool mTransformToDisplayInverse;
bool &mFreezeGeometryUpdates;
};
} // namespace android
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 389fbd2..06e3d9c 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#include "MessageQueue.h"
#include "MonitoredProducer.h"
-#include "SurfaceFlinger.h"
#include "Layer.h"
+#include "SurfaceFlinger.h"
+
+#include "Scheduler/MessageQueue.h"
namespace android {
diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp
index 1a8edf3..93759e8 100644
--- a/services/surfaceflinger/RenderArea.cpp
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -1,7 +1,5 @@
#include "RenderArea.h"
-#include <gui/LayerState.h>
-
namespace android {
float RenderArea::getCaptureFillValue(CaptureFill captureFill) {
@@ -13,37 +11,5 @@
return 1.0f;
}
}
-/*
- * Checks that the requested width and height are valid and updates them to the render area
- * dimensions if they are set to 0
- */
-status_t RenderArea::updateDimensions(int displayRotation) {
- // get screen geometry
-
- uint32_t width = getWidth();
- uint32_t height = getHeight();
-
- if (mRotationFlags & Transform::ROT_90) {
- std::swap(width, height);
- }
-
- if (displayRotation & DisplayState::eOrientationSwapMask) {
- std::swap(width, height);
- }
-
- if ((mReqWidth > width) || (mReqHeight > height)) {
- ALOGE("size mismatch (%d, %d) > (%d, %d)", mReqWidth, mReqHeight, width, height);
- return BAD_VALUE;
- }
-
- if (mReqWidth == 0) {
- mReqWidth = width;
- }
- if (mReqHeight == 0) {
- mReqHeight = height;
- }
-
- return NO_ERROR;
-}
} // namespace android
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 96e4b5f..3c11e73 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -1,50 +1,80 @@
#pragma once
-#include <ui/GraphicTypes.h>
-
-#include "Transform.h"
+#include <ui/Transform.h>
#include <functional>
namespace android {
+// RenderArea describes a rectangular area that layers can be rendered to.
+//
+// There is a logical render area and a physical render area. When a layer is
+// rendered to the render area, it is first transformed and clipped to the logical
+// render area. The transformed and clipped layer is then projected onto the
+// physical render area.
class RenderArea {
-
public:
enum class CaptureFill {CLEAR, OPAQUE};
static float getCaptureFillValue(CaptureFill captureFill);
- RenderArea(uint32_t reqHeight, uint32_t reqWidth, CaptureFill captureFill,
- ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
- : mReqHeight(reqHeight), mReqWidth(reqWidth), mCaptureFill(captureFill) {
- mRotationFlags = Transform::fromRotation(rotation);
- }
+ RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill,
+ ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
+ : mReqWidth(reqWidth),
+ mReqHeight(reqHeight),
+ mCaptureFill(captureFill),
+ mRotationFlags(rotation) {}
virtual ~RenderArea() = default;
- virtual const Transform& getTransform() const = 0;
- virtual Rect getBounds() const = 0;
- virtual int getHeight() const = 0;
- virtual int getWidth() const = 0;
- virtual bool isSecure() const = 0;
- virtual bool needsFiltering() const = 0;
- virtual Rect getSourceCrop() const = 0;
-
+ // Invoke drawLayers to render layers into the render area.
virtual void render(std::function<void()> drawLayers) { drawLayers(); }
- int getReqHeight() const { return mReqHeight; };
- int getReqWidth() const { return mReqWidth; };
- Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
- status_t updateDimensions(int displayRotation);
+ // Returns true if the render area is secure. A secure layer should be
+ // blacked out / skipped when rendered to an insecure render area.
+ virtual bool isSecure() const = 0;
+ // Returns true if the otherwise disabled layer filtering should be
+ // enabled when rendering to this render area.
+ virtual bool needsFiltering() const = 0;
+
+ // Returns the transform to be applied on layers to transform them into
+ // the logical render area.
+ virtual const ui::Transform& getTransform() const = 0;
+
+ // Returns the size of the logical render area. Layers are clipped to the
+ // logical render area.
+ virtual int getWidth() const = 0;
+ virtual int getHeight() const = 0;
+ virtual Rect getBounds() const = 0;
+
+ // Returns the source crop of the render area. The source crop defines
+ // how layers are projected from the logical render area onto the physical
+ // render area. It can be larger than the logical render area. It can
+ // also be optionally rotated.
+ //
+ // Layers are first clipped to the source crop (in addition to being
+ // clipped to the logical render area already). The source crop and the
+ // layers are then rotated around the center of the source crop, and
+ // scaled to the physical render area linearly.
+ virtual Rect getSourceCrop() const = 0;
+
+ // Returns the rotation of the source crop and the layers.
+ ui::Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
+
+ // Returns the size of the physical render area.
+ int getReqWidth() const { return mReqWidth; };
+ int getReqHeight() const { return mReqHeight; };
+
+ // Returns the fill color of the physical render area. Regions not
+ // covered by any rendered layer should be filled with this color.
CaptureFill getCaptureFill() const { return mCaptureFill; };
private:
- uint32_t mReqHeight;
- uint32_t mReqWidth;
- Transform::orientation_flags mRotationFlags;
- CaptureFill mCaptureFill;
+ const uint32_t mReqWidth;
+ const uint32_t mReqHeight;
+ const CaptureFill mCaptureFill;
+ const ui::Transform::orientation_flags mRotationFlags;
};
} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Android.bp b/services/surfaceflinger/RenderEngine/Android.bp
new file mode 100644
index 0000000..e1ab066
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Android.bp
@@ -0,0 +1,79 @@
+// TODO(b/112585051) Add to VNDK once moved to libs/
+cc_defaults {
+ name: "renderengine_defaults",
+ cflags: [
+ "-DLOG_TAG=\"RenderEngine\"",
+ "-Wall",
+ "-Werror",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ cppflags: ["-std=c++1z"],
+}
+
+cc_defaults {
+ name: "librenderengine_defaults",
+ defaults: ["renderengine_defaults"],
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libGLESv2",
+ "libgui",
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+}
+
+filegroup {
+ name: "librenderengine_sources",
+ srcs: [
+ "Description.cpp",
+ "Mesh.cpp",
+ "RenderEngine.cpp",
+ "Texture.cpp",
+ ],
+}
+
+filegroup {
+ name: "librenderengine_gl_sources",
+ srcs: [
+ "gl/GLES20RenderEngine.cpp",
+ "gl/GLExtensions.cpp",
+ "gl/GLFramebuffer.cpp",
+ "gl/GLImage.cpp",
+ "gl/GLSurface.cpp",
+ "gl/Program.cpp",
+ "gl/ProgramCache.cpp",
+ ],
+}
+
+cc_library_static {
+ name: "librenderengine",
+ defaults: ["librenderengine_defaults"],
+ double_loadable: true,
+
+ clang: true,
+ cflags: [
+ "-fvisibility=hidden",
+ "-Werror=format",
+ ],
+ cppflags: [
+ "-fwhole-program-vtables", // requires ThinLTO
+ ],
+ srcs: [
+ ":librenderengine_sources",
+ ":librenderengine_gl_sources",
+ ],
+ lto: {
+ thin: true,
+ },
+}
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index c218e4d..b7522da 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -14,17 +14,14 @@
* limitations under the License.
*/
+#include <renderengine/private/Description.h>
+
#include <stdint.h>
-#include <string.h>
#include <utils/TypeHelpers.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include "Description.h"
-
namespace android {
+namespace renderengine {
void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
mPremultipliedAlpha = premultipliedAlpha;
@@ -98,4 +95,5 @@
mDisplayMaxLuminance = maxLuminance;
}
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
deleted file mode 100644
index 744a70c..0000000
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Copyright 2013 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.
- */
-
-//#define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "RenderEngine"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <ui/ColorSpace.h>
-#include <ui/DebugUtils.h>
-#include <ui/Rect.h>
-
-#include <utils/String8.h>
-#include <utils/Trace.h>
-
-#include <cutils/compiler.h>
-#include <gui/ISurfaceComposer.h>
-#include <math.h>
-
-#include "Description.h"
-#include "GLES20RenderEngine.h"
-#include "Mesh.h"
-#include "Program.h"
-#include "ProgramCache.h"
-#include "Texture.h"
-
-#include <fstream>
-#include <sstream>
-
-// ---------------------------------------------------------------------------
-bool checkGlError(const char* op, int lineNumber) {
- bool errorFound = false;
- GLint error = glGetError();
- while (error != GL_NO_ERROR) {
- errorFound = true;
- error = glGetError();
- ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error);
- }
- return errorFound;
-}
-
-static constexpr bool outputDebugPPMs = false;
-
-void writePPM(const char* basename, GLuint width, GLuint height) {
- ALOGV("writePPM #%s: %d x %d", basename, width, height);
-
- std::vector<GLubyte> pixels(width * height * 4);
- std::vector<GLubyte> outBuffer(width * height * 3);
-
- // TODO(courtneygo): We can now have float formats, need
- // to remove this code or update to support.
- // Make returned pixels fit in uint32_t, one byte per component
- glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
- if (checkGlError(__FUNCTION__, __LINE__)) {
- return;
- }
-
- std::string filename(basename);
- filename.append(".ppm");
- std::ofstream file(filename.c_str(), std::ios::binary);
- if (!file.is_open()) {
- ALOGE("Unable to open file: %s", filename.c_str());
- ALOGE("You may need to do: \"adb shell setenforce 0\" to enable "
- "surfaceflinger to write debug images");
- return;
- }
-
- file << "P6\n";
- file << width << "\n";
- file << height << "\n";
- file << 255 << "\n";
-
- auto ptr = reinterpret_cast<char*>(pixels.data());
- auto outPtr = reinterpret_cast<char*>(outBuffer.data());
- for (int y = height - 1; y >= 0; y--) {
- char* data = ptr + y * width * sizeof(uint32_t);
-
- for (GLuint x = 0; x < width; x++) {
- // Only copy R, G and B components
- outPtr[0] = data[0];
- outPtr[1] = data[1];
- outPtr[2] = data[2];
- data += sizeof(uint32_t);
- outPtr += 3;
- }
- }
- file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size());
-}
-
-// ---------------------------------------------------------------------------
-namespace android {
-namespace RE {
-namespace impl {
-// ---------------------------------------------------------------------------
-
-using ui::Dataspace;
-
-GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
- : RenderEngine(featureFlags),
- mVpWidth(0),
- mVpHeight(0),
- mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
- glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glPixelStorei(GL_PACK_ALIGNMENT, 4);
-
- const uint16_t protTexData[] = {0};
- glGenTextures(1, &mProtectedTexName);
- glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
-
- // mColorBlindnessCorrection = M;
-
- if (mPlatformHasWideColor) {
- ColorSpace srgb(ColorSpace::sRGB());
- ColorSpace displayP3(ColorSpace::DisplayP3());
- ColorSpace bt2020(ColorSpace::BT2020());
-
- // Compute sRGB to Display P3 transform matrix.
- // NOTE: For now, we are limiting output wide color space support to
- // Display-P3 only.
- mSrgbToDisplayP3 = mat4(ColorSpaceConnector(srgb, displayP3).getTransform());
-
- // Compute Display P3 to sRGB transform matrix.
- mDisplayP3ToSrgb = mat4(ColorSpaceConnector(displayP3, srgb).getTransform());
-
- // no chromatic adaptation needed since all color spaces use D65 for their white points.
- mSrgbToXyz = srgb.getRGBtoXYZ();
- mDisplayP3ToXyz = displayP3.getRGBtoXYZ();
- mBt2020ToXyz = bt2020.getRGBtoXYZ();
- mXyzToSrgb = mat4(srgb.getXYZtoRGB());
- mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB());
- mXyzToBt2020 = mat4(bt2020.getXYZtoRGB());
- }
-}
-
-GLES20RenderEngine::~GLES20RenderEngine() {}
-
-size_t GLES20RenderEngine::getMaxTextureSize() const {
- return mMaxTextureSize;
-}
-
-size_t GLES20RenderEngine::getMaxViewportDims() const {
- return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
-}
-
-void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
- size_t hwh, bool yswap,
- Transform::orientation_flags rotation) {
- int32_t l = sourceCrop.left;
- int32_t r = sourceCrop.right;
-
- // In GL, (0, 0) is the bottom-left corner, so flip y coordinates
- int32_t t = hwh - sourceCrop.top;
- int32_t b = hwh - sourceCrop.bottom;
-
- mat4 m;
- if (yswap) {
- m = mat4::ortho(l, r, t, b, 0, 1);
- } else {
- m = mat4::ortho(l, r, b, t, 0, 1);
- }
-
- // Apply custom rotation to the projection.
- float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
- switch (rotation) {
- case Transform::ROT_0:
- break;
- case Transform::ROT_90:
- m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
- break;
- case Transform::ROT_180:
- m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m;
- break;
- case Transform::ROT_270:
- m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m;
- break;
- default:
- break;
- }
-
- glViewport(0, 0, vpw, vph);
- mState.setProjectionMatrix(m);
- mVpWidth = vpw;
- mVpHeight = vph;
-}
-
-void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque,
- bool disableTexture, const half4& color) {
- mState.setPremultipliedAlpha(premultipliedAlpha);
- mState.setOpaque(opaque);
- mState.setColor(color);
-
- if (disableTexture) {
- mState.disableTexture();
- }
-
- if (color.a < 1.0f || !opaque) {
- glEnable(GL_BLEND);
- glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- } else {
- glDisable(GL_BLEND);
- }
-}
-
-void GLES20RenderEngine::setSourceY410BT2020(bool enable) {
- mState.setY410BT2020(enable);
-}
-
-void GLES20RenderEngine::setSourceDataSpace(Dataspace source) {
- mDataSpace = source;
-}
-
-void GLES20RenderEngine::setOutputDataSpace(Dataspace dataspace) {
- mOutputDataSpace = dataspace;
-}
-
-void GLES20RenderEngine::setDisplayMaxLuminance(const float maxLuminance) {
- mState.setDisplayMaxLuminance(maxLuminance);
-}
-
-void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) {
- GLuint target = texture.getTextureTarget();
- glBindTexture(target, texture.getTextureName());
- GLenum filter = GL_NEAREST;
- if (texture.getFiltering()) {
- filter = GL_LINEAR;
- }
- glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
-
- mState.setTexture(texture);
-}
-
-void GLES20RenderEngine::setupLayerBlackedOut() {
- glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
- Texture texture(Texture::TEXTURE_2D, mProtectedTexName);
- texture.setDimensions(1, 1); // FIXME: we should get that from somewhere
- mState.setTexture(texture);
-}
-
-void GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
- mState.setColorMatrix(colorTransform);
-}
-
-void GLES20RenderEngine::disableTexturing() {
- mState.disableTexture();
-}
-
-void GLES20RenderEngine::disableBlending() {
- glDisable(GL_BLEND);
-}
-
-void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName,
- uint32_t* fbName, uint32_t* status) {
- GLuint tname, name;
- // turn our EGLImage into a texture
- glGenTextures(1, &tname);
- glBindTexture(GL_TEXTURE_2D, tname);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
-
- // create a Framebuffer Object to render into
- glGenFramebuffers(1, &name);
- glBindFramebuffer(GL_FRAMEBUFFER, name);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
-
- *status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- *texName = tname;
- *fbName = name;
-}
-
-void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) {
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glDeleteFramebuffers(1, &fbName);
- glDeleteTextures(1, &texName);
-}
-
-void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
- mState.setPremultipliedAlpha(true);
- mState.setOpaque(false);
- mState.setColor(half4(r, g, b, a));
- mState.disableTexture();
- glDisable(GL_BLEND);
-}
-
-void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
- ATRACE_CALL();
- if (mesh.getTexCoordsSize()) {
- glEnableVertexAttribArray(Program::texCoords);
- glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE,
- mesh.getByteStride(), mesh.getTexCoords());
- }
-
- glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
- mesh.getByteStride(), mesh.getPositions());
-
- // By default, DISPLAY_P3 is the only supported wide color output. However,
- // when HDR content is present, hardware composer may be able to handle
- // BT2020 data space, in that case, the output data space is set to be
- // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need
- // to respect this and convert non-HDR content to HDR format.
- if (mPlatformHasWideColor) {
- Description wideColorState = mState;
- Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK);
- Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
- Dataspace outputStandard = static_cast<Dataspace>(mOutputDataSpace &
- Dataspace::STANDARD_MASK);
- Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
- Dataspace::TRANSFER_MASK);
- bool needsXYZConversion = needsXYZTransformMatrix();
-
- if (needsXYZConversion) {
- // The supported input color spaces are standard RGB, Display P3 and BT2020.
- switch (inputStandard) {
- case Dataspace::STANDARD_DCI_P3:
- wideColorState.setInputTransformMatrix(mDisplayP3ToXyz);
- break;
- case Dataspace::STANDARD_BT2020:
- wideColorState.setInputTransformMatrix(mBt2020ToXyz);
- break;
- default:
- wideColorState.setInputTransformMatrix(mSrgbToXyz);
- break;
- }
-
- // The supported output color spaces are BT2020, Display P3 and standard RGB.
- switch (outputStandard) {
- case Dataspace::STANDARD_BT2020:
- wideColorState.setOutputTransformMatrix(mXyzToBt2020);
- break;
- case Dataspace::STANDARD_DCI_P3:
- wideColorState.setOutputTransformMatrix(mXyzToDisplayP3);
- break;
- default:
- wideColorState.setOutputTransformMatrix(mXyzToSrgb);
- break;
- }
- } else if (inputStandard != outputStandard) {
- // At this point, the input data space and output data space could be both
- // HDR data spaces, but they match each other, we do nothing in this case.
- // In addition to the case above, the input data space could be
- // - scRGB linear
- // - scRGB non-linear
- // - sRGB
- // - Display P3
- // The output data spaces could be
- // - sRGB
- // - Display P3
- if (outputStandard == Dataspace::STANDARD_BT709) {
- wideColorState.setOutputTransformMatrix(mDisplayP3ToSrgb);
- } else if (outputStandard == Dataspace::STANDARD_DCI_P3) {
- wideColorState.setOutputTransformMatrix(mSrgbToDisplayP3);
- }
- }
-
- // we need to convert the RGB value to linear space and convert it back when:
- // - there is a color matrix that is not an identity matrix, or
- // - there is an output transform matrix that is not an identity matrix, or
- // - the input transfer function doesn't match the output transfer function.
- if (wideColorState.hasColorMatrix() || wideColorState.hasOutputTransformMatrix() ||
- inputTransfer != outputTransfer) {
- switch (inputTransfer) {
- case Dataspace::TRANSFER_ST2084:
- wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084);
- break;
- case Dataspace::TRANSFER_HLG:
- wideColorState.setInputTransferFunction(Description::TransferFunction::HLG);
- break;
- case Dataspace::TRANSFER_LINEAR:
- wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
- break;
- default:
- wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
- break;
- }
-
- switch (outputTransfer) {
- case Dataspace::TRANSFER_ST2084:
- wideColorState.setOutputTransferFunction(Description::TransferFunction::ST2084);
- break;
- case Dataspace::TRANSFER_HLG:
- wideColorState.setOutputTransferFunction(Description::TransferFunction::HLG);
- break;
- default:
- wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
- break;
- }
- }
-
- ProgramCache::getInstance().useProgram(wideColorState);
-
- glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
-
- if (outputDebugPPMs) {
- static uint64_t wideColorFrameCount = 0;
- std::ostringstream out;
- out << "/data/texture_out" << wideColorFrameCount++;
- writePPM(out.str().c_str(), mVpWidth, mVpHeight);
- }
- } else {
- ProgramCache::getInstance().useProgram(mState);
-
- glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
- }
-
- if (mesh.getTexCoordsSize()) {
- glDisableVertexAttribArray(Program::texCoords);
- }
-}
-
-void GLES20RenderEngine::dump(String8& result) {
- RenderEngine::dump(result);
- result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
- dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
- dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
-}
-
-bool GLES20RenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
- const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
- const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
- return standard == Dataspace::STANDARD_BT2020 &&
- (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
-}
-
-// For convenience, we want to convert the input color space to XYZ color space first,
-// and then convert from XYZ color space to output color space when
-// - SDR and HDR contents are mixed, either SDR content will be converted to HDR or
-// HDR content will be tone-mapped to SDR; Or,
-// - there are HDR PQ and HLG contents presented at the same time, where we want to convert
-// HLG content to PQ content.
-// In either case above, we need to operate the Y value in XYZ color space. Thus, when either
-// input data space or output data space is HDR data space, and the input transfer function
-// doesn't match the output transfer function, we would enable an intermediate transfrom to
-// XYZ color space.
-bool GLES20RenderEngine::needsXYZTransformMatrix() const {
- const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace);
- const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace);
- const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
- const Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
- Dataspace::TRANSFER_MASK);
-
- return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
-}
-
-// ---------------------------------------------------------------------------
-} // namespace impl
-} // namespace RE
-} // namespace android
-// ---------------------------------------------------------------------------
-
-#if defined(__gl_h_)
-#error "don't include gl/gl.h in this file"
-#endif
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
deleted file mode 100644
index cc8eb1d..0000000
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2013 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.
- */
-
-#ifndef SF_GLES20RENDERENGINE_H_
-#define SF_GLES20RENDERENGINE_H_
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <GLES2/gl2.h>
-#include <Transform.h>
-
-#include "Description.h"
-#include "ProgramCache.h"
-#include "RenderEngine.h"
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-class String8;
-class Mesh;
-class Texture;
-
-namespace RE {
-namespace impl {
-
-class GLES20RenderEngine : public RenderEngine {
- GLuint mProtectedTexName;
- GLint mMaxViewportDims[2];
- GLint mMaxTextureSize;
- GLuint mVpWidth;
- GLuint mVpHeight;
-
- struct Group {
- GLuint texture;
- GLuint fbo;
- GLuint width;
- GLuint height;
- mat4 colorTransform;
- };
-
- Description mState;
- Vector<Group> mGroupStack;
-
- virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
- uint32_t* status);
- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName);
-
-public:
- GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
- virtual ~GLES20RenderEngine();
-
-protected:
- virtual void dump(String8& result);
- virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
- bool yswap, Transform::orientation_flags rotation);
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
- const half4& color) override;
-
- // Color management related functions and state
- void setSourceY410BT2020(bool enable) override;
- void setSourceDataSpace(ui::Dataspace source) override;
- void setOutputDataSpace(ui::Dataspace dataspace) override;
- void setDisplayMaxLuminance(const float maxLuminance) override;
-
- virtual void setupLayerTexturing(const Texture& texture);
- virtual void setupLayerBlackedOut();
- virtual void setupFillWithColor(float r, float g, float b, float a);
- virtual void setupColorTransform(const mat4& colorTransform);
- virtual void disableTexturing();
- virtual void disableBlending();
-
- virtual void drawMesh(const Mesh& mesh);
-
- virtual size_t getMaxTextureSize() const;
- virtual size_t getMaxViewportDims() const;
-
- // Current dataspace of layer being rendered
- ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
-
- // Current output dataspace of the render engine
- ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
-
- // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
- const bool mPlatformHasWideColor = false;
- mat4 mSrgbToDisplayP3;
- mat4 mDisplayP3ToSrgb;
- mat3 mSrgbToXyz;
- mat3 mBt2020ToXyz;
- mat3 mDisplayP3ToXyz;
- mat4 mXyzToSrgb;
- mat4 mXyzToDisplayP3;
- mat4 mXyzToBt2020;
-
-private:
- // A data space is considered HDR data space if it has BT2020 color space
- // with PQ or HLG transfer function.
- bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
- bool needsXYZTransformMatrix() const;
-};
-
-// ---------------------------------------------------------------------------
-} // namespace impl
-} // namespace RE
-} // namespace android
-// ---------------------------------------------------------------------------
-
-#endif /* SF_GLES20RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/Image.h b/services/surfaceflinger/RenderEngine/Image.h
deleted file mode 100644
index 1ae7e09..0000000
--- a/services/surfaceflinger/RenderEngine/Image.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2017 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 <cstdint>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-struct ANativeWindowBuffer;
-
-namespace android {
-namespace RE {
-
-class Image {
-public:
- virtual ~Image() = 0;
- virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected,
- int32_t cropWidth, int32_t cropHeight) = 0;
-};
-
-namespace impl {
-
-class RenderEngine;
-
-class Image : public RE::Image {
-public:
- explicit Image(const RenderEngine& engine);
- ~Image() override;
-
- Image(const Image&) = delete;
- Image& operator=(const Image&) = delete;
-
- bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
- int32_t cropHeight) override;
-
-private:
- // methods internal to RenderEngine
- friend class RenderEngine;
- EGLSurface getEGLImage() const { return mEGLImage; }
-
- EGLDisplay mEGLDisplay;
- EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
-};
-
-} // namespace impl
-} // namespace RE
-} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index 6a62b1d..5a3c2c8 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-#include "Mesh.h"
+#include <renderengine/Mesh.h>
#include <utils/Log.h>
namespace android {
+namespace renderengine {
Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
: mVertexCount(vertexCount),
@@ -94,4 +95,5 @@
return mStride;
}
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index d745770..3b54873 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -14,588 +14,44 @@
* limitations under the License.
*/
+#include <renderengine/RenderEngine.h>
+
+#include <cutils/properties.h>
#include <log/log.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
+#include <private/gui/SyncFeatures.h>
+#include "gl/GLES20RenderEngine.h"
-#include "GLES20RenderEngine.h"
-#include "GLExtensions.h"
-#include "Image.h"
-#include "Mesh.h"
-#include "RenderEngine.h"
-
-#include <SurfaceFlinger.h>
-#include <vector>
-
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <configstore/Utils.h>
-
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-
-// ---------------------------------------------------------------------------
namespace android {
-namespace RE {
-// ---------------------------------------------------------------------------
+namespace renderengine {
+
+std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+ char prop[PROPERTY_VALUE_MAX];
+ property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "gles");
+ if (strcmp(prop, "gles") == 0) {
+ ALOGD("RenderEngine GLES Backend");
+ return renderengine::gl::GLES20RenderEngine::create(hwcFormat, featureFlags);
+ }
+ ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
+ return renderengine::gl::GLES20RenderEngine::create(hwcFormat, featureFlags);
+}
RenderEngine::~RenderEngine() = default;
namespace impl {
-std::unique_ptr<RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
- // initialize EGL for the default display
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (!eglInitialize(display, nullptr, nullptr)) {
- LOG_ALWAYS_FATAL("failed to initialize EGL");
- }
-
- GLExtensions& extensions = GLExtensions::getInstance();
- extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
- eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
-
- // The code assumes that ES2 or later is available if this extension is
- // supported.
- EGLConfig config = EGL_NO_CONFIG;
- if (!extensions.hasNoConfigContext()) {
- config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
- }
-
- EGLint renderableType = 0;
- if (config == EGL_NO_CONFIG) {
- renderableType = EGL_OPENGL_ES2_BIT;
- } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
- LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
- }
- EGLint contextClientVersion = 0;
- if (renderableType & EGL_OPENGL_ES2_BIT) {
- contextClientVersion = 2;
- } else if (renderableType & EGL_OPENGL_ES_BIT) {
- contextClientVersion = 1;
- } else {
- LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
- }
-
- std::vector<EGLint> contextAttributes;
- contextAttributes.reserve(6);
- contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
- contextAttributes.push_back(contextClientVersion);
- bool useContextPriority = overrideUseContextPriorityFromConfig(extensions.hasContextPriority());
- if (useContextPriority) {
- contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
- contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
- }
- contextAttributes.push_back(EGL_NONE);
-
- EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());
-
- // if can't create a GL context, we can only abort.
- LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
-
- // now figure out what version of GL did we actually get
- // NOTE: a dummy surface is not needed if KHR_create_context is supported
-
- EGLConfig dummyConfig = config;
- if (dummyConfig == EGL_NO_CONFIG) {
- dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
- }
- EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
- EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
- LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
- EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
- LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
-
- extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
- glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
-
- GlesVersion version = parseGlesVersion(extensions.getVersion());
-
- // initialize the renderer while GL is current
-
- std::unique_ptr<RenderEngine> engine;
- switch (version) {
- case GLES_VERSION_1_0:
- case GLES_VERSION_1_1:
- LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
- break;
- case GLES_VERSION_2_0:
- case GLES_VERSION_3_0:
- engine = std::make_unique<GLES20RenderEngine>(featureFlags);
- break;
- }
- engine->setEGLHandles(display, config, ctxt);
-
- ALOGI("OpenGL ES informations:");
- ALOGI("vendor : %s", extensions.getVendor());
- ALOGI("renderer : %s", extensions.getRenderer());
- ALOGI("version : %s", extensions.getVersion());
- ALOGI("extensions: %s", extensions.getExtensions());
- ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
- ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
-
- eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroySurface(display, dummy);
-
- return engine;
-}
-
-bool RenderEngine::overrideUseContextPriorityFromConfig(bool useContextPriority) {
- OptionalBool ret;
- ISurfaceFlingerConfigs::getService()->useContextPriority([&ret](OptionalBool b) { ret = b; });
- if (ret.specified) {
- return ret.value;
- } else {
- return useContextPriority;
- }
-}
-
RenderEngine::RenderEngine(uint32_t featureFlags)
- : mEGLDisplay(EGL_NO_DISPLAY),
- mEGLConfig(nullptr),
- mEGLContext(EGL_NO_CONTEXT),
- mFeatureFlags(featureFlags) {}
+ : mFeatureFlags(featureFlags) {}
-RenderEngine::~RenderEngine() {
- eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglTerminate(mEGLDisplay);
+RenderEngine::~RenderEngine() = default;
+
+bool RenderEngine::useNativeFenceSync() const {
+ return SyncFeatures::getInstance().useNativeFenceSync();
}
-void RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
- mEGLDisplay = display;
- mEGLConfig = config;
- mEGLContext = ctxt;
+bool RenderEngine::useWaitSync() const {
+ return SyncFeatures::getInstance().useWaitSync();
}
-EGLDisplay RenderEngine::getEGLDisplay() const {
- return mEGLDisplay;
-}
-
-EGLConfig RenderEngine::getEGLConfig() const {
- return mEGLConfig;
-}
-
-bool RenderEngine::supportsImageCrop() const {
- return GLExtensions::getInstance().hasImageCrop();
-}
-
-bool RenderEngine::isCurrent() const {
- return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
-}
-
-std::unique_ptr<RE::Surface> RenderEngine::createSurface() {
- return std::make_unique<Surface>(*this);
-}
-
-std::unique_ptr<RE::Image> RenderEngine::createImage() {
- return std::make_unique<Image>(*this);
-}
-
-bool RenderEngine::setCurrentSurface(const android::RE::Surface& surface) {
- // Note: RE::Surface is an abstract interface. This implementation only ever
- // creates RE::impl::Surface's, so it is safe to just cast to the actual
- // type.
- return setCurrentSurface(static_cast<const android::RE::impl::Surface&>(surface));
-}
-
-bool RenderEngine::setCurrentSurface(const android::RE::impl::Surface& surface) {
- bool success = true;
- EGLSurface eglSurface = surface.getEGLSurface();
- if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) {
- success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE;
- if (success && surface.getAsync()) {
- eglSwapInterval(mEGLDisplay, 0);
- }
- }
-
- return success;
-}
-
-void RenderEngine::resetCurrentSurface() {
- eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-}
-
-base::unique_fd RenderEngine::flush() {
- if (!GLExtensions::getInstance().hasNativeFenceSync()) {
- return base::unique_fd();
- }
-
- EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
- if (sync == EGL_NO_SYNC_KHR) {
- ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
- return base::unique_fd();
- }
-
- // native fence fd will not be populated until flush() is done.
- glFlush();
-
- // get the fence fd
- base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
- eglDestroySyncKHR(mEGLDisplay, sync);
- if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
- }
-
- return fenceFd;
-}
-
-bool RenderEngine::finish() {
- if (!GLExtensions::getInstance().hasFenceSync()) {
- ALOGW("no synchronization support");
- return false;
- }
-
- EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
- if (sync == EGL_NO_SYNC_KHR) {
- ALOGW("failed to create EGL fence sync: %#x", eglGetError());
- return false;
- }
-
- EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
- 2000000000 /*2 sec*/);
- EGLint error = eglGetError();
- eglDestroySyncKHR(mEGLDisplay, sync);
- if (result != EGL_CONDITION_SATISFIED_KHR) {
- if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ALOGW("fence wait timed out");
- } else {
- ALOGW("error waiting on EGL fence: %#x", error);
- }
- return false;
- }
-
- return true;
-}
-
-bool RenderEngine::waitFence(base::unique_fd fenceFd) {
- if (!GLExtensions::getInstance().hasNativeFenceSync() ||
- !GLExtensions::getInstance().hasWaitSync()) {
- return false;
- }
-
- EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
- EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
- if (sync == EGL_NO_SYNC_KHR) {
- ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
- return false;
- }
-
- // fenceFd is now owned by EGLSync
- (void)fenceFd.release();
-
- // XXX: The spec draft is inconsistent as to whether this should return an
- // EGLint or void. Ignore the return value for now, as it's not strictly
- // needed.
- eglWaitSyncKHR(mEGLDisplay, sync, 0);
- EGLint error = eglGetError();
- eglDestroySyncKHR(mEGLDisplay, sync);
- if (error != EGL_SUCCESS) {
- ALOGE("failed to wait for EGL native fence sync: %#x", error);
- return false;
- }
-
- return true;
-}
-
-void RenderEngine::checkErrors() const {
- do {
- // there could be more than one error flag
- GLenum error = glGetError();
- if (error == GL_NO_ERROR) break;
- ALOGE("GL error 0x%04x", int(error));
- } while (true);
-}
-
-RenderEngine::GlesVersion RenderEngine::parseGlesVersion(const char* str) {
- int major, minor;
- if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
- if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) {
- ALOGW("Unable to parse GL_VERSION string: \"%s\"", str);
- return GLES_VERSION_1_0;
- }
- }
-
- if (major == 1 && minor == 0) return GLES_VERSION_1_0;
- if (major == 1 && minor >= 1) return GLES_VERSION_1_1;
- if (major == 2 && minor >= 0) return GLES_VERSION_2_0;
- if (major == 3 && minor >= 0) return GLES_VERSION_3_0;
-
- ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor);
- return GLES_VERSION_1_0;
-}
-
-void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red,
- float green, float blue, float alpha) {
- size_t c;
- Rect const* r = region.getArray(&c);
- Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
- Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
- for (size_t i = 0; i < c; i++, r++) {
- position[i * 6 + 0].x = r->left;
- position[i * 6 + 0].y = height - r->top;
- position[i * 6 + 1].x = r->left;
- position[i * 6 + 1].y = height - r->bottom;
- position[i * 6 + 2].x = r->right;
- position[i * 6 + 2].y = height - r->bottom;
- position[i * 6 + 3].x = r->left;
- position[i * 6 + 3].y = height - r->top;
- position[i * 6 + 4].x = r->right;
- position[i * 6 + 4].y = height - r->bottom;
- position[i * 6 + 5].x = r->right;
- position[i * 6 + 5].y = height - r->top;
- }
- setupFillWithColor(red, green, blue, alpha);
- drawMesh(mesh);
-}
-
-void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
- glClearColor(red, green, blue, alpha);
- glClear(GL_COLOR_BUFFER_BIT);
-}
-
-void RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
- glScissor(left, bottom, right, top);
- glEnable(GL_SCISSOR_TEST);
-}
-
-void RenderEngine::disableScissor() {
- glDisable(GL_SCISSOR_TEST);
-}
-
-void RenderEngine::genTextures(size_t count, uint32_t* names) {
- glGenTextures(count, names);
-}
-
-void RenderEngine::deleteTextures(size_t count, uint32_t const* names) {
- glDeleteTextures(count, names);
-}
-
-void RenderEngine::bindExternalTextureImage(uint32_t texName, const android::RE::Image& image) {
- // Note: RE::Image is an abstract interface. This implementation only ever
- // creates RE::impl::Image's, so it is safe to just cast to the actual type.
- return bindExternalTextureImage(texName, static_cast<const android::RE::impl::Image&>(image));
-}
-
-void RenderEngine::bindExternalTextureImage(uint32_t texName,
- const android::RE::impl::Image& image) {
- const GLenum target = GL_TEXTURE_EXTERNAL_OES;
-
- glBindTexture(target, texName);
- if (image.getEGLImage() != EGL_NO_IMAGE_KHR) {
- glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image.getEGLImage()));
- }
-}
-
-void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
- glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-}
-
-void RenderEngine::dump(String8& result) {
- const GLExtensions& extensions = GLExtensions::getInstance();
-
- result.appendFormat("EGL implementation : %s\n", extensions.getEGLVersion());
- result.appendFormat("%s\n", extensions.getEGLExtensions());
-
- result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
- extensions.getVersion());
- result.appendFormat("%s\n", extensions.getExtensions());
-}
-
-// ---------------------------------------------------------------------------
-
-void RenderEngine::bindNativeBufferAsFrameBuffer(ANativeWindowBuffer* buffer,
- RE::BindNativeBufferAsFramebuffer* bindHelper) {
- bindHelper->mImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- buffer, nullptr);
- if (bindHelper->mImage == EGL_NO_IMAGE_KHR) {
- bindHelper->mStatus = NO_MEMORY;
- return;
- }
-
- uint32_t glStatus;
- bindImageAsFramebuffer(bindHelper->mImage, &bindHelper->mTexName, &bindHelper->mFbName,
- &glStatus);
-
- ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
- glStatus);
-
- bindHelper->mStatus = glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
-}
-
-void RenderEngine::unbindNativeBufferAsFrameBuffer(RE::BindNativeBufferAsFramebuffer* bindHelper) {
- if (bindHelper->mImage == EGL_NO_IMAGE_KHR) {
- return;
- }
-
- // back to main framebuffer
- unbindFramebuffer(bindHelper->mTexName, bindHelper->mFbName);
- eglDestroyImageKHR(mEGLDisplay, bindHelper->mImage);
-
- // Workaround for b/77935566 to force the EGL driver to release the
- // screenshot buffer
- setScissor(0, 0, 0, 0);
- clearWithColor(0.0, 0.0, 0.0, 0.0);
- disableScissor();
-}
-
-// ---------------------------------------------------------------------------
-
-static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
- EGLint wanted, EGLConfig* outConfig) {
- EGLint numConfigs = -1, n = 0;
- eglGetConfigs(dpy, nullptr, 0, &numConfigs);
- EGLConfig* const configs = new EGLConfig[numConfigs];
- eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
-
- if (n) {
- if (attribute != EGL_NONE) {
- for (int i = 0; i < n; i++) {
- EGLint value = 0;
- eglGetConfigAttrib(dpy, configs[i], attribute, &value);
- if (wanted == value) {
- *outConfig = configs[i];
- delete[] configs;
- return NO_ERROR;
- }
- }
- } else {
- // just pick the first one
- *outConfig = configs[0];
- delete[] configs;
- return NO_ERROR;
- }
- }
- delete[] configs;
- return NAME_NOT_FOUND;
-}
-
-class EGLAttributeVector {
- struct Attribute;
- class Adder;
- friend class Adder;
- KeyedVector<Attribute, EGLint> mList;
- struct Attribute {
- Attribute() : v(0){};
- explicit Attribute(EGLint v) : v(v) {}
- EGLint v;
- bool operator<(const Attribute& other) const {
- // this places EGL_NONE at the end
- EGLint lhs(v);
- EGLint rhs(other.v);
- if (lhs == EGL_NONE) lhs = 0x7FFFFFFF;
- if (rhs == EGL_NONE) rhs = 0x7FFFFFFF;
- return lhs < rhs;
- }
- };
- class Adder {
- friend class EGLAttributeVector;
- EGLAttributeVector& v;
- EGLint attribute;
- Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
-
- public:
- void operator=(EGLint value) {
- if (attribute != EGL_NONE) {
- v.mList.add(Attribute(attribute), value);
- }
- }
- operator EGLint() const { return v.mList[attribute]; }
- };
-
-public:
- EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
- void remove(EGLint attribute) {
- if (attribute != EGL_NONE) {
- mList.removeItem(Attribute(attribute));
- }
- }
- Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
- EGLint operator[](EGLint attribute) const { return mList[attribute]; }
- // cast-operator to (EGLint const*)
- operator EGLint const*() const { return &mList.keyAt(0).v; }
-};
-
-static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
- EGLConfig* config) {
- // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
- // it is to be used with WIFI displays
- status_t err;
- EGLint wantedAttribute;
- EGLint wantedAttributeValue;
-
- EGLAttributeVector attribs;
- if (renderableType) {
- attribs[EGL_RENDERABLE_TYPE] = renderableType;
- attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
- attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
- attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
- attribs[EGL_RED_SIZE] = 8;
- attribs[EGL_GREEN_SIZE] = 8;
- attribs[EGL_BLUE_SIZE] = 8;
- attribs[EGL_ALPHA_SIZE] = 8;
- wantedAttribute = EGL_NONE;
- wantedAttributeValue = EGL_NONE;
- } else {
- // if no renderable type specified, fallback to a simplified query
- wantedAttribute = EGL_NATIVE_VISUAL_ID;
- wantedAttributeValue = format;
- }
-
- err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
- if (err == NO_ERROR) {
- EGLint caveat;
- if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
- ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
- }
-
- return err;
-}
-
-EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
- status_t err;
- EGLConfig config;
-
- // First try to get an ES2 config
- err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
- if (err != NO_ERROR) {
- // If ES2 fails, try ES1
- err = selectEGLConfig(display, format, EGL_OPENGL_ES_BIT, &config);
- if (err != NO_ERROR) {
- // still didn't work, probably because we're on the emulator...
- // try a simplified query
- ALOGW("no suitable EGLConfig found, trying a simpler query");
- err = selectEGLConfig(display, format, 0, &config);
- if (err != NO_ERROR) {
- // this EGL is too lame for android
- LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
- }
- }
- }
-
- if (logConfig) {
- // print some debugging info
- EGLint r, g, b, a;
- eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
- eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
- eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
- eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
- ALOGI("EGL information:");
- ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR));
- ALOGI("version : %s", eglQueryString(display, EGL_VERSION));
- ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
- ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
- ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
- }
-
- return config;
-}
-
-void RenderEngine::primeCache() const {
- ProgramCache::getInstance().primeCache(mFeatureFlags & WIDE_COLOR_SUPPORT);
-}
-
-// ---------------------------------------------------------------------------
-
-} // namespace impl
-} // namespace RE
-} // namespace android
+} // namespace impl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
deleted file mode 100644
index 1786155..0000000
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright 2013 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.
- */
-
-#ifndef SF_RENDERENGINE_H_
-#define SF_RENDERENGINE_H_
-
-#include <memory>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <Transform.h>
-#include <android-base/unique_fd.h>
-#include <gui/SurfaceControl.h>
-#include <math/mat4.h>
-
-#define EGL_NO_CONFIG ((EGLConfig)0)
-
-struct ANativeWindowBuffer;
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-class String8;
-class Rect;
-class Region;
-class Mesh;
-class Texture;
-
-namespace RE {
-
-class Image;
-class Surface;
-class BindNativeBufferAsFramebuffer;
-
-namespace impl {
-class RenderEngine;
-}
-
-class RenderEngine {
-public:
- enum FeatureFlag {
- WIDE_COLOR_SUPPORT = 1 << 0 // Platform has a wide color display
- };
-
- virtual ~RenderEngine() = 0;
-
- virtual std::unique_ptr<RE::Surface> createSurface() = 0;
- virtual std::unique_ptr<RE::Image> createImage() = 0;
-
- virtual void primeCache() const = 0;
-
- // dump the extension strings. always call the base class.
- virtual void dump(String8& result) = 0;
-
- virtual bool supportsImageCrop() const = 0;
-
- virtual bool isCurrent() const = 0;
- virtual bool setCurrentSurface(const RE::Surface& surface) = 0;
- virtual void resetCurrentSurface() = 0;
-
- // helpers
- // flush submits RenderEngine command stream for execution and returns a
- // native fence fd that is signaled when the execution has completed. It
- // returns -1 on errors.
- virtual base::unique_fd flush() = 0;
- // finish waits until RenderEngine command stream has been executed. It
- // returns false on errors.
- virtual bool finish() = 0;
- // waitFence inserts a wait on an external fence fd to RenderEngine
- // command stream. It returns false on errors.
- virtual bool waitFence(base::unique_fd fenceFd) = 0;
-
- virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
- virtual void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
- float blue, float alpha) = 0;
-
- // common to all GL versions
- virtual void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) = 0;
- virtual void disableScissor() = 0;
- virtual void genTextures(size_t count, uint32_t* names) = 0;
- virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
- virtual void bindExternalTextureImage(uint32_t texName, const RE::Image& image) = 0;
- virtual void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) = 0;
- virtual void bindNativeBufferAsFrameBuffer(ANativeWindowBuffer* buffer,
- RE::BindNativeBufferAsFramebuffer* bindHelper) = 0;
- virtual void unbindNativeBufferAsFrameBuffer(RE::BindNativeBufferAsFramebuffer* bindHelper) = 0;
-
- // set-up
- virtual void checkErrors() const;
- virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
- bool yswap, Transform::orientation_flags rotation) = 0;
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
- const half4& color) = 0;
- virtual void setupLayerTexturing(const Texture& texture) = 0;
- virtual void setupLayerBlackedOut() = 0;
- virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
-
- virtual void setupColorTransform(const mat4& /* colorTransform */) = 0;
-
- virtual void disableTexturing() = 0;
- virtual void disableBlending() = 0;
-
- // HDR and wide color gamut support
- virtual void setSourceY410BT2020(bool enable) = 0;
- virtual void setSourceDataSpace(ui::Dataspace source) = 0;
- virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0;
- virtual void setDisplayMaxLuminance(const float maxLuminance) = 0;
-
- // drawing
- virtual void drawMesh(const Mesh& mesh) = 0;
-
- // queries
- virtual size_t getMaxTextureSize() const = 0;
- virtual size_t getMaxViewportDims() const = 0;
-};
-
-class BindNativeBufferAsFramebuffer {
-public:
- BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
- : mEngine(engine) {
- mEngine.bindNativeBufferAsFrameBuffer(buffer, this);
- }
- ~BindNativeBufferAsFramebuffer() { mEngine.unbindNativeBufferAsFrameBuffer(this); }
- status_t getStatus() const { return mStatus; }
-
-protected:
- friend impl::RenderEngine;
-
- RenderEngine& mEngine;
- EGLImageKHR mImage;
- uint32_t mTexName, mFbName;
- status_t mStatus;
-};
-
-namespace impl {
-
-class Image;
-class Surface;
-
-class RenderEngine : public RE::RenderEngine {
- enum GlesVersion {
- GLES_VERSION_1_0 = 0x10000,
- GLES_VERSION_1_1 = 0x10001,
- GLES_VERSION_2_0 = 0x20000,
- GLES_VERSION_3_0 = 0x30000,
- };
- static GlesVersion parseGlesVersion(const char* str);
-
- EGLDisplay mEGLDisplay;
- EGLConfig mEGLConfig;
- EGLContext mEGLContext;
- void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
-
- static bool overrideUseContextPriorityFromConfig(bool useContextPriority);
-
-protected:
- RenderEngine(uint32_t featureFlags);
-
- const uint32_t mFeatureFlags;
-
-public:
- virtual ~RenderEngine() = 0;
-
- static std::unique_ptr<RenderEngine> create(int hwcFormat, uint32_t featureFlags);
-
- static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
-
- // RenderEngine interface implementation
-
- std::unique_ptr<RE::Surface> createSurface() override;
- std::unique_ptr<RE::Image> createImage() override;
-
- void primeCache() const override;
-
- // dump the extension strings. always call the base class.
- void dump(String8& result) override;
-
- bool supportsImageCrop() const override;
-
- bool isCurrent() const;
- bool setCurrentSurface(const RE::Surface& surface) override;
- void resetCurrentSurface() override;
-
- // synchronization
-
- // flush submits RenderEngine command stream for execution and returns a
- // native fence fd that is signaled when the execution has completed. It
- // returns -1 on errors.
- base::unique_fd flush() override;
- // finish waits until RenderEngine command stream has been executed. It
- // returns false on errors.
- bool finish() override;
- // waitFence inserts a wait on an external fence fd to RenderEngine
- // command stream. It returns false on errors.
- bool waitFence(base::unique_fd fenceFd) override;
-
- // helpers
- void clearWithColor(float red, float green, float blue, float alpha) override;
- void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
- float blue, float alpha) override;
-
- // common to all GL versions
- void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) override;
- void disableScissor() override;
- void genTextures(size_t count, uint32_t* names) override;
- void deleteTextures(size_t count, uint32_t const* names) override;
- void bindExternalTextureImage(uint32_t texName, const RE::Image& image) override;
- void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) override;
-
- void checkErrors() const override;
-
- void setupColorTransform(const mat4& /* colorTransform */) override {}
-
- // internal to RenderEngine
- EGLDisplay getEGLDisplay() const;
- EGLConfig getEGLConfig() const;
-
- // Common implementation
- bool setCurrentSurface(const RE::impl::Surface& surface);
- void bindExternalTextureImage(uint32_t texName, const RE::impl::Image& image);
-
- void bindNativeBufferAsFrameBuffer(ANativeWindowBuffer* buffer,
- RE::BindNativeBufferAsFramebuffer* bindHelper) override;
- void unbindNativeBufferAsFrameBuffer(RE::BindNativeBufferAsFramebuffer* bindHelper) override;
-
- // Overriden by each specialization
- virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
- uint32_t* status) = 0;
- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0;
-};
-
-} // namespace impl
-} // namespace RE
-} // namespace android
-
-#endif /* SF_RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/Texture.cpp b/services/surfaceflinger/RenderEngine/Texture.cpp
index 351430f..5eabbcf 100644
--- a/services/surfaceflinger/RenderEngine/Texture.cpp
+++ b/services/surfaceflinger/RenderEngine/Texture.cpp
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-#include <string.h>
-
-#include "Texture.h"
+#include <renderengine/Texture.h>
namespace android {
+namespace renderengine {
Texture::Texture()
: mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) {}
@@ -74,4 +73,5 @@
return mHeight;
}
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
new file mode 100644
index 0000000..0f0ff62
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -0,0 +1,957 @@
+/*
+ * Copyright 2013 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.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GLES20RenderEngine.h"
+
+#include <math.h>
+#include <fstream>
+#include <sstream>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <cutils/compiler.h>
+#include <renderengine/Mesh.h>
+#include <renderengine/Texture.h>
+#include <renderengine/private/Description.h>
+#include <ui/ColorSpace.h>
+#include <ui/DebugUtils.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+#include "GLExtensions.h"
+#include "GLFramebuffer.h"
+#include "GLImage.h"
+#include "GLSurface.h"
+#include "Program.h"
+#include "ProgramCache.h"
+
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+
+bool checkGlError(const char* op, int lineNumber) {
+ bool errorFound = false;
+ GLint error = glGetError();
+ while (error != GL_NO_ERROR) {
+ errorFound = true;
+ error = glGetError();
+ ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error);
+ }
+ return errorFound;
+}
+
+static constexpr bool outputDebugPPMs = false;
+
+void writePPM(const char* basename, GLuint width, GLuint height) {
+ ALOGV("writePPM #%s: %d x %d", basename, width, height);
+
+ std::vector<GLubyte> pixels(width * height * 4);
+ std::vector<GLubyte> outBuffer(width * height * 3);
+
+ // TODO(courtneygo): We can now have float formats, need
+ // to remove this code or update to support.
+ // Make returned pixels fit in uint32_t, one byte per component
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+ if (checkGlError(__FUNCTION__, __LINE__)) {
+ return;
+ }
+
+ std::string filename(basename);
+ filename.append(".ppm");
+ std::ofstream file(filename.c_str(), std::ios::binary);
+ if (!file.is_open()) {
+ ALOGE("Unable to open file: %s", filename.c_str());
+ ALOGE("You may need to do: \"adb shell setenforce 0\" to enable "
+ "surfaceflinger to write debug images");
+ return;
+ }
+
+ file << "P6\n";
+ file << width << "\n";
+ file << height << "\n";
+ file << 255 << "\n";
+
+ auto ptr = reinterpret_cast<char*>(pixels.data());
+ auto outPtr = reinterpret_cast<char*>(outBuffer.data());
+ for (int y = height - 1; y >= 0; y--) {
+ char* data = ptr + y * width * sizeof(uint32_t);
+
+ for (GLuint x = 0; x < width; x++) {
+ // Only copy R, G and B components
+ outPtr[0] = data[0];
+ outPtr[1] = data[1];
+ outPtr[2] = data[2];
+ data += sizeof(uint32_t);
+ outPtr += 3;
+ }
+ }
+ file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size());
+}
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+using ui::Dataspace;
+
+static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
+ EGLint wanted, EGLConfig* outConfig) {
+ EGLint numConfigs = -1, n = 0;
+ eglGetConfigs(dpy, nullptr, 0, &numConfigs);
+ EGLConfig* const configs = new EGLConfig[numConfigs];
+ eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
+
+ if (n) {
+ if (attribute != EGL_NONE) {
+ for (int i = 0; i < n; i++) {
+ EGLint value = 0;
+ eglGetConfigAttrib(dpy, configs[i], attribute, &value);
+ if (wanted == value) {
+ *outConfig = configs[i];
+ delete[] configs;
+ return NO_ERROR;
+ }
+ }
+ } else {
+ // just pick the first one
+ *outConfig = configs[0];
+ delete[] configs;
+ return NO_ERROR;
+ }
+ }
+ delete[] configs;
+ return NAME_NOT_FOUND;
+}
+
+class EGLAttributeVector {
+ struct Attribute;
+ class Adder;
+ friend class Adder;
+ KeyedVector<Attribute, EGLint> mList;
+ struct Attribute {
+ Attribute() : v(0){};
+ explicit Attribute(EGLint v) : v(v) {}
+ EGLint v;
+ bool operator<(const Attribute& other) const {
+ // this places EGL_NONE at the end
+ EGLint lhs(v);
+ EGLint rhs(other.v);
+ if (lhs == EGL_NONE) lhs = 0x7FFFFFFF;
+ if (rhs == EGL_NONE) rhs = 0x7FFFFFFF;
+ return lhs < rhs;
+ }
+ };
+ class Adder {
+ friend class EGLAttributeVector;
+ EGLAttributeVector& v;
+ EGLint attribute;
+ Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
+
+ public:
+ void operator=(EGLint value) {
+ if (attribute != EGL_NONE) {
+ v.mList.add(Attribute(attribute), value);
+ }
+ }
+ operator EGLint() const { return v.mList[attribute]; }
+ };
+
+public:
+ EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
+ void remove(EGLint attribute) {
+ if (attribute != EGL_NONE) {
+ mList.removeItem(Attribute(attribute));
+ }
+ }
+ Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
+ EGLint operator[](EGLint attribute) const { return mList[attribute]; }
+ // cast-operator to (EGLint const*)
+ operator EGLint const*() const { return &mList.keyAt(0).v; }
+};
+
+static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
+ EGLConfig* config) {
+ // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
+ // it is to be used with WIFI displays
+ status_t err;
+ EGLint wantedAttribute;
+ EGLint wantedAttributeValue;
+
+ EGLAttributeVector attribs;
+ if (renderableType) {
+ attribs[EGL_RENDERABLE_TYPE] = renderableType;
+ attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
+ attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
+ attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
+ attribs[EGL_RED_SIZE] = 8;
+ attribs[EGL_GREEN_SIZE] = 8;
+ attribs[EGL_BLUE_SIZE] = 8;
+ attribs[EGL_ALPHA_SIZE] = 8;
+ wantedAttribute = EGL_NONE;
+ wantedAttributeValue = EGL_NONE;
+ } else {
+ // if no renderable type specified, fallback to a simplified query
+ wantedAttribute = EGL_NATIVE_VISUAL_ID;
+ wantedAttributeValue = format;
+ }
+
+ err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
+ if (err == NO_ERROR) {
+ EGLint caveat;
+ if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
+ ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
+ }
+
+ return err;
+}
+
+std::unique_ptr<GLES20RenderEngine> GLES20RenderEngine::create(int hwcFormat,
+ uint32_t featureFlags) {
+ // initialize EGL for the default display
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (!eglInitialize(display, nullptr, nullptr)) {
+ LOG_ALWAYS_FATAL("failed to initialize EGL");
+ }
+
+ GLExtensions& extensions = GLExtensions::getInstance();
+ extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
+ eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
+
+ // The code assumes that ES2 or later is available if this extension is
+ // supported.
+ EGLConfig config = EGL_NO_CONFIG;
+ if (!extensions.hasNoConfigContext()) {
+ config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+ }
+
+ EGLint renderableType = 0;
+ if (config == EGL_NO_CONFIG) {
+ renderableType = EGL_OPENGL_ES2_BIT;
+ } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
+ LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
+ }
+ EGLint contextClientVersion = 0;
+ if (renderableType & EGL_OPENGL_ES2_BIT) {
+ contextClientVersion = 2;
+ } else if (renderableType & EGL_OPENGL_ES_BIT) {
+ contextClientVersion = 1;
+ } else {
+ LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
+ }
+
+ std::vector<EGLint> contextAttributes;
+ contextAttributes.reserve(6);
+ contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+ contextAttributes.push_back(contextClientVersion);
+ bool useContextPriority = extensions.hasContextPriority() &&
+ (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
+ if (useContextPriority) {
+ contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
+ contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+ }
+ contextAttributes.push_back(EGL_NONE);
+
+ EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());
+
+ // if can't create a GL context, we can only abort.
+ LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
+
+ // now figure out what version of GL did we actually get
+ // NOTE: a dummy surface is not needed if KHR_create_context is supported
+
+ EGLConfig dummyConfig = config;
+ if (dummyConfig == EGL_NO_CONFIG) {
+ dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+ }
+ EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
+ EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
+ LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
+ EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
+ LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
+
+ extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
+ glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
+
+ GlesVersion version = parseGlesVersion(extensions.getVersion());
+
+ // initialize the renderer while GL is current
+
+ std::unique_ptr<GLES20RenderEngine> engine;
+ switch (version) {
+ case GLES_VERSION_1_0:
+ case GLES_VERSION_1_1:
+ LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
+ break;
+ case GLES_VERSION_2_0:
+ case GLES_VERSION_3_0:
+ engine = std::make_unique<GLES20RenderEngine>(featureFlags);
+ break;
+ }
+ engine->setEGLHandles(display, config, ctxt);
+
+ ALOGI("OpenGL ES informations:");
+ ALOGI("vendor : %s", extensions.getVendor());
+ ALOGI("renderer : %s", extensions.getRenderer());
+ ALOGI("version : %s", extensions.getVersion());
+ ALOGI("extensions: %s", extensions.getExtensions());
+ ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
+ ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
+
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(display, dummy);
+
+ return engine;
+}
+
+EGLConfig GLES20RenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
+ status_t err;
+ EGLConfig config;
+
+ // First try to get an ES2 config
+ err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
+ if (err != NO_ERROR) {
+ // If ES2 fails, try ES1
+ err = selectEGLConfig(display, format, EGL_OPENGL_ES_BIT, &config);
+ if (err != NO_ERROR) {
+ // still didn't work, probably because we're on the emulator...
+ // try a simplified query
+ ALOGW("no suitable EGLConfig found, trying a simpler query");
+ err = selectEGLConfig(display, format, 0, &config);
+ if (err != NO_ERROR) {
+ // this EGL is too lame for android
+ LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
+ }
+ }
+ }
+
+ if (logConfig) {
+ // print some debugging info
+ EGLint r, g, b, a;
+ eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
+ ALOGI("EGL information:");
+ ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR));
+ ALOGI("version : %s", eglQueryString(display, EGL_VERSION));
+ ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
+ ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
+ ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+ }
+
+ return config;
+}
+
+GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
+ : renderengine::impl::RenderEngine(featureFlags),
+ mEGLDisplay(EGL_NO_DISPLAY),
+ mEGLConfig(nullptr),
+ mEGLContext(EGL_NO_CONTEXT),
+ mVpWidth(0),
+ mVpHeight(0),
+ mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
+
+ const uint16_t protTexData[] = {0};
+ glGenTextures(1, &mProtectedTexName);
+ glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
+
+ // mColorBlindnessCorrection = M;
+
+ if (mUseColorManagement) {
+ ColorSpace srgb(ColorSpace::sRGB());
+ ColorSpace displayP3(ColorSpace::DisplayP3());
+ ColorSpace bt2020(ColorSpace::BT2020());
+
+ // Compute sRGB to Display P3 transform matrix.
+ // NOTE: For now, we are limiting output wide color space support to
+ // Display-P3 only.
+ mSrgbToDisplayP3 = mat4(ColorSpaceConnector(srgb, displayP3).getTransform());
+
+ // Compute Display P3 to sRGB transform matrix.
+ mDisplayP3ToSrgb = mat4(ColorSpaceConnector(displayP3, srgb).getTransform());
+
+ // no chromatic adaptation needed since all color spaces use D65 for their white points.
+ mSrgbToXyz = srgb.getRGBtoXYZ();
+ mDisplayP3ToXyz = displayP3.getRGBtoXYZ();
+ mBt2020ToXyz = bt2020.getRGBtoXYZ();
+ mXyzToSrgb = mat4(srgb.getXYZtoRGB());
+ mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB());
+ mXyzToBt2020 = mat4(bt2020.getXYZtoRGB());
+ }
+}
+
+GLES20RenderEngine::~GLES20RenderEngine() {
+ eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglTerminate(mEGLDisplay);
+}
+
+std::unique_ptr<Framebuffer> GLES20RenderEngine::createFramebuffer() {
+ return std::make_unique<GLFramebuffer>(*this);
+}
+
+std::unique_ptr<Surface> GLES20RenderEngine::createSurface() {
+ return std::make_unique<GLSurface>(*this);
+}
+
+std::unique_ptr<Image> GLES20RenderEngine::createImage() {
+ return std::make_unique<GLImage>(*this);
+}
+
+void GLES20RenderEngine::primeCache() const {
+ ProgramCache::getInstance().primeCache(mFeatureFlags & USE_COLOR_MANAGEMENT);
+}
+
+bool GLES20RenderEngine::isCurrent() const {
+ return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
+}
+
+bool GLES20RenderEngine::setCurrentSurface(const Surface& surface) {
+ // Surface is an abstract interface. GLES20RenderEngine only ever
+ // creates GLSurface's, so it is safe to just cast to the actual
+ // type.
+ bool success = true;
+ const GLSurface& glSurface = static_cast<const GLSurface&>(surface);
+ EGLSurface eglSurface = glSurface.getEGLSurface();
+ if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) {
+ success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE;
+ if (success && glSurface.getAsync()) {
+ eglSwapInterval(mEGLDisplay, 0);
+ }
+ }
+ return success;
+}
+
+void GLES20RenderEngine::resetCurrentSurface() {
+ eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+base::unique_fd GLES20RenderEngine::flush() {
+ if (!GLExtensions::getInstance().hasNativeFenceSync()) {
+ return base::unique_fd();
+ }
+
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+ return base::unique_fd();
+ }
+
+ // native fence fd will not be populated until flush() is done.
+ glFlush();
+
+ // get the fence fd
+ base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
+ }
+
+ return fenceFd;
+}
+
+bool GLES20RenderEngine::finish() {
+ if (!GLExtensions::getInstance().hasFenceSync()) {
+ ALOGW("no synchronization support");
+ return false;
+ }
+
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGW("failed to create EGL fence sync: %#x", eglGetError());
+ return false;
+ }
+
+ EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+ 2000000000 /*2 sec*/);
+ EGLint error = eglGetError();
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (result != EGL_CONDITION_SATISFIED_KHR) {
+ if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGW("fence wait timed out");
+ } else {
+ ALOGW("error waiting on EGL fence: %#x", error);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool GLES20RenderEngine::waitFence(base::unique_fd fenceFd) {
+ if (!GLExtensions::getInstance().hasNativeFenceSync() ||
+ !GLExtensions::getInstance().hasWaitSync()) {
+ return false;
+ }
+
+ EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
+ return false;
+ }
+
+ // fenceFd is now owned by EGLSync
+ (void)fenceFd.release();
+
+ // XXX: The spec draft is inconsistent as to whether this should return an
+ // EGLint or void. Ignore the return value for now, as it's not strictly
+ // needed.
+ eglWaitSyncKHR(mEGLDisplay, sync, 0);
+ EGLint error = eglGetError();
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (error != EGL_SUCCESS) {
+ ALOGE("failed to wait for EGL native fence sync: %#x", error);
+ return false;
+ }
+
+ return true;
+}
+
+void GLES20RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+ glClearColor(red, green, blue, alpha);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+void GLES20RenderEngine::fillRegionWithColor(const Region& region, float red, float green,
+ float blue, float alpha) {
+ size_t c;
+ Rect const* r = region.getArray(&c);
+ Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
+ Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+ for (size_t i = 0; i < c; i++, r++) {
+ position[i * 6 + 0].x = r->left;
+ position[i * 6 + 0].y = r->top;
+ position[i * 6 + 1].x = r->left;
+ position[i * 6 + 1].y = r->bottom;
+ position[i * 6 + 2].x = r->right;
+ position[i * 6 + 2].y = r->bottom;
+ position[i * 6 + 3].x = r->left;
+ position[i * 6 + 3].y = r->top;
+ position[i * 6 + 4].x = r->right;
+ position[i * 6 + 4].y = r->bottom;
+ position[i * 6 + 5].x = r->right;
+ position[i * 6 + 5].y = r->top;
+ }
+ setupFillWithColor(red, green, blue, alpha);
+ drawMesh(mesh);
+}
+
+void GLES20RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
+ glScissor(left, bottom, right, top);
+ glEnable(GL_SCISSOR_TEST);
+}
+
+void GLES20RenderEngine::disableScissor() {
+ glDisable(GL_SCISSOR_TEST);
+}
+
+void GLES20RenderEngine::genTextures(size_t count, uint32_t* names) {
+ glGenTextures(count, names);
+}
+
+void GLES20RenderEngine::deleteTextures(size_t count, uint32_t const* names) {
+ glDeleteTextures(count, names);
+}
+
+void GLES20RenderEngine::bindExternalTextureImage(uint32_t texName,
+ const Image& image) {
+ const GLImage& glImage = static_cast<const GLImage&>(image);
+ const GLenum target = GL_TEXTURE_EXTERNAL_OES;
+
+ glBindTexture(target, texName);
+ if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) {
+ glEGLImageTargetTexture2DOES(target,
+ static_cast<GLeglImageOES>(glImage.getEGLImage()));
+ }
+}
+
+void GLES20RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
+ glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+}
+
+status_t GLES20RenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
+ GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
+ EGLImageKHR eglImage = glFramebuffer->getEGLImage();
+ uint32_t textureName = glFramebuffer->getTextureName();
+ uint32_t framebufferName = glFramebuffer->getFramebufferName();
+
+ // Bind the texture and turn our EGLImage into a texture
+ glBindTexture(GL_TEXTURE_2D, textureName);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage);
+
+ // Bind the Framebuffer to render into
+ glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, textureName, 0);
+
+ mRenderToFbo = true;
+
+ uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES,
+ "glCheckFramebufferStatusOES error %d", glStatus);
+
+ return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
+}
+
+void GLES20RenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
+ mRenderToFbo = false;
+
+ // back to main framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // Workaround for b/77935566 to force the EGL driver to release the
+ // screenshot buffer
+ setScissor(0, 0, 0, 0);
+ clearWithColor(0.0, 0.0, 0.0, 0.0);
+ disableScissor();
+}
+
+void GLES20RenderEngine::checkErrors() const {
+ do {
+ // there could be more than one error flag
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) break;
+ ALOGE("GL error 0x%04x", int(error));
+ } while (true);
+}
+
+void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+ ui::Transform::orientation_flags rotation) {
+ int32_t l = sourceCrop.left;
+ int32_t r = sourceCrop.right;
+ int32_t b = sourceCrop.bottom;
+ int32_t t = sourceCrop.top;
+ if (mRenderToFbo) {
+ std::swap(t, b);
+ }
+ mat4 m = mat4::ortho(l, r, b, t, 0, 1);
+
+ // Apply custom rotation to the projection.
+ float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
+ switch (rotation) {
+ case ui::Transform::ROT_0:
+ break;
+ case ui::Transform::ROT_90:
+ m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
+ break;
+ case ui::Transform::ROT_180:
+ m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m;
+ break;
+ case ui::Transform::ROT_270:
+ m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m;
+ break;
+ default:
+ break;
+ }
+
+ glViewport(0, 0, vpw, vph);
+ mState.setProjectionMatrix(m);
+ mVpWidth = vpw;
+ mVpHeight = vph;
+}
+
+void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque,
+ bool disableTexture, const half4& color) {
+ mState.setPremultipliedAlpha(premultipliedAlpha);
+ mState.setOpaque(opaque);
+ mState.setColor(color);
+
+ if (disableTexture) {
+ mState.disableTexture();
+ }
+
+ if (color.a < 1.0f || !opaque) {
+ glEnable(GL_BLEND);
+ glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glDisable(GL_BLEND);
+ }
+}
+
+void GLES20RenderEngine::setSourceY410BT2020(bool enable) {
+ mState.setY410BT2020(enable);
+}
+
+void GLES20RenderEngine::setSourceDataSpace(Dataspace source) {
+ mDataSpace = source;
+}
+
+void GLES20RenderEngine::setOutputDataSpace(Dataspace dataspace) {
+ mOutputDataSpace = dataspace;
+}
+
+void GLES20RenderEngine::setDisplayMaxLuminance(const float maxLuminance) {
+ mState.setDisplayMaxLuminance(maxLuminance);
+}
+
+void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) {
+ GLuint target = texture.getTextureTarget();
+ glBindTexture(target, texture.getTextureName());
+ GLenum filter = GL_NEAREST;
+ if (texture.getFiltering()) {
+ filter = GL_LINEAR;
+ }
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
+
+ mState.setTexture(texture);
+}
+
+void GLES20RenderEngine::setupLayerBlackedOut() {
+ glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
+ Texture texture(Texture::TEXTURE_2D, mProtectedTexName);
+ texture.setDimensions(1, 1); // FIXME: we should get that from somewhere
+ mState.setTexture(texture);
+}
+
+void GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
+ mState.setColorMatrix(colorTransform);
+}
+
+void GLES20RenderEngine::disableTexturing() {
+ mState.disableTexture();
+}
+
+void GLES20RenderEngine::disableBlending() {
+ glDisable(GL_BLEND);
+}
+
+void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
+ mState.setPremultipliedAlpha(true);
+ mState.setOpaque(false);
+ mState.setColor(half4(r, g, b, a));
+ mState.disableTexture();
+ glDisable(GL_BLEND);
+}
+
+void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
+ ATRACE_CALL();
+ if (mesh.getTexCoordsSize()) {
+ glEnableVertexAttribArray(Program::texCoords);
+ glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE,
+ mesh.getByteStride(), mesh.getTexCoords());
+ }
+
+ glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
+ mesh.getByteStride(), mesh.getPositions());
+
+ // By default, DISPLAY_P3 is the only supported wide color output. However,
+ // when HDR content is present, hardware composer may be able to handle
+ // BT2020 data space, in that case, the output data space is set to be
+ // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need
+ // to respect this and convert non-HDR content to HDR format.
+ if (mUseColorManagement) {
+ Description managedState = mState;
+ Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK);
+ Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
+ Dataspace outputStandard = static_cast<Dataspace>(mOutputDataSpace &
+ Dataspace::STANDARD_MASK);
+ Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
+ Dataspace::TRANSFER_MASK);
+ bool needsXYZConversion = needsXYZTransformMatrix();
+
+ if (needsXYZConversion) {
+ // The supported input color spaces are standard RGB, Display P3 and BT2020.
+ switch (inputStandard) {
+ case Dataspace::STANDARD_DCI_P3:
+ managedState.setInputTransformMatrix(mDisplayP3ToXyz);
+ break;
+ case Dataspace::STANDARD_BT2020:
+ managedState.setInputTransformMatrix(mBt2020ToXyz);
+ break;
+ default:
+ managedState.setInputTransformMatrix(mSrgbToXyz);
+ break;
+ }
+
+ // The supported output color spaces are BT2020, Display P3 and standard RGB.
+ switch (outputStandard) {
+ case Dataspace::STANDARD_BT2020:
+ managedState.setOutputTransformMatrix(mXyzToBt2020);
+ break;
+ case Dataspace::STANDARD_DCI_P3:
+ managedState.setOutputTransformMatrix(mXyzToDisplayP3);
+ break;
+ default:
+ managedState.setOutputTransformMatrix(mXyzToSrgb);
+ break;
+ }
+ } else if (inputStandard != outputStandard) {
+ // At this point, the input data space and output data space could be both
+ // HDR data spaces, but they match each other, we do nothing in this case.
+ // In addition to the case above, the input data space could be
+ // - scRGB linear
+ // - scRGB non-linear
+ // - sRGB
+ // - Display P3
+ // The output data spaces could be
+ // - sRGB
+ // - Display P3
+ if (outputStandard == Dataspace::STANDARD_BT709) {
+ managedState.setOutputTransformMatrix(mDisplayP3ToSrgb);
+ } else if (outputStandard == Dataspace::STANDARD_DCI_P3) {
+ managedState.setOutputTransformMatrix(mSrgbToDisplayP3);
+ }
+ }
+
+ // we need to convert the RGB value to linear space and convert it back when:
+ // - there is a color matrix that is not an identity matrix, or
+ // - there is an output transform matrix that is not an identity matrix, or
+ // - the input transfer function doesn't match the output transfer function.
+ if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() ||
+ inputTransfer != outputTransfer) {
+ switch (inputTransfer) {
+ case Dataspace::TRANSFER_ST2084:
+ managedState.setInputTransferFunction(Description::TransferFunction::ST2084);
+ break;
+ case Dataspace::TRANSFER_HLG:
+ managedState.setInputTransferFunction(Description::TransferFunction::HLG);
+ break;
+ case Dataspace::TRANSFER_LINEAR:
+ managedState.setInputTransferFunction(Description::TransferFunction::LINEAR);
+ break;
+ default:
+ managedState.setInputTransferFunction(Description::TransferFunction::SRGB);
+ break;
+ }
+
+ switch (outputTransfer) {
+ case Dataspace::TRANSFER_ST2084:
+ managedState.setOutputTransferFunction(Description::TransferFunction::ST2084);
+ break;
+ case Dataspace::TRANSFER_HLG:
+ managedState.setOutputTransferFunction(Description::TransferFunction::HLG);
+ break;
+ default:
+ managedState.setOutputTransferFunction(Description::TransferFunction::SRGB);
+ break;
+ }
+ }
+
+ ProgramCache::getInstance().useProgram(managedState);
+
+ glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+
+ if (outputDebugPPMs) {
+ static uint64_t managedColorFrameCount = 0;
+ std::ostringstream out;
+ out << "/data/texture_out" << managedColorFrameCount++;
+ writePPM(out.str().c_str(), mVpWidth, mVpHeight);
+ }
+ } else {
+ ProgramCache::getInstance().useProgram(mState);
+
+ glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+ }
+
+ if (mesh.getTexCoordsSize()) {
+ glDisableVertexAttribArray(Program::texCoords);
+ }
+}
+
+size_t GLES20RenderEngine::getMaxTextureSize() const {
+ return mMaxTextureSize;
+}
+
+size_t GLES20RenderEngine::getMaxViewportDims() const {
+ return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
+}
+
+void GLES20RenderEngine::dump(String8& result) {
+ const GLExtensions& extensions = GLExtensions::getInstance();
+
+ result.appendFormat("EGL implementation : %s\n", extensions.getEGLVersion());
+ result.appendFormat("%s\n", extensions.getEGLExtensions());
+
+ result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
+ extensions.getVersion());
+ result.appendFormat("%s\n", extensions.getExtensions());
+ result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
+ dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
+ dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
+}
+
+GLES20RenderEngine::GlesVersion GLES20RenderEngine::parseGlesVersion(const char* str) {
+ int major, minor;
+ if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
+ if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) {
+ ALOGW("Unable to parse GL_VERSION string: \"%s\"", str);
+ return GLES_VERSION_1_0;
+ }
+ }
+
+ if (major == 1 && minor == 0) return GLES_VERSION_1_0;
+ if (major == 1 && minor >= 1) return GLES_VERSION_1_1;
+ if (major == 2 && minor >= 0) return GLES_VERSION_2_0;
+ if (major == 3 && minor >= 0) return GLES_VERSION_3_0;
+
+ ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor);
+ return GLES_VERSION_1_0;
+}
+
+bool GLES20RenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
+ const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
+ const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
+ return standard == Dataspace::STANDARD_BT2020 &&
+ (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
+}
+
+// For convenience, we want to convert the input color space to XYZ color space first,
+// and then convert from XYZ color space to output color space when
+// - SDR and HDR contents are mixed, either SDR content will be converted to HDR or
+// HDR content will be tone-mapped to SDR; Or,
+// - there are HDR PQ and HLG contents presented at the same time, where we want to convert
+// HLG content to PQ content.
+// In either case above, we need to operate the Y value in XYZ color space. Thus, when either
+// input data space or output data space is HDR data space, and the input transfer function
+// doesn't match the output transfer function, we would enable an intermediate transfrom to
+// XYZ color space.
+bool GLES20RenderEngine::needsXYZTransformMatrix() const {
+ const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace);
+ const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace);
+ const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
+ const Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
+ Dataspace::TRANSFER_MASK);
+
+ return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
+}
+
+void GLES20RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
+ mEGLDisplay = display;
+ mEGLConfig = config;
+ mEGLContext = ctxt;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
new file mode 100644
index 0000000..1abc5ba
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2013 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.
+ */
+
+#ifndef SF_GLES20RENDERENGINE_H_
+#define SF_GLES20RENDERENGINE_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <renderengine/RenderEngine.h>
+#include <renderengine/private/Description.h>
+
+#define EGL_NO_CONFIG ((EGLConfig)0)
+
+namespace android {
+
+class String8;
+
+namespace renderengine {
+
+class Mesh;
+class Texture;
+
+namespace gl {
+
+class GLImage;
+class GLSurface;
+
+class GLES20RenderEngine : public impl::RenderEngine {
+public:
+ static std::unique_ptr<GLES20RenderEngine> create(int hwcFormat, uint32_t featureFlags);
+ static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
+
+ GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
+ ~GLES20RenderEngine() override;
+
+ std::unique_ptr<Framebuffer> createFramebuffer() override;
+ std::unique_ptr<Surface> createSurface() override;
+ std::unique_ptr<Image> createImage() override;
+
+ void primeCache() const override;
+ bool isCurrent() const override;
+ bool setCurrentSurface(const Surface& surface) override;
+ void resetCurrentSurface() override;
+ base::unique_fd flush() override;
+ bool finish() override;
+ bool waitFence(base::unique_fd fenceFd) override;
+ void clearWithColor(float red, float green, float blue, float alpha) override;
+ void fillRegionWithColor(const Region& region, float red, float green, float blue,
+ float alpha) override;
+ void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) override;
+ void disableScissor() override;
+ void genTextures(size_t count, uint32_t* names) override;
+ void deleteTextures(size_t count, uint32_t const* names) override;
+ void bindExternalTextureImage(uint32_t texName, const Image& image) override;
+ void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) override;
+ status_t bindFrameBuffer(Framebuffer* framebuffer) override;
+ void unbindFrameBuffer(Framebuffer* framebuffer) override;
+ void checkErrors() const override;
+
+ // internal to RenderEngine
+ EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
+ EGLConfig getEGLConfig() const { return mEGLConfig; }
+
+protected:
+ void dump(String8& result) override;
+ void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+ ui::Transform::orientation_flags rotation) override;
+ void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+ const half4& color) override;
+ void setupLayerTexturing(const Texture& texture) override;
+ void setupLayerBlackedOut() override;
+ void setupFillWithColor(float r, float g, float b, float a) override;
+ void setupColorTransform(const mat4& colorTransform) override;
+ void disableTexturing() override;
+ void disableBlending() override;
+
+ // HDR and color management related functions and state
+ void setSourceY410BT2020(bool enable) override;
+ void setSourceDataSpace(ui::Dataspace source) override;
+ void setOutputDataSpace(ui::Dataspace dataspace) override;
+ void setDisplayMaxLuminance(const float maxLuminance) override;
+
+ // drawing
+ void drawMesh(const Mesh& mesh) override;
+
+ size_t getMaxTextureSize() const override;
+ size_t getMaxViewportDims() const override;
+
+private:
+ enum GlesVersion {
+ GLES_VERSION_1_0 = 0x10000,
+ GLES_VERSION_1_1 = 0x10001,
+ GLES_VERSION_2_0 = 0x20000,
+ GLES_VERSION_3_0 = 0x30000,
+ };
+
+ static GlesVersion parseGlesVersion(const char* str);
+
+ // A data space is considered HDR data space if it has BT2020 color space
+ // with PQ or HLG transfer function.
+ bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
+ bool needsXYZTransformMatrix() const;
+ void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
+
+ EGLDisplay mEGLDisplay;
+ EGLConfig mEGLConfig;
+ EGLContext mEGLContext;
+ GLuint mProtectedTexName;
+ GLint mMaxViewportDims[2];
+ GLint mMaxTextureSize;
+ GLuint mVpWidth;
+ GLuint mVpHeight;
+ Description mState;
+
+ mat4 mSrgbToDisplayP3;
+ mat4 mDisplayP3ToSrgb;
+ mat3 mSrgbToXyz;
+ mat3 mBt2020ToXyz;
+ mat3 mDisplayP3ToXyz;
+ mat4 mXyzToSrgb;
+ mat4 mXyzToDisplayP3;
+ mat4 mXyzToBt2020;
+
+ bool mRenderToFbo = false;
+
+ // Current dataspace of layer being rendered
+ ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
+
+ // Current output dataspace of the render engine
+ ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
+
+ // Whether device supports color management, currently color management
+ // supports sRGB, DisplayP3 color spaces.
+ const bool mUseColorManagement = false;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
+
+#endif /* SF_GLES20RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
similarity index 91%
rename from services/surfaceflinger/RenderEngine/GLExtensions.cpp
rename to services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
index dc09a37..6f50ea7 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
@@ -14,16 +14,17 @@
* limitations under the License.
*/
+#include "GLExtensions.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include "GLExtensions.h"
+ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::GLExtensions)
namespace android {
-// ---------------------------------------------------------------------------
-
-ANDROID_SINGLETON_STATIC_INSTANCE(GLExtensions)
+namespace renderengine {
+namespace gl {
SortedVector<String8> GLExtensions::parseExtensionString(char const* extensions) {
SortedVector<String8> list;
@@ -99,10 +100,6 @@
if (hasEGLExtension("EGL_KHR_wait_sync")) {
mHasWaitSync = true;
}
-
- if (hasEGLExtension("EGL_ANDROID_image_crop")) {
- mHasImageCrop = true;
- }
if (hasEGLExtension("EGL_EXT_protected_content")) {
mHasProtectedContent = true;
}
@@ -124,5 +121,6 @@
return mEGLExtensionList.indexOf(s) >= 0;
}
-// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
similarity index 90%
rename from services/surfaceflinger/RenderEngine/GLExtensions.h
rename to services/surfaceflinger/RenderEngine/gl/GLExtensions.h
index 0d8c10b..efdd8b7 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
@@ -20,17 +20,17 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Singleton.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include <utils/Singleton.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
namespace android {
-// ---------------------------------------------------------------------------
+namespace renderengine {
+namespace gl {
class GLExtensions : public Singleton<GLExtensions> {
friend class Singleton<GLExtensions>;
@@ -39,7 +39,6 @@
bool mHasNativeFenceSync = false;
bool mHasFenceSync = false;
bool mHasWaitSync = false;
- bool mHasImageCrop = false;
bool mHasProtectedContent = false;
bool mHasContextPriority = false;
@@ -66,7 +65,6 @@
bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
bool hasFenceSync() const { return mHasFenceSync; }
bool hasWaitSync() const { return mHasWaitSync; }
- bool hasImageCrop() const { return mHasImageCrop; }
bool hasProtectedContent() const { return mHasProtectedContent; }
bool hasContextPriority() const { return mHasContextPriority; }
@@ -84,7 +82,8 @@
bool hasEGLExtension(char const* extension) const;
};
-// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
#endif // ANDROID_SF_GLEXTENSION_H
diff --git a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp b/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp
new file mode 100644
index 0000000..6aca1c8
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018 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 "GLFramebuffer.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include "GLES20RenderEngine.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+GLFramebuffer::GLFramebuffer(const GLES20RenderEngine& engine)
+ : mEGLDisplay(engine.getEGLDisplay()),
+ mEGLImage(EGL_NO_IMAGE_KHR) {
+ glGenTextures(1, &mTextureName);
+ glGenFramebuffers(1, &mFramebufferName);
+}
+
+GLFramebuffer::~GLFramebuffer() {
+ glDeleteFramebuffers(1, &mFramebufferName);
+ glDeleteTextures(1, &mTextureName);
+ eglDestroyImageKHR(mEGLDisplay, mEGLImage);
+}
+
+bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) {
+ if (mEGLImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mEGLDisplay, mEGLImage);
+ mEGLImage = EGL_NO_IMAGE_KHR;
+ }
+
+ if (nativeBuffer) {
+ mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID,
+ nativeBuffer, nullptr);
+ if (mEGLImage == EGL_NO_IMAGE_KHR) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h b/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h
new file mode 100644
index 0000000..90b2248
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 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 <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <renderengine/Framebuffer.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLES20RenderEngine;
+
+class GLFramebuffer : public renderengine::Framebuffer {
+public:
+ explicit GLFramebuffer(const GLES20RenderEngine& engine);
+ ~GLFramebuffer() override;
+
+ bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) override;
+ EGLImageKHR getEGLImage() const { return mEGLImage; }
+ uint32_t getTextureName() const { return mTextureName; }
+ uint32_t getFramebufferName() const { return mFramebufferName; }
+
+private:
+ EGLDisplay mEGLDisplay;
+ EGLImageKHR mEGLImage;
+ uint32_t mTextureName, mFramebufferName;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Image.cpp b/services/surfaceflinger/RenderEngine/gl/GLImage.cpp
similarity index 60%
rename from services/surfaceflinger/RenderEngine/Image.cpp
rename to services/surfaceflinger/RenderEngine/gl/GLImage.cpp
index 0d06422..746f3e7 100644
--- a/services/surfaceflinger/RenderEngine/Image.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLImage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,30 +14,19 @@
* limitations under the License.
*/
-#include "Image.h"
+#include "GLImage.h"
#include <vector>
#include <log/log.h>
-
#include "GLExtensions.h"
-#include "RenderEngine.h"
+#include "GLES20RenderEngine.h"
namespace android {
-namespace RE {
+namespace renderengine {
+namespace gl {
-Image::~Image() = default;
-
-namespace impl {
-
-Image::Image(const RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
-
-Image::~Image() {
- setNativeWindowBuffer(nullptr, false, 0, 0);
-}
-
-static std::vector<EGLint> buildAttributeList(bool isProtected, int32_t cropWidth,
- int32_t cropHeight) {
+static std::vector<EGLint> buildAttributeList(bool isProtected) {
std::vector<EGLint> attrs;
attrs.reserve(16);
@@ -49,24 +38,18 @@
attrs.push_back(EGL_TRUE);
}
- if (cropWidth > 0 && cropHeight > 0) {
- attrs.push_back(EGL_IMAGE_CROP_LEFT_ANDROID);
- attrs.push_back(0);
- attrs.push_back(EGL_IMAGE_CROP_TOP_ANDROID);
- attrs.push_back(0);
- attrs.push_back(EGL_IMAGE_CROP_RIGHT_ANDROID);
- attrs.push_back(cropWidth);
- attrs.push_back(EGL_IMAGE_CROP_BOTTOM_ANDROID);
- attrs.push_back(cropHeight);
- }
-
attrs.push_back(EGL_NONE);
return attrs;
}
-bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
- int32_t cropHeight) {
+GLImage::GLImage(const GLES20RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
+
+GLImage::~GLImage() {
+ setNativeWindowBuffer(nullptr, false);
+}
+
+bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) {
if (mEGLImage != EGL_NO_IMAGE_KHR) {
if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
ALOGE("failed to destroy image: %#x", eglGetError());
@@ -75,7 +58,7 @@
}
if (buffer) {
- std::vector<EGLint> attrs = buildAttributeList(isProtected, cropWidth, cropHeight);
+ std::vector<EGLint> attrs = buildAttributeList(isProtected);
mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
static_cast<EGLClientBuffer>(buffer), attrs.data());
if (mEGLImage == EGL_NO_IMAGE_KHR) {
@@ -87,6 +70,6 @@
return true;
}
-} // namespace impl
-} // namespace RE
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLImage.h b/services/surfaceflinger/RenderEngine/gl/GLImage.h
new file mode 100644
index 0000000..f670783
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLImage.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 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 <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <android-base/macros.h>
+#include <renderengine/Image.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLES20RenderEngine;
+
+class GLImage : public renderengine::Image {
+public:
+ explicit GLImage(const GLES20RenderEngine& engine);
+ ~GLImage() override;
+
+ bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override;
+
+ EGLImageKHR getEGLImage() const { return mEGLImage; }
+
+private:
+ EGLDisplay mEGLDisplay;
+ EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
+
+ DISALLOW_COPY_AND_ASSIGN(GLImage);
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Surface.cpp b/services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
similarity index 68%
rename from services/surfaceflinger/RenderEngine/Surface.cpp
rename to services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
index 0d20f1f..ff9a252 100644
--- a/services/surfaceflinger/RenderEngine/Surface.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,32 +14,30 @@
* limitations under the License.
*/
-#include "Surface.h"
-
-#include "RenderEngine.h"
+#include "GLSurface.h"
#include <log/log.h>
+#include <ui/PixelFormat.h>
+#include "GLES20RenderEngine.h"
namespace android {
-namespace RE {
+namespace renderengine {
+namespace gl {
-Surface::~Surface() = default;
-
-namespace impl {
-
-Surface::Surface(const RenderEngine& engine)
+GLSurface::GLSurface(const GLES20RenderEngine& engine)
: mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) {
// RE does not assume any config when EGL_KHR_no_config_context is supported
if (mEGLConfig == EGL_NO_CONFIG_KHR) {
- mEGLConfig = RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false);
+ mEGLConfig = GLES20RenderEngine::chooseEglConfig(mEGLDisplay,
+ PIXEL_FORMAT_RGBA_8888, false);
}
}
-Surface::~Surface() {
+GLSurface::~GLSurface() {
setNativeWindow(nullptr);
}
-void Surface::setNativeWindow(ANativeWindow* window) {
+void GLSurface::setNativeWindow(ANativeWindow* window) {
if (mEGLSurface != EGL_NO_SURFACE) {
eglDestroySurface(mEGLDisplay, mEGLSurface);
mEGLSurface = EGL_NO_SURFACE;
@@ -51,7 +49,7 @@
}
}
-void Surface::swapBuffers() const {
+void GLSurface::swapBuffers() const {
if (!eglSwapBuffers(mEGLDisplay, mEGLSurface)) {
EGLint error = eglGetError();
@@ -64,7 +62,7 @@
}
}
-EGLint Surface::queryConfig(EGLint attrib) const {
+EGLint GLSurface::queryConfig(EGLint attrib) const {
EGLint value;
if (!eglGetConfigAttrib(mEGLDisplay, mEGLConfig, attrib, &value)) {
value = 0;
@@ -73,7 +71,7 @@
return value;
}
-EGLint Surface::querySurface(EGLint attrib) const {
+EGLint GLSurface::querySurface(EGLint attrib) const {
EGLint value;
if (!eglQuerySurface(mEGLDisplay, mEGLSurface, attrib, &value)) {
value = 0;
@@ -82,30 +80,30 @@
return value;
}
-int32_t Surface::queryRedSize() const {
+int32_t GLSurface::queryRedSize() const {
return queryConfig(EGL_RED_SIZE);
}
-int32_t Surface::queryGreenSize() const {
+int32_t GLSurface::queryGreenSize() const {
return queryConfig(EGL_GREEN_SIZE);
}
-int32_t Surface::queryBlueSize() const {
+int32_t GLSurface::queryBlueSize() const {
return queryConfig(EGL_BLUE_SIZE);
}
-int32_t Surface::queryAlphaSize() const {
+int32_t GLSurface::queryAlphaSize() const {
return queryConfig(EGL_ALPHA_SIZE);
}
-int32_t Surface::queryWidth() const {
+int32_t GLSurface::queryWidth() const {
return querySurface(EGL_WIDTH);
}
-int32_t Surface::queryHeight() const {
+int32_t GLSurface::queryHeight() const {
return querySurface(EGL_HEIGHT);
}
-} // namespace impl
-} // namespace RE
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Surface.h b/services/surfaceflinger/RenderEngine/gl/GLSurface.h
similarity index 61%
rename from services/surfaceflinger/RenderEngine/Surface.h
rename to services/surfaceflinger/RenderEngine/gl/GLSurface.h
index d4d3d8c..0b89c70 100644
--- a/services/surfaceflinger/RenderEngine/Surface.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLSurface.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -19,44 +19,23 @@
#include <cstdint>
#include <EGL/egl.h>
+#include <android-base/macros.h>
+#include <renderengine/Surface.h>
struct ANativeWindow;
namespace android {
-namespace RE {
+namespace renderengine {
+namespace gl {
-class Surface {
+class GLES20RenderEngine;
+
+class GLSurface final : public renderengine::Surface {
public:
- virtual ~Surface() = 0;
+ GLSurface(const GLES20RenderEngine& engine);
+ ~GLSurface() override;
- virtual void setCritical(bool enable) = 0;
- virtual void setAsync(bool enable) = 0;
-
- virtual void setNativeWindow(ANativeWindow* window) = 0;
- virtual void swapBuffers() const = 0;
-
- virtual int32_t queryRedSize() const = 0;
- virtual int32_t queryGreenSize() const = 0;
- virtual int32_t queryBlueSize() const = 0;
- virtual int32_t queryAlphaSize() const = 0;
-
- virtual int32_t queryWidth() const = 0;
- virtual int32_t queryHeight() const = 0;
-};
-
-namespace impl {
-
-class RenderEngine;
-
-class Surface final : public RE::Surface {
-public:
- Surface(const RenderEngine& engine);
- ~Surface();
-
- Surface(const Surface&) = delete;
- Surface& operator=(const Surface&) = delete;
-
- // RE::Surface implementation
+ // renderengine::Surface implementation
void setCritical(bool enable) override { mCritical = enable; }
void setAsync(bool enable) override { mAsync = enable; }
@@ -71,15 +50,13 @@
int32_t queryWidth() const override;
int32_t queryHeight() const override;
+ bool getAsync() const { return mAsync; }
+ EGLSurface getEGLSurface() const { return mEGLSurface; }
+
private:
EGLint queryConfig(EGLint attrib) const;
EGLint querySurface(EGLint attrib) const;
- // methods internal to RenderEngine
- friend class RenderEngine;
- bool getAsync() const { return mAsync; }
- EGLSurface getEGLSurface() const { return mEGLSurface; }
-
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
@@ -88,8 +65,10 @@
ANativeWindow* mWindow = nullptr;
EGLSurface mEGLSurface = EGL_NO_SURFACE;
+
+ DISALLOW_COPY_AND_ASSIGN(GLSurface);
};
-} // namespace impl
-} // namespace RE
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/gl/Program.cpp
similarity index 97%
rename from services/surfaceflinger/RenderEngine/Program.cpp
rename to services/surfaceflinger/RenderEngine/gl/Program.cpp
index fe536f0..c8d6cf9 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/Program.cpp
@@ -14,17 +14,18 @@
* limitations under the License.
*/
+#include "Program.h"
+
#include <stdint.h>
#include <log/log.h>
-#include <utils/String8.h>
-
#include <math/mat4.h>
-#include "Description.h"
-#include "Program.h"
+#include <utils/String8.h>
#include "ProgramCache.h"
namespace android {
+namespace renderengine {
+namespace gl {
Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
: mInitialized(false) {
@@ -152,4 +153,6 @@
glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray());
}
-} /* namespace android */
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/gl/Program.h
similarity index 93%
rename from services/surfaceflinger/RenderEngine/Program.h
rename to services/surfaceflinger/RenderEngine/gl/Program.h
index ae796c5..bb429ef 100644
--- a/services/surfaceflinger/RenderEngine/Program.h
+++ b/services/surfaceflinger/RenderEngine/gl/Program.h
@@ -20,14 +20,16 @@
#include <stdint.h>
#include <GLES2/gl2.h>
-
-#include "Description.h"
+#include <renderengine/private/Description.h>
#include "ProgramCache.h"
namespace android {
class String8;
+namespace renderengine {
+namespace gl {
+
/*
* Abstracts a GLSL program comprising a vertex and fragment shader
*/
@@ -86,6 +88,8 @@
GLint mOutputTransformMatrixLoc;
};
-} /* namespace android */
+} // namespace gl
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_PROGRAM_H */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
similarity index 98%
rename from services/surfaceflinger/RenderEngine/ProgramCache.cpp
rename to services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
index 9dc6858..a19c1f1 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
@@ -16,18 +16,20 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <utils/String8.h>
-#include <utils/Trace.h>
-
-#include "Description.h"
-#include "Program.h"
#include "ProgramCache.h"
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <renderengine/private/Description.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+#include "Program.h"
+
+ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::ProgramCache)
+
namespace android {
-// -----------------------------------------------------------------------------------------------
+namespace renderengine {
+namespace gl {
/*
* A simple formatter class to automatically add the endl and
@@ -74,15 +76,11 @@
return f;
}
-// -----------------------------------------------------------------------------------------------
-
-ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)
-
ProgramCache::ProgramCache() {}
ProgramCache::~ProgramCache() {}
-void ProgramCache::primeCache(bool hasWideColor) {
+void ProgramCache::primeCache(bool useColorManagement) {
uint32_t shaderCount = 0;
uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK;
// Prime the cache for all combinations of the above masks,
@@ -105,7 +103,7 @@
}
// Prime for sRGB->P3 conversion
- if (hasWideColor) {
+ if (useColorManagement) {
Key shaderKey;
shaderKey.set(Key::BLEND_MASK | Key::TEXTURE_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK |
Key::INPUT_TF_MASK | Key::OUTPUT_TF_MASK,
@@ -686,4 +684,6 @@
}
}
-} /* namespace android */
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/ProgramCache.h
rename to services/surfaceflinger/RenderEngine/gl/ProgramCache.h
index 983e7ba..ea77a2d 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
@@ -18,19 +18,23 @@
#define SF_RENDER_ENGINE_PROGRAMCACHE_H
#include <GLES2/gl2.h>
-
+#include <renderengine/private/Description.h>
#include <utils/KeyedVector.h>
#include <utils/Singleton.h>
#include <utils/TypeHelpers.h>
-#include "Description.h"
-
namespace android {
+class String8;
+
+namespace renderengine {
+
class Description;
+
+namespace gl {
+
class Formatter;
class Program;
-class String8;
/*
* This class generates GLSL programs suitable to handle a given
@@ -161,7 +165,7 @@
~ProgramCache();
// Generate shaders to populate the cache
- void primeCache(bool hasWideColor);
+ void primeCache(bool useColorManagement);
// useProgram lookup a suitable program in the cache or generates one
// if none can be found.
@@ -190,8 +194,11 @@
DefaultKeyedVector<Key, Program*> mCache;
};
-ANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key)
+} // namespace gl
+} // namespace renderengine
-} /* namespace android */
+ANDROID_BASIC_TYPES_TRAITS(renderengine::gl::ProgramCache::Key)
+
+} // namespace android
#endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h b/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
new file mode 100644
index 0000000..6595466
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 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 <cstdint>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+
+class Framebuffer {
+public:
+ virtual ~Framebuffer() = default;
+
+ virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) = 0;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Image.h b/services/surfaceflinger/RenderEngine/include/renderengine/Image.h
new file mode 100644
index 0000000..85ec91a
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Image.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 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
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+
+class Image {
+public:
+ virtual ~Image() = default;
+ virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) = 0;
+};
+
+} // namespace renderengine
+} // namespace android
+
diff --git a/services/surfaceflinger/RenderEngine/Mesh.h b/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/Mesh.h
rename to services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
index d0a9ac0..39ca2f7 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
@@ -20,6 +20,7 @@
#include <stdint.h>
namespace android {
+namespace renderengine {
class Mesh {
public:
@@ -97,5 +98,6 @@
Primitive mPrimitive;
};
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_MESH_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
new file mode 100644
index 0000000..17d8782
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2013 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.
+ */
+
+#ifndef SF_RENDERENGINE_H_
+#define SF_RENDERENGINE_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <memory>
+
+#include <android-base/unique_fd.h>
+#include <math/mat4.h>
+#include <renderengine/Framebuffer.h>
+#include <renderengine/Image.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Transform.h>
+
+/**
+ * Allows to set RenderEngine backend to GLES (default) or Vulkan (NOT yet supported).
+ */
+#define PROPERTY_DEBUG_RENDERENGINE_BACKEND "debug.renderengine.backend"
+
+struct ANativeWindowBuffer;
+
+namespace android {
+
+class String8;
+class Rect;
+class Region;
+
+namespace renderengine {
+
+class BindNativeBufferAsFramebuffer;
+class Image;
+class Mesh;
+class Surface;
+class Texture;
+
+namespace impl {
+class RenderEngine;
+}
+
+class RenderEngine {
+public:
+ enum FeatureFlag {
+ USE_COLOR_MANAGEMENT = 1 << 0, // Device manages color
+ USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
+ };
+
+ static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags);
+
+ virtual ~RenderEngine() = 0;
+
+ virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0;
+ virtual std::unique_ptr<Surface> createSurface() = 0;
+ virtual std::unique_ptr<Image> createImage() = 0;
+
+ virtual void primeCache() const = 0;
+
+ // dump the extension strings. always call the base class.
+ virtual void dump(String8& result) = 0;
+
+ virtual bool useNativeFenceSync() const = 0;
+ virtual bool useWaitSync() const = 0;
+
+ virtual bool isCurrent() const = 0;
+ virtual bool setCurrentSurface(const Surface& surface) = 0;
+ virtual void resetCurrentSurface() = 0;
+
+ // helpers
+ // flush submits RenderEngine command stream for execution and returns a
+ // native fence fd that is signaled when the execution has completed. It
+ // returns -1 on errors.
+ virtual base::unique_fd flush() = 0;
+ // finish waits until RenderEngine command stream has been executed. It
+ // returns false on errors.
+ virtual bool finish() = 0;
+ // waitFence inserts a wait on an external fence fd to RenderEngine
+ // command stream. It returns false on errors.
+ virtual bool waitFence(base::unique_fd fenceFd) = 0;
+
+ virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
+ virtual void fillRegionWithColor(const Region& region, float red, float green,
+ float blue, float alpha) = 0;
+
+ virtual void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) = 0;
+ virtual void disableScissor() = 0;
+ virtual void genTextures(size_t count, uint32_t* names) = 0;
+ virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
+ virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
+ virtual void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) = 0;
+ // When binding a native buffer, it must be done before setViewportAndProjection
+ // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
+ virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
+ virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0;
+
+ // set-up
+ virtual void checkErrors() const = 0;
+ virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+ ui::Transform::orientation_flags rotation) = 0;
+ virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+ const half4& color) = 0;
+ virtual void setupLayerTexturing(const Texture& texture) = 0;
+ virtual void setupLayerBlackedOut() = 0;
+ virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
+ virtual void setupColorTransform(const mat4& /* colorTransform */) = 0;
+ virtual void disableTexturing() = 0;
+ virtual void disableBlending() = 0;
+
+ // HDR and color management support
+ virtual void setSourceY410BT2020(bool enable) = 0;
+ virtual void setSourceDataSpace(ui::Dataspace source) = 0;
+ virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0;
+ virtual void setDisplayMaxLuminance(const float maxLuminance) = 0;
+
+ // drawing
+ virtual void drawMesh(const Mesh& mesh) = 0;
+
+ // queries
+ virtual size_t getMaxTextureSize() const = 0;
+ virtual size_t getMaxViewportDims() const = 0;
+};
+
+class BindNativeBufferAsFramebuffer {
+public:
+ BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
+ : mEngine(engine),
+ mFramebuffer(mEngine.createFramebuffer()),
+ mStatus(NO_ERROR) {
+ mStatus = mFramebuffer->setNativeWindowBuffer(buffer) ?
+ mEngine.bindFrameBuffer(mFramebuffer.get()) : NO_MEMORY;
+ }
+ ~BindNativeBufferAsFramebuffer() {
+ mFramebuffer->setNativeWindowBuffer(nullptr);
+ mEngine.unbindFrameBuffer(mFramebuffer.get());
+ }
+ status_t getStatus() const { return mStatus; }
+
+private:
+ RenderEngine& mEngine;
+ std::unique_ptr<Framebuffer> mFramebuffer;
+ status_t mStatus;
+};
+
+namespace impl {
+
+// impl::RenderEngine contains common implementation that is graphics back-end agnostic.
+class RenderEngine : public renderengine::RenderEngine {
+public:
+ virtual ~RenderEngine() = 0;
+
+ bool useNativeFenceSync() const override;
+ bool useWaitSync() const override;
+ void setupColorTransform(const mat4& /* colorTransform */) override {}
+
+protected:
+ RenderEngine(uint32_t featureFlags);
+ const uint32_t mFeatureFlags;
+};
+
+} // namespace impl
+} // namespace renderengine
+} // namespace android
+
+#endif /* SF_RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h b/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h
new file mode 100644
index 0000000..3343e1f
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 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 <cstdint>
+
+struct ANativeWindow;
+
+namespace android {
+namespace renderengine {
+
+class Surface {
+public:
+ virtual ~Surface() = default;
+
+ virtual void setCritical(bool enable) = 0;
+ virtual void setAsync(bool enable) = 0;
+
+ virtual void setNativeWindow(ANativeWindow* window) = 0;
+ virtual void swapBuffers() const = 0;
+
+ virtual int32_t queryRedSize() const = 0;
+ virtual int32_t queryGreenSize() const = 0;
+ virtual int32_t queryBlueSize() const = 0;
+ virtual int32_t queryAlphaSize() const = 0;
+
+ virtual int32_t queryWidth() const = 0;
+ virtual int32_t queryHeight() const = 0;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Texture.h b/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
similarity index 94%
rename from services/surfaceflinger/RenderEngine/Texture.h
rename to services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
index 56b6b31..fb3e0cc 100644
--- a/services/surfaceflinger/RenderEngine/Texture.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
@@ -14,22 +14,17 @@
* limitations under the License.
*/
-#include <math/mat4.h>
-#include <stdint.h>
-
#ifndef SF_RENDER_ENGINE_TEXTURE_H
#define SF_RENDER_ENGINE_TEXTURE_H
+#include <stdint.h>
+
+#include <math/mat4.h>
+
namespace android {
+namespace renderengine {
class Texture {
- uint32_t mTextureName;
- uint32_t mTextureTarget;
- size_t mWidth;
- size_t mHeight;
- bool mFiltering;
- mat4 mTextureMatrix;
-
public:
enum Target { TEXTURE_2D = 0x0DE1, TEXTURE_EXTERNAL = 0x8D65 };
@@ -50,7 +45,16 @@
bool getFiltering() const;
size_t getWidth() const;
size_t getHeight() const;
+
+private:
+ uint32_t mTextureName;
+ uint32_t mTextureTarget;
+ size_t mWidth;
+ size_t mHeight;
+ bool mFiltering;
+ mat4 mTextureMatrix;
};
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_TEXTURE_H */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
similarity index 92%
rename from services/surfaceflinger/RenderEngine/Description.h
rename to services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
index 6ebb340..a6301ae 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-#include <GLES2/gl2.h>
-#include "Texture.h"
-
#ifndef SF_RENDER_ENGINE_DESCRIPTION_H_
#define SF_RENDER_ENGINE_DESCRIPTION_H_
-namespace android {
+#include <renderengine/Texture.h>
+namespace android {
+namespace renderengine {
+
+namespace gl {
class Program;
+class ProgramCache;
+}
/*
* This holds the state of the rendering engine. This class is used
@@ -63,8 +66,8 @@
void setDisplayMaxLuminance(const float maxLuminance);
private:
- friend class Program;
- friend class ProgramCache;
+ friend class gl::Program;
+ friend class gl::ProgramCache;
// whether textures are premultiplied
bool mPremultipliedAlpha = false;
@@ -94,6 +97,7 @@
mat4 mOutputTransformMatrix;
};
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_DESCRIPTION_H_ */
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
similarity index 88%
rename from services/surfaceflinger/DispSync.cpp
rename to services/surfaceflinger/Scheduler/DispSync.cpp
index 37dc27d..54a1b51 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -28,7 +28,6 @@
#include <utils/String8.h>
#include <utils/Thread.h>
#include <utils/Trace.h>
-#include <utils/Vector.h>
#include <ui/FenceTime.h>
@@ -41,6 +40,10 @@
namespace android {
+DispSync::~DispSync() = default;
+
+namespace impl {
+
// Setting this to true enables verbose tracing that can be used to debug
// vsync event model or phase issues.
static const bool kTraceDetailedInfo = false;
@@ -94,7 +97,7 @@
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
while (true) {
- Vector<CallbackInvocation> callbackInvocations;
+ std::vector<CallbackInvocation> callbackInvocations;
nsecs_t targetTime = 0;
@@ -187,7 +190,7 @@
// allowing any past events to fire
listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;
- mEventListeners.push(listener);
+ mEventListeners.push_back(listener);
mCond.signal();
@@ -198,9 +201,10 @@
if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
- for (size_t i = 0; i < mEventListeners.size(); i++) {
- if (mEventListeners[i].mCallback == callback) {
- mEventListeners.removeAt(i);
+ for (std::vector<EventListener>::iterator it = mEventListeners.begin();
+ it != mEventListeners.end(); ++it) {
+ if (it->mCallback == callback) {
+ mEventListeners.erase(it);
mCond.signal();
return NO_ERROR;
}
@@ -213,11 +217,10 @@
if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
- for (size_t i = 0; i < mEventListeners.size(); i++) {
- if (mEventListeners[i].mCallback == callback) {
- EventListener& listener = mEventListeners.editItemAt(i);
- const nsecs_t oldPhase = listener.mPhase;
- listener.mPhase = phase;
+ for (auto& eventListener : mEventListeners) {
+ if (eventListener.mCallback == callback) {
+ const nsecs_t oldPhase = eventListener.mPhase;
+ eventListener.mPhase = phase;
// Pretend that the last time this event was handled at the same frame but with the
// new offset to allow for a seamless offset change without double-firing or
@@ -228,7 +231,7 @@
} else if (diff < -mPeriod / 2) {
diff += mPeriod;
}
- listener.mLastEventTime -= diff;
+ eventListener.mLastEventTime -= diff;
mCond.signal();
return NO_ERROR;
}
@@ -237,14 +240,6 @@
return BAD_VALUE;
}
- // This method is only here to handle the !SurfaceFlinger::hasSyncFramework
- // case.
- bool hasAnyEventListeners() {
- if (kTraceDetailedInfo) ATRACE_CALL();
- Mutex::Autolock lock(mMutex);
- return !mEventListeners.empty();
- }
-
private:
struct EventListener {
const char* mName;
@@ -274,23 +269,23 @@
return nextEventTime;
}
- Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
+ std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
if (kTraceDetailedInfo) ATRACE_CALL();
ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
- Vector<CallbackInvocation> callbackInvocations;
+ std::vector<CallbackInvocation> callbackInvocations;
nsecs_t onePeriodAgo = now - mPeriod;
- for (size_t i = 0; i < mEventListeners.size(); i++) {
- nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], onePeriodAgo);
+ for (auto& eventListener : mEventListeners) {
+ nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
if (t < now) {
CallbackInvocation ci;
- ci.mCallback = mEventListeners[i].mCallback;
+ ci.mCallback = eventListener.mCallback;
ci.mEventTime = t;
- ALOGV("[%s] [%s] Preparing to fire", mName, mEventListeners[i].mName);
- callbackInvocations.push(ci);
- mEventListeners.editItemAt(i).mLastEventTime = t;
+ ALOGV("[%s] [%s] Preparing to fire", mName, eventListener.mName);
+ callbackInvocations.push_back(ci);
+ eventListener.mLastEventTime = t;
}
}
@@ -348,7 +343,7 @@
return t;
}
- void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
+ void fireCallbackInvocations(const std::vector<CallbackInvocation>& callbacks) {
if (kTraceDetailedInfo) ATRACE_CALL();
for (size_t i = 0; i < callbacks.size(); i++) {
callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
@@ -366,7 +361,7 @@
int64_t mFrameNumber;
- Vector<EventListener> mEventListeners;
+ std::vector<EventListener> mEventListeners;
Mutex mMutex;
Condition mCond;
@@ -408,22 +403,18 @@
reset();
beginResync();
- if (kTraceDetailedInfo) {
- // If we're not getting present fences then the ZeroPhaseTracer
- // would prevent HW vsync event from ever being turned off.
- // Even if we're just ignoring the fences, the zero-phase tracing is
- // not needed because any time there is an event registered we will
- // turn on the HW vsync events.
- if (!mIgnorePresentFences && kEnableZeroPhaseTracer) {
- mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
- addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
- }
+ if (kTraceDetailedInfo && kEnableZeroPhaseTracer) {
+ mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
+ addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
}
}
void DispSync::reset() {
Mutex::Autolock lock(mMutex);
+ resetLocked();
+}
+void DispSync::resetLocked() {
mPhase = 0;
mReferenceTime = 0;
mModelUpdated = false;
@@ -436,6 +427,10 @@
bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
Mutex::Autolock lock(mMutex);
+ if (mIgnorePresentFences) {
+ return true;
+ }
+
mPresentFences[mPresentSampleOffset] = fenceTime;
mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES;
mNumResyncSamplesSincePresent = 0;
@@ -481,12 +476,10 @@
}
if (mIgnorePresentFences) {
- // If we don't have the sync framework we will never have
- // addPresentFence called. This means we have no way to know whether
+ // If we're ignoring the present fences we have no way to know whether
// or not we're synchronized with the HW vsyncs, so we just request
- // that the HW vsync events be turned on whenever we need to generate
- // SW vsync events.
- return mThread->hasAnyEventListeners();
+ // that the HW vsync events be turned on.
+ return true;
}
// Check against kErrorThreshold / 2 to add some hysteresis before having to
@@ -522,12 +515,27 @@
void DispSync::setPeriod(nsecs_t period) {
Mutex::Autolock lock(mMutex);
- mPeriod = period;
+ mPeriodBase = mPeriod = period;
mPhase = 0;
mReferenceTime = 0;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}
+void DispSync::scalePeriod(HWC2::Device::FrequencyScaler frequencyScaler) {
+ Mutex::Autolock lock(mMutex);
+
+ // if only 1 of the properties is updated, we will get to this
+ // point "attempting" to set the scale to 1 when it is already
+ // 1. Check that special case so that we don't do a useless
+ // update of the model.
+ if ((frequencyScaler.multiplier == 1) &&
+ (frequencyScaler.divisor == 1) &&
+ (mPeriod == mPeriodBase)) return;
+
+ mPeriod = mPeriodBase * frequencyScaler.multiplier / frequencyScaler.divisor;
+ mThread->updateModel(mPeriod, mPhase, mReferenceTime);
+}
+
nsecs_t DispSync::getPeriod() {
// lock mutex as mPeriod changes multiple times in updateModelLocked
Mutex::Autolock lock(mMutex);
@@ -552,7 +560,7 @@
// Exclude the min and max from the average
durationSum -= minDuration + maxDuration;
- mPeriod = durationSum / (mNumResyncSamples - 3);
+ mPeriodBase = mPeriod = durationSum / (mNumResyncSamples - 3);
ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
@@ -660,6 +668,14 @@
return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
}
+void DispSync::setIgnorePresentFences(bool ignore) {
+ Mutex::Autolock lock(mMutex);
+ if (mIgnorePresentFences != ignore) {
+ mIgnorePresentFences = ignore;
+ resetLocked();
+ }
+}
+
void DispSync::dump(String8& result) const {
Mutex::Autolock lock(mMutex);
result.appendFormat("present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
@@ -710,4 +726,6 @@
result.appendFormat("current monotonic time: %" PRId64 "\n", now);
}
+} // namespace impl
+
} // namespace android
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
similarity index 75%
rename from services/surfaceflinger/DispSync.h
rename to services/surfaceflinger/Scheduler/DispSync.h
index 077256a..b3aef2d 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -24,6 +24,7 @@
#include <utils/Timers.h>
#include <ui/FenceTime.h>
+#include <DisplayHardware/HWC2.h>
#include <memory>
@@ -31,6 +32,37 @@
class String8;
class FenceTime;
+
+class DispSync {
+public:
+ class Callback {
+ public:
+ virtual ~Callback() = default;
+ virtual void onDispSyncEvent(nsecs_t when) = 0;
+ };
+
+ virtual ~DispSync();
+
+ virtual void reset() = 0;
+ virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
+ virtual void beginResync() = 0;
+ virtual bool addResyncSample(nsecs_t timestamp) = 0;
+ virtual void endResync() = 0;
+ virtual void setPeriod(nsecs_t period) = 0;
+ virtual void scalePeriod(HWC2::Device::FrequencyScaler) = 0;
+ virtual nsecs_t getPeriod() = 0;
+ virtual void setRefreshSkipCount(int count) = 0;
+ virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) = 0;
+ virtual status_t removeEventListener(Callback* callback) = 0;
+ virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0;
+ virtual nsecs_t computeNextRefresh(int periodOffset) const = 0;
+ virtual void setIgnorePresentFences(bool ignore) = 0;
+
+ virtual void dump(String8& result) const = 0;
+};
+
+namespace impl {
+
class DispSyncThread;
// DispSync maintains a model of the periodic hardware-based vsync events of a
@@ -46,21 +78,15 @@
// current model accurately represents the hardware event times it will return
// false to indicate that a resynchronization (via addResyncSample) is not
// needed.
-class DispSync {
+class DispSync : public android::DispSync {
public:
- class Callback {
- public:
- virtual ~Callback(){};
- virtual void onDispSyncEvent(nsecs_t when) = 0;
- };
-
explicit DispSync(const char* name);
- ~DispSync();
+ ~DispSync() override;
void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset);
// reset clears the resync samples and error value.
- void reset();
+ void reset() override;
// addPresentFence adds a fence for use in validating the current vsync
// event model. The fence need not be signaled at the time
@@ -71,7 +97,7 @@
//
// This method should be called with the retire fence from each HWComposer
// set call that affects the display.
- bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
+ bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) override;
// The beginResync, addResyncSample, and endResync methods are used to re-
// synchronize the DispSync's model to the hardware vsync events. The re-
@@ -84,52 +110,67 @@
// is turned on (i.e. once immediately after it's turned on) and whenever
// addPresentFence returns true indicating that the model has drifted away
// from the hardware vsync events.
- void beginResync();
- bool addResyncSample(nsecs_t timestamp);
- void endResync();
+ void beginResync() override;
+ bool addResyncSample(nsecs_t timestamp) override;
+ void endResync() override;
// The setPeriod method sets the vsync event model's period to a specific
// value. This should be used to prime the model when a display is first
// turned on. It should NOT be used after that.
- void setPeriod(nsecs_t period);
+ void setPeriod(nsecs_t period) override;
+
+ // The scalePeriod method applies the multiplier and divisor to
+ // scale the vsync event model's period. The function is added
+ // for an experimental test mode and should not be used outside
+ // of that purpose.
+ void scalePeriod(HWC2::Device::FrequencyScaler frequencyScaler);
// The getPeriod method returns the current vsync period.
- nsecs_t getPeriod();
+ nsecs_t getPeriod() override;
// setRefreshSkipCount specifies an additional number of refresh
// cycles to skip. For example, on a 60Hz display, a skip count of 1
// will result in events happening at 30Hz. Default is zero. The idea
// is to sacrifice smoothness for battery life.
- void setRefreshSkipCount(int count);
+ void setRefreshSkipCount(int count) override;
// addEventListener registers a callback to be called repeatedly at the
// given phase offset from the hardware vsync events. The callback is
// called from a separate thread and it should return reasonably quickly
// (i.e. within a few hundred microseconds).
- status_t addEventListener(const char* name, nsecs_t phase, Callback* callback);
+ status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) override;
// removeEventListener removes an already-registered event callback. Once
// this method returns that callback will no longer be called by the
// DispSync object.
- status_t removeEventListener(Callback* callback);
+ status_t removeEventListener(Callback* callback) override;
// changePhaseOffset changes the phase offset of an already-registered event callback. The
// method will make sure that there is no skipping or double-firing on the listener per frame,
// even when changing the offsets multiple times.
- status_t changePhaseOffset(Callback* callback, nsecs_t phase);
+ status_t changePhaseOffset(Callback* callback, nsecs_t phase) override;
// computeNextRefresh computes when the next refresh is expected to begin.
// The periodOffset value can be used to move forward or backward; an
// offset of zero is the next refresh, -1 is the previous refresh, 1 is
// the refresh after next. etc.
- nsecs_t computeNextRefresh(int periodOffset) const;
+ nsecs_t computeNextRefresh(int periodOffset) const override;
+
+ // In certain situations the present fences aren't a good indicator of vsync
+ // time, e.g. when vr flinger is active, or simply aren't available,
+ // e.g. when the sync framework isn't present. Use this method to toggle
+ // whether or not DispSync ignores present fences. If present fences are
+ // ignored, DispSync will always ask for hardware vsync events by returning
+ // true from addPresentFence() and addResyncSample().
+ void setIgnorePresentFences(bool ignore) override;
// dump appends human-readable debug info to the result string.
- void dump(String8& result) const;
+ void dump(String8& result) const override;
private:
void updateModelLocked();
void updateErrorLocked();
+ void resetLocked();
void resetErrorLocked();
enum { MAX_RESYNC_SAMPLES = 32 };
@@ -143,6 +184,7 @@
// mPeriod is the computed period of the modeled vsync events in
// nanoseconds.
nsecs_t mPeriod;
+ nsecs_t mPeriodBase;
// mPhase is the phase offset of the modeled vsync events. It is the
// number of nanoseconds from time 0 to the first vsync event.
@@ -197,6 +239,8 @@
std::unique_ptr<Callback> mZeroPhaseTracer;
};
+} // namespace impl
+
} // namespace android
#endif // ANDROID_DISPSYNC_H
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
new file mode 100644
index 0000000..697d634
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "DispSyncSource.h"
+
+#include <android-base/stringprintf.h>
+#include <utils/Trace.h>
+#include <mutex>
+
+#include "DispSync.h"
+#include "EventThread.h"
+
+namespace android {
+
+DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+ const char* name)
+ : mName(name),
+ mTraceVsync(traceVsync),
+ mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
+ mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
+ mDispSync(dispSync),
+ mPhaseOffset(phaseOffset) {}
+
+void DispSyncSource::setVSyncEnabled(bool enable) {
+ std::lock_guard lock(mVsyncMutex);
+ if (enable) {
+ status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
+ static_cast<DispSync::Callback*>(this));
+ if (err != NO_ERROR) {
+ ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err);
+ }
+ // ATRACE_INT(mVsyncOnLabel.c_str(), 1);
+ } else {
+ status_t err = mDispSync->removeEventListener(static_cast<DispSync::Callback*>(this));
+ if (err != NO_ERROR) {
+ ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err);
+ }
+ // ATRACE_INT(mVsyncOnLabel.c_str(), 0);
+ }
+ mEnabled = enable;
+}
+
+void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
+ std::lock_guard lock(mCallbackMutex);
+ mCallback = callback;
+}
+
+void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
+ std::lock_guard lock(mVsyncMutex);
+
+ // Normalize phaseOffset to [0, period)
+ auto period = mDispSync->getPeriod();
+ phaseOffset %= period;
+ if (phaseOffset < 0) {
+ // If we're here, then phaseOffset is in (-period, 0). After this
+ // operation, it will be in (0, period)
+ phaseOffset += period;
+ }
+ mPhaseOffset = phaseOffset;
+
+ // If we're not enabled, we don't need to mess with the listeners
+ if (!mEnabled) {
+ return;
+ }
+
+ status_t err =
+ mDispSync->changePhaseOffset(static_cast<DispSync::Callback*>(this), mPhaseOffset);
+ if (err != NO_ERROR) {
+ ALOGE("error changing vsync offset: %s (%d)", strerror(-err), err);
+ }
+}
+
+void DispSyncSource::onDispSyncEvent(nsecs_t when) {
+ VSyncSource::Callback* callback;
+ {
+ std::lock_guard lock(mCallbackMutex);
+ callback = mCallback;
+
+ if (mTraceVsync) {
+ mValue = (mValue + 1) % 2;
+ ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
+ }
+ }
+
+ if (callback != nullptr) {
+ callback->onVSyncEvent(when);
+ }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
new file mode 100644
index 0000000..0fd84a2
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 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 <mutex>
+#include <string>
+
+#include "DispSync.h"
+#include "EventThread.h"
+
+namespace android {
+
+class DispSyncSource final : public VSyncSource, private DispSync::Callback {
+public:
+ DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name);
+
+ ~DispSyncSource() override = default;
+
+ // The following methods are implementation of VSyncSource.
+ void setVSyncEnabled(bool enable) override;
+ void setCallback(VSyncSource::Callback* callback) override;
+ void setPhaseOffset(nsecs_t phaseOffset) override;
+
+private:
+ // The following method is the implementation of the DispSync::Callback.
+ virtual void onDispSyncEvent(nsecs_t when);
+
+ const char* const mName;
+ int mValue = 0;
+
+ const bool mTraceVsync;
+ const std::string mVsyncOnLabel;
+ const std::string mVsyncEventLabel;
+
+ DispSync* mDispSync;
+
+ std::mutex mCallbackMutex;
+ VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
+
+ std::mutex mVsyncMutex;
+ nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
+ bool mEnabled GUARDED_BY(mVsyncMutex) = false;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/Scheduler/EventControlThread.cpp
similarity index 100%
rename from services/surfaceflinger/EventControlThread.cpp
rename to services/surfaceflinger/Scheduler/EventControlThread.cpp
diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/Scheduler/EventControlThread.h
similarity index 100%
rename from services/surfaceflinger/EventControlThread.h
rename to services/surfaceflinger/Scheduler/EventControlThread.h
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
similarity index 88%
rename from services/surfaceflinger/EventThread.cpp
rename to services/surfaceflinger/Scheduler/EventThread.cpp
index bc271c8..fa2b0a6 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -45,11 +45,27 @@
namespace impl {
+EventThread::EventThread(std::unique_ptr<VSyncSource> src,
+ ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
+ : EventThread(nullptr, std::move(src), resyncWithRateLimitCallback, interceptVSyncsCallback,
+ threadName) {}
+
EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
+ : EventThread(src, nullptr, resyncWithRateLimitCallback, interceptVSyncsCallback,
+ threadName) {}
+
+EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
+ ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
: mVSyncSource(src),
+ mVSyncSourceUnique(std::move(uniqueSrc)),
mResyncWithRateLimitCallback(resyncWithRateLimitCallback),
mInterceptVSyncsCallback(interceptVSyncsCallback) {
+ if (src == nullptr) {
+ mVSyncSource = mVSyncSourceUnique.get();
+ }
for (auto& event : mVSyncEvent) {
event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
event.header.id = 0;
@@ -100,7 +116,8 @@
return NO_ERROR;
}
-void EventThread::removeDisplayEventConnectionLocked(const wp<EventThread::Connection>& connection) {
+void EventThread::removeDisplayEventConnectionLocked(
+ const wp<EventThread::Connection>& connection) {
mDisplayEventConnections.remove(connection);
}
@@ -155,20 +172,17 @@
mCondition.notify_all();
}
-void EventThread::onHotplugReceived(int type, bool connected) {
- ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
- "received hotplug event for an invalid display (id=%d)", type);
-
+void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
std::lock_guard<std::mutex> lock(mMutex);
- if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
- DisplayEventReceiver::Event event;
- event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
- event.header.id = type;
- event.header.timestamp = systemTime();
- event.hotplug.connected = connected;
- mPendingEvents.add(event);
- mCondition.notify_all();
- }
+
+ DisplayEventReceiver::Event event;
+ event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
+ event.header.id = displayType == DisplayType::Primary ? 0 : 1;
+ event.header.timestamp = systemTime();
+ event.hotplug.connected = connected;
+
+ mPendingEvents.add(event);
+ mCondition.notify_all();
}
void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
@@ -205,7 +219,7 @@
// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked(
- std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* event) {
+ std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* outEvent) {
Vector<sp<EventThread::Connection> > signalConnections;
while (signalConnections.isEmpty() && mKeepRunning) {
@@ -214,16 +228,16 @@
size_t vsyncCount = 0;
nsecs_t timestamp = 0;
- for (int32_t i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; i++) {
- timestamp = mVSyncEvent[i].header.timestamp;
+ for (auto& event : mVSyncEvent) {
+ timestamp = event.header.timestamp;
if (timestamp) {
// we have a vsync event to dispatch
if (mInterceptVSyncsCallback) {
mInterceptVSyncsCallback(timestamp);
}
- *event = mVSyncEvent[i];
- mVSyncEvent[i].header.timestamp = 0;
- vsyncCount = mVSyncEvent[i].vsync.count;
+ *outEvent = event;
+ event.header.timestamp = 0;
+ vsyncCount = event.vsync.count;
break;
}
}
@@ -233,7 +247,7 @@
eventPending = !mPendingEvents.isEmpty();
if (eventPending) {
// we have some other event to dispatch
- *event = mPendingEvents[0];
+ *outEvent = mPendingEvents[0];
mPendingEvents.removeAt(0);
}
}
@@ -319,7 +333,7 @@
// FIXME: how do we decide which display id the fake
// vsync came from ?
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
- mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;
+ mVSyncEvent[0].header.id = 0;
mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
mVSyncEvent[0].vsync.count++;
}
@@ -364,8 +378,7 @@
result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
result.appendFormat(" soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
result.appendFormat(" numListeners=%zu,\n events-delivered: %u\n",
- mDisplayEventConnections.size(),
- mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
+ mDisplayEventConnections.size(), mVSyncEvent[0].vsync.count);
for (size_t i = 0; i < mDisplayEventConnections.size(); i++) {
sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
result.appendFormat(" %p: count=%d\n", connection.get(),
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
similarity index 80%
rename from services/surfaceflinger/EventThread.h
rename to services/surfaceflinger/Scheduler/EventThread.h
index 9c13ed2..127891e 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -16,9 +16,11 @@
#pragma once
-#include <stdint.h>
#include <sys/types.h>
+
+#include <array>
#include <condition_variable>
+#include <cstdint>
#include <mutex>
#include <thread>
@@ -31,8 +33,6 @@
#include <utils/Errors.h>
#include <utils/SortedVector.h>
-#include "DisplayDevice.h"
-
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -59,6 +59,9 @@
class EventThread {
public:
+ // TODO: Remove once stable display IDs are plumbed through SF/WM interface.
+ enum class DisplayType { Primary, External };
+
virtual ~EventThread();
virtual sp<BnDisplayEventConnection> createEventConnection() const = 0;
@@ -70,7 +73,7 @@
virtual void onScreenAcquired() = 0;
// called when receiving a hotplug event
- virtual void onHotplugReceived(int type, bool connected) = 0;
+ virtual void onHotplugReceived(DisplayType displayType, bool connected) = 0;
virtual void dump(String8& result) const = 0;
@@ -105,8 +108,12 @@
using ResyncWithRateLimitCallback = std::function<void()>;
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
+ // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+ EventThread(std::unique_ptr<VSyncSource> src,
+ ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
~EventThread();
sp<BnDisplayEventConnection> createEventConnection() const override;
@@ -122,7 +129,7 @@
void onScreenAcquired() override;
// called when receiving a hotplug event
- void onHotplugReceived(int type, bool connected) override;
+ void onHotplugReceived(DisplayType displayType, bool connected) override;
void dump(String8& result) const override;
@@ -131,6 +138,11 @@
private:
friend EventThreadTest;
+ // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
+ EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
+ ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+
void threadMain();
Vector<sp<EventThread::Connection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
DisplayEventReceiver::Event* event)
@@ -143,8 +155,10 @@
// Implements VSyncSource::Callback
void onVSyncEvent(nsecs_t timestamp) override;
+ // TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
+ VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
+ std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
// constants
- VSyncSource* const mVSyncSource GUARDED_BY(mMutex) = nullptr;
const ResyncWithRateLimitCallback mResyncWithRateLimitCallback;
const InterceptVSyncsCallback mInterceptVSyncsCallback;
@@ -155,8 +169,7 @@
// protected by mLock
SortedVector<wp<Connection>> mDisplayEventConnections GUARDED_BY(mMutex);
Vector<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
- DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES] GUARDED_BY(
- mMutex);
+ std::array<DisplayEventReceiver::Event, 2> mVSyncEvent GUARDED_BY(mMutex);
bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
bool mVsyncEnabled GUARDED_BY(mMutex) = false;
bool mKeepRunning GUARDED_BY(mMutex) = true;
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
new file mode 100644
index 0000000..a0e1447
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 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 <mutex>
+
+#include "EventThread.h"
+
+namespace android {
+
+/**
+ * VSync signals used during SurfaceFlinger trace playback (traces we captured
+ * with SurfaceInterceptor).
+ */
+class InjectVSyncSource final : public VSyncSource {
+public:
+ ~InjectVSyncSource() override = default;
+
+ void setCallback(VSyncSource::Callback* callback) override {
+ std::lock_guard<std::mutex> lock(mCallbackMutex);
+ mCallback = callback;
+ }
+
+ void onInjectSyncEvent(nsecs_t when) {
+ std::lock_guard<std::mutex> lock(mCallbackMutex);
+ if (mCallback) {
+ mCallback->onVSyncEvent(when);
+ }
+ }
+
+ void setVSyncEnabled(bool) override {}
+ void setPhaseOffset(nsecs_t) override {}
+
+private:
+ std::mutex mCallbackMutex;
+ VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
similarity index 92%
rename from services/surfaceflinger/MessageQueue.cpp
rename to services/surfaceflinger/Scheduler/MessageQueue.cpp
index 056d381..58355ae 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -101,6 +101,17 @@
this);
}
+void MessageQueue::setEventConnection(const sp<BnDisplayEventConnection>& connection) {
+ if (mEventTube.getFd() >= 0) {
+ mLooper->removeFd(mEventTube.getFd());
+ }
+
+ mEvents = connection;
+ mEvents->stealReceiveChannel(&mEventTube);
+ mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
+ this);
+}
+
void MessageQueue::waitMessage() {
do {
IPCThreadState::self()->flushCommands();
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
similarity index 93%
rename from services/surfaceflinger/MessageQueue.h
rename to services/surfaceflinger/Scheduler/MessageQueue.h
index 90d1c72..2ec697e 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -85,7 +85,9 @@
virtual ~MessageQueue();
virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
+ // TODO(akrulec): Remove this function once everything is migrated to Scheduler.
virtual void setEventThread(EventThread* events) = 0;
+ virtual void setEventConnection(const sp<BnDisplayEventConnection>& connection) = 0;
virtual void waitMessage() = 0;
virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
virtual void invalidate() = 0;
@@ -125,6 +127,7 @@
~MessageQueue() override = default;
void init(const sp<SurfaceFlinger>& flinger) override;
void setEventThread(android::EventThread* events) override;
+ void setEventConnection(const sp<BnDisplayEventConnection>& connection) override;
void waitMessage() override;
status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) override;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
new file mode 100644
index 0000000..54e19c7
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2018 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 "Scheduler.h"
+
+#include <cinttypes>
+#include <cstdint>
+#include <memory>
+
+#include <gui/ISurfaceComposer.h>
+
+#include "DispSync.h"
+#include "DispSyncSource.h"
+#include "EventThread.h"
+#include "InjectVSyncSource.h"
+
+namespace android {
+
+#define RETURN_VALUE_IF_INVALID(value) \
+ if (handle == nullptr || mConnections.count(handle->id) == 0) return value
+#define RETURN_IF_INVALID() \
+ if (handle == nullptr || mConnections.count(handle->id) == 0) return
+
+std::atomic<int64_t> Scheduler::sNextId = 0;
+
+Scheduler::~Scheduler() = default;
+
+sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
+ const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback interceptCallback) {
+ const int64_t id = sNextId++;
+ ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
+
+ std::unique_ptr<EventThread> eventThread =
+ makeEventThread(connectionName, dispSync, phaseOffsetNs, resyncCallback,
+ interceptCallback);
+ auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
+ eventThread->createEventConnection(),
+ std::move(eventThread));
+ mConnections.insert(std::make_pair(id, std::move(connection)));
+ return mConnections[id]->handle;
+}
+
+std::unique_ptr<EventThread> Scheduler::makeEventThread(
+ const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback interceptCallback) {
+ const std::string sourceName = connectionName + "Source";
+ std::unique_ptr<VSyncSource> eventThreadSource =
+ std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, sourceName.c_str());
+ const std::string threadName = connectionName + "Thread";
+ return std::make_unique<impl::EventThread>(std::move(eventThreadSource), resyncCallback,
+ interceptCallback, threadName.c_str());
+}
+
+sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
+ const sp<Scheduler::ConnectionHandle>& handle) {
+ RETURN_VALUE_IF_INVALID(nullptr);
+ return mConnections[handle->id]->thread->createEventConnection();
+}
+
+EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
+ RETURN_VALUE_IF_INVALID(nullptr);
+ return mConnections[handle->id]->thread.get();
+}
+
+sp<BnDisplayEventConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) {
+ RETURN_VALUE_IF_INVALID(nullptr);
+ return mConnections[handle->id]->eventConnection;
+}
+
+void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
+ EventThread::DisplayType displayType, bool connected) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->onHotplugReceived(displayType, connected);
+}
+
+void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->onScreenAcquired();
+}
+
+void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->onScreenReleased();
+}
+
+void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, String8& result) const {
+ RETURN_IF_INVALID();
+ mConnections.at(handle->id)->thread->dump(result);
+}
+
+void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
+}
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
new file mode 100644
index 0000000..fcb46e6
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 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 <cstdint>
+#include <memory>
+
+#include <gui/ISurfaceComposer.h>
+
+#include "DispSync.h"
+#include "EventThread.h"
+#include "InjectVSyncSource.h"
+
+namespace android {
+
+class Scheduler {
+public:
+ /* The scheduler handle is a BBinder object passed to the client from which we can extract
+ * an ID for subsequent operations.
+ */
+ class ConnectionHandle : public BBinder {
+ public:
+ ConnectionHandle(int64_t id) : id(id) {}
+ ~ConnectionHandle() = default;
+ const int64_t id;
+ };
+
+ class Connection {
+ public:
+ Connection(sp<ConnectionHandle> handle, sp<BnDisplayEventConnection> eventConnection,
+ std::unique_ptr<EventThread> eventThread)
+ : handle(handle), eventConnection(eventConnection), thread(std::move(eventThread)) {}
+ ~Connection() = default;
+
+ sp<ConnectionHandle> handle;
+ sp<BnDisplayEventConnection> eventConnection;
+ const std::unique_ptr<EventThread> thread;
+ };
+
+ Scheduler() = default;
+ virtual ~Scheduler();
+
+ /** Creates an EventThread connection. */
+ sp<ConnectionHandle> createConnection(
+ const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback interceptCallback);
+ sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle);
+
+ // Getter methods.
+ EventThread* getEventThread(const sp<ConnectionHandle>& handle);
+ sp<BnDisplayEventConnection> getEventConnection(const sp<ConnectionHandle>& handle);
+
+ // Should be called when receiving a hotplug event.
+ void hotplugReceived(const sp<ConnectionHandle>& handle, EventThread::DisplayType displayType,
+ bool connected);
+ // Should be called after the screen is turned on.
+ void onScreenAcquired(const sp<ConnectionHandle>& handle);
+ // Should be called before the screen is turned off.
+ void onScreenReleased(const sp<ConnectionHandle>& handle);
+ // Should be called when dumpsys command is received.
+ void dump(const sp<ConnectionHandle>& handle, String8& result) const;
+ // Offers ability to modify phase offset in the event thread.
+ void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
+
+protected:
+ virtual std::unique_ptr<EventThread> makeEventThread(
+ const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback interceptCallback);
+
+private:
+ static std::atomic<int64_t> sNextId;
+ std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
similarity index 79%
rename from services/surfaceflinger/VSyncModulator.h
rename to services/surfaceflinger/Scheduler/VSyncModulator.h
index e071a59..ea8ca4c 100644
--- a/services/surfaceflinger/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -29,22 +29,17 @@
*/
class VSyncModulator {
private:
-
// Number of frames we'll keep the early phase offsets once they are activated. This acts as a
// low-pass filter in case the client isn't quick enough in sending new transactions.
const int MIN_EARLY_FRAME_COUNT = 2;
public:
-
struct Offsets {
nsecs_t sf;
nsecs_t app;
};
- enum TransactionStart {
- EARLY,
- NORMAL
- };
+ enum TransactionStart { EARLY, NORMAL };
// Sets the phase offsets
//
@@ -63,21 +58,24 @@
mOffsets = late;
}
- Offsets getEarlyOffsets() const {
- return mEarlyOffsets;
- }
+ Offsets getEarlyOffsets() const { return mEarlyOffsets; }
- Offsets getEarlyGlOffsets() const {
- return mEarlyGlOffsets;
- }
+ Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; }
void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) {
mSfEventThread = sfEventThread;
mAppEventThread = appEventThread;
}
- void setTransactionStart(TransactionStart transactionStart) {
+ void setSchedulerAndHandles(Scheduler* scheduler,
+ Scheduler::ConnectionHandle* appConnectionHandle,
+ Scheduler::ConnectionHandle* sfConnectionHandle) {
+ mScheduler = scheduler;
+ mAppConnectionHandle = appConnectionHandle;
+ mSfConnectionHandle = sfConnectionHandle;
+ }
+ void setTransactionStart(TransactionStart transactionStart) {
if (transactionStart == TransactionStart::EARLY) {
mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT;
}
@@ -112,18 +110,25 @@
}
private:
-
void updateOffsets() {
const Offsets desired = getOffsets();
const Offsets current = mOffsets;
bool changed = false;
if (desired.sf != current.sf) {
- mSfEventThread->setPhaseOffset(desired.sf);
+ if (mSfConnectionHandle != nullptr) {
+ mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
+ } else {
+ mSfEventThread->setPhaseOffset(desired.sf);
+ }
changed = true;
}
if (desired.app != current.app) {
- mAppEventThread->setPhaseOffset(desired.app);
+ if (mSfConnectionHandle != nullptr) {
+ mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
+ } else {
+ mAppEventThread->setPhaseOffset(desired.app);
+ }
changed = true;
}
@@ -149,6 +154,10 @@
EventThread* mSfEventThread = nullptr;
EventThread* mAppEventThread = nullptr;
+ Scheduler* mScheduler = nullptr;
+ Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr;
+ Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr;
+
std::atomic<Offsets> mOffsets;
std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 28b447f..f17710e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -47,7 +47,7 @@
#include <gui/IDisplayEventConnection.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
-
+#include <renderengine/RenderEngine.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
#include <ui/UiConfig.h>
@@ -63,33 +63,39 @@
#include <private/gui/SyncFeatures.h>
#include "BufferLayer.h"
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
#include "Client.h"
#include "ColorLayer.h"
#include "Colorizer.h"
#include "ContainerLayer.h"
#include "DdmConnection.h"
-#include "DispSync.h"
#include "DisplayDevice.h"
-#include "EventControlThread.h"
-#include "EventThread.h"
#include "Layer.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
-#include "clz.h"
#include "DisplayHardware/ComposerHal.h"
+#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
-
#include "Effects/Daltonizer.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/DispSyncSource.h"
+#include "Scheduler/EventControlThread.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/InjectVSyncSource.h"
+#include "Scheduler/Scheduler.h"
-#include "RenderEngine/RenderEngine.h"
#include <cutils/compiler.h>
+#include "android-base/stringprintf.h"
+
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
#include <configstore/Utils.h>
@@ -113,6 +119,48 @@
using ui::RenderIntent;
namespace {
+
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wswitch-enum"
+
+bool isWideColorMode(const ColorMode colorMode) {
+ switch (colorMode) {
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::ADOBE_RGB:
+ case ColorMode::DCI_P3:
+ case ColorMode::BT2020:
+ case ColorMode::BT2100_PQ:
+ case ColorMode::BT2100_HLG:
+ return true;
+ case ColorMode::NATIVE:
+ case ColorMode::STANDARD_BT601_625:
+ case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+ case ColorMode::STANDARD_BT601_525:
+ case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+ case ColorMode::STANDARD_BT709:
+ case ColorMode::SRGB:
+ return false;
+ }
+ return false;
+}
+
+ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
+ switch (rotation) {
+ case ISurfaceComposer::eRotateNone:
+ return ui::Transform::ROT_0;
+ case ISurfaceComposer::eRotate90:
+ return ui::Transform::ROT_90;
+ case ISurfaceComposer::eRotate180:
+ return ui::Transform::ROT_180;
+ case ISurfaceComposer::eRotate270:
+ return ui::Transform::ROT_270;
+ }
+ ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
+ return ui::Transform::ROT_0;
+}
+
+#pragma clang diagnostic pop
+
class ConditionalLock {
public:
ConditionalLock(Mutex& mutex, bool lock) : mMutex(mutex), mLocked(lock) {
@@ -125,6 +173,7 @@
Mutex& mMutex;
bool mLocked;
};
+
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -145,7 +194,11 @@
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
// TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
bool SurfaceFlinger::hasWideColorDisplay;
-
+int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
+bool SurfaceFlinger::useColorManagement;
+bool SurfaceFlinger::useContextPriority;
+Dataspace SurfaceFlinger::compositionDataSpace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::compositionPixelFormat = ui::PixelFormat::RGBA_8888;
std::string getHwcServiceName() {
char value[PROPERTY_VALUE_MAX] = {};
@@ -219,7 +272,7 @@
mLayersAdded(false),
mRepaintEverything(0),
mBootTime(systemTime()),
- mBuiltinDisplays(),
+ mDisplayTokens(),
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
@@ -228,14 +281,12 @@
mDebugDDMS(0),
mDebugDisableHWC(0),
mDebugDisableTransformHint(0),
- mDebugInSwapBuffers(0),
- mLastSwapBufferTime(0),
mDebugInTransaction(0),
mLastTransactionTime(0),
mForceFullDamage(false),
- mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
+ mRefreshStartTime(0),
mHasPoweredOff(false),
mNumLayers(0),
mVrFlingerRequestsDisplay(false),
@@ -273,28 +324,50 @@
hasWideColorDisplay =
getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+ useColorManagement =
+ getBool<V1_2::ISurfaceFlingerConfigs,
+ &V1_2::ISurfaceFlingerConfigs::useColorManagement>(false);
+
+ auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
+ if (surfaceFlingerConfigsServiceV1_2) {
+ surfaceFlingerConfigsServiceV1_2->getCompositionPreference(
+ [&](Dataspace tmpDataSpace, ui::PixelFormat tmpPixelFormat) {
+ compositionDataSpace = tmpDataSpace;
+ compositionPixelFormat = tmpPixelFormat;
+ });
+ }
+
+ useContextPriority = getBool<ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::useContextPriority>(true);
V1_1::DisplayOrientation primaryDisplayOrientation =
- getDisplayOrientation< V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
+ getDisplayOrientation<V1_1::ISurfaceFlingerConfigs,
+ &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
V1_1::DisplayOrientation::ORIENTATION_0);
switch (primaryDisplayOrientation) {
case V1_1::DisplayOrientation::ORIENTATION_90:
- mPrimaryDisplayOrientation = DisplayState::eOrientation90;
+ SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation90;
break;
case V1_1::DisplayOrientation::ORIENTATION_180:
- mPrimaryDisplayOrientation = DisplayState::eOrientation180;
+ SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation180;
break;
case V1_1::DisplayOrientation::ORIENTATION_270:
- mPrimaryDisplayOrientation = DisplayState::eOrientation270;
+ SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation270;
break;
default:
- mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
+ SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
break;
}
- ALOGV("Primary Display Orientation is set to %2d.", mPrimaryDisplayOrientation);
+ ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
- mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset);
+ // Note: We create a local temporary with the real DispSync implementation
+ // type temporarily so we can initialize it with the configured values,
+ // before storing it for more generic use using the interface type.
+ auto primaryDispSync = std::make_unique<impl::DispSync>("PrimaryDispSync");
+ primaryDispSync->init(SurfaceFlinger::hasSyncFramework,
+ SurfaceFlinger::dispSyncPresentTimeOffset);
+ mPrimaryDispSync = std::move(primaryDispSync);
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -322,7 +395,7 @@
property_get("debug.sf.enable_hwc_vds", value, "0");
mUseHwcVirtualDisplays = atoi(value);
- ALOGI_IF(!mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
+ ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
property_get("ro.sf.disable_triple_buffer", value, "1");
mLayerTripleBufferingDisabled = atoi(value);
@@ -344,6 +417,9 @@
property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
const int earlyGlAppOffsetNs = atoi(value);
+ property_get("debug.sf.use_scheduler", value, "0");
+ mUseScheduler = atoi(value);
+
const VSyncModulator::Offsets earlyOffsets =
{earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
@@ -433,28 +509,30 @@
sp<BBinder> token = new DisplayToken(this);
Mutex::Autolock _l(mStateLock);
- DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
+ DisplayDeviceState info;
+ info.type = DisplayDevice::DISPLAY_VIRTUAL;
info.displayName = displayName;
+ info.isSecure = secure;
mCurrentState.displays.add(token, info);
mInterceptor->saveDisplayCreation(info);
return token;
}
-void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) {
+void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) {
Mutex::Autolock _l(mStateLock);
- ssize_t idx = mCurrentState.displays.indexOfKey(display);
+ ssize_t idx = mCurrentState.displays.indexOfKey(displayToken);
if (idx < 0) {
- ALOGW("destroyDisplay: invalid display token");
+ ALOGE("destroyDisplay: Invalid display token %p", displayToken.get());
return;
}
const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- if (!info.isVirtualDisplay()) {
+ if (!info.isVirtual()) {
ALOGE("destroyDisplay called for non-virtual display");
return;
}
- mInterceptor->saveDisplayDeletion(info.displayId);
+ mInterceptor->saveDisplayDeletion(info.sequenceId);
mCurrentState.displays.removeItemsAt(idx);
setTransactionFlags(eDisplayTransactionNeeded);
}
@@ -464,7 +542,7 @@
ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
return nullptr;
}
- return mBuiltinDisplays[id];
+ return mDisplayTokens[id];
}
void SurfaceFlinger::bootFinished()
@@ -496,11 +574,10 @@
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
+ postMessageAsync(new LambdaMessage([this] {
readPersistentProperties();
mBootStage = BootStage::FINISHED;
- });
- postMessageAsync(readProperties);
+ }));
}
uint32_t SurfaceFlinger::getNewTexture() {
@@ -525,151 +602,9 @@
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
- class MessageDestroyGLTexture : public MessageBase {
- RE::RenderEngine& engine;
- uint32_t texture;
- public:
- MessageDestroyGLTexture(RE::RenderEngine& engine, uint32_t texture)
- : engine(engine), texture(texture) {}
- virtual bool handler() {
- engine.deleteTextures(1, &texture);
- return true;
- }
- };
- postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
+ postMessageAsync(new LambdaMessage([=] { getRenderEngine().deleteTextures(1, &texture); }));
}
-class DispSyncSource final : public VSyncSource, private DispSync::Callback {
-public:
- DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
- const char* name) :
- mName(name),
- mValue(0),
- mTraceVsync(traceVsync),
- mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
- mVsyncEventLabel(String8::format("VSYNC-%s", name)),
- mDispSync(dispSync),
- mCallbackMutex(),
- mVsyncMutex(),
- mPhaseOffset(phaseOffset),
- mEnabled(false) {}
-
- ~DispSyncSource() override = default;
-
- void setVSyncEnabled(bool enable) override {
- Mutex::Autolock lock(mVsyncMutex);
- if (enable) {
- status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
- static_cast<DispSync::Callback*>(this));
- if (err != NO_ERROR) {
- ALOGE("error registering vsync callback: %s (%d)",
- strerror(-err), err);
- }
- //ATRACE_INT(mVsyncOnLabel.string(), 1);
- } else {
- status_t err = mDispSync->removeEventListener(
- static_cast<DispSync::Callback*>(this));
- if (err != NO_ERROR) {
- ALOGE("error unregistering vsync callback: %s (%d)",
- strerror(-err), err);
- }
- //ATRACE_INT(mVsyncOnLabel.string(), 0);
- }
- mEnabled = enable;
- }
-
- void setCallback(VSyncSource::Callback* callback) override{
- Mutex::Autolock lock(mCallbackMutex);
- mCallback = callback;
- }
-
- void setPhaseOffset(nsecs_t phaseOffset) override {
- Mutex::Autolock lock(mVsyncMutex);
-
- // Normalize phaseOffset to [0, period)
- auto period = mDispSync->getPeriod();
- phaseOffset %= period;
- if (phaseOffset < 0) {
- // If we're here, then phaseOffset is in (-period, 0). After this
- // operation, it will be in (0, period)
- phaseOffset += period;
- }
- mPhaseOffset = phaseOffset;
-
- // If we're not enabled, we don't need to mess with the listeners
- if (!mEnabled) {
- return;
- }
-
- status_t err = mDispSync->changePhaseOffset(static_cast<DispSync::Callback*>(this),
- mPhaseOffset);
- if (err != NO_ERROR) {
- ALOGE("error changing vsync offset: %s (%d)",
- strerror(-err), err);
- }
- }
-
-private:
- virtual void onDispSyncEvent(nsecs_t when) {
- VSyncSource::Callback* callback;
- {
- Mutex::Autolock lock(mCallbackMutex);
- callback = mCallback;
-
- if (mTraceVsync) {
- mValue = (mValue + 1) % 2;
- ATRACE_INT(mVsyncEventLabel.string(), mValue);
- }
- }
-
- if (callback != nullptr) {
- callback->onVSyncEvent(when);
- }
- }
-
- const char* const mName;
-
- int mValue;
-
- const bool mTraceVsync;
- const String8 mVsyncOnLabel;
- const String8 mVsyncEventLabel;
-
- DispSync* mDispSync;
-
- Mutex mCallbackMutex; // Protects the following
- VSyncSource::Callback* mCallback = nullptr;
-
- Mutex mVsyncMutex; // Protects the following
- nsecs_t mPhaseOffset;
- bool mEnabled;
-};
-
-class InjectVSyncSource final : public VSyncSource {
-public:
- InjectVSyncSource() = default;
- ~InjectVSyncSource() override = default;
-
- void setCallback(VSyncSource::Callback* callback) override {
- std::lock_guard<std::mutex> lock(mCallbackMutex);
- mCallback = callback;
- }
-
- void onInjectSyncEvent(nsecs_t when) {
- std::lock_guard<std::mutex> lock(mCallbackMutex);
- if (mCallback) {
- mCallback->onVSyncEvent(when);
- }
- }
-
- void setVSyncEnabled(bool) override {}
- void setPhaseOffset(nsecs_t) override {}
-
-private:
- std::mutex mCallbackMutex; // Protects the following
- VSyncSource::Callback* mCallback = nullptr;
-};
-
// Do not call property_set on main thread which will be blocked by init
// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
@@ -681,33 +616,59 @@
Mutex::Autolock _l(mStateLock);
// start the EventThread
- mEventThreadSource =
- std::make_unique<DispSyncSource>(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs,
- true, "app");
- mEventThread = std::make_unique<impl::EventThread>(mEventThreadSource.get(),
- [this]() { resyncWithRateLimit(); },
- impl::EventThread::InterceptVSyncsCallback(),
- "appEventThread");
- mSfEventThreadSource =
- std::make_unique<DispSyncSource>(&mPrimaryDispSync,
- SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+ if (mUseScheduler) {
+ mScheduler = std::make_unique<Scheduler>();
+ mAppConnectionHandle =
+ mScheduler->createConnection("appConnection", mPrimaryDispSync.get(),
+ SurfaceFlinger::vsyncPhaseOffsetNs,
+ [this] { resyncWithRateLimit(); },
+ impl::EventThread::InterceptVSyncsCallback());
+ mSfConnectionHandle =
+ mScheduler->createConnection("sfConnection", mPrimaryDispSync.get(),
+ SurfaceFlinger::sfVsyncPhaseOffsetNs,
+ [this] { resyncWithRateLimit(); },
+ [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ });
- mSFEventThread =
- std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
- [this]() { resyncWithRateLimit(); },
- [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- },
- "sfEventThread");
- mEventQueue->setEventThread(mSFEventThread.get());
- mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
+ mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
+ mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
+ mSfConnectionHandle.get());
+ } else {
+ mEventThreadSource =
+ std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
+ SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
+ mEventThread =
+ std::make_unique<impl::EventThread>(mEventThreadSource.get(),
+ [this] { resyncWithRateLimit(); },
+ impl::EventThread::InterceptVSyncsCallback(),
+ "appEventThread");
+ mSfEventThreadSource =
+ std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
+ SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+
+ mSFEventThread =
+ std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
+ [this] { resyncWithRateLimit(); },
+ [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ },
+ "sfEventThread");
+ mEventQueue->setEventThread(mSFEventThread.get());
+ mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
+ }
// Get a RenderEngine for the given display / config (can't fail)
+ int32_t renderEngineFeature = 0;
+ renderEngineFeature |= (useColorManagement ?
+ renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);
+ renderEngineFeature |= (useContextPriority ?
+ renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
+
+ // TODO(b/77156734): We need to stop casting and use HAL types when possible.
getBE().mRenderEngine =
- RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
- hasWideColorDisplay
- ? RE::RenderEngine::WIDE_COLOR_SUPPORT
- : 0);
+ renderengine::RenderEngine::create(static_cast<int32_t>(compositionPixelFormat),
+ renderEngineFeature);
LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
@@ -717,31 +678,34 @@
getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
- LOG_ALWAYS_FATAL_IF(!getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY),
- "Registered composer callback but didn't create the default primary display");
+ const auto display = getDefaultDisplayDeviceLocked();
+ LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
+ LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getId()),
+ "Internal display is disconnected.");
// make the default display GLContext current so that we can create textures
// when creating Layers (which may happens before we render something)
- getDefaultDisplayDeviceLocked()->makeCurrent();
+ display->makeCurrent();
if (useVrFlinger) {
- auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
+ auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
// This callback is called from the vr flinger dispatch thread. We
// need to call signalTransaction(), which requires holding
// mStateLock when we're not on the main thread. Acquiring
// mStateLock from the vr flinger dispatch thread might trigger a
// deadlock in surface flinger (see b/66916578), so post a message
// to be handled on the main thread instead.
- sp<LambdaMessage> message = new LambdaMessage([=]() {
+ postMessageAsync(new LambdaMessage([=] {
ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
mVrFlingerRequestsDisplay = requestDisplay;
signalTransaction();
- });
- postMessageAsync(message);
+ }));
};
- mVrFlinger = dvr::VrFlinger::Create(getBE().mHwc->getComposer(),
- getBE().mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0),
- vrFlingerRequestDisplayCallback);
+ mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
+ getHwComposer()
+ .getHwcDisplayId(display->getId())
+ .value_or(0),
+ vrFlingerRequestDisplayCallback);
if (!mVrFlinger) {
ALOGE("Failed to start vrflinger");
}
@@ -776,7 +740,7 @@
// and apply this saturation matrix on Display P3 content. Unless the risk of applying
// such saturation matrix on Display P3 is understood fully, the API should always return
// identify matrix.
- mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
+ mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(display->getId(),
Dataspace::SRGB_LINEAR);
// we will apply this on Display P3.
@@ -858,18 +822,15 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs) {
- if (configs == nullptr || display.get() == nullptr) {
+status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
+ Vector<DisplayInfo>* configs) {
+ if (!displayToken || !configs) {
return BAD_VALUE;
}
- if (!display.get())
- return NAME_NOT_FOUND;
-
int32_t type = NAME_NOT_FOUND;
- for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- if (display == mBuiltinDisplays[i]) {
+ for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
+ if (displayToken == mDisplayTokens[i]) {
type = i;
break;
}
@@ -881,18 +842,18 @@
// TODO: Not sure if display density should handled by SF any longer
class Density {
- static int getDensityFromProperty(char const* propName) {
+ static float getDensityFromProperty(char const* propName) {
char property[PROPERTY_VALUE_MAX];
- int density = 0;
+ float density = 0.0f;
if (property_get(propName, property, nullptr) > 0) {
- density = atoi(property);
+ density = strtof(property, nullptr);
}
return density;
}
public:
- static int getEmuDensity() {
+ static float getEmuDensity() {
return getDensityFromProperty("qemu.sf.lcd_density"); }
- static int getBuildDensity() {
+ static float getBuildDensity() {
return getDensityFromProperty("ro.sf.lcd_density"); }
};
@@ -906,6 +867,12 @@
float xdpi = hwConfig->getDpiX();
float ydpi = hwConfig->getDpiY();
+ info.w = hwConfig->getWidth();
+ info.h = hwConfig->getHeight();
+ // Default display viewport to display width and height
+ info.viewportW = info.w;
+ info.viewportH = info.h;
+
if (type == DisplayDevice::DISPLAY_PRIMARY) {
// The density of the device is provided by a build property
float density = Density::getBuildDensity() / 160.0f;
@@ -923,8 +890,15 @@
info.density = density;
// TODO: this needs to go away (currently needed only by webkit)
- sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
- info.orientation = hw ? hw->getOrientation() : 0;
+ const auto display = getDefaultDisplayDeviceLocked();
+ info.orientation = display ? display->getOrientation() : 0;
+
+ // This is for screenrecord
+ const Rect viewport = display->getViewport();
+ if (viewport.isValid()) {
+ info.viewportW = uint32_t(viewport.getWidth());
+ info.viewportH = uint32_t(viewport.getHeight());
+ }
} else {
// TODO: where should this value come from?
static const int TV_DENSITY = 213;
@@ -932,8 +906,6 @@
info.orientation = 0;
}
- info.w = hwConfig->getWidth();
- info.h = hwConfig->getHeight();
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
@@ -958,7 +930,7 @@
info.secure = true;
if (type == DisplayDevice::DISPLAY_PRIMARY &&
- mPrimaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
+ primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
std::swap(info.w, info.h);
}
@@ -968,115 +940,74 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
- DisplayStatInfo* stats) {
- if (stats == nullptr) {
+status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* stats) {
+ if (!stats) {
return BAD_VALUE;
}
// FIXME for now we always return stats for the primary display
memset(stats, 0, sizeof(*stats));
- stats->vsyncTime = mPrimaryDispSync.computeNextRefresh(0);
- stats->vsyncPeriod = mPrimaryDispSync.getPeriod();
+ stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+ stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
- if (outViewport == nullptr || display.get() == nullptr) {
+int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) {
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("getActiveConfig: Invalid display token %p", displayToken.get());
return BAD_VALUE;
}
- sp<const DisplayDevice> device(getDisplayDevice(display));
- if (device == nullptr) {
- return BAD_VALUE;
- }
-
- *outViewport = device->getViewport();
-
- return NO_ERROR;
+ return display->getActiveConfig();
}
-int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
- if (display == nullptr) {
- ALOGE("%s : display is nullptr", __func__);
- return BAD_VALUE;
- }
-
- sp<const DisplayDevice> device(getDisplayDevice(display));
- if (device != nullptr) {
- return device->getActiveConfig();
- }
-
- return BAD_VALUE;
-}
-
-void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) {
- ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
- this);
- int32_t type = hw->getDisplayType();
- int currentMode = hw->getActiveConfig();
-
+void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+ int currentMode = display->getActiveConfig();
if (mode == currentMode) {
- ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
return;
}
- if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ if (display->isVirtual()) {
ALOGW("Trying to set config for virtual display");
return;
}
- hw->setActiveConfig(mode);
- getHwComposer().setActiveConfig(type, mode);
+ display->setActiveConfig(mode);
+ getHwComposer().setActiveConfig(display->getDisplayType(), mode);
}
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
- class MessageSetActiveConfig: public MessageBase {
- SurfaceFlinger& mFlinger;
- sp<IBinder> mDisplay;
- int mMode;
- public:
- MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp,
- int mode) :
- mFlinger(flinger), mDisplay(disp) { mMode = mode; }
- virtual bool handler() {
- Vector<DisplayInfo> configs;
- mFlinger.getDisplayConfigs(mDisplay, &configs);
- if (mMode < 0 || mMode >= static_cast<int>(configs.size())) {
- ALOGE("Attempt to set active config = %d for display with %zu configs",
- mMode, configs.size());
- return true;
- }
- sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == nullptr) {
- ALOGE("Attempt to set active config = %d for null display %p",
- mMode, mDisplay.get());
- } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
- ALOGW("Attempt to set active config = %d for virtual display",
- mMode);
- } else {
- mFlinger.setActiveConfigInternal(hw, mMode);
- }
- return true;
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+ postMessageSync(new LambdaMessage([&] {
+ Vector<DisplayInfo> configs;
+ getDisplayConfigs(displayToken, &configs);
+ if (mode < 0 || mode >= static_cast<int>(configs.size())) {
+ ALOGE("Attempt to set active config %d for display with %zu configs", mode,
+ configs.size());
+ return;
}
- };
- sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode);
- postMessageSync(msg);
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set active config %d for invalid display token %p", mode,
+ displayToken.get());
+ } else if (display->isVirtual()) {
+ ALOGW("Attempt to set active config %d for virtual display", mode);
+ } else {
+ setActiveConfigInternal(display, mode);
+ }
+ }));
+
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
- Vector<ColorMode>* outColorModes) {
- if ((outColorModes == nullptr) || (display.get() == nullptr)) {
+status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
+ Vector<ColorMode>* outColorModes) {
+ if (!displayToken || !outColorModes) {
return BAD_VALUE;
}
- if (!display.get()) {
- return NAME_NOT_FOUND;
- }
-
int32_t type = NAME_NOT_FOUND;
- for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- if (display == mBuiltinDisplays[i]) {
+ for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
+ if (displayToken == mDisplayTokens[i]) {
type = i;
break;
}
@@ -1098,79 +1029,62 @@
return NO_ERROR;
}
-ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
- sp<const DisplayDevice> device(getDisplayDevice(display));
- if (device != nullptr) {
- return device->getActiveColorMode();
+ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
+ if (const auto display = getDisplayDevice(displayToken)) {
+ return display->getActiveColorMode();
}
return static_cast<ColorMode>(BAD_VALUE);
}
-void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
- ColorMode mode, Dataspace dataSpace,
- RenderIntent renderIntent) {
- int32_t type = hw->getDisplayType();
- ColorMode currentMode = hw->getActiveColorMode();
- Dataspace currentDataSpace = hw->getCompositionDataSpace();
- RenderIntent currentRenderIntent = hw->getActiveRenderIntent();
+void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& display, ColorMode mode,
+ Dataspace dataSpace, RenderIntent renderIntent) {
+ ColorMode currentMode = display->getActiveColorMode();
+ Dataspace currentDataSpace = display->getCompositionDataSpace();
+ RenderIntent currentRenderIntent = display->getActiveRenderIntent();
if (mode == currentMode && dataSpace == currentDataSpace &&
renderIntent == currentRenderIntent) {
return;
}
- if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ if (display->isVirtual()) {
ALOGW("Trying to set config for virtual display");
return;
}
- hw->setActiveColorMode(mode);
- hw->setCompositionDataSpace(dataSpace);
- hw->setActiveRenderIntent(renderIntent);
- getHwComposer().setActiveColorMode(type, mode, renderIntent);
+ display->setActiveColorMode(mode);
+ display->setCompositionDataSpace(dataSpace);
+ display->setActiveRenderIntent(renderIntent);
+ getHwComposer().setActiveColorMode(display->getDisplayType(), mode, renderIntent);
ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
- decodeColorMode(mode).c_str(), mode,
- decodeRenderIntent(renderIntent).c_str(), renderIntent,
- hw->getDisplayType());
+ decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
+ renderIntent, display->getDisplayType());
}
-
-status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
- ColorMode colorMode) {
- class MessageSetActiveColorMode: public MessageBase {
- SurfaceFlinger& mFlinger;
- sp<IBinder> mDisplay;
- ColorMode mMode;
- public:
- MessageSetActiveColorMode(SurfaceFlinger& flinger, const sp<IBinder>& disp,
- ColorMode mode) :
- mFlinger(flinger), mDisplay(disp) { mMode = mode; }
- virtual bool handler() {
- Vector<ColorMode> modes;
- mFlinger.getDisplayColorModes(mDisplay, &modes);
- bool exists = std::find(std::begin(modes), std::end(modes), mMode) != std::end(modes);
- if (mMode < ColorMode::NATIVE || !exists) {
- ALOGE("Attempt to set invalid active color mode %s (%d) for display %p",
- decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
- return true;
- }
- sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == nullptr) {
- ALOGE("Attempt to set active color mode %s (%d) for null display %p",
- decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
- } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
- ALOGW("Attempt to set active color mode %s %d for virtual display",
- decodeColorMode(mMode).c_str(), mMode);
- } else {
- mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC);
- }
- return true;
+status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
+ postMessageSync(new LambdaMessage([&] {
+ Vector<ColorMode> modes;
+ getDisplayColorModes(displayToken, &modes);
+ bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
+ if (mode < ColorMode::NATIVE || !exists) {
+ ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
+ decodeColorMode(mode).c_str(), mode, displayToken.get());
+ return;
}
- };
- sp<MessageBase> msg = new MessageSetActiveColorMode(*this, display, colorMode);
- postMessageSync(msg);
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
+ decodeColorMode(mode).c_str(), mode, displayToken.get());
+ } else if (display->isVirtual()) {
+ ALOGW("Attempt to set active color mode %s (%d) for virtual display",
+ decodeColorMode(mode).c_str(), mode);
+ } else {
+ setActiveColorModeInternal(display, mode, Dataspace::UNKNOWN,
+ RenderIntent::COLORIMETRIC);
+ }
+ }));
+
return NO_ERROR;
}
@@ -1186,20 +1100,20 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display,
- HdrCapabilities* outCapabilities) const {
+status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& displayToken,
+ HdrCapabilities* outCapabilities) const {
Mutex::Autolock _l(mStateLock);
- sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display));
- if (displayDevice == nullptr) {
- ALOGE("getHdrCapabilities: Invalid display %p", displayDevice.get());
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ ALOGE("getHdrCapabilities: Invalid display token %p", displayToken.get());
return BAD_VALUE;
}
// At this point the DisplayDeivce should already be set up,
// meaning the luminance information is already queried from
// hardware composer and stored properly.
- const HdrCapabilities& capabilities = displayDevice->getHdrCapabilities();
+ const HdrCapabilities& capabilities = display->getHdrCapabilities();
*outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(),
capabilities.getDesiredMaxLuminance(),
capabilities.getDesiredMaxAverageLuminance(),
@@ -1209,20 +1123,21 @@
}
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
- sp<LambdaMessage> enableVSyncInjections = new LambdaMessage([&]() {
+ postMessageSync(new LambdaMessage([&] {
Mutex::Autolock _l(mStateLock);
if (mInjectVSyncs == enable) {
return;
}
+ // TODO(akrulec): Part of the Injector should be refactored, so that it
+ // can be passed to Scheduler.
if (enable) {
ALOGV("VSync Injections enabled");
if (mVSyncInjector.get() == nullptr) {
mVSyncInjector = std::make_unique<InjectVSyncSource>();
mInjectorEventThread = std::make_unique<
- impl::EventThread>(mVSyncInjector.get(),
- [this]() { resyncWithRateLimit(); },
+ impl::EventThread>(mVSyncInjector.get(), [this] { resyncWithRateLimit(); },
impl::EventThread::InterceptVSyncsCallback(),
"injEventThread");
}
@@ -1233,8 +1148,8 @@
}
mInjectVSyncs = enable;
- });
- postMessageSync(enableVSyncInjections);
+ }));
+
return NO_ERROR;
}
@@ -1254,15 +1169,6 @@
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
NO_THREAD_SAFETY_ANALYSIS {
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- if ((uid != AID_SHELL) &&
- !PermissionCache::checkPermission(sDump, pid, uid)) {
- ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
-
// Try to acquire a lock for 1s, fail gracefully
const status_t err = mStateLock.timedLock(s2ns(1));
const bool locked = (err == NO_ERROR);
@@ -1280,14 +1186,29 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getCompositionPreference(Dataspace* outDataSpace,
+ ui::PixelFormat* outPixelFormat) const {
+ *outDataSpace = compositionDataSpace;
+ *outPixelFormat = compositionPixelFormat;
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
- if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mSFEventThread->createEventConnection();
+ if (mUseScheduler) {
+ if (vsyncSource == eVsyncSourceSurfaceFlinger) {
+ return mScheduler->createDisplayEventConnection(mSfConnectionHandle);
+ } else {
+ return mScheduler->createDisplayEventConnection(mAppConnectionHandle);
+ }
} else {
- return mEventThread->createEventConnection();
+ if (vsyncSource == eVsyncSourceSurfaceFlinger) {
+ return mSFEventThread->createEventConnection();
+ } else {
+ return mEventThread->createEventConnection();
+ }
}
}
@@ -1333,8 +1254,7 @@
void SurfaceFlinger::enableHardwareVsync() {
Mutex::Autolock _l(mHWVsyncLock);
if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
- mPrimaryDispSync.beginResync();
- //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
+ mPrimaryDispSync->beginResync();
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
}
@@ -1351,15 +1271,19 @@
return;
}
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
+ if (!getHwComposer().isConnected(displayId)) {
+ return;
+ }
+
+ const auto activeConfig = getHwComposer().getActiveConfig(displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
- mPrimaryDispSync.reset();
- mPrimaryDispSync.setPeriod(period);
+ mPrimaryDispSync->reset();
+ mPrimaryDispSync->setPeriod(period);
if (!mPrimaryHWVsyncEnabled) {
- mPrimaryDispSync.beginResync();
- //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
+ mPrimaryDispSync->beginResync();
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
}
@@ -1368,9 +1292,8 @@
void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
Mutex::Autolock _l(mHWVsyncLock);
if (mPrimaryHWVsyncEnabled) {
- //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
mEventControlThread->setVsyncEnabled(false);
- mPrimaryDispSync.endResync();
+ mPrimaryDispSync->endResync();
mPrimaryHWVsyncEnabled = false;
}
if (makeUnavailable) {
@@ -1390,8 +1313,10 @@
sLastResyncAttempted = now;
}
-void SurfaceFlinger::onVsyncReceived(int32_t sequenceId,
- hwc2_display_t displayId, int64_t timestamp) {
+void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
+ int64_t timestamp) {
+ ATRACE_NAME("SF onVsync");
+
Mutex::Autolock lock(mStateLock);
// Ignore any vsyncs from a previous hardware composer.
if (sequenceId != getBE().mComposerSequenceId) {
@@ -1399,7 +1324,12 @@
}
int32_t type;
- if (!getBE().mHwc->onVsync(displayId, timestamp, &type)) {
+ if (!getBE().mHwc->onVsync(hwcDisplayId, timestamp, &type)) {
+ return;
+ }
+
+ if (type != DisplayDevice::DISPLAY_PRIMARY) {
+ // For now, we don't do anything with external display vsyncs.
return;
}
@@ -1407,8 +1337,8 @@
{ // Scope for the lock
Mutex::Autolock _l(mHWVsyncLock);
- if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) {
- needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
+ if (mPrimaryHWVsyncEnabled) {
+ needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
}
}
@@ -1424,9 +1354,9 @@
*compositorTiming = getBE().mCompositorTiming;
}
-void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
- ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s)", sequenceId, display,
+ ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
connection == HWC2::Connection::Connected ? "connected" : "disconnected");
// Ignore events that do not have the right sequenceId.
@@ -1440,7 +1370,7 @@
// acquire it here.
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
- mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection});
+ mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});
if (std::this_thread::get_id() == mMainThreadId) {
// Process all pending hot plug events immediately if we are on the main thread.
@@ -1450,8 +1380,7 @@
setTransactionFlags(eDisplayTransactionNeeded);
}
-void SurfaceFlinger::onRefreshReceived(int sequenceId,
- hwc2_display_t /*display*/) {
+void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) {
Mutex::Autolock lock(mStateLock);
if (sequenceId != getBE().mComposerSequenceId) {
return;
@@ -1496,8 +1425,13 @@
Mutex::Autolock _l(mStateLock);
- int currentDisplayPowerMode = getDisplayDeviceLocked(
- mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode();
+ sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
+ LOG_ALWAYS_FATAL_IF(!display);
+ const int currentDisplayPowerMode = display->getPowerMode();
+ // This DisplayDevice will no longer be relevant once resetDisplayState() is
+ // called below. Clear the reference now so we don't accidentally use it
+ // later.
+ display.clear();
if (!vrFlingerRequestsDisplay) {
mVrFlinger->SeizeDisplayOwnership();
@@ -1514,27 +1448,32 @@
if (vrFlingerRequestsDisplay) {
mVrFlinger->GrantDisplayOwnership();
- } else {
- enableHardwareVsync();
}
mVisibleRegionsDirty = true;
invalidateHwcGeometry();
// Re-enable default display.
- sp<DisplayDevice> hw(getDisplayDeviceLocked(
- mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
- setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true);
+ display = getDefaultDisplayDeviceLocked();
+ LOG_ALWAYS_FATAL_IF(!display);
+ setPowerModeInternal(display, currentDisplayPowerMode, /*stateLockHeld*/ true);
// Reset the timing values to account for the period of the swapped in HWC
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
+ // The present fences returned from vr_hwc are not an accurate
+ // representation of vsync times.
+ mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
+ !hasSyncFramework);
+
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
setCompositorTimingSnapped(0, period, 0);
+ resyncToHardwareVsync(false);
+
android_atomic_or(1, &mRepaintEverything);
setTransactionFlags(eDisplayTransactionNeeded);
}
@@ -1547,6 +1486,7 @@
mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getSignalTime() ==
Fence::SIGNAL_TIME_PENDING);
+ mFrameMissedCount += frameMissed;
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
if (frameMissed) {
mTimeStats.incrementMissedFrames();
@@ -1588,83 +1528,186 @@
return false;
}
-bool SurfaceFlinger::handleMessageInvalidate() {
- ATRACE_CALL();
- return handlePageFlip();
-}
-
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
mRefreshPending = false;
- nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
- preComposition(refreshStartTime);
+ const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
+ preComposition();
rebuildLayerStacks();
- setUpHWComposer();
- doDebugFlashRegions();
+ calculateWorkingSet();
+
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ beginFrame(display);
+ for (auto& compositionInfo : getBE().mCompositionInfo[displayId]) {
+ setUpHWComposer(compositionInfo);
+ }
+ prepareFrame(display);
+ doDebugFlashRegions(display, repaintEverything);
+ doComposition(display, repaintEverything);
+ }
+
doTracing("handleRefresh");
logLayerStats();
- doComposition();
- postComposition(refreshStartTime);
- mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+ postFrame();
+ postComposition();
mHadClientComposition = false;
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
+ for (const auto& [token, display] : mDisplays) {
mHadClientComposition = mHadClientComposition ||
- getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
+ getBE().mHwc->hasClientComposition(display->getId());
}
+
mVsyncModulator.onRefreshed(mHadClientComposition);
+ getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ for (auto& compositionInfo : getBE().mEndOfFrameCompositionInfo[displayId]) {
+ compositionInfo.hwc.hwcLayer = nullptr;
+ }
+ }
+
mLayersWithQueuedFrames.clear();
}
-void SurfaceFlinger::doDebugFlashRegions()
-{
- // is debugging enabled
- if (CC_LIKELY(!mDebugRegion))
- return;
- const bool repaintEverything = mRepaintEverything;
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- const sp<DisplayDevice>& hw(mDisplays[dpy]);
- if (hw->isDisplayOn()) {
- // transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
- if (!dirtyRegion.isEmpty()) {
- // redraw the whole screen
- doComposeSurfaces(hw);
+bool SurfaceFlinger::handleMessageInvalidate() {
+ ATRACE_CALL();
+ return handlePageFlip();
+}
- // and draw the dirty region
- const int32_t height = hw->getHeight();
- auto& engine(getRenderEngine());
- engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
+void SurfaceFlinger::calculateWorkingSet() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
- hw->swapBuffers(getHwComposer());
+ // build the h/w work list
+ if (CC_UNLIKELY(mGeometryInvalid)) {
+ mGeometryInvalid = false;
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ if (displayId >= 0) {
+ const Vector<sp<Layer>>& currentLayers(
+ display->getVisibleLayersSortedByZ());
+ for (size_t i = 0; i < currentLayers.size(); i++) {
+ const auto& layer = currentLayers[i];
+
+ if (!layer->hasHwcLayer(displayId)) {
+ if (!layer->createHwcLayer(getBE().mHwc.get(), displayId)) {
+ layer->forceClientComposition(displayId);
+ continue;
+ }
+ }
+
+ layer->setGeometry(display, i);
+ if (mDebugDisableHWC || mDebugRegion) {
+ layer->forceClientComposition(displayId);
+ }
+ }
}
}
}
- postFramebuffer();
+ // Set the per-frame data
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ if (displayId < 0) {
+ continue;
+ }
+
+ if (mDrawingState.colorMatrixChanged) {
+ display->setColorTransform(mDrawingState.colorMatrix);
+ status_t result = getBE().mHwc->setColorTransform(displayId, mDrawingState.colorMatrix);
+ ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
+ "display %d: %d", displayId, result);
+ }
+ for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ if (layer->isHdrY410()) {
+ layer->forceClientComposition(displayId);
+ } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
+ layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
+ !display->hasHDR10Support()) {
+ layer->forceClientComposition(displayId);
+ } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
+ layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
+ !display->hasHLGSupport()) {
+ layer->forceClientComposition(displayId);
+ }
+
+ if (layer->getForceClientComposition(displayId)) {
+ ALOGV("[%s] Requesting Client composition", layer->getName().string());
+ layer->setCompositionType(displayId, HWC2::Composition::Client);
+ continue;
+ }
+
+ layer->setPerFrameData(display);
+ }
+
+ if (useColorManagement) {
+ ColorMode colorMode;
+ Dataspace dataSpace;
+ RenderIntent renderIntent;
+ pickColorMode(display, &colorMode, &dataSpace, &renderIntent);
+ setActiveColorModeInternal(display, colorMode, dataSpace, renderIntent);
+ }
+ }
+
+ mDrawingState.colorMatrixChanged = false;
+
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ getBE().mCompositionInfo[displayId].clear();
+ for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ auto displayId = display->getId();
+ layer->getBE().compositionInfo.compositionType = layer->getCompositionType(displayId);
+ if (!layer->setHwcLayer(displayId)) {
+ ALOGV("Need to create HWCLayer for %s", layer->getName().string());
+ }
+ layer->getBE().compositionInfo.hwc.displayId = displayId;
+ getBE().mCompositionInfo[displayId].push_back(layer->getBE().compositionInfo);
+ layer->getBE().compositionInfo.hwc.hwcLayer = nullptr;
+ }
+ }
+}
+
+void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything)
+{
+ const auto displayId = display->getId();
+ // is debugging enabled
+ if (CC_LIKELY(!mDebugRegion))
+ return;
+
+ if (display->isPoweredOn()) {
+ // transform the dirty region into this screen's coordinate space
+ const Region dirtyRegion(display->getDirtyRegion(repaintEverything));
+ if (!dirtyRegion.isEmpty()) {
+ // redraw the whole screen
+ doComposeSurfaces(display);
+
+ // and draw the dirty region
+ auto& engine(getRenderEngine());
+ engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
+
+ display->swapBuffers(getHwComposer());
+ }
+ }
+
+ postFramebuffer(display);
if (mDebugRegion > 1) {
usleep(mDebugRegion * 1000);
}
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- if (!displayDevice->isDisplayOn()) {
- continue;
- }
-
- status_t result = displayDevice->prepareFrame(*getBE().mHwc);
+ if (display->isPoweredOn()) {
+ status_t result = display->prepareFrame(
+ *getBE().mHwc, getBE().mCompositionInfo[displayId]);
ALOGE_IF(result != NO_ERROR,
- "prepareFrame for display %zd failed:"
+ "prepareFrame for display %d failed:"
" %d (%s)",
- displayId, result, strerror(-result));
+ display->getId(), result, strerror(-result));
}
}
@@ -1679,30 +1722,27 @@
void SurfaceFlinger::logLayerStats() {
ATRACE_CALL();
if (CC_UNLIKELY(mLayerStats.isEnabled())) {
- int32_t hwcId = -1;
- for (size_t dpy = 0; dpy < mDisplays.size(); ++dpy) {
- const sp<const DisplayDevice>& displayDevice(mDisplays[dpy]);
- if (displayDevice->isPrimary()) {
- hwcId = displayDevice->getHwcDisplayId();
- break;
+ for (const auto& [token, display] : mDisplays) {
+ if (display->isPrimary()) {
+ mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(*display));
+ return;
}
}
- if (hwcId < 0) {
- ALOGE("LayerStats: Hmmm, no primary display?");
- return;
- }
- mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
+
+ ALOGE("logLayerStats: no primary display");
}
}
-void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
+void SurfaceFlinger::preComposition()
{
ATRACE_CALL();
ALOGV("preComposition");
+ mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
bool needExtraInvalidate = false;
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->onPreComposition(refreshStartTime)) {
+ if (layer->onPreComposition(mRefreshStartTime)) {
needExtraInvalidate = true;
}
});
@@ -1771,7 +1811,7 @@
getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
-void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+void SurfaceFlinger::postComposition()
{
ATRACE_CALL();
ALOGV("postComposition");
@@ -1783,31 +1823,32 @@
}
// |mStateLock| not needed as we are on the main thread
- const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+ const auto display = getDefaultDisplayDeviceLocked();
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (hw && getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
+ if (display && getHwComposer().hasClientComposition(display->getId())) {
glCompositionDoneFenceTime =
- std::make_shared<FenceTime>(hw->getClientTargetAcquireFence());
+ std::make_shared<FenceTime>(display->getClientTargetAcquireFence());
getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
getBE().mDisplayTimeline.updateSignalTimes();
- sp<Fence> presentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
- auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+ mPreviousPresentFence =
+ display ? getHwComposer().getPresentFence(display->getId()) : Fence::NO_FENCE;
+ auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
getBE().mDisplayTimeline.push(presentFenceTime);
- nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
- nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
+ nsecs_t vsyncPhase = mPrimaryDispSync->computeNextRefresh(0);
+ nsecs_t vsyncInterval = mPrimaryDispSync->getPeriod();
- // We use the refreshStartTime which might be sampled a little later than
+ // We use the mRefreshStartTime which might be sampled a little later than
// when we started doing work for this frame, but that should be okay
// since updateCompositorTiming has snapping logic.
updateCompositorTiming(
- vsyncPhase, vsyncInterval, refreshStartTime, presentFenceTime);
+ vsyncPhase, vsyncInterval, mRefreshStartTime, presentFenceTime);
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -1824,7 +1865,7 @@
});
if (presentFenceTime->isValid()) {
- if (mPrimaryDispSync.addPresentFence(presentFenceTime)) {
+ if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
@@ -1832,7 +1873,7 @@
}
if (!hasSyncFramework) {
- if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) && hw->isDisplayOn()) {
+ if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
enableHardwareVsync();
}
}
@@ -1843,11 +1884,10 @@
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
- } else if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
+ } else if (display && getHwComposer().isConnected(display->getId())) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- nsecs_t presentTime =
- getBE().mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(display->getId());
mAnimFrameTracker.setActualPresentTime(presentTime);
}
mAnimFrameTracker.advanceFrame();
@@ -1858,8 +1898,8 @@
mTimeStats.incrementClientCompositionFrames();
}
- if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) &&
- hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+ if (display && getHwComposer().isConnected(display->getId()) &&
+ display->getPowerMode() == HWC_POWER_MODE_OFF) {
return;
}
@@ -1900,21 +1940,20 @@
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ for (const auto& pair : mDisplays) {
+ const auto& display = pair.second;
Region opaqueRegion;
Region dirtyRegion;
Vector<sp<Layer>> layersSortedByZ;
Vector<sp<Layer>> layersNeedingFences;
- const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
- const Transform& tr(displayDevice->getTransform());
- const Rect bounds(displayDevice->getBounds());
- if (displayDevice->isDisplayOn()) {
- computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
+ const ui::Transform& tr = display->getTransform();
+ const Rect bounds = display->getBounds();
+ if (display->isPoweredOn()) {
+ computeVisibleRegions(display, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool hwcLayerDestroyed = false;
- if (layer->belongsToDisplay(displayDevice->getLayerStack(),
- displayDevice->isPrimary())) {
+ if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
@@ -1923,15 +1962,13 @@
} else {
// Clear out the HWC layer if this layer was
// previously visible, but no longer is
- hwcLayerDestroyed = layer->destroyHwcLayer(
- displayDevice->getHwcDisplayId());
+ hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
}
} else {
- // WM changes displayDevice->layerStack upon sleep/awake.
+ // WM changes display->layerStack upon sleep/awake.
// Here we make sure we delete the HWC layers even if
// WM changed their layer stack.
- hwcLayerDestroyed = layer->destroyHwcLayer(
- displayDevice->getHwcDisplayId());
+ hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
}
// If a layer is not going to get a release fence because
@@ -1947,12 +1984,11 @@
}
});
}
- displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
- displayDevice->setLayersNeedingFences(layersNeedingFences);
- displayDevice->undefinedRegion.set(bounds);
- displayDevice->undefinedRegion.subtractSelf(
- tr.transform(opaqueRegion));
- displayDevice->dirtyRegion.orSelf(dirtyRegion);
+ display->setVisibleLayersSortedByZ(layersSortedByZ);
+ display->setLayersNeedingFences(layersNeedingFences);
+ display->undefinedRegion.set(bounds);
+ display->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
+ display->dirtyRegion.orSelf(dirtyRegion);
}
}
}
@@ -1965,12 +2001,12 @@
// - Dataspace::UNKNOWN
// - Dataspace::BT2020_HLG
// - Dataspace::BT2020_PQ
-Dataspace SurfaceFlinger::getBestDataspace(
- const sp<const DisplayDevice>& displayDevice, Dataspace* outHdrDataSpace) const {
+Dataspace SurfaceFlinger::getBestDataspace(const sp<const DisplayDevice>& display,
+ Dataspace* outHdrDataSpace) const {
Dataspace bestDataSpace = Dataspace::SRGB;
*outHdrDataSpace = Dataspace::UNKNOWN;
- for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ for (const auto& layer : display->getVisibleLayersSortedByZ()) {
switch (layer->getDataSpace()) {
case Dataspace::V0_SCRGB:
case Dataspace::V0_SCRGB_LINEAR:
@@ -1998,9 +2034,8 @@
}
// Pick the ColorMode / Dataspace for the display device.
-void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
- ColorMode* outMode, Dataspace* outDataSpace,
- RenderIntent* outRenderIntent) const {
+void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& display, ColorMode* outMode,
+ Dataspace* outDataSpace, RenderIntent* outRenderIntent) const {
if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
*outMode = ColorMode::NATIVE;
*outDataSpace = Dataspace::UNKNOWN;
@@ -2009,11 +2044,11 @@
}
Dataspace hdrDataSpace;
- Dataspace bestDataSpace = getBestDataspace(displayDevice, &hdrDataSpace);
+ Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace);
// respect hdrDataSpace only when there is no legacy HDR support
const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
- !displayDevice->hasLegacyHdrSupport(hdrDataSpace);
+ !display->hasLegacyHdrSupport(hdrDataSpace);
if (isHdr) {
bestDataSpace = hdrDataSpace;
}
@@ -2032,177 +2067,259 @@
break;
}
- displayDevice->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
+ display->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
-void SurfaceFlinger::setUpHWComposer() {
+void SurfaceFlinger::configureSidebandComposition(const CompositionInfo& compositionInfo) const
+{
+ HWC2::Error error;
+ LOG_ALWAYS_FATAL_IF(compositionInfo.hwc.sidebandStream == nullptr,
+ "CompositionType is sideband, but sideband stream is nullptr");
+ error = (compositionInfo.hwc.hwcLayer)
+ ->setSidebandStream(compositionInfo.hwc.sidebandStream->handle());
+ if (error != HWC2::Error::None) {
+ ALOGE("[SF] Failed to set sideband stream %p: %s (%d)",
+ compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void SurfaceFlinger::configureHwcCommonData(const CompositionInfo& compositionInfo) const
+{
+ HWC2::Error error;
+
+ if (!compositionInfo.hwc.skipGeometry) {
+ error = (compositionInfo.hwc.hwcLayer)->setBlendMode(compositionInfo.hwc.blendMode);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set blend mode %s:"
+ " %s (%d)",
+ to_string(compositionInfo.hwc.blendMode).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+
+ error = (compositionInfo.hwc.hwcLayer)->setDisplayFrame(compositionInfo.hwc.displayFrame);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set the display frame [%d, %d, %d, %d] %s (%d)",
+ compositionInfo.hwc.displayFrame.left,
+ compositionInfo.hwc.displayFrame.right,
+ compositionInfo.hwc.displayFrame.top,
+ compositionInfo.hwc.displayFrame.bottom,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+
+ error = (compositionInfo.hwc.hwcLayer)->setSourceCrop(compositionInfo.hwc.sourceCrop);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: %s (%d)",
+ compositionInfo.hwc.sourceCrop.left,
+ compositionInfo.hwc.sourceCrop.right,
+ compositionInfo.hwc.sourceCrop.top,
+ compositionInfo.hwc.sourceCrop.bottom,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+
+ error = (compositionInfo.hwc.hwcLayer)->setPlaneAlpha(compositionInfo.hwc.alpha);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set plane alpha %.3f: "
+ "%s (%d)",
+ compositionInfo.hwc.alpha,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+
+
+ error = (compositionInfo.hwc.hwcLayer)->setZOrder(compositionInfo.hwc.z);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set Z %u: %s (%d)",
+ compositionInfo.hwc.z,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+
+ error = (compositionInfo.hwc.hwcLayer)
+ ->setInfo(compositionInfo.hwc.type, compositionInfo.hwc.appId);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set info (%d)",
+ static_cast<int32_t>(error));
+
+ error = (compositionInfo.hwc.hwcLayer)->setTransform(compositionInfo.hwc.transform);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set transform %s: "
+ "%s (%d)",
+ to_string(compositionInfo.hwc.transform).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ error = (compositionInfo.hwc.hwcLayer)->setCompositionType(compositionInfo.compositionType);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set composition type: %s (%d)",
+ to_string(error).c_str(), static_cast<int32_t>(error));
+
+ error = (compositionInfo.hwc.hwcLayer)->setDataspace(compositionInfo.hwc.dataspace);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set dataspace: %s (%d)",
+ to_string(error).c_str(), static_cast<int32_t>(error));
+
+ error = (compositionInfo.hwc.hwcLayer)->setPerFrameMetadata(
+ compositionInfo.hwc.supportedPerFrameMetadata, compositionInfo.hwc.hdrMetadata);
+ ALOGE_IF(error != HWC2::Error::None && error != HWC2::Error::Unsupported,
+ "[SF] Failed to set hdrMetadata: %s (%d)",
+ to_string(error).c_str(), static_cast<int32_t>(error));
+
+ if (compositionInfo.compositionType == HWC2::Composition::SolidColor) {
+ error = (compositionInfo.hwc.hwcLayer)->setColor(compositionInfo.hwc.color);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set color: %s (%d)",
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ error = (compositionInfo.hwc.hwcLayer)->setVisibleRegion(compositionInfo.hwc.visibleRegion);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set visible region: %s (%d)",
+ to_string(error).c_str(), static_cast<int32_t>(error));
+
+ error = (compositionInfo.hwc.hwcLayer)->setSurfaceDamage(compositionInfo.hwc.surfaceDamage);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set surface damage: %s (%d)",
+ to_string(error).c_str(), static_cast<int32_t>(error));
+}
+
+void SurfaceFlinger::configureDeviceComposition(const CompositionInfo& compositionInfo) const
+{
+ HWC2::Error error;
+
+ if (compositionInfo.hwc.fence) {
+ error = (compositionInfo.hwc.hwcLayer)->setBuffer(compositionInfo.mBufferSlot,
+ compositionInfo.mBuffer, compositionInfo.hwc.fence);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set buffer: %s (%d)",
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
+void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& display)
+{
+ bool dirty = !display->getDirtyRegion(false).isEmpty();
+ bool empty = display->getVisibleLayersSortedByZ().size() == 0;
+ bool wasEmpty = !display->lastCompositionHadVisibleLayers;
+
+ // If nothing has changed (!dirty), don't recompose.
+ // If something changed, but we don't currently have any visible layers,
+ // and didn't when we last did a composition, then skip it this time.
+ // The second rule does two things:
+ // - When all layers are removed from a display, we'll emit one black
+ // frame, then nothing more until we get new layers.
+ // - When a display is created with a private layer stack, we won't
+ // emit any black frames until a layer is added to the layer stack.
+ bool mustRecompose = dirty && !(empty && wasEmpty);
+
+ ALOGV_IF(display->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
+ "id[%d]: %s composition (%sdirty %sempty %swasEmpty)", display->getId(),
+ mustRecompose ? "doing" : "skipping",
+ dirty ? "+" : "-",
+ empty ? "+" : "-",
+ wasEmpty ? "+" : "-");
+
+ display->beginFrame(mustRecompose);
+
+ if (mustRecompose) {
+ display->lastCompositionHadVisibleLayers = !empty;
+ }
+}
+
+void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& display)
+{
+ const auto displayId = display->getId();
+ if (!display->isPoweredOn()) {
+ return;
+ }
+
+ status_t result = display->prepareFrame(
+ *getBE().mHwc, getBE().mCompositionInfo[displayId]);
+ ALOGE_IF(result != NO_ERROR,
+ "prepareFrame for display %d failed:"
+ " %d (%s)",
+ display->getId(), result, strerror(-result));
+}
+
+void SurfaceFlinger::setUpHWComposer(const CompositionInfo& compositionInfo) {
ATRACE_CALL();
ALOGV("setUpHWComposer");
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- bool dirty = !mDisplays[dpy]->getDirtyRegion(mRepaintEverything).isEmpty();
- bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
- bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
+ switch (compositionInfo.compositionType)
+ {
+ case HWC2::Composition::Invalid:
+ break;
- // If nothing has changed (!dirty), don't recompose.
- // If something changed, but we don't currently have any visible layers,
- // and didn't when we last did a composition, then skip it this time.
- // The second rule does two things:
- // - When all layers are removed from a display, we'll emit one black
- // frame, then nothing more until we get new layers.
- // - When a display is created with a private layer stack, we won't
- // emit any black frames until a layer is added to the layer stack.
- bool mustRecompose = dirty && !(empty && wasEmpty);
-
- ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
- "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
- mustRecompose ? "doing" : "skipping",
- dirty ? "+" : "-",
- empty ? "+" : "-",
- wasEmpty ? "+" : "-");
-
- mDisplays[dpy]->beginFrame(mustRecompose);
-
- if (mustRecompose) {
- mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
- }
- }
-
- // build the h/w work list
- if (CC_UNLIKELY(mGeometryInvalid)) {
- mGeometryInvalid = false;
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> displayDevice(mDisplays[dpy]);
- const auto hwcId = displayDevice->getHwcDisplayId();
- if (hwcId >= 0) {
- const Vector<sp<Layer>>& currentLayers(
- displayDevice->getVisibleLayersSortedByZ());
- for (size_t i = 0; i < currentLayers.size(); i++) {
- const auto& layer = currentLayers[i];
- if (!layer->hasHwcLayer(hwcId)) {
- if (!layer->createHwcLayer(getBE().mHwc.get(), hwcId)) {
- layer->forceClientComposition(hwcId);
- continue;
- }
- }
-
- layer->setGeometry(displayDevice, i);
- if (mDebugDisableHWC || mDebugRegion) {
- layer->forceClientComposition(hwcId);
- }
- }
+ case HWC2::Composition::Client:
+ if (compositionInfo.hwc.hwcLayer) {
+ auto error = (compositionInfo.hwc.hwcLayer)->
+ setCompositionType(compositionInfo.compositionType);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set composition type: %s (%d)",
+ to_string(error).c_str(), static_cast<int32_t>(error));
}
- }
- }
+ break;
- // Set the per-frame data
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- const auto hwcId = displayDevice->getHwcDisplayId();
+ case HWC2::Composition::Sideband:
+ configureHwcCommonData(compositionInfo);
+ configureSidebandComposition(compositionInfo);
+ break;
- if (hwcId < 0) {
- continue;
- }
- if (mDrawingState.colorMatrixChanged) {
- displayDevice->setColorTransform(mDrawingState.colorMatrix);
- status_t result = getBE().mHwc->setColorTransform(hwcId, mDrawingState.colorMatrix);
- ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
- "display %zd: %d", displayId, result);
- }
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- if (layer->isHdrY410()) {
- layer->forceClientComposition(hwcId);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !displayDevice->hasHDR10Support()) {
- layer->forceClientComposition(hwcId);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
- !displayDevice->hasHLGSupport()) {
- layer->forceClientComposition(hwcId);
- }
+ case HWC2::Composition::SolidColor:
+ configureHwcCommonData(compositionInfo);
+ break;
- if (layer->getForceClientComposition(hwcId)) {
- ALOGV("[%s] Requesting Client composition", layer->getName().string());
- layer->setCompositionType(hwcId, HWC2::Composition::Client);
- continue;
- }
-
- layer->setPerFrameData(displayDevice);
- }
-
- if (hasWideColorDisplay) {
- ColorMode colorMode;
- Dataspace dataSpace;
- RenderIntent renderIntent;
- pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
- setActiveColorModeInternal(displayDevice, colorMode, dataSpace, renderIntent);
- }
- }
-
- mDrawingState.colorMatrixChanged = false;
-
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- if (!displayDevice->isDisplayOn()) {
- continue;
- }
-
- status_t result = displayDevice->prepareFrame(*getBE().mHwc);
- ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
- " %d (%s)", displayId, result, strerror(-result));
+ case HWC2::Composition::Device:
+ case HWC2::Composition::Cursor:
+ configureHwcCommonData(compositionInfo);
+ configureDeviceComposition(compositionInfo);
+ break;
}
}
-void SurfaceFlinger::doComposition() {
+void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
ATRACE_CALL();
ALOGV("doComposition");
- const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- const sp<DisplayDevice>& hw(mDisplays[dpy]);
- if (hw->isDisplayOn()) {
- // transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
+ if (display->isPoweredOn()) {
+ // transform the dirty region into this screen's coordinate space
+ const Region dirtyRegion(display->getDirtyRegion(repaintEverything));
- // repaint the framebuffer (if needed)
- doDisplayComposition(hw, dirtyRegion);
+ // repaint the framebuffer (if needed)
+ doDisplayComposition(display, dirtyRegion);
- hw->dirtyRegion.clear();
- hw->flip();
- }
+ display->dirtyRegion.clear();
+ display->flip();
}
- postFramebuffer();
+ postFramebuffer(display);
}
-void SurfaceFlinger::postFramebuffer()
+void SurfaceFlinger::postFrame()
+{
+ // |mStateLock| not needed as we are on the main thread
+ if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
+ uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+ if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
+ logFrameStats();
+ }
+ }
+}
+
+void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& display)
{
ATRACE_CALL();
ALOGV("postFramebuffer");
- const nsecs_t now = systemTime();
- mDebugInSwapBuffers = now;
+ mPostFramebufferTime = systemTime();
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- if (!displayDevice->isDisplayOn()) {
- continue;
+ if (display->isPoweredOn()) {
+ const auto displayId = display->getId();
+ if (displayId >= 0) {
+ getBE().mHwc->presentAndGetReleaseFences(displayId);
}
- const auto hwcId = displayDevice->getHwcDisplayId();
- if (hwcId >= 0) {
- getBE().mHwc->presentAndGetReleaseFences(hwcId);
- }
- displayDevice->onSwapBuffersCompleted();
- displayDevice->makeCurrent();
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ display->onSwapBuffersCompleted();
+ display->makeCurrent();
+ for (auto& compositionInfo : getBE().mCompositionInfo[displayId]) {
sp<Fence> releaseFence = Fence::NO_FENCE;
-
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
// signaled. Always get the release fence from HWC first.
- auto hwcLayer = layer->getHwcLayer(hwcId);
- if (hwcId >= 0) {
- releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);
+ auto hwcLayer = compositionInfo.hwc.hwcLayer;
+ if ((displayId >= 0) && hwcLayer) {
+ releaseFence = getBE().mHwc->getLayerReleaseFence(displayId, hwcLayer.get());
}
// If the layer was client composited in the previous frame, we
@@ -2210,37 +2327,28 @@
// Since we do not track that, always merge with the current
// client target acquire fence when it is available, even though
// this is suboptimal.
- if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) {
+ if (compositionInfo.compositionType == HWC2::Composition::Client) {
releaseFence = Fence::merge("LayerRelease", releaseFence,
- displayDevice->getClientTargetAcquireFence());
+ display->getClientTargetAcquireFence());
}
- layer->onLayerDisplayed(releaseFence);
+ if (compositionInfo.layer) {
+ compositionInfo.layer->onLayerDisplayed(releaseFence);
+ }
}
// We've got a list of layers needing fences, that are disjoint with
- // displayDevice->getVisibleLayersSortedByZ. The best we can do is to
+ // display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
- if (!displayDevice->getLayersNeedingFences().isEmpty()) {
- sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId);
- for (auto& layer : displayDevice->getLayersNeedingFences()) {
- layer->onLayerDisplayed(presentFence);
+ if (!display->getLayersNeedingFences().isEmpty()) {
+ sp<Fence> presentFence = getBE().mHwc->getPresentFence(displayId);
+ for (auto& layer : display->getLayersNeedingFences()) {
+ layer->getBE().onLayerDisplayed(presentFence);
}
}
- if (hwcId >= 0) {
- getBE().mHwc->clearReleaseFences(hwcId);
- }
- }
-
- mLastSwapBufferTime = systemTime() - now;
- mDebugInSwapBuffers = 0;
-
- // |mStateLock| not needed as we are on the main thread
- if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
- uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
- if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
- logFrameStats();
+ if (displayId >= 0) {
+ getBE().mHwc->clearReleaseFences(displayId);
}
}
}
@@ -2275,7 +2383,7 @@
// here the transaction has been committed
}
-DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t display,
+DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t hwcDisplayId,
HWC2::Connection connection) const {
// Figure out whether the event is for the primary display or an
// external display by matching the Hwc display id against one for a
@@ -2284,17 +2392,16 @@
// have a connected primary display, we assume the new display is meant to
// be the primary display, and then if we don't have an external display,
// we assume it is that.
- const auto primaryDisplayId =
- getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
- const auto externalDisplayId =
+ const auto primaryHwcDisplayId = getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
+ const auto externalHwcDisplayId =
getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
- if (primaryDisplayId && primaryDisplayId == display) {
+ if (primaryHwcDisplayId && primaryHwcDisplayId == hwcDisplayId) {
return DisplayDevice::DISPLAY_PRIMARY;
- } else if (externalDisplayId && externalDisplayId == display) {
- return DisplayDevice::DISPLAY_EXTERNAL;
- } else if (connection == HWC2::Connection::Connected && !primaryDisplayId) {
+ } else if (externalHwcDisplayId && externalHwcDisplayId == hwcDisplayId) {
+ return DisplayDevice::DISPLAY_EXTERNAL;
+ } else if (connection == HWC2::Connection::Connected && !primaryHwcDisplayId) {
return DisplayDevice::DISPLAY_PRIMARY;
- } else if (connection == HWC2::Connection::Connected && !externalDisplayId) {
+ } else if (connection == HWC2::Connection::Connected && !externalHwcDisplayId) {
return DisplayDevice::DISPLAY_EXTERNAL;
}
@@ -2303,9 +2410,9 @@
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
for (const auto& event : mPendingHotplugEvents) {
- auto displayType = determineDisplayType(event.display, event.connection);
+ auto displayType = determineDisplayType(event.hwcDisplayId, event.connection);
if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
- ALOGW("Unable to determine the display type for display %" PRIu64, event.display);
+ ALOGW("Unable to determine the display type for display %" PRIu64, event.hwcDisplayId);
continue;
}
@@ -2314,29 +2421,34 @@
continue;
}
- getBE().mHwc->onHotplug(event.display, displayType, event.connection);
+ const auto displayId =
+ getBE().mHwc->onHotplug(event.hwcDisplayId, displayType, event.connection);
+ if (displayId) {
+ ALOGV("Display %" PRIu64 " has stable ID %" PRIu64, event.hwcDisplayId, *displayId);
+ }
if (event.connection == HWC2::Connection::Connected) {
- if (!mBuiltinDisplays[displayType].get()) {
+ if (!mDisplayTokens[displayType].get()) {
ALOGV("Creating built in display %d", displayType);
- mBuiltinDisplays[displayType] = new BBinder();
- // All non-virtual displays are currently considered secure.
- DisplayDeviceState info(displayType, true);
+ mDisplayTokens[displayType] = new BBinder();
+ DisplayDeviceState info;
+ info.type = displayType;
info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
"Built-in Screen" : "External Screen";
- mCurrentState.displays.add(mBuiltinDisplays[displayType], info);
+ info.isSecure = true; // All physical displays are currently considered secure.
+ mCurrentState.displays.add(mDisplayTokens[displayType], info);
mInterceptor->saveDisplayCreation(info);
}
} else {
ALOGV("Removing built in display %d", displayType);
- ssize_t idx = mCurrentState.displays.indexOfKey(mBuiltinDisplays[displayType]);
+ ssize_t idx = mCurrentState.displays.indexOfKey(mDisplayTokens[displayType]);
if (idx >= 0) {
const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- mInterceptor->saveDisplayDeletion(info.displayId);
+ mInterceptor->saveDisplayDeletion(info.sequenceId);
mCurrentState.displays.removeItemsAt(idx);
}
- mBuiltinDisplays[displayType].clear();
+ mDisplayTokens[displayType].clear();
}
processDisplayChangesLocked();
@@ -2346,35 +2458,29 @@
}
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
- const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state,
+ const wp<IBinder>& displayToken, int32_t displayId, const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
bool hasWideColorGamut = false;
std::unordered_map<ColorMode, std::vector<RenderIntent>> hwcColorModes;
HdrCapabilities hdrCapabilities;
int32_t supportedPerFrameMetadata = 0;
- if (hasWideColorDisplay && hwcId >= 0) {
- std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
+ if (useColorManagement && displayId >= 0) {
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
for (ColorMode colorMode : modes) {
- switch (colorMode) {
- case ColorMode::DISPLAY_P3:
- case ColorMode::ADOBE_RGB:
- case ColorMode::DCI_P3:
- hasWideColorGamut = true;
- break;
- default:
- break;
+ if (isWideColorMode(colorMode)) {
+ hasWideColorGamut = true;
}
- std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId,
- colorMode);
+ std::vector<RenderIntent> renderIntents =
+ getHwComposer().getRenderIntents(displayId, colorMode);
hwcColorModes.emplace(colorMode, renderIntents);
}
}
- if (hwcId >= 0) {
- getHwComposer().getHdrCapabilities(hwcId, &hdrCapabilities);
- supportedPerFrameMetadata = getHwComposer().getSupportedPerFrameMetadata(hwcId);
+ if (displayId >= 0) {
+ getHwComposer().getHdrCapabilities(displayId, &hdrCapabilities);
+ supportedPerFrameMetadata = getHwComposer().getSupportedPerFrameMetadata(displayId);
}
auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
@@ -2383,9 +2489,9 @@
/*
* Create our display's surface
*/
- std::unique_ptr<RE::Surface> renderSurface = getRenderEngine().createSurface();
+ std::unique_ptr<renderengine::Surface> renderSurface = getRenderEngine().createSurface();
renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
- renderSurface->setAsync(state.type >= DisplayDevice::DISPLAY_VIRTUAL);
+ renderSurface->setAsync(state.isVirtual());
renderSurface->setNativeWindow(nativeWindow.get());
const int displayWidth = renderSurface->queryWidth();
const int displayHeight = renderSurface->queryHeight();
@@ -2397,19 +2503,22 @@
// * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
// window's swap interval in eglMakeCurrent, so they'll override the
// interval we set here.
- if (state.type >= DisplayDevice::DISPLAY_VIRTUAL) {
+ if (state.isVirtual()) {
nativeWindow->setSwapInterval(nativeWindow.get(), 0);
}
- // virtual displays are always considered enabled
- auto initialPowerMode = (state.type >= DisplayDevice::DISPLAY_VIRTUAL) ? HWC_POWER_MODE_NORMAL
- : HWC_POWER_MODE_OFF;
+ const int displayInstallOrientation = state.type == DisplayDevice::DISPLAY_PRIMARY ?
+ primaryDisplayOrientation : DisplayState::eOrientationDefault;
- sp<DisplayDevice> hw =
- new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
- dispSurface, std::move(renderSurface), displayWidth, displayHeight,
- hasWideColorGamut, hdrCapabilities,
- supportedPerFrameMetadata, hwcColorModes, initialPowerMode);
+ // virtual displays are always considered enabled
+ auto initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
+
+ sp<DisplayDevice> display =
+ new DisplayDevice(this, state.type, displayId, state.isSecure, displayToken,
+ nativeWindow, dispSurface, std::move(renderSurface), displayWidth,
+ displayHeight, displayInstallOrientation, hasWideColorGamut,
+ hdrCapabilities, supportedPerFrameMetadata, hwcColorModes,
+ initialPowerMode);
if (maxFrameBufferAcquiredBuffers >= 3) {
nativeWindowSurface->preallocateBuffers();
@@ -2421,16 +2530,16 @@
defaultColorMode = ColorMode::SRGB;
defaultDataSpace = Dataspace::SRGB;
}
- setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace,
+ setActiveColorModeInternal(display, defaultColorMode, defaultDataSpace,
RenderIntent::COLORIMETRIC);
if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
- hw->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+ display->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
}
- hw->setLayerStack(state.layerStack);
- hw->setProjection(state.orientation, state.viewport, state.frame);
- hw->setDisplayName(state.displayName);
+ display->setLayerStack(state.layerStack);
+ display->setProjection(state.orientation, state.viewport, state.frame);
+ display->setDisplayName(state.displayName);
- return hw;
+ return display;
}
void SurfaceFlinger::processDisplayChangesLocked() {
@@ -2455,17 +2564,32 @@
// Call makeCurrent() on the primary display so we can
// be sure that nothing associated with this display
// is current.
- const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
- if (defaultDisplay != nullptr) defaultDisplay->makeCurrent();
- sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
- if (hw != nullptr) hw->disconnect(getHwComposer());
- if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
- mEventThread->onHotplugReceived(draw[i].type, false);
- mDisplays.removeItem(draw.keyAt(i));
+ if (const auto defaultDisplay = getDefaultDisplayDeviceLocked()) {
+ defaultDisplay->makeCurrent();
+ }
+ if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
+ display->disconnect(getHwComposer());
+ }
+ if (draw[i].type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle,
+ EventThread::DisplayType::Primary, false);
+ } else {
+ mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+ }
+ } else if (draw[i].type == DisplayDevice::DISPLAY_EXTERNAL) {
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle,
+ EventThread::DisplayType::External, false);
+ } else {
+ mEventThread->onHotplugReceived(EventThread::DisplayType::External, false);
+ }
+ }
+ mDisplays.erase(draw.keyAt(i));
} else {
// this display is in both lists. see if something changed.
const DisplayDeviceState& state(curr[j]);
- const wp<IBinder>& display(curr.keyAt(j));
+ const wp<IBinder>& displayToken = curr.keyAt(j);
const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
if (state_binder != draw_binder) {
@@ -2473,26 +2597,26 @@
// recreating the DisplayDevice, so we just remove it
// from the drawing state, so that it get re-added
// below.
- sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
- if (hw != nullptr) hw->disconnect(getHwComposer());
- mDisplays.removeItem(display);
+ if (const auto display = getDisplayDeviceLocked(displayToken)) {
+ display->disconnect(getHwComposer());
+ }
+ mDisplays.erase(displayToken);
mDrawingState.displays.removeItemsAt(i);
dc--;
// at this point we must loop to the next item
continue;
}
- const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
- if (disp != nullptr) {
+ if (const auto display = getDisplayDeviceLocked(displayToken)) {
if (state.layerStack != draw[i].layerStack) {
- disp->setLayerStack(state.layerStack);
+ display->setLayerStack(state.layerStack);
}
if ((state.orientation != draw[i].orientation) ||
(state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) {
- disp->setProjection(state.orientation, state.viewport, state.frame);
+ display->setProjection(state.orientation, state.viewport, state.frame);
}
if (state.width != draw[i].width || state.height != draw[i].height) {
- disp->setDisplaySize(state.width, state.height);
+ display->setDisplaySize(state.width, state.height);
}
}
}
@@ -2511,8 +2635,8 @@
sp<IGraphicBufferConsumer> bqConsumer;
mCreateBufferQueue(&bqProducer, &bqConsumer, false);
- int32_t hwcId = -1;
- if (state.isVirtualDisplay()) {
+ int32_t displayId = -1;
+ if (state.isVirtual()) {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
// etc.) but no internal state (i.e. a DisplayDevice).
@@ -2530,13 +2654,14 @@
ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
auto format = static_cast<ui::PixelFormat>(intFormat);
- getBE().mHwc->allocateVirtualDisplay(width, height, &format, &hwcId);
+ getBE().mHwc->allocateVirtualDisplay(width, height, &format,
+ &displayId);
}
// TODO: Plumb requested format back up to consumer
sp<VirtualDisplaySurface> vds =
- new VirtualDisplaySurface(*getBE().mHwc, hwcId, state.surface,
+ new VirtualDisplaySurface(*getBE().mHwc, displayId, state.surface,
bqProducer, bqConsumer,
state.displayName);
@@ -2549,18 +2674,36 @@
"surface is provided (%p), ignoring it",
state.surface.get());
- hwcId = state.type;
- dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
+ displayId = state.type;
+ dispSurface = new FramebufferSurface(*getBE().mHwc, displayId, bqConsumer);
producer = bqProducer;
}
- const wp<IBinder>& display(curr.keyAt(i));
+ const wp<IBinder>& displayToken = curr.keyAt(i);
if (dispSurface != nullptr) {
- mDisplays.add(display,
- setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface,
- producer));
- if (!state.isVirtualDisplay()) {
- mEventThread->onHotplugReceived(state.type, true);
+ mDisplays.emplace(displayToken,
+ setupNewDisplayDeviceInternal(displayToken, displayId, state,
+ dispSurface, producer));
+ if (!state.isVirtual()) {
+ if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle,
+ EventThread::DisplayType::Primary,
+ true);
+ } else {
+ mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
+ true);
+ }
+ } else if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle,
+ EventThread::DisplayType::External,
+ true);
+ } else {
+ mEventThread->onHotplugReceived(EventThread::DisplayType::External,
+ true);
+ }
+ }
}
}
}
@@ -2622,7 +2765,7 @@
// happened yet, so we must use the current state layer list
// (soon to become the drawing state list).
//
- sp<const DisplayDevice> disp;
+ sp<const DisplayDevice> hintDisplay;
uint32_t currentlayerStack = 0;
bool first = true;
mCurrentState.traverseInZOrder([&](Layer* layer) {
@@ -2635,34 +2778,33 @@
// figure out if this layerstack is mirrored
// (more than one display) if so, pick the default display,
// if not, pick the only display it's on.
- disp.clear();
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
- if (disp == nullptr) {
- disp = std::move(hw);
- } else {
- disp = nullptr;
+ hintDisplay = nullptr;
+ for (const auto& [token, display] : mDisplays) {
+ if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ if (hintDisplay) {
+ hintDisplay = nullptr;
break;
+ } else {
+ hintDisplay = display;
}
}
}
}
- if (disp == nullptr) {
+ if (!hintDisplay) {
// NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
// redraw after transform hint changes. See bug 8508397.
// could be null when this layer is using a layerStack
// that is not visible on any display. Also can occur at
// screen off/on times.
- disp = getDefaultDisplayDeviceLocked();
+ hintDisplay = getDefaultDisplayDeviceLocked();
}
- // disp can be null if there is no display available at all to get
+ // could be null if there is no display available at all to get
// the transform hint from.
- if (disp != nullptr) {
- layer->updateTransformHint(disp);
+ if (hintDisplay) {
+ layer->updateTransformHint(hintDisplay);
}
first = false;
@@ -2705,14 +2847,13 @@
void SurfaceFlinger::updateCursorAsync()
{
- for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
- auto& displayDevice = mDisplays[displayId];
- if (displayDevice->getHwcDisplayId() < 0) {
+ for (const auto& [token, display] : mDisplays) {
+ if (display->getId() < 0) {
continue;
}
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- layer->updateCursorPosition(displayDevice);
+ for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ layer->updateCursorPosition(display);
}
}
}
@@ -2745,9 +2886,8 @@
mTransactionCV.broadcast();
}
-void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
- Region& outDirtyRegion, Region& outOpaqueRegion)
-{
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& display,
+ Region& outDirtyRegion, Region& outOpaqueRegion) {
ATRACE_CALL();
ALOGV("computeVisibleRegions");
@@ -2762,8 +2902,9 @@
const Layer::State& s(layer->getDrawingState());
// only consider the layers on the given layer stack
- if (!layer->belongsToDisplay(displayDevice->getLayerStack(), displayDevice->isPrimary()))
+ if (!layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
return;
+ }
/*
* opaqueRegion: area of a surface that is fully opaque.
@@ -2800,13 +2941,13 @@
const bool translucent = !layer->isOpaque(s);
Rect bounds(layer->computeScreenBounds());
visibleRegion.set(bounds);
- Transform tr = layer->getTransform();
+ ui::Transform tr = layer->getTransform();
if (!visibleRegion.isEmpty()) {
// Remove the transparent area from the visible region
if (translucent) {
if (tr.preserveRects()) {
// transform the transparent region
- transparentRegion = tr.transform(s.activeTransparentRegion);
+ transparentRegion = tr.transform(layer->getActiveTransparentRegion(s));
} else {
// transformation too complex, can't do the
// transparent region optimization.
@@ -2817,7 +2958,7 @@
// compute the opaque region
const int32_t layerOrientation = tr.getOrientation();
if (layer->getAlpha() == 1.0f && !translucent &&
- ((layerOrientation & Transform::ROT_INVALID) == false)) {
+ ((layerOrientation & ui::Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
}
@@ -2883,10 +3024,9 @@
}
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- const sp<DisplayDevice>& hw(mDisplays[dpy]);
- if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
- hw->dirtyRegion.orSelf(dirty);
+ for (const auto& [token, display] : mDisplays) {
+ if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ display->dirtyRegion.orSelf(dirty);
}
}
}
@@ -2911,9 +3051,9 @@
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display.
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->hasQueuedFrame()) {
+ if (layer->hasReadyFrame()) {
frameQueued = true;
- if (layer->shouldPresentNow(mPrimaryDispSync)) {
+ if (layer->shouldPresentNow(*mPrimaryDispSync)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
layer->useEmptyDamage();
@@ -2956,36 +3096,32 @@
mGeometryInvalid = true;
}
-
-void SurfaceFlinger::doDisplayComposition(
- const sp<const DisplayDevice>& displayDevice,
- const Region& inDirtyRegion)
-{
+void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& display,
+ const Region& inDirtyRegion) {
// 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
// 2) There is work to be done (the dirty region isn't empty)
- bool isHwcDisplay = displayDevice->getHwcDisplayId() >= 0;
+ bool isHwcDisplay = display->getId() >= 0;
if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
ALOGV("Skipping display composition");
return;
}
ALOGV("doDisplayComposition");
- if (!doComposeSurfaces(displayDevice)) return;
+ if (!doComposeSurfaces(display)) return;
// swap buffers (presentation)
- displayDevice->swapBuffers(getHwComposer());
+ display->swapBuffers(getHwComposer());
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDevice)
-{
+bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& display) {
ALOGV("doComposeSurfaces");
- const Region bounds(displayDevice->bounds());
- const DisplayRenderArea renderArea(displayDevice);
- const auto hwcId = displayDevice->getHwcDisplayId();
- const bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
+ const Region bounds(display->bounds());
+ const DisplayRenderArea renderArea(display);
+ const auto displayId = display->getId();
+ const bool hasClientComposition = getBE().mHwc->hasClientComposition(displayId);
ATRACE_INT("hasClientComposition", hasClientComposition);
bool applyColorMatrix = false;
@@ -2995,14 +3131,14 @@
ALOGV("hasClientComposition");
Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (displayDevice->hasWideColorGamut()) {
- outputDataspace = displayDevice->getCompositionDataSpace();
+ if (display->hasWideColorGamut()) {
+ outputDataspace = display->getCompositionDataSpace();
}
getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
getBE().mRenderEngine->setDisplayMaxLuminance(
- displayDevice->getHdrCapabilities().getDesiredMaxLuminance());
+ display->getHdrCapabilities().getDesiredMaxLuminance());
- const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
+ const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(displayId);
const bool skipClientColorTransform = getBE().mHwc->hasCapability(
HWC2::Capability::SkipClientColorTransform);
@@ -3016,7 +3152,7 @@
// thus we only apply this matrix when the render intent is not colorimetric
// and the output color space is Display P3.
needsEnhancedColorMatrix =
- (displayDevice->getActiveRenderIntent() >= RenderIntent::ENHANCE &&
+ (display->getActiveRenderIntent() >= RenderIntent::ENHANCE &&
outputDataspace == Dataspace::DISPLAY_P3);
if (needsEnhancedColorMatrix) {
colorMatrix *= mEnhancedSaturationMatrix;
@@ -3024,14 +3160,15 @@
getRenderEngine().setupColorTransform(colorMatrix);
- if (!displayDevice->makeCurrent()) {
+ if (!display->makeCurrent()) {
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
- displayDevice->getDisplayName().string());
+ display->getDisplayName().c_str());
getRenderEngine().resetCurrentSurface();
// |mStateLock| not needed as we are on the main thread
- if(!getDefaultDisplayDeviceLocked()->makeCurrent()) {
- ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
+ const auto defaultDisplay = getDefaultDisplayDeviceLocked();
+ if (!defaultDisplay || !defaultDisplay->makeCurrent()) {
+ ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
}
return false;
}
@@ -3048,27 +3185,27 @@
// we start with the whole screen area and remove the scissor part
// we're left with the letterbox region
// (common case is that letterbox ends-up being empty)
- const Region letterbox(bounds.subtract(displayDevice->getScissor()));
+ const Region letterbox = bounds.subtract(display->getScissor());
// compute the area to clear
- Region region(displayDevice->undefinedRegion.merge(letterbox));
+ const Region region = display->undefinedRegion.merge(letterbox);
// screen is already cleared here
if (!region.isEmpty()) {
// can happen with SurfaceView
- drawWormhole(displayDevice, region);
+ drawWormhole(region);
}
}
- const Rect& bounds(displayDevice->getBounds());
- const Rect& scissor(displayDevice->getScissor());
+ const Rect& bounds = display->getBounds();
+ const Rect& scissor = display->getScissor();
if (scissor != bounds) {
// scissor doesn't match the screen's dimensions, so we
// need to clear everything outside of it and enable
// the GL scissor so we don't draw anything where we shouldn't
// enable scissor for this frame
- const uint32_t height = displayDevice->getHeight();
+ const uint32_t height = display->getHeight();
getBE().mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
scissor.getWidth(), scissor.getHeight());
}
@@ -3079,24 +3216,23 @@
*/
ALOGV("Rendering client layers");
- const Transform& displayTransform = displayDevice->getTransform();
+ const ui::Transform& displayTransform = display->getTransform();
bool firstLayer = true;
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ for (auto& layer : display->getVisibleLayersSortedByZ()) {
const Region clip(bounds.intersect(
displayTransform.transform(layer->visibleRegion)));
ALOGV("Layer: %s", layer->getName().string());
- ALOGV(" Composition type: %s",
- to_string(layer->getCompositionType(hwcId)).c_str());
+ ALOGV(" Composition type: %s", to_string(layer->getCompositionType(displayId)).c_str());
if (!clip.isEmpty()) {
- switch (layer->getCompositionType(hwcId)) {
+ switch (layer->getCompositionType(displayId)) {
case HWC2::Composition::Cursor:
case HWC2::Composition::Device:
case HWC2::Composition::Sideband:
case HWC2::Composition::SolidColor: {
const Layer::State& state(layer->getDrawingState());
- if (layer->getClearClientTarget(hwcId) && !firstLayer &&
- layer->isOpaque(state) && (state.color.a == 1.0f)
- && hasClientComposition) {
+ if (layer->getClearClientTarget(displayId) && !firstLayer &&
+ layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
+ hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
layer->clearWithOpenGL(renderArea);
@@ -3125,10 +3261,9 @@
return true;
}
-void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const {
- const int32_t height = displayDevice->getHeight();
+void SurfaceFlinger::drawWormhole(const Region& region) const {
auto& engine(getRenderEngine());
- engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
+ engine.fillRegionWithColor(region, 0, 0, 0, 0);
}
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
@@ -3357,53 +3492,51 @@
}
}
-uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
-{
- ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
- if (dpyIdx < 0)
- return 0;
+uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
+ const ssize_t index = mCurrentState.displays.indexOfKey(s.token);
+ if (index < 0) return 0;
uint32_t flags = 0;
- DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
- if (disp.isValid()) {
- const uint32_t what = s.what;
- if (what & DisplayState::eSurfaceChanged) {
- if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) {
- disp.surface = s.surface;
- flags |= eDisplayTransactionNeeded;
- }
- }
- if (what & DisplayState::eLayerStackChanged) {
- if (disp.layerStack != s.layerStack) {
- disp.layerStack = s.layerStack;
- flags |= eDisplayTransactionNeeded;
- }
- }
- if (what & DisplayState::eDisplayProjectionChanged) {
- if (disp.orientation != s.orientation) {
- disp.orientation = s.orientation;
- flags |= eDisplayTransactionNeeded;
- }
- if (disp.frame != s.frame) {
- disp.frame = s.frame;
- flags |= eDisplayTransactionNeeded;
- }
- if (disp.viewport != s.viewport) {
- disp.viewport = s.viewport;
- flags |= eDisplayTransactionNeeded;
- }
- }
- if (what & DisplayState::eDisplaySizeChanged) {
- if (disp.width != s.width) {
- disp.width = s.width;
- flags |= eDisplayTransactionNeeded;
- }
- if (disp.height != s.height) {
- disp.height = s.height;
- flags |= eDisplayTransactionNeeded;
- }
+ DisplayDeviceState& state = mCurrentState.displays.editValueAt(index);
+
+ const uint32_t what = s.what;
+ if (what & DisplayState::eSurfaceChanged) {
+ if (IInterface::asBinder(state.surface) != IInterface::asBinder(s.surface)) {
+ state.surface = s.surface;
+ flags |= eDisplayTransactionNeeded;
}
}
+ if (what & DisplayState::eLayerStackChanged) {
+ if (state.layerStack != s.layerStack) {
+ state.layerStack = s.layerStack;
+ flags |= eDisplayTransactionNeeded;
+ }
+ }
+ if (what & DisplayState::eDisplayProjectionChanged) {
+ if (state.orientation != s.orientation) {
+ state.orientation = s.orientation;
+ flags |= eDisplayTransactionNeeded;
+ }
+ if (state.frame != s.frame) {
+ state.frame = s.frame;
+ flags |= eDisplayTransactionNeeded;
+ }
+ if (state.viewport != s.viewport) {
+ state.viewport = s.viewport;
+ flags |= eDisplayTransactionNeeded;
+ }
+ }
+ if (what & DisplayState::eDisplaySizeChanged) {
+ if (state.width != s.width) {
+ state.width = s.width;
+ flags |= eDisplayTransactionNeeded;
+ }
+ if (state.height != s.height) {
+ state.height = s.height;
+ flags |= eDisplayTransactionNeeded;
+ }
+ }
+
return flags;
}
@@ -3411,9 +3544,8 @@
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
-
if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
- !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
+ !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
return false;
}
return true;
@@ -3441,7 +3573,7 @@
// If we are deferring transaction, make sure to push the pending state, as otherwise the
// pending state will also be deferred.
- if (what & layer_state_t::eDeferTransaction) {
+ if (what & layer_state_t::eDeferTransaction_legacy) {
layer->pushPendingState();
}
@@ -3526,12 +3658,8 @@
if (layer->setFlags(s.flags, s.mask))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eCropChanged) {
- if (layer->setCrop(s.crop, !geometryAppliesWithResize))
- flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eFinalCropChanged) {
- if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
+ if (what & layer_state_t::eCropChanged_legacy) {
+ if (layer->setCrop_legacy(s.crop_legacy, !geometryAppliesWithResize))
flags |= eTraversalNeeded;
}
if (what & layer_state_t::eLayerStackChanged) {
@@ -3553,15 +3681,15 @@
flags |= eTransactionNeeded|eTraversalNeeded|eDisplayLayerStackChanged;
}
}
- if (what & layer_state_t::eDeferTransaction) {
- if (s.barrierHandle != nullptr) {
- layer->deferTransactionUntil(s.barrierHandle, s.frameNumber);
- } else if (s.barrierGbp != nullptr) {
- const sp<IGraphicBufferProducer>& gbp = s.barrierGbp;
+ if (what & layer_state_t::eDeferTransaction_legacy) {
+ if (s.barrierHandle_legacy != nullptr) {
+ layer->deferTransactionUntil_legacy(s.barrierHandle_legacy, s.frameNumber_legacy);
+ } else if (s.barrierGbp_legacy != nullptr) {
+ const sp<IGraphicBufferProducer>& gbp = s.barrierGbp_legacy;
if (authenticateSurfaceTextureLocked(gbp)) {
const auto& otherLayer =
(static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
- layer->deferTransactionUntil(otherLayer, s.frameNumber);
+ layer->deferTransactionUntil_legacy(otherLayer, s.frameNumber_legacy);
} else {
ALOGE("Attempt to defer transaction to to an"
" unrecognized GraphicBufferProducer");
@@ -3592,6 +3720,37 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
+ if (what & layer_state_t::eTransformChanged) {
+ if (layer->setTransform(s.transform)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eTransformToDisplayInverseChanged) {
+ if (layer->setTransformToDisplayInverse(s.transformToDisplayInverse))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eCropChanged) {
+ if (layer->setCrop(s.crop)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eBufferChanged) {
+ if (layer->setBuffer(s.buffer)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eAcquireFenceChanged) {
+ if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eDataspaceChanged) {
+ if (layer->setDataspace(s.dataspace)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eHdrMetadataChanged) {
+ if (layer->setHdrMetadata(s.hdrMetadata)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eSurfaceDamageRegionChanged) {
+ if (layer->setSurfaceDamageRegion(s.surfaceDamageRegion)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eApiChanged) {
+ if (layer->setApi(s.api)) flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eSidebandStreamChanged) {
+ if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
+ }
return flags;
}
@@ -3634,17 +3793,24 @@
String8 uniqueName = getUniqueLayerName(name);
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
- case ISurfaceComposerClient::eFXSurfaceNormal:
- result = createBufferLayer(client,
- uniqueName, w, h, flags, format,
- handle, gbp, &layer);
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ result = createBufferQueueLayer(client, uniqueName, w, h, flags, format, handle, gbp,
+ &layer);
break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ result = createBufferStateLayer(client, uniqueName, w, h, flags, handle, &layer);
+ break;
case ISurfaceComposerClient::eFXSurfaceColor:
result = createColorLayer(client,
uniqueName, w, h, flags,
handle, &layer);
break;
+ case ISurfaceComposerClient::eFXSurfaceContainer:
+ result = createContainerLayer(client,
+ uniqueName, w, h, flags,
+ handle, &layer);
+ break;
default:
result = BAD_VALUE;
break;
@@ -3695,15 +3861,17 @@
});
}
- ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+ ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(),
+ uniqueName.c_str());
return uniqueName;
}
-status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
- const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
-{
+status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags,
+ PixelFormat& format, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp,
+ sp<Layer>* outLayer) {
// initialize the surfaces
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
@@ -3715,18 +3883,28 @@
break;
}
- sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
- status_t err = layer->setBuffers(w, h, format, flags);
+ sp<BufferQueueLayer> layer = new BufferQueueLayer(this, client, name, w, h, flags);
+ status_t err = layer->setDefaultBufferProperties(w, h, format);
if (err == NO_ERROR) {
*handle = layer->getHandle();
*gbp = layer->getProducer();
*outLayer = layer;
}
- ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
+ ALOGE_IF(err, "createBufferQueueLayer() failed (%s)", strerror(-err));
return err;
}
+status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags,
+ sp<IBinder>* handle, sp<Layer>* outLayer) {
+ sp<BufferStateLayer> layer = new BufferStateLayer(this, client, name, w, h, flags);
+ *handle = layer->getHandle();
+ *outLayer = layer;
+
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags,
sp<IBinder>* handle, sp<Layer>* outLayer)
@@ -3736,6 +3914,16 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+ sp<IBinder>* handle, sp<Layer>* outLayer)
+{
+ *outLayer = new ContainerLayer(this, client, name, w, h, flags);
+ *handle = (*outLayer)->getHandle();
+ return NO_ERROR;
+}
+
+
status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
{
// called by a client when it wants to remove a Layer
@@ -3766,13 +3954,16 @@
// ---------------------------------------------------------------------------
void SurfaceFlinger::onInitializeDisplays() {
+ const auto displayToken = mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY];
+ if (!displayToken) return;
+
// reset screen orientation and use primary layer stack
Vector<ComposerState> state;
Vector<DisplayState> displays;
DisplayState d;
d.what = DisplayState::eDisplayProjectionChanged |
DisplayState::eLayerStackChanged;
- d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
+ d.token = displayToken;
d.layerStack = 0;
d.orientation = DisplayState::eOrientationDefault;
d.frame.makeInvalid();
@@ -3781,10 +3972,13 @@
d.height = 0;
displays.add(d);
setTransactionState(state, displays, 0);
- setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL,
- /*stateLockHeld*/ false);
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) return;
+
+ setPowerModeInternal(display, HWC_POWER_MODE_NORMAL, /*stateLockHeld*/ false);
+
+ const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
@@ -3794,53 +3988,48 @@
}
void SurfaceFlinger::initializeDisplays() {
- class MessageScreenInitialized : public MessageBase {
- SurfaceFlinger* flinger;
- public:
- explicit MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
- virtual bool handler() {
- flinger->onInitializeDisplays();
- return true;
- }
- };
- sp<MessageBase> msg = new MessageScreenInitialized(this);
- postMessageAsync(msg); // we may be called from main thread, use async message
+ // Async since we may be called from the main thread.
+ postMessageAsync(new LambdaMessage([this] { onInitializeDisplays(); }));
}
-void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
- int mode, bool stateLockHeld) {
- ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
- this);
- int32_t type = hw->getDisplayType();
- int currentMode = hw->getPowerMode();
+void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode,
+ bool stateLockHeld) {
+ const int32_t displayId = display->getId();
+ ALOGD("Setting power mode %d on display %d", mode, displayId);
+ int currentMode = display->getPowerMode();
if (mode == currentMode) {
return;
}
- hw->setPowerMode(mode);
- if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ if (display->isVirtual()) {
ALOGW("Trying to set power mode for virtual display");
return;
}
+ display->setPowerMode(mode);
+
if (mInterceptor->isEnabled()) {
ConditionalLock lock(mStateLock, !stateLockHeld);
- ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken());
+ ssize_t idx = mCurrentState.displays.indexOfKey(display->getDisplayToken());
if (idx < 0) {
ALOGW("Surface Interceptor SavePowerMode: invalid display token");
return;
}
- mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode);
+ mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).sequenceId, mode);
}
+ int32_t type = display->getDisplayType();
if (currentMode == HWC_POWER_MODE_OFF) {
// Turn on the display
getHwComposer().setPowerMode(type, mode);
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
- mode != HWC_POWER_MODE_DOZE_SUSPEND) {
+ if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
// FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenAcquired();
+ if (mUseScheduler) {
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ } else {
+ mEventThread->onScreenAcquired();
+ }
resyncToHardwareVsync(true);
}
@@ -3860,12 +4049,15 @@
ALOGW("Couldn't set SCHED_OTHER on display off");
}
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
- currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
+ if (display->isPrimary() && currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
disableHardwareVsync(true); // also cancels any in-progress resync
// FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenReleased();
+ if (mUseScheduler) {
+ mScheduler->onScreenReleased(mAppConnectionHandle);
+ } else {
+ mEventThread->onScreenReleased();
+ }
}
getHwComposer().setPowerMode(type, mode);
@@ -3875,53 +4067,47 @@
mode == HWC_POWER_MODE_NORMAL) {
// Update display while dozing
getHwComposer().setPowerMode(type, mode);
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
- currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
+ if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
// FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenAcquired();
+ if (mUseScheduler) {
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ } else {
+ mEventThread->onScreenAcquired();
+ }
resyncToHardwareVsync(true);
}
} else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
// Leave display going to doze
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (display->isPrimary()) {
disableHardwareVsync(true); // also cancels any in-progress resync
// FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenReleased();
+ if (mUseScheduler) {
+ mScheduler->onScreenReleased(mAppConnectionHandle);
+ } else {
+ mEventThread->onScreenReleased();
+ }
}
getHwComposer().setPowerMode(type, mode);
} else {
ALOGE("Attempting to set unknown power mode: %d\n", mode);
getHwComposer().setPowerMode(type, mode);
}
- ALOGD("Finished set power mode=%d, type=%d", mode, hw->getDisplayType());
+
+ ALOGD("Finished setting power mode %d on display %d", mode, displayId);
}
-void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
- class MessageSetPowerMode: public MessageBase {
- SurfaceFlinger& mFlinger;
- sp<IBinder> mDisplay;
- int mMode;
- public:
- MessageSetPowerMode(SurfaceFlinger& flinger,
- const sp<IBinder>& disp, int mode) : mFlinger(flinger),
- mDisplay(disp) { mMode = mode; }
- virtual bool handler() {
- sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == nullptr) {
- ALOGE("Attempt to set power mode = %d for null display %p",
- mMode, mDisplay.get());
- } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
- ALOGW("Attempt to set power mode = %d for virtual display",
- mMode);
- } else {
- mFlinger.setPowerModeInternal(
- hw, mMode, /*stateLockHeld*/ false);
- }
- return true;
+void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
+ postMessageSync(new LambdaMessage([&] {
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
+ displayToken.get());
+ } else if (display->isVirtual()) {
+ ALOGW("Attempt to set power mode %d for virtual display", mode);
+ } else {
+ setPowerModeInternal(display, mode, /*stateLockHeld*/ false);
}
- };
- sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode);
- postMessageSync(msg);
+ }));
}
// ---------------------------------------------------------------------------
@@ -3979,7 +4165,7 @@
if ((index < numArgs) &&
(args[index] == String16("--dispsync"))) {
index++;
- mPrimaryDispSync.dump(result);
+ mPrimaryDispSync->dump(result);
dumpAll = false;
}
@@ -4031,6 +4217,20 @@
dumpAll = false;
}
+ if ((index < numArgs) &&
+ (args[index] == String16("--frame-composition"))) {
+ index++;
+ dumpFrameCompositionInfo(result);
+ dumpAll = false;
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--display-identification"))) {
+ index++;
+ dumpDisplayIdentificationData(result);
+ dumpAll = false;
+ }
+
if ((index < numArgs) && (args[index] == String16("--timestats"))) {
index++;
mTimeStats.parseArgs(asProto, args, index, result);
@@ -4072,9 +4272,12 @@
index++;
}
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
- const nsecs_t period = activeConfig->getVsyncPeriod();
- result.appendFormat("%" PRId64 "\n", period);
+ if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
+ getHwComposer().isConnected(displayId)) {
+ const auto activeConfig = getBE().mHwc->getActiveConfig(displayId);
+ const nsecs_t period = activeConfig->getVsyncPeriod();
+ result.appendFormat("%" PRId64 "\n", period);
+ }
if (name.isEmpty()) {
mAnimFrameTracker.dumpStats(result);
@@ -4210,33 +4413,100 @@
result.append("\n");
}
+void SurfaceFlinger::dumpDisplayIdentificationData(String8& result) const {
+ for (const auto& [token, display] : mDisplays) {
+ const int32_t displayId = display->getId();
+ const auto hwcDisplayId = getHwComposer().getHwcDisplayId(displayId);
+ if (!hwcDisplayId) {
+ continue;
+ }
+
+ result.appendFormat("Display %d (HWC display %" PRIu64 "): ", displayId, *hwcDisplayId);
+ uint8_t port;
+ DisplayIdentificationData data;
+ if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
+ result.append("no identification data\n");
+ continue;
+ }
+
+ if (!isEdid(data)) {
+ result.append("unknown identification data: ");
+ for (uint8_t byte : data) {
+ result.appendFormat("%x ", byte);
+ }
+ result.append("\n");
+ continue;
+ }
+
+ const auto edid = parseEdid(data);
+ if (!edid) {
+ result.append("invalid EDID: ");
+ for (uint8_t byte : data) {
+ result.appendFormat("%x ", byte);
+ }
+ result.append("\n");
+ continue;
+ }
+
+ result.appendFormat("port=%u pnpId=%s displayName=\"", port, edid->pnpId.data());
+ result.append(edid->displayName.data(), edid->displayName.length());
+ result.append("\"\n");
+ }
+ result.append("\n");
+}
+
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
- result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
+ result.appendFormat("Device has wide color display: %d\n", hasWideColorDisplay);
+ result.appendFormat("Device uses color management: %d\n", useColorManagement);
result.appendFormat("DisplayColorSetting: %s\n",
decodeDisplayColorSetting(mDisplayColorSetting).c_str());
// TODO: print out if wide-color mode is active or not
- for (size_t d = 0; d < mDisplays.size(); d++) {
- const sp<const DisplayDevice>& displayDevice(mDisplays[d]);
- int32_t hwcId = displayDevice->getHwcDisplayId();
- if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+ for (const auto& [token, display] : mDisplays) {
+ const int32_t displayId = display->getId();
+ if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
continue;
}
- result.appendFormat("Display %d color modes:\n", hwcId);
- std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
+ result.appendFormat("Display %d color modes:\n", displayId);
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
for (auto&& mode : modes) {
result.appendFormat(" %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
- ColorMode currentMode = displayDevice->getActiveColorMode();
+ ColorMode currentMode = display->getActiveColorMode();
result.appendFormat(" Current color mode: %s (%d)\n",
decodeColorMode(currentMode).c_str(), currentMode);
}
result.append("\n");
}
+void SurfaceFlinger::dumpFrameCompositionInfo(String8& result) const {
+ std::string stringResult;
+
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = display->getId();
+ if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ continue;
+ }
+
+ const auto& compositionInfoIt = getBE().mEndOfFrameCompositionInfo.find(displayId);
+ if (compositionInfoIt == getBE().mEndOfFrameCompositionInfo.end()) {
+ break;
+ }
+ const auto& compositionInfoList = compositionInfoIt->second;
+ stringResult += base::StringPrintf("Display: %d\n", displayId);
+ stringResult += base::StringPrintf("numComponents: %zu\n", compositionInfoList.size());
+ for (const auto& compositionInfo : compositionInfoList) {
+ compositionInfo.dump(stringResult, nullptr);
+ stringResult += base::StringPrintf("\n");
+ }
+ }
+
+ result.append(stringResult.c_str());
+}
+
LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const {
LayersProto layersProto;
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
@@ -4249,23 +4519,22 @@
return layersProto;
}
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& display) const {
LayersProto layersProto;
- const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
SizeProto* resolution = layersProto.mutable_resolution();
- resolution->set_w(displayDevice->getWidth());
- resolution->set_h(displayDevice->getHeight());
+ resolution->set_w(display.getWidth());
+ resolution->set_h(display.getHeight());
- layersProto.set_color_mode(decodeColorMode(displayDevice->getActiveColorMode()));
- layersProto.set_color_transform(decodeColorTransform(displayDevice->getColorTransform()));
- layersProto.set_global_transform(
- static_cast<int32_t>(displayDevice->getOrientationTransform()));
+ layersProto.set_color_mode(decodeColorMode(display.getActiveColorMode()));
+ layersProto.set_color_transform(decodeColorTransform(display.getColorTransform()));
+ layersProto.set_global_transform(static_cast<int32_t>(display.getOrientationTransform()));
+ const int32_t displayId = display.getId();
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(hwcId)) {
+ if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(displayId)) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, hwcId);
+ layer->writeToProto(layerProto, displayId);
}
});
@@ -4286,9 +4555,7 @@
// figure out if we're stuck somewhere
const nsecs_t now = systemTime();
- const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
const nsecs_t inTransaction(mDebugInTransaction);
- nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
/*
@@ -4303,6 +4570,9 @@
appendGuiConfigString(result);
result.append("\n");
+ result.append("\nDisplay identification data:\n");
+ dumpDisplayIdentificationData(result);
+
result.append("\nWide-Color information:\n");
dumpWideColorInfo(result);
@@ -4312,28 +4582,32 @@
result.append(SyncFeatures::getInstance().toString());
result.append("\n");
- const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
-
colorizer.bold(result);
- result.append("DispSync configuration: ");
+ result.append("DispSync configuration:\n");
colorizer.reset(result);
+
const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
- result.appendFormat(
- "app phase %" PRId64 " ns, "
- "sf phase %" PRId64 " ns, "
- "early app phase %" PRId64 " ns, "
- "early sf phase %" PRId64 " ns, "
- "early app gl phase %" PRId64 " ns, "
- "early sf gl phase %" PRId64 " ns, "
- "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
- vsyncPhaseOffsetNs,
- sfVsyncPhaseOffsetNs,
- appEarlyOffset,
- sfEarlyOffset,
- appEarlyGlOffset,
- sfEarlyOffset,
- dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+ if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
+ getHwComposer().isConnected(displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(displayId);
+ result.appendFormat("Display %d: "
+ "app phase %" PRId64 " ns, "
+ "sf phase %" PRId64 " ns, "
+ "early app phase %" PRId64 " ns, "
+ "early sf phase %" PRId64 " ns, "
+ "early app gl phase %" PRId64 " ns, "
+ "early sf gl phase %" PRId64 " ns, "
+ "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+ displayId,
+ vsyncPhaseOffsetNs,
+ sfVsyncPhaseOffsetNs,
+ appEarlyOffset,
+ sfEarlyOffset,
+ appEarlyGlOffset,
+ sfEarlyGlOffset,
+ dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+ }
result.append("\n");
// Dump static screen stats
@@ -4341,6 +4615,8 @@
dumpStaticScreenStats(result);
result.append("\n");
+ result.appendFormat("Missed frame count: %u\n\n", mFrameMissedCount.load());
+
dumpBufferingStats(result);
/*
@@ -4357,6 +4633,10 @@
result.append(LayerProtoParser::layersToString(std::move(layerTree)).c_str());
result.append("\n");
+ result.append("\nFrame-Composition information:\n");
+ dumpFrameCompositionInfo(result);
+ result.append("\n");
+
/*
* Dump Display state
*/
@@ -4364,9 +4644,8 @@
colorizer.bold(result);
result.appendFormat("Displays (%zu entries)\n", mDisplays.size());
colorizer.reset(result);
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- const sp<const DisplayDevice>& hw(mDisplays[dpy]);
- hw->dump(result);
+ for (const auto& [token, display] : mDisplays) {
+ display->dump(result);
}
result.append("\n");
@@ -4379,59 +4658,54 @@
colorizer.reset(result);
HWComposer& hwc(getHwComposer());
- sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+ const auto display = getDefaultDisplayDeviceLocked();
getBE().mRenderEngine->dump(result);
- if (hw) {
- hw->undefinedRegion.dump(result, "undefinedRegion");
- result.appendFormat(" orientation=%d, isDisplayOn=%d\n",
- hw->getOrientation(), hw->isDisplayOn());
+ if (display) {
+ display->undefinedRegion.dump(result, "undefinedRegion");
+ result.appendFormat(" orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
+ display->isPoweredOn());
}
- result.appendFormat(
- " last eglSwapBuffers() time: %f us\n"
- " last transaction time : %f us\n"
- " transaction-flags : %08x\n"
- " refresh-rate : %f fps\n"
- " x-dpi : %f\n"
- " y-dpi : %f\n"
- " gpu_to_cpu_unsupported : %d\n"
- ,
- mLastSwapBufferTime/1000.0,
- mLastTransactionTime/1000.0,
- mTransactionFlags,
- 1e9 / activeConfig->getVsyncPeriod(),
- activeConfig->getDpiX(),
- activeConfig->getDpiY(),
- !mGpuToCpuSupported);
+ result.appendFormat(" transaction-flags : %08x\n"
+ " gpu_to_cpu_unsupported : %d\n",
+ mTransactionFlags, !mGpuToCpuSupported);
- result.appendFormat(" eglSwapBuffers time: %f us\n",
- inSwapBuffersDuration/1000.0);
+ if (display) {
+ const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ result.appendFormat(" refresh-rate : %f fps\n"
+ " x-dpi : %f\n"
+ " y-dpi : %f\n",
+ 1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(),
+ activeConfig->getDpiY());
+ }
result.appendFormat(" transaction time: %f us\n",
inTransactionDuration/1000.0);
+ result.appendFormat(" use Scheduler: %s\n", mUseScheduler ? "true" : "false");
/*
* VSYNC state
*/
- mEventThread->dump(result);
+ if (mUseScheduler) {
+ mScheduler->dump(mAppConnectionHandle, result);
+ } else {
+ mEventThread->dump(result);
+ }
result.append("\n");
/*
* HWC layer minidump
*/
- for (size_t d = 0; d < mDisplays.size(); d++) {
- const sp<const DisplayDevice>& displayDevice(mDisplays[d]);
- int32_t hwcId = displayDevice->getHwcDisplayId();
- if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+ for (const auto& [token, display] : mDisplays) {
+ const int32_t displayId = display->getId();
+ if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
continue;
}
- result.appendFormat("Display %d HWC layers:\n", hwcId);
+ result.appendFormat("Display %d HWC layers:\n", displayId);
Layer::miniDumpHeader(result);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
- layer->miniDump(result, hwcId);
- });
+ mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, displayId); });
result.append("\n");
}
@@ -4462,22 +4736,17 @@
}
}
-const Vector< sp<Layer> >&
-SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) {
+const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(int32_t displayId) {
// Note: mStateLock is held here
- wp<IBinder> dpy;
- for (size_t i=0 ; i<mDisplays.size() ; i++) {
- if (mDisplays.valueAt(i)->getHwcDisplayId() == id) {
- dpy = mDisplays.keyAt(i);
- break;
+ for (const auto& [token, display] : mDisplays) {
+ if (display->getId() == displayId) {
+ return getDisplayDeviceLocked(token)->getVisibleLayersSortedByZ();
}
}
- if (dpy == nullptr) {
- ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id);
- // Just use the primary display so we have something to return
- dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
- }
- return getDisplayDeviceLocked(dpy)->getVisibleLayersSortedByZ();
+
+ ALOGE("%s: Invalid display %d", __FUNCTION__, displayId);
+ static const Vector<sp<Layer>> empty;
+ return empty;
}
bool SurfaceFlinger::startDdmConnection()
@@ -4523,51 +4792,65 @@
}
status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
- switch (code) {
- case CREATE_CONNECTION:
- case CREATE_DISPLAY:
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wswitch-enum"
+ switch (static_cast<ISurfaceComposerTag>(code)) {
+ // These methods should at minimum make sure that the client requested
+ // access to SF.
case BOOT_FINISHED:
case CLEAR_ANIMATION_FRAME_STATS:
- case GET_ANIMATION_FRAME_STATS:
- case SET_POWER_MODE:
- case GET_HDR_CAPABILITIES:
+ case CREATE_CONNECTION:
+ case CREATE_DISPLAY:
+ case DESTROY_DISPLAY:
case ENABLE_VSYNC_INJECTIONS:
+ case GET_ACTIVE_COLOR_MODE:
+ case GET_ANIMATION_FRAME_STATS:
+ case GET_HDR_CAPABILITIES:
+ case SET_ACTIVE_CONFIG:
+ case SET_ACTIVE_COLOR_MODE:
case INJECT_VSYNC:
- {
- // codes that require permission check
+ case SET_POWER_MODE: {
if (!callingThreadHasUnscopedSurfaceFlingerAccess()) {
IPCThreadState* ipc = IPCThreadState::self();
ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
ipc->getCallingPid(), ipc->getCallingUid());
return PERMISSION_DENIED;
}
- break;
- }
- /*
- * Calling setTransactionState is safe, because you need to have been
- * granted a reference to Client* and Handle* to do anything with it.
- *
- * Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
- */
- case SET_TRANSACTION_STATE:
- case CREATE_SCOPED_CONNECTION:
- {
return OK;
}
- case CAPTURE_SCREEN:
- {
- // codes that require permission check
+ case GET_LAYER_DEBUG_INFO: {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
- !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
- ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
+ if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
+ ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
- break;
+ return OK;
}
- case CAPTURE_LAYERS: {
+ // Used by apps to hook Choreographer to SurfaceFlinger.
+ case CREATE_DISPLAY_EVENT_CONNECTION:
+ // The following calls are currently used by clients that do not
+ // request necessary permissions. However, they do not expose any secret
+ // information, so it is OK to pass them.
+ case AUTHENTICATE_SURFACE:
+ case GET_ACTIVE_CONFIG:
+ case GET_BUILT_IN_DISPLAY:
+ case GET_DISPLAY_COLOR_MODES:
+ case GET_DISPLAY_CONFIGS:
+ 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.
+ case SET_TRANSACTION_STATE:
+ // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
+ case CREATE_SCOPED_CONNECTION:
+ case GET_COMPOSITION_PREFERENCE: {
+ return OK;
+ }
+ case CAPTURE_LAYERS:
+ case CAPTURE_SCREEN: {
+ // codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
@@ -4576,15 +4859,37 @@
ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
- break;
+ return OK;
+ }
+ // The following codes are deprecated and should never be allowed to access SF.
+ case CONNECT_DISPLAY_UNUSED:
+ case CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED: {
+ ALOGE("Attempting to access SurfaceFlinger with unused code: %u", code);
+ return PERMISSION_DENIED;
}
}
- return OK;
+
+ // These codes are used for the IBinder protocol to either interrogate the recipient
+ // side of the transaction for its canonical interface descriptor or to dump its state.
+ // We let them pass by default.
+ if (code == IBinder::INTERFACE_TRANSACTION || code == IBinder::DUMP_TRANSACTION ||
+ code == IBinder::PING_TRANSACTION || code == IBinder::SHELL_COMMAND_TRANSACTION ||
+ code == IBinder::SYSPROPS_TRANSACTION) {
+ return OK;
+ }
+ // Numbers from 1000 to 1029 are currently use for backdoors. The code
+ // in onTransact verifies that the user is root, and has access to use SF.
+ if (code >= 1000 && code <= 1029) {
+ ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
+ return OK;
+ }
+ ALOGE("Permission Denial: SurfaceFlinger did not recognize request code: %u", code);
+ return PERMISSION_DENIED;
+#pragma clang diagnostic pop
}
-status_t SurfaceFlinger::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
+status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
status_t credentialCheck = CheckTransactCodeCredentials(code);
if (credentialCheck != OK) {
return credentialCheck;
@@ -4649,8 +4954,12 @@
reply->writeInt32(mDebugDisableHWC);
return NO_ERROR;
case 1013: {
- sp<const DisplayDevice> hw(getDefaultDisplayDevice());
- reply->writeInt32(hw->getPageFlipCount());
+ const auto display = getDefaultDisplayDevice();
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+
+ reply->writeInt32(display->getPageFlipCount());
return NO_ERROR;
}
case 1014: {
@@ -4709,7 +5018,7 @@
// Needs to be shifted to proper binder interface when we productize
case 1016: {
n = data.readInt32();
- mPrimaryDispSync.setRefreshSkipCount(n);
+ mPrimaryDispSync->setRefreshSkipCount(n);
return NO_ERROR;
}
case 1017: {
@@ -4719,12 +5028,20 @@
}
case 1018: { // Modify Choreographer's phase offset
n = data.readInt32();
- mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ if (mUseScheduler) {
+ mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n));
+ } else {
+ mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ }
return NO_ERROR;
}
case 1019: { // Modify SurfaceFlinger's phase offset
n = data.readInt32();
- mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ if (mUseScheduler) {
+ mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n));
+ } else {
+ mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ }
return NO_ERROR;
}
case 1020: { // Layer updates interceptor
@@ -4757,7 +5074,9 @@
repaintEverything();
return NO_ERROR;
}
- case 1024: { // Is wide color gamut rendering/color management supported?
+ // TODO(b/111505327): Find out whether the usage of 1024 can switch to 1030,
+ // deprecate 1024 if they can.
+ case 1024: { // Does device have wide color gamut display?
reply->writeBool(hasWideColorDisplay);
return NO_ERROR;
}
@@ -4781,28 +5100,80 @@
}
// Is a DisplayColorSetting supported?
case 1027: {
- sp<const DisplayDevice> hw(getDefaultDisplayDevice());
- if (!hw) {
+ const auto display = getDefaultDisplayDevice();
+ if (!display) {
return NAME_NOT_FOUND;
}
DisplayColorSetting setting = static_cast<DisplayColorSetting>(data.readInt32());
switch (setting) {
case DisplayColorSetting::MANAGED:
- reply->writeBool(hasWideColorDisplay);
+ reply->writeBool(useColorManagement);
break;
case DisplayColorSetting::UNMANAGED:
reply->writeBool(true);
break;
case DisplayColorSetting::ENHANCED:
- reply->writeBool(hw->hasRenderIntent(RenderIntent::ENHANCE));
+ reply->writeBool(display->hasRenderIntent(RenderIntent::ENHANCE));
break;
default: // vendor display color setting
- reply->writeBool(hw->hasRenderIntent(static_cast<RenderIntent>(setting)));
+ reply->writeBool(
+ display->hasRenderIntent(static_cast<RenderIntent>(setting)));
break;
}
return NO_ERROR;
}
+ // Is VrFlinger active?
+ case 1028: {
+ Mutex::Autolock _l(mStateLock);
+ reply->writeBool(getBE().mHwc->isUsingVrComposer());
+ return NO_ERROR;
+ }
+ case 1029: {
+ // Code 1029 is an experimental feature that allows applications to
+ // simulate a high frequency panel by setting a multiplier and divisor
+ // on the VSYNC-sf clock. If either the multiplier or divisor are
+ // 0, then the code simply return the current multiplier and divisor.
+ HWC2::Device::FrequencyScaler frequencyScaler;
+ frequencyScaler.multiplier = data.readInt32();
+ frequencyScaler.divisor = data.readInt32();
+
+ if ((frequencyScaler.multiplier == 0) || (frequencyScaler.divisor == 0)) {
+ frequencyScaler = getBE().mHwc->getDisplayFrequencyScaleParameters();
+ reply->writeInt32(frequencyScaler.multiplier);
+ reply->writeInt32(frequencyScaler.divisor);
+ return NO_ERROR;
+ }
+
+ if ((frequencyScaler.multiplier == 1) && (frequencyScaler.divisor == 1)) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(true);
+ }
+ mPrimaryDispSync->scalePeriod(frequencyScaler);
+ getBE().mHwc->setDisplayFrequencyScaleParameters(frequencyScaler);
+
+ ATRACE_INT("PeriodMultiplier", frequencyScaler.multiplier);
+ ATRACE_INT("PeriodDivisor", frequencyScaler.divisor);
+
+ const hwc2_display_t hwcDisplayId = getBE().mHwc->getActiveConfig(
+ DisplayDevice::DISPLAY_PRIMARY)->getDisplayId();
+
+ onHotplugReceived(getBE().mComposerSequenceId,
+ hwcDisplayId, HWC2::Connection::Disconnected);
+ onHotplugReceived(getBE().mComposerSequenceId,
+ hwcDisplayId, HWC2::Connection::Connected);
+ frequencyScaler = getBE().mHwc->getDisplayFrequencyScaleParameters();
+ reply->writeInt32(frequencyScaler.multiplier);
+ reply->writeInt32(frequencyScaler.divisor);
+
+ return NO_ERROR;
+ }
+ // Is device color managed?
+ case 1030: {
+ reply->writeBool(useColorManagement);
+ return NO_ERROR;
+ }
}
}
return err;
@@ -4826,32 +5197,40 @@
const int mApi;
};
-status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform,
+status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken,
+ sp<GraphicBuffer>* outBuffer, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
+ int32_t maxLayerZ, bool useIdentityTransform,
ISurfaceComposer::Rotation rotation) {
ATRACE_CALL();
- if (CC_UNLIKELY(display == 0)) return BAD_VALUE;
+ if (!displayToken) return BAD_VALUE;
- const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
- if (CC_UNLIKELY(device == 0)) return BAD_VALUE;
+ auto renderAreaRotation = fromSurfaceComposerRotation(rotation);
- const Rect& dispScissor = device->getScissor();
- if (!dispScissor.isEmpty()) {
- sourceCrop.set(dispScissor);
- // adb shell screencap will default reqWidth and reqHeight to zeros.
+ sp<DisplayDevice> display;
+ {
+ Mutex::Autolock _l(mStateLock);
+
+ display = getDisplayDeviceLocked(displayToken);
+ if (!display) return BAD_VALUE;
+
+ // ignore sourceCrop (i.e., use the projected logical display
+ // viewport) until the framework is fixed
+ sourceCrop.clear();
+
+ // set the requested width/height to the logical display viewport size
+ // by default
if (reqWidth == 0 || reqHeight == 0) {
- reqWidth = uint32_t(device->getViewport().width());
- reqHeight = uint32_t(device->getViewport().height());
+ reqWidth = uint32_t(display->getViewport().width());
+ reqHeight = uint32_t(display->getViewport().height());
}
}
- DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
+ DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, renderAreaRotation);
auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
- device, minLayerZ, maxLayerZ, std::placeholders::_1);
+ display, minLayerZ, maxLayerZ, std::placeholders::_1);
return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform);
}
@@ -4864,20 +5243,23 @@
public:
LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
- : RenderArea(reqHeight, reqWidth, CaptureFill::CLEAR),
+ : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR),
mLayer(layer),
mCrop(crop),
+ mNeedsFiltering(false),
mFlinger(flinger),
mChildrenOnly(childrenOnly) {}
- const Transform& getTransform() const override { return mTransform; }
+ const ui::Transform& getTransform() const override { return mTransform; }
Rect getBounds() const override {
const Layer::State& layerState(mLayer->getDrawingState());
- return Rect(layerState.active.w, layerState.active.h);
+ return Rect(mLayer->getActiveWidth(layerState), mLayer->getActiveHeight(layerState));
}
- int getHeight() const override { return mLayer->getDrawingState().active.h; }
- int getWidth() const override { return mLayer->getDrawingState().active.w; }
+ int getHeight() const override {
+ return mLayer->getActiveHeight(mLayer->getDrawingState());
+ }
+ int getWidth() const override { return mLayer->getActiveWidth(mLayer->getDrawingState()); }
bool isSecure() const override { return false; }
- bool needsFiltering() const override { return false; }
+ bool needsFiltering() const override { return mNeedsFiltering; }
Rect getSourceCrop() const override {
if (mCrop.isEmpty()) {
return getBounds();
@@ -4898,6 +5280,11 @@
};
void render(std::function<void()> drawLayers) override {
+ const Rect sourceCrop = getSourceCrop();
+ // no need to check rotation because there is none
+ mNeedsFiltering = sourceCrop.width() != getReqWidth() ||
+ sourceCrop.height() != getReqHeight();
+
if (!mChildrenOnly) {
mTransform = mLayer->getTransform().inverse();
drawLayers();
@@ -4919,7 +5306,8 @@
// In the "childrenOnly" case we reparent the children to a screenshot
// layer which has no properties set and which does not draw.
sp<ContainerLayer> screenshotParentLayer;
- Transform mTransform;
+ ui::Transform mTransform;
+ bool mNeedsFiltering;
SurfaceFlinger* mFlinger;
const bool mChildrenOnly;
@@ -4943,17 +5331,25 @@
Rect crop(sourceCrop);
if (sourceCrop.width() <= 0) {
crop.left = 0;
- crop.right = parent->getCurrentState().active.w;
+ crop.right = parent->getActiveWidth(parent->getCurrentState());
}
if (sourceCrop.height() <= 0) {
crop.top = 0;
- crop.bottom = parent->getCurrentState().active.h;
+ crop.bottom = parent->getActiveHeight(parent->getCurrentState());
}
int32_t reqWidth = crop.width() * frameScale;
int32_t reqHeight = crop.height() * frameScale;
+ // really small crop or frameScale
+ if (reqWidth <= 0) {
+ reqWidth = 1;
+ }
+ if (reqHeight <= 0) {
+ reqHeight = 1;
+ }
+
LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
@@ -4975,8 +5371,6 @@
bool useIdentityTransform) {
ATRACE_CALL();
- renderArea.updateDimensions(mPrimaryDisplayOrientation);
-
const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
*outBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
@@ -4993,7 +5387,7 @@
const int uid = IPCThreadState::self()->getCallingUid();
const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
- sp<LambdaMessage> message = new LambdaMessage([&]() {
+ sp<LambdaMessage> message = new LambdaMessage([&] {
// If there is a refresh pending, bug out early and tell the binder thread to try again
// after the refresh.
if (mRefreshPending) {
@@ -5008,7 +5402,7 @@
int fd = -1;
{
Mutex::Autolock _l(mStateLock);
- renderArea.render([&]() {
+ renderArea.render([&] {
result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
useIdentityTransform, forSystem, &fd);
});
@@ -5024,14 +5418,14 @@
status_t result = postMessageAsync(message);
if (result == NO_ERROR) {
- captureCondition.wait(captureLock, [&]() { return captureResult; });
+ captureCondition.wait(captureLock, [&] { return captureResult; });
while (*captureResult == EAGAIN) {
captureResult.reset();
result = postMessageAsync(message);
if (result != NO_ERROR) {
return result;
}
- captureCondition.wait(captureLock, [&]() { return captureResult; });
+ captureCondition.wait(captureLock, [&] { return captureResult; });
}
result = *captureResult;
}
@@ -5045,64 +5439,16 @@
}
void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
- TraverseLayersFunction traverseLayers, bool yswap,
+ TraverseLayersFunction traverseLayers,
bool useIdentityTransform) {
ATRACE_CALL();
auto& engine(getRenderEngine());
- // get screen geometry
- const auto raWidth = renderArea.getWidth();
- const auto raHeight = renderArea.getHeight();
-
const auto reqWidth = renderArea.getReqWidth();
const auto reqHeight = renderArea.getReqHeight();
- Rect sourceCrop = renderArea.getSourceCrop();
-
- bool filtering = false;
- if (mPrimaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
- filtering = static_cast<int32_t>(reqWidth) != raHeight ||
- static_cast<int32_t>(reqHeight) != raWidth;
- } else {
- filtering = static_cast<int32_t>(reqWidth) != raWidth ||
- static_cast<int32_t>(reqHeight) != raHeight;
- }
-
- // if a default or invalid sourceCrop is passed in, set reasonable values
- if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) {
- sourceCrop.setLeftTop(Point(0, 0));
- sourceCrop.setRightBottom(Point(raWidth, raHeight));
- } else if (mPrimaryDisplayOrientation != DisplayState::eOrientationDefault) {
- Transform tr;
- uint32_t flags = 0x00;
- switch (mPrimaryDisplayOrientation) {
- case DisplayState::eOrientation90:
- flags = Transform::ROT_90;
- break;
- case DisplayState::eOrientation180:
- flags = Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- flags = Transform::ROT_270;
- break;
- }
- tr.set(flags, raWidth, raHeight);
- sourceCrop = tr.transform(sourceCrop);
- }
-
- // ensure that sourceCrop is inside screen
- if (sourceCrop.left < 0) {
- ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
- }
- if (sourceCrop.right > raWidth) {
- ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth);
- }
- if (sourceCrop.top < 0) {
- ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
- }
- if (sourceCrop.bottom > raHeight) {
- ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
- }
+ const auto sourceCrop = renderArea.getSourceCrop();
+ const auto rotation = renderArea.getRotationFlags();
// assume ColorMode::SRGB / RenderIntent::COLORIMETRIC
engine.setOutputDataSpace(Dataspace::SRGB);
@@ -5111,40 +5457,8 @@
// make sure to clear all GL error flags
engine.checkErrors();
- Transform::orientation_flags rotation = renderArea.getRotationFlags();
- if (mPrimaryDisplayOrientation != DisplayState::eOrientationDefault) {
- // convert hw orientation into flag presentation
- // here inverse transform needed
- uint8_t hw_rot_90 = 0x00;
- uint8_t hw_flip_hv = 0x00;
- switch (mPrimaryDisplayOrientation) {
- case DisplayState::eOrientation90:
- hw_rot_90 = Transform::ROT_90;
- hw_flip_hv = Transform::ROT_180;
- break;
- case DisplayState::eOrientation180:
- hw_flip_hv = Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- hw_rot_90 = Transform::ROT_90;
- break;
- }
-
- // transform flags operation
- // 1) flip H V if both have ROT_90 flag
- // 2) XOR these flags
- uint8_t rotation_rot_90 = rotation & Transform::ROT_90;
- uint8_t rotation_flip_hv = rotation & Transform::ROT_180;
- if (rotation_rot_90 & hw_rot_90) {
- rotation_flip_hv = (~rotation_flip_hv) & Transform::ROT_180;
- }
- rotation = static_cast<Transform::orientation_flags>
- ((rotation_rot_90 ^ hw_rot_90) | (rotation_flip_hv ^ hw_flip_hv));
- }
-
// set-up our viewport
- engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, raHeight, yswap,
- rotation);
+ engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, rotation);
engine.disableTexturing();
const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
@@ -5152,9 +5466,7 @@
engine.clearWithColor(0, 0, 0, alpha);
traverseLayers([&](Layer* layer) {
- if (filtering) layer->setFiltering(true);
layer->draw(renderArea, useIdentityTransform);
- if (filtering) layer->setFiltering(false);
});
}
@@ -5182,7 +5494,7 @@
// this binds the given EGLImage as a framebuffer for the
// duration of this scope.
- RE::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
+ renderengine::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
if (bufferBond.getStatus() != NO_ERROR) {
ALOGE("got ANWB binding error while taking screenshot");
return INVALID_OPERATION;
@@ -5192,7 +5504,7 @@
// via an FBO, which means we didn't have to create
// an EGLSurface and therefore we're not
// dependent on the context's EGLConfig.
- renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
+ renderScreenImplLocked(renderArea, traverseLayers, useIdentityTransform);
if (DEBUG_SCREENSHOTS) {
getRenderEngine().finish();
@@ -5249,13 +5561,13 @@
layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
}
-void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw, int32_t minLayerZ,
- int32_t maxLayerZ,
+void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& display,
+ int32_t minLayerZ, int32_t maxLayerZ,
const LayerVector::Visitor& visitor) {
// We loop through the first level of layers without traversing,
// as we need to interpret min/max layer Z in the top level Z space.
for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+ if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
continue;
}
const Layer::State& state(layer->getDrawingState());
@@ -5264,7 +5576,7 @@
continue;
}
layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+ if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
return;
}
if (!layer->isVisible()) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0148ab6..00ee2c4 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -45,6 +45,7 @@
#include <gui/LayerState.h>
#include <gui/OccupancyTracker.h>
+#include <gui/BufferQueue.h>
#include <hardware/hwcomposer_defs.h>
@@ -54,22 +55,23 @@
#include "Barrier.h"
#include "DisplayDevice.h"
-#include "DispSync.h"
-#include "EventThread.h"
#include "FrameTracker.h"
+#include "LayerBE.h"
#include "LayerStats.h"
#include "LayerVector.h"
-#include "MessageQueue.h"
+#include "StartPropertySetThread.h"
#include "SurfaceInterceptor.h"
#include "SurfaceTracing.h"
-#include "StartPropertySetThread.h"
-#include "TimeStats/TimeStats.h"
-#include "VSyncModulator.h"
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/HWComposer.h"
-
#include "Effects/Daltonizer.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/MessageQueue.h"
+#include "Scheduler/Scheduler.h"
+#include "Scheduler/VSyncModulator.h"
+#include "TimeStats/TimeStats.h"
#include <map>
#include <mutex>
@@ -99,12 +101,13 @@
class Surface;
class SurfaceFlingerBE;
class VSyncSource;
+struct CompositionInfo;
namespace impl {
class EventThread;
} // namespace impl
-namespace RE {
+namespace renderengine {
class RenderEngine;
}
@@ -173,7 +176,7 @@
const std::string mHwcServiceName; // "default" for real use, something else for testing.
// constant members (no synchronization needed for access)
- std::unique_ptr<RE::RenderEngine> mRenderEngine;
+ std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
EGLContext mEGLContext;
EGLDisplay mEGLDisplay;
@@ -223,6 +226,9 @@
// use to differentiate callbacks from different hardware composer
// instances. Each hardware composer instance gets a different sequence id.
int32_t mComposerSequenceId;
+
+ std::unordered_map<int32_t, std::vector<CompositionInfo>> mCompositionInfo;
+ std::unordered_map<int32_t, std::vector<CompositionInfo>> mEndOfFrameCompositionInfo;
};
@@ -279,13 +285,23 @@
// FramebufferSurface
static int64_t maxFrameBufferAcquiredBuffers;
- // Indicate if platform supports color management on its
- // wide-color display. This is typically found on devices
- // with wide gamut (e.g. Display-P3) display.
- // This also allows devices with wide-color displays that don't
- // want to support color management to disable color management.
+ // Indicate if a device has wide color gamut display. This is typically
+ // found on devices with wide color gamut (e.g. Display-P3) display.
static bool hasWideColorDisplay;
+ static int primaryDisplayOrientation;
+
+ // Indicate if device wants color management on its display.
+ static bool useColorManagement;
+
+ static bool useContextPriority;
+
+ // The data space and pixel format that SurfaceFlinger expects hardware composer
+ // to composite efficiently. Meaning under most scenarios, hardware composer
+ // will accept layers with the data space and pixel format.
+ static ui::Dataspace compositionDataSpace;
+ static ui::PixelFormat compositionPixelFormat;
+
static char const* getServiceName() ANDROID_API {
return "SurfaceFlinger";
}
@@ -340,19 +356,19 @@
// TODO: this should be made accessible only to HWComposer
const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id);
- RE::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
+ renderengine::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
bool authenticateSurfaceTextureLocked(
const sp<IGraphicBufferProducer>& bufferProducer) const;
- int getPrimaryDisplayOrientation() const { return mPrimaryDisplayOrientation; }
-
private:
friend class Client;
friend class DisplayEventConnection;
friend class impl::EventThread;
friend class Layer;
friend class BufferLayer;
+ friend class BufferQueueLayer;
+ friend class BufferStateLayer;
friend class MonitoredProducer;
// For unit tests
@@ -410,7 +426,7 @@
virtual sp<ISurfaceComposerClient> createConnection();
virtual sp<ISurfaceComposerClient> createScopedConnection(const sp<IGraphicBufferProducer>& gbp);
virtual sp<IBinder> createDisplay(const String8& displayName, bool secure);
- virtual void destroyDisplay(const sp<IBinder>& display);
+ virtual void destroyDisplay(const sp<IBinder>& displayToken);
virtual sp<IBinder> getBuiltInDisplay(int32_t id);
virtual void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags);
@@ -421,31 +437,31 @@
std::vector<FrameEvent>* outSupported) const;
virtual sp<IDisplayEventConnection> createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
- virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+ virtual status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
ISurfaceComposer::Rotation rotation);
virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
const Rect& sourceCrop, float frameScale, bool childrenOnly);
- virtual status_t getDisplayStats(const sp<IBinder>& display,
- DisplayStatInfo* stats);
- virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport);
- virtual status_t getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs);
- virtual int getActiveConfig(const sp<IBinder>& display);
- virtual status_t getDisplayColorModes(const sp<IBinder>& display,
- Vector<ui::ColorMode>* configs);
- virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
- virtual status_t setActiveColorMode(const sp<IBinder>& display, ui::ColorMode colorMode);
- virtual void setPowerMode(const sp<IBinder>& display, int mode);
- virtual status_t setActiveConfig(const sp<IBinder>& display, int id);
+ virtual status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
+ virtual status_t getDisplayConfigs(const sp<IBinder>& displayToken,
+ Vector<DisplayInfo>* configs);
+ virtual int getActiveConfig(const sp<IBinder>& displayToken);
+ virtual status_t getDisplayColorModes(const sp<IBinder>& displayToken,
+ Vector<ui::ColorMode>* configs);
+ virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken);
+ virtual status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode);
+ virtual void setPowerMode(const sp<IBinder>& displayToken, int mode);
+ virtual status_t setActiveConfig(const sp<IBinder>& displayToken, int id);
virtual status_t clearAnimationFrameStats();
virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
- virtual status_t getHdrCapabilities(const sp<IBinder>& display,
- HdrCapabilities* outCapabilities) const;
+ virtual status_t getHdrCapabilities(const sp<IBinder>& displayToken,
+ HdrCapabilities* outCapabilities) const;
virtual status_t enableVSyncInjections(bool enable);
virtual status_t injectVSync(nsecs_t when);
virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
+ status_t getCompositionPreference(ui::Dataspace* outDataSpace,
+ ui::PixelFormat* outPixelFormat) const override;
/* ------------------------------------------------------------------------
@@ -461,11 +477,11 @@
/* ------------------------------------------------------------------------
* HWC2::ComposerCallback / HWComposer::EventHandler interface
*/
- void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
+ void onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
int64_t timestamp) override;
- void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+ void onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
HWC2::Connection connection) override;
- void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override;
+ void onRefreshReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId) override;
/* ------------------------------------------------------------------------
* Message handling
@@ -480,16 +496,13 @@
// called on the main thread in response to initializeDisplays()
void onInitializeDisplays();
// called on the main thread in response to setActiveConfig()
- void setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode);
+ void setActiveConfigInternal(const sp<DisplayDevice>& display, int mode);
// called on the main thread in response to setPowerMode()
- void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode,
- bool stateLockHeld);
+ void setPowerModeInternal(const sp<DisplayDevice>& display, int mode, bool stateLockHeld);
// Called on the main thread in response to setActiveColorMode()
- void setActiveColorModeInternal(const sp<DisplayDevice>& hw,
- ui::ColorMode colorMode,
- ui::Dataspace dataSpace,
- ui::RenderIntent renderIntent);
+ void setActiveColorModeInternal(const sp<DisplayDevice>& display, ui::ColorMode colorMode,
+ ui::Dataspace dataSpace, ui::RenderIntent renderIntent);
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -532,15 +545,23 @@
int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
- status_t createBufferLayer(const sp<Client>& client, const String8& name,
- uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
- sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
- sp<Layer>* outLayer);
+ status_t createBufferQueueLayer(const sp<Client>& client, const String8& name, uint32_t w,
+ uint32_t h, uint32_t flags, PixelFormat& format,
+ sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
+ sp<Layer>* outLayer);
+
+ status_t createBufferStateLayer(const sp<Client>& client, const String8& name, uint32_t w,
+ uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
+ sp<Layer>* outLayer);
status_t createColorLayer(const sp<Client>& client, const String8& name,
uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
sp<Layer>* outLayer);
+ status_t createContainerLayer(const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
+ sp<Layer>* outLayer);
+
String8 getUniqueLayerName(const String8& name);
// called in response to the window-manager calling
@@ -570,7 +591,7 @@
void startBootAnim();
void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
- bool yswap, bool useIdentityTransform);
+ bool useIdentityTransform);
status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>* outBuffer,
bool useIdentityTransform);
@@ -600,38 +621,33 @@
// called when starting, or restarting after system_server death
void initializeDisplays();
- sp<const DisplayDevice> getDisplayDevice(const wp<IBinder>& dpy) const {
- Mutex::Autolock _l(mStateLock);
- return getDisplayDeviceLocked(dpy);
+ sp<const DisplayDevice> getDisplayDevice(const wp<IBinder>& displayToken) const {
+ Mutex::Autolock _l(mStateLock);
+ return getDisplayDeviceLocked(displayToken);
}
- sp<DisplayDevice> getDisplayDevice(const wp<IBinder>& dpy) {
- Mutex::Autolock _l(mStateLock);
- return getDisplayDeviceLocked(dpy);
+ sp<DisplayDevice> getDisplayDevice(const wp<IBinder>& displayToken) {
+ Mutex::Autolock _l(mStateLock);
+ return getDisplayDeviceLocked(displayToken);
}
// NOTE: can only be called from the main thread or with mStateLock held
- sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& dpy) const {
- return mDisplays.valueFor(dpy);
+ sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const {
+ return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(displayToken);
}
// NOTE: can only be called from the main thread or with mStateLock held
- sp<DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& dpy) {
- return mDisplays.valueFor(dpy);
+ sp<DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) {
+ const auto it = mDisplays.find(displayToken);
+ return it == mDisplays.end() ? nullptr : it->second;
}
sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const {
- return getDisplayDeviceLocked(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]);
+ return const_cast<SurfaceFlinger*>(this)->getDefaultDisplayDeviceLocked();
}
- int32_t getDisplayType(const sp<IBinder>& display) {
- if (!display.get()) return NAME_NOT_FOUND;
- for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
- if (display == mBuiltinDisplays[i]) {
- return i;
- }
- }
- return NAME_NOT_FOUND;
+ sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
+ return getDisplayDeviceLocked(mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY]);
}
// mark a region of a layer stack dirty. this updates the dirty
@@ -648,11 +664,11 @@
* Compositing
*/
void invalidateHwcGeometry();
- void computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
- Region& dirtyRegion, Region& opaqueRegion);
+ void computeVisibleRegions(const sp<const DisplayDevice>& display, Region& dirtyRegion,
+ Region& opaqueRegion);
- void preComposition(nsecs_t refreshStartTime);
- void postComposition(nsecs_t refreshStartTime);
+ void preComposition();
+ void postComposition();
void updateCompositorTiming(
nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime);
@@ -661,37 +677,48 @@
nsecs_t compositeToPresentLatency);
void rebuildLayerStacks();
- ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice,
+ ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& display,
ui::Dataspace* outHdrDataSpace) const;
// Returns the appropriate ColorMode, Dataspace and RenderIntent for the
// DisplayDevice. The function only returns the supported ColorMode,
// Dataspace and RenderIntent.
- void pickColorMode(const sp<DisplayDevice>& displayDevice,
- ui::ColorMode* outMode,
- ui::Dataspace* outDataSpace,
- ui::RenderIntent* outRenderIntent) const;
+ void pickColorMode(const sp<DisplayDevice>& display, ui::ColorMode* outMode,
+ ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const;
- void setUpHWComposer();
- void doComposition();
- void doDebugFlashRegions();
+ void calculateWorkingSet();
+ /*
+ * beginFrame - This function handles any pre-frame processing that needs to be
+ * prior to any CompositionInfo handling and is not dependent on data in
+ * CompositionInfo
+ */
+ void beginFrame(const sp<DisplayDevice>& display);
+ /* prepareFrame - This function will call into the DisplayDevice to prepare a
+ * frame after CompositionInfo has been programmed. This provides a mechanism
+ * to prepare the hardware composer
+ */
+ void prepareFrame(const sp<DisplayDevice>& display);
+ void setUpHWComposer(const CompositionInfo& compositionInfo);
+ void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
+ void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
void doTracing(const char* where);
void logLayerStats();
- void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion);
+ void doDisplayComposition(const sp<const DisplayDevice>& display, const Region& dirtyRegion);
- // compose surfaces for display hw. this fails if using GL and the surface
- // has been destroyed and is no longer valid.
- bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice);
+ // This fails if using GL and the surface has been destroyed.
+ bool doComposeSurfaces(const sp<const DisplayDevice>& display);
- void postFramebuffer();
- void drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const;
+ void postFramebuffer(const sp<DisplayDevice>& display);
+ void postFrame();
+ void drawWormhole(const Region& region) const;
/* ------------------------------------------------------------------------
* Display management
*/
- DisplayDevice::DisplayType determineDisplayType(hwc2_display_t display,
- HWC2::Connection connection) const;
- sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& display, int hwcId,
+ DisplayDevice::DisplayType determineDisplayType(hwc2_display_t hwcDisplayId,
+ HWC2::Connection connection) const;
+ sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
+ int32_t displayId,
const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer);
@@ -741,9 +768,11 @@
void recordBufferingStats(const char* layerName,
std::vector<OccupancyTracker::Segment>&& history);
void dumpBufferingStats(String8& result) const;
+ void dumpDisplayIdentificationData(String8& result) const;
void dumpWideColorInfo(String8& result) const;
+ void dumpFrameCompositionInfo(String8& result) const;
LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
- LayersProto dumpVisibleLayersProtoInfo(int32_t hwcId) const;
+ LayersProto dumpVisibleLayersProtoInfo(const DisplayDevice& display) const;
bool isLayerTripleBufferingDisabled() const {
return this->mLayerTripleBufferingDisabled;
@@ -789,6 +818,11 @@
// access must be protected by mInvalidateLock
volatile int32_t mRepaintEverything;
+ // helper methods
+ void configureHwcCommonData(const CompositionInfo& compositionInfo) const;
+ void configureDeviceComposition(const CompositionInfo& compositionInfo) const;
+ void configureSidebandComposition(const CompositionInfo& compositionInfo) const;
+
// constant members (no synchronization needed for access)
nsecs_t mBootTime;
bool mGpuToCpuSupported;
@@ -799,7 +833,7 @@
std::unique_ptr<VSyncSource> mSfEventThreadSource;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
std::unique_ptr<EventControlThread> mEventControlThread;
- sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
+ sp<IBinder> mDisplayTokens[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
VSyncModulator mVsyncModulator;
@@ -821,7 +855,7 @@
BootStage mBootStage;
struct HotplugEvent {
- hwc2_display_t display;
+ hwc2_display_t hwcDisplayId;
HWC2::Connection connection = HWC2::Connection::Invalid;
};
// protected by mStateLock
@@ -829,7 +863,7 @@
// this may only be written from the main thread with mStateLock held
// it may be read from other threads with mStateLock held
- DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays;
+ std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays;
// don't use a lock for these, we don't care
int mDebugRegion;
@@ -837,9 +871,9 @@
int mDebugDisableHWC;
int mDebugDisableTransformHint;
volatile nsecs_t mDebugInSwapBuffers;
- nsecs_t mLastSwapBufferTime;
volatile nsecs_t mDebugInTransaction;
nsecs_t mLastTransactionTime;
+ nsecs_t mPostFramebufferTime;
bool mForceFullDamage;
bool mPropagateBackpressure = true;
std::unique_ptr<SurfaceInterceptor> mInterceptor =
@@ -848,6 +882,7 @@
LayerStats mLayerStats;
TimeStats& mTimeStats = TimeStats::getInstance();
bool mUseHwcVirtualDisplays = false;
+ std::atomic<uint32_t> mFrameMissedCount{0};
// Restrict layers to use two buffers in their bufferqueues.
bool mLayerTripleBufferingDisabled = false;
@@ -855,8 +890,7 @@
// these are thread safe
mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()};
FrameTracker mAnimFrameTracker;
- DispSync mPrimaryDispSync;
- int mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
+ std::unique_ptr<DispSync> mPrimaryDispSync;
// protected by mDestroyedLayerLock;
mutable Mutex mDestroyedLayerLock;
@@ -866,6 +900,7 @@
Mutex mHWVsyncLock;
bool mPrimaryHWVsyncEnabled;
bool mHWVsyncAvailable;
+ nsecs_t mRefreshStartTime;
std::atomic<bool> mRefreshPending{false};
@@ -911,6 +946,11 @@
CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
SurfaceFlingerBE mBE;
+
+ bool mUseScheduler = false;
+ std::unique_ptr<Scheduler> mScheduler;
+ sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
+ sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 4596a21..0b4c6fc 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -30,6 +30,7 @@
namespace android {
// ----------------------------------------------------------------------------
+// TODO(marissaw): add new layer state values to SurfaceInterceptor
SurfaceInterceptor::~SurfaceInterceptor() = default;
@@ -99,18 +100,19 @@
transaction->set_animation(layer->mTransactionFlags & BnSurfaceComposer::eAnimation);
const int32_t layerId(getLayerId(layer));
- addPositionLocked(transaction, layerId, layer->mCurrentState.active.transform.tx(),
- layer->mCurrentState.active.transform.ty());
+ addPositionLocked(transaction, layerId, layer->mCurrentState.active_legacy.transform.tx(),
+ layer->mCurrentState.active_legacy.transform.ty());
addDepthLocked(transaction, layerId, layer->mCurrentState.z);
addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a);
- addTransparentRegionLocked(transaction, layerId, layer->mCurrentState.activeTransparentRegion);
+ addTransparentRegionLocked(transaction, layerId,
+ layer->mCurrentState.activeTransparentRegion_legacy);
addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
- addCropLocked(transaction, layerId, layer->mCurrentState.crop);
- if (layer->mCurrentState.barrierLayer != nullptr) {
- addDeferTransactionLocked(transaction, layerId, layer->mCurrentState.barrierLayer.promote(),
- layer->mCurrentState.frameNumber);
+ addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
+ if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
+ addDeferTransactionLocked(transaction, layerId,
+ layer->mCurrentState.barrierLayer_legacy.promote(),
+ layer->mCurrentState.frameNumber_legacy);
}
- addFinalCropLocked(transaction, layerId, layer->mCurrentState.finalCrop);
addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode());
addFlagsLocked(transaction, layerId, layer->mCurrentState.flags);
}
@@ -122,10 +124,10 @@
transaction->set_synchronous(false);
transaction->set_animation(false);
- addDisplaySurfaceLocked(transaction, display.displayId, display.surface);
- addDisplayLayerStackLocked(transaction, display.displayId, display.layerStack);
- addDisplaySizeLocked(transaction, display.displayId, display.width, display.height);
- addDisplayProjectionLocked(transaction, display.displayId, display.orientation,
+ addDisplaySurfaceLocked(transaction, display.sequenceId, display.surface);
+ addDisplayLayerStackLocked(transaction, display.sequenceId, display.layerStack);
+ addDisplaySizeLocked(transaction, display.sequenceId, display.width, display.height);
+ addDisplayProjectionLocked(transaction, display.sequenceId, display.orientation,
display.viewport, display.frame);
}
@@ -177,10 +179,10 @@
}
DisplayChange* SurfaceInterceptor::createDisplayChangeLocked(Transaction* transaction,
- int32_t displayId)
+ int32_t sequenceId)
{
DisplayChange* dispChange(transaction->add_display_change());
- dispChange->set_id(displayId);
+ dispChange->set_id(sequenceId);
return dispChange;
}
@@ -286,15 +288,6 @@
setProtoRectLocked(protoRect, rect);
}
-void SurfaceInterceptor::addFinalCropLocked(Transaction* transaction, int32_t layerId,
- const Rect& rect)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- FinalCropChange* finalCropChange(change->mutable_final_crop());
- Rectangle* protoRect(finalCropChange->mutable_rectangle());
- setProtoRectLocked(protoRect, rect);
-}
-
void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber)
{
@@ -353,25 +346,23 @@
if (state.what & layer_state_t::eLayerStackChanged) {
addLayerStackLocked(transaction, layerId, state.layerStack);
}
- if (state.what & layer_state_t::eCropChanged) {
- addCropLocked(transaction, layerId, state.crop);
+ if (state.what & layer_state_t::eCropChanged_legacy) {
+ addCropLocked(transaction, layerId, state.crop_legacy);
}
- if (state.what & layer_state_t::eDeferTransaction) {
+ if (state.what & layer_state_t::eDeferTransaction_legacy) {
sp<Layer> otherLayer = nullptr;
- if (state.barrierHandle != nullptr) {
- otherLayer = static_cast<Layer::Handle*>(state.barrierHandle.get())->owner.promote();
- } else if (state.barrierGbp != nullptr) {
- auto const& gbp = state.barrierGbp;
+ if (state.barrierHandle_legacy != nullptr) {
+ otherLayer =
+ static_cast<Layer::Handle*>(state.barrierHandle_legacy.get())->owner.promote();
+ } else if (state.barrierGbp_legacy != nullptr) {
+ auto const& gbp = state.barrierGbp_legacy;
if (mFlinger->authenticateSurfaceTextureLocked(gbp)) {
otherLayer = (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
} else {
ALOGE("Attempt to defer transaction to to an unrecognized GraphicBufferProducer");
}
}
- addDeferTransactionLocked(transaction, layerId, otherLayer, state.frameNumber);
- }
- if (state.what & layer_state_t::eFinalCropChanged) {
- addFinalCropLocked(transaction, layerId, state.finalCrop);
+ addDeferTransactionLocked(transaction, layerId, otherLayer, state.frameNumber_legacy);
}
if (state.what & layer_state_t::eOverrideScalingModeChanged) {
addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode);
@@ -379,19 +370,19 @@
}
void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction,
- const DisplayState& state, int32_t displayId)
+ const DisplayState& state, int32_t sequenceId)
{
if (state.what & DisplayState::eSurfaceChanged) {
- addDisplaySurfaceLocked(transaction, displayId, state.surface);
+ addDisplaySurfaceLocked(transaction, sequenceId, state.surface);
}
if (state.what & DisplayState::eLayerStackChanged) {
- addDisplayLayerStackLocked(transaction, displayId, state.layerStack);
+ addDisplayLayerStackLocked(transaction, sequenceId, state.layerStack);
}
if (state.what & DisplayState::eDisplaySizeChanged) {
- addDisplaySizeLocked(transaction, displayId, state.width, state.height);
+ addDisplaySizeLocked(transaction, sequenceId, state.width, state.height);
}
if (state.what & DisplayState::eDisplayProjectionChanged) {
- addDisplayProjectionLocked(transaction, displayId, state.orientation, state.viewport,
+ addDisplayProjectionLocked(transaction, sequenceId, state.orientation, state.viewport,
state.frame);
}
}
@@ -411,7 +402,7 @@
ssize_t dpyIdx = displays.indexOfKey(disp.token);
if (dpyIdx >= 0) {
const DisplayDeviceState& dispState(displays.valueAt(dpyIdx));
- addDisplayChangesLocked(transaction, disp, dispState.displayId);
+ addDisplayChangesLocked(transaction, disp, dispState.sequenceId);
}
}
}
@@ -422,8 +413,8 @@
SurfaceCreation* creation(increment->mutable_surface_creation());
creation->set_id(getLayerId(layer));
creation->set_name(getLayerName(layer));
- creation->set_w(layer->mCurrentState.active.w);
- creation->set_h(layer->mCurrentState.active.h);
+ creation->set_w(layer->mCurrentState.active_legacy.w);
+ creation->set_h(layer->mCurrentState.active_legacy.h);
}
void SurfaceInterceptor::addSurfaceDeletionLocked(Increment* increment,
@@ -448,7 +439,7 @@
event->set_when(timestamp);
}
-void SurfaceInterceptor::addDisplaySurfaceLocked(Transaction* transaction, int32_t displayId,
+void SurfaceInterceptor::addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId,
const sp<const IGraphicBufferProducer>& surface)
{
if (surface == nullptr) {
@@ -457,7 +448,7 @@
uint64_t bufferQueueId = 0;
status_t err(surface->getUniqueId(&bufferQueueId));
if (err == NO_ERROR) {
- DisplayChange* dispChange(createDisplayChangeLocked(transaction, displayId));
+ DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
DispSurfaceChange* surfaceChange(dispChange->mutable_surface());
surfaceChange->set_buffer_queue_id(bufferQueueId);
surfaceChange->set_buffer_queue_name(surface->getConsumerName().string());
@@ -469,26 +460,26 @@
}
void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction,
- int32_t displayId, uint32_t layerStack)
+ int32_t sequenceId, uint32_t layerStack)
{
- DisplayChange* dispChange(createDisplayChangeLocked(transaction, displayId));
+ DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
LayerStackChange* layerStackChange(dispChange->mutable_layer_stack());
layerStackChange->set_layer_stack(layerStack);
}
-void SurfaceInterceptor::addDisplaySizeLocked(Transaction* transaction, int32_t displayId,
+void SurfaceInterceptor::addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId,
uint32_t w, uint32_t h)
{
- DisplayChange* dispChange(createDisplayChangeLocked(transaction, displayId));
+ DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
SizeChange* sizeChange(dispChange->mutable_size());
sizeChange->set_w(w);
sizeChange->set_h(h);
}
void SurfaceInterceptor::addDisplayProjectionLocked(Transaction* transaction,
- int32_t displayId, int32_t orientation, const Rect& viewport, const Rect& frame)
+ int32_t sequenceId, int32_t orientation, const Rect& viewport, const Rect& frame)
{
- DisplayChange* dispChange(createDisplayChangeLocked(transaction, displayId));
+ DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
ProjectionChange* projectionChange(dispChange->mutable_projection());
projectionChange->set_orientation(orientation);
Rectangle* viewportRect(projectionChange->mutable_viewport());
@@ -501,22 +492,22 @@
const DisplayDeviceState& info)
{
DisplayCreation* creation(increment->mutable_display_creation());
- creation->set_id(info.displayId);
+ creation->set_id(info.sequenceId);
creation->set_name(info.displayName);
creation->set_type(info.type);
creation->set_is_secure(info.isSecure);
}
-void SurfaceInterceptor::addDisplayDeletionLocked(Increment* increment, int32_t displayId) {
+void SurfaceInterceptor::addDisplayDeletionLocked(Increment* increment, int32_t sequenceId) {
DisplayDeletion* deletion(increment->mutable_display_deletion());
- deletion->set_id(displayId);
+ deletion->set_id(sequenceId);
}
-void SurfaceInterceptor::addPowerModeUpdateLocked(Increment* increment, int32_t displayId,
+void SurfaceInterceptor::addPowerModeUpdateLocked(Increment* increment, int32_t sequenceId,
int32_t mode)
{
PowerModeUpdate* powerModeUpdate(increment->mutable_power_mode_update());
- powerModeUpdate->set_id(displayId);
+ powerModeUpdate->set_id(sequenceId);
powerModeUpdate->set_mode(mode);
}
@@ -579,22 +570,22 @@
addDisplayCreationLocked(createTraceIncrementLocked(), info);
}
-void SurfaceInterceptor::saveDisplayDeletion(int32_t displayId) {
+void SurfaceInterceptor::saveDisplayDeletion(int32_t sequenceId) {
if (!mEnabled) {
return;
}
ATRACE_CALL();
std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addDisplayDeletionLocked(createTraceIncrementLocked(), displayId);
+ addDisplayDeletionLocked(createTraceIncrementLocked(), sequenceId);
}
-void SurfaceInterceptor::savePowerModeUpdate(int32_t displayId, int32_t mode) {
+void SurfaceInterceptor::savePowerModeUpdate(int32_t sequenceId, int32_t mode) {
if (!mEnabled) {
return;
}
ATRACE_CALL();
std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addPowerModeUpdateLocked(createTraceIncrementLocked(), displayId, mode);
+ addPowerModeUpdateLocked(createTraceIncrementLocked(), sequenceId, mode);
}
} // namespace impl
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 96defcc..394b99b 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -66,8 +66,8 @@
// Intercept display data
virtual void saveDisplayCreation(const DisplayDeviceState& info) = 0;
- virtual void saveDisplayDeletion(int32_t displayId) = 0;
- virtual void savePowerModeUpdate(int32_t displayId, int32_t mode) = 0;
+ virtual void saveDisplayDeletion(int32_t sequenceId) = 0;
+ virtual void savePowerModeUpdate(int32_t sequenceId, int32_t mode) = 0;
virtual void saveVSyncEvent(nsecs_t timestamp) = 0;
};
@@ -101,8 +101,8 @@
// Intercept display data
void saveDisplayCreation(const DisplayDeviceState& info) override;
- void saveDisplayDeletion(int32_t displayId) override;
- void savePowerModeUpdate(int32_t displayId, int32_t mode) override;
+ void saveDisplayDeletion(int32_t sequenceId) override;
+ void savePowerModeUpdate(int32_t sequenceId, int32_t mode) override;
void saveVSyncEvent(nsecs_t timestamp) override;
private:
@@ -127,8 +127,8 @@
uint32_t height, uint64_t frameNumber);
void addVSyncUpdateLocked(Increment* increment, nsecs_t timestamp);
void addDisplayCreationLocked(Increment* increment, const DisplayDeviceState& info);
- void addDisplayDeletionLocked(Increment* increment, int32_t displayId);
- void addPowerModeUpdateLocked(Increment* increment, int32_t displayId, int32_t mode);
+ void addDisplayDeletionLocked(Increment* increment, int32_t sequenceId);
+ void addPowerModeUpdateLocked(Increment* increment, int32_t sequenceId, int32_t mode);
// Add surface transactions to the trace
SurfaceChange* createSurfaceChangeLocked(Transaction* transaction, int32_t layerId);
@@ -146,7 +146,6 @@
void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber);
- void addFinalCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
void addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId,
int32_t overrideScalingMode);
void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state);
@@ -155,17 +154,17 @@
const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags);
// Add display transactions to the trace
- DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t displayId);
- void addDisplaySurfaceLocked(Transaction* transaction, int32_t displayId,
+ DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId);
+ void addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId,
const sp<const IGraphicBufferProducer>& surface);
- void addDisplayLayerStackLocked(Transaction* transaction, int32_t displayId,
+ void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId,
uint32_t layerStack);
- void addDisplaySizeLocked(Transaction* transaction, int32_t displayId, uint32_t w,
+ void addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w,
uint32_t h);
- void addDisplayProjectionLocked(Transaction* transaction, int32_t displayId,
+ void addDisplayProjectionLocked(Transaction* transaction, int32_t sequenceId,
int32_t orientation, const Rect& viewport, const Rect& frame);
void addDisplayChangesLocked(Transaction* transaction,
- const DisplayState& state, int32_t displayId);
+ const DisplayState& state, int32_t sequenceId);
bool mEnabled {false};
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index f8c466e..0e9b04e 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -58,7 +58,9 @@
void SurfaceTracing::traceLayers(const char* where, LayersProto layers) {
std::lock_guard<std::mutex> protoGuard(mTraceMutex);
-
+ if (!mEnabled) {
+ return;
+ }
LayersTraceProto* entry = mTrace.add_entry();
entry->set_elapsed_realtime_nanos(elapsedRealtimeNano());
entry->set_where(where);
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index d4f1e29..d77a324 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -109,7 +109,7 @@
bool TimeStats::recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord) {
if (!timeRecord->ready) {
ALOGV("[%s]-[%" PRIu64 "]-presentFence is still not received", layerName.c_str(),
- timeRecord->frameNumber);
+ timeRecord->frameTime.frameNumber);
return false;
}
@@ -118,11 +118,11 @@
return false;
}
if (timeRecord->acquireFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
- timeRecord->acquireTime = timeRecord->acquireFence->getSignalTime();
+ timeRecord->frameTime.acquireTime = timeRecord->acquireFence->getSignalTime();
timeRecord->acquireFence = nullptr;
} else {
ALOGV("[%s]-[%" PRIu64 "]-acquireFence signal time is invalid", layerName.c_str(),
- timeRecord->frameNumber);
+ timeRecord->frameTime.frameNumber);
}
}
@@ -131,11 +131,11 @@
return false;
}
if (timeRecord->presentFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
- timeRecord->presentTime = timeRecord->presentFence->getSignalTime();
+ timeRecord->frameTime.presentTime = timeRecord->presentFence->getSignalTime();
timeRecord->presentFence = nullptr;
} else {
ALOGV("[%s]-[%" PRIu64 "]-presentFence signal time invalid", layerName.c_str(),
- timeRecord->frameNumber);
+ timeRecord->frameTime.frameNumber);
}
}
@@ -172,48 +172,53 @@
while (!timeRecords.empty()) {
if (!recordReadyLocked(layerName, &timeRecords[0])) break;
ALOGV("[%s]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerName.c_str(),
- timeRecords[0].frameNumber, timeRecords[0].presentTime);
+ timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
if (prevTimeRecord.ready) {
if (!timeStats.stats.count(layerName)) {
timeStats.stats[layerName].layerName = layerName;
timeStats.stats[layerName].packageName = getPackageName(layerName);
- timeStats.stats[layerName].statsStart = static_cast<int64_t>(std::time(0));
}
TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timeStats.stats[layerName];
timeStatsLayer.totalFrames++;
+ timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
+ layerRecord.droppedFrames = 0;
- const int32_t postToPresentMs =
- msBetween(timeRecords[0].postTime, timeRecords[0].presentTime);
+ const int32_t postToAcquireMs = msBetween(timeRecords[0].frameTime.postTime,
+ timeRecords[0].frameTime.acquireTime);
+ ALOGV("[%s]-[%" PRIu64 "]-post2acquire[%d]", layerName.c_str(),
+ timeRecords[0].frameTime.frameNumber, postToAcquireMs);
+ timeStatsLayer.deltas["post2acquire"].insert(postToAcquireMs);
+
+ const int32_t postToPresentMs = msBetween(timeRecords[0].frameTime.postTime,
+ timeRecords[0].frameTime.presentTime);
ALOGV("[%s]-[%" PRIu64 "]-post2present[%d]", layerName.c_str(),
- timeRecords[0].frameNumber, postToPresentMs);
+ timeRecords[0].frameTime.frameNumber, postToPresentMs);
timeStatsLayer.deltas["post2present"].insert(postToPresentMs);
- const int32_t acquireToPresentMs =
- msBetween(timeRecords[0].acquireTime, timeRecords[0].presentTime);
+ const int32_t acquireToPresentMs = msBetween(timeRecords[0].frameTime.acquireTime,
+ timeRecords[0].frameTime.presentTime);
ALOGV("[%s]-[%" PRIu64 "]-acquire2present[%d]", layerName.c_str(),
- timeRecords[0].frameNumber, acquireToPresentMs);
+ timeRecords[0].frameTime.frameNumber, acquireToPresentMs);
timeStatsLayer.deltas["acquire2present"].insert(acquireToPresentMs);
- const int32_t latchToPresentMs =
- msBetween(timeRecords[0].latchTime, timeRecords[0].presentTime);
+ const int32_t latchToPresentMs = msBetween(timeRecords[0].frameTime.latchTime,
+ timeRecords[0].frameTime.presentTime);
ALOGV("[%s]-[%" PRIu64 "]-latch2present[%d]", layerName.c_str(),
- timeRecords[0].frameNumber, latchToPresentMs);
+ timeRecords[0].frameTime.frameNumber, latchToPresentMs);
timeStatsLayer.deltas["latch2present"].insert(latchToPresentMs);
- const int32_t desiredToPresentMs =
- msBetween(timeRecords[0].desiredTime, timeRecords[0].presentTime);
+ const int32_t desiredToPresentMs = msBetween(timeRecords[0].frameTime.desiredTime,
+ timeRecords[0].frameTime.presentTime);
ALOGV("[%s]-[%" PRIu64 "]-desired2present[%d]", layerName.c_str(),
- timeRecords[0].frameNumber, desiredToPresentMs);
+ timeRecords[0].frameTime.frameNumber, desiredToPresentMs);
timeStatsLayer.deltas["desired2present"].insert(desiredToPresentMs);
- const int32_t presentToPresentMs =
- msBetween(prevTimeRecord.presentTime, timeRecords[0].presentTime);
+ const int32_t presentToPresentMs = msBetween(prevTimeRecord.frameTime.presentTime,
+ timeRecords[0].frameTime.presentTime);
ALOGV("[%s]-[%" PRIu64 "]-present2present[%d]", layerName.c_str(),
- timeRecords[0].frameNumber, presentToPresentMs);
+ timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
-
- timeStats.stats[layerName].statsEnd = static_cast<int64_t>(std::time(0));
}
prevTimeRecord = timeRecords[0];
timeRecords.pop_front();
@@ -225,12 +230,12 @@
// This regular expression captures the following layer names for instance:
// 1) StatusBat#0
// 2) NavigationBar#1
- // 3) com.*#0
- // 4) SurfaceView - com.*#0
- // Using [-\\s\t]+ for the conjunction part between SurfaceView and com.* is
- // a bit more robust in case there's a slight change.
+ // 3) co(m).*#0
+ // 4) SurfaceView - co(m).*#0
+ // Using [-\\s\t]+ for the conjunction part between SurfaceView and co(m).*
+ // is a bit more robust in case there's a slight change.
// The layer name would only consist of . / $ _ 0-9 a-z A-Z in most cases.
- std::regex re("(((SurfaceView[-\\s\\t]+)?com\\.[./$\\w]+)|((Status|Navigation)Bar))#\\d+");
+ std::regex re("(((SurfaceView[-\\s\\t]+)?com?\\.[./$\\w]+)|((Status|Navigation)Bar))#\\d+");
return std::regex_match(layerName.begin(), layerName.end(), re);
}
@@ -257,9 +262,12 @@
// ready at the queueBuffer stage. In this case, acquireTime should be given
// a default value as postTime.
TimeRecord timeRecord = {
- .frameNumber = frameNumber,
- .postTime = postTime,
- .acquireTime = postTime,
+ .frameTime =
+ {
+ .frameNumber = frameNumber,
+ .postTime = postTime,
+ .acquireTime = postTime,
+ },
};
layerRecord.timeRecords.push_back(timeRecord);
if (layerRecord.waitData < 0 ||
@@ -278,8 +286,8 @@
if (!timeStatsTracker.count(layerName)) return;
LayerRecord& layerRecord = timeStatsTracker[layerName];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
- if (timeRecord.frameNumber == frameNumber) {
- timeRecord.latchTime = latchTime;
+ if (timeRecord.frameTime.frameNumber == frameNumber) {
+ timeRecord.frameTime.latchTime = latchTime;
}
}
@@ -295,8 +303,8 @@
if (!timeStatsTracker.count(layerName)) return;
LayerRecord& layerRecord = timeStatsTracker[layerName];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
- if (timeRecord.frameNumber == frameNumber) {
- timeRecord.desiredTime = desiredTime;
+ if (timeRecord.frameTime.frameNumber == frameNumber) {
+ timeRecord.frameTime.desiredTime = desiredTime;
}
}
@@ -312,8 +320,8 @@
if (!timeStatsTracker.count(layerName)) return;
LayerRecord& layerRecord = timeStatsTracker[layerName];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
- if (timeRecord.frameNumber == frameNumber) {
- timeRecord.acquireTime = acquireTime;
+ if (timeRecord.frameTime.frameNumber == frameNumber) {
+ timeRecord.frameTime.acquireTime = acquireTime;
}
}
@@ -329,7 +337,7 @@
if (!timeStatsTracker.count(layerName)) return;
LayerRecord& layerRecord = timeStatsTracker[layerName];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
- if (timeRecord.frameNumber == frameNumber) {
+ if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.acquireFence = acquireFence;
}
}
@@ -346,8 +354,8 @@
if (!timeStatsTracker.count(layerName)) return;
LayerRecord& layerRecord = timeStatsTracker[layerName];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
- if (timeRecord.frameNumber == frameNumber) {
- timeRecord.presentTime = presentTime;
+ if (timeRecord.frameTime.frameNumber == frameNumber) {
+ timeRecord.frameTime.presentTime = presentTime;
timeRecord.ready = true;
layerRecord.waitData++;
}
@@ -367,7 +375,7 @@
if (!timeStatsTracker.count(layerName)) return;
LayerRecord& layerRecord = timeStatsTracker[layerName];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
- if (timeRecord.frameNumber == frameNumber) {
+ if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.presentFence = presentFence;
timeRecord.ready = true;
layerRecord.waitData++;
@@ -400,6 +408,7 @@
layerRecord.timeRecords.clear();
layerRecord.prevTimeRecord.ready = false;
layerRecord.waitData = -1;
+ layerRecord.droppedFrames = 0;
}
void TimeStats::removeTimeRecord(const std::string& layerName, uint64_t frameNumber) {
@@ -413,14 +422,15 @@
LayerRecord& layerRecord = timeStatsTracker[layerName];
size_t removeAt = 0;
for (const TimeRecord& record : layerRecord.timeRecords) {
- if (record.frameNumber == frameNumber) break;
+ if (record.frameTime.frameNumber == frameNumber) break;
removeAt++;
}
if (removeAt == layerRecord.timeRecords.size()) return;
layerRecord.timeRecords.erase(layerRecord.timeRecords.begin() + removeAt);
if (layerRecord.waitData > static_cast<int32_t>(removeAt)) {
- --layerRecord.waitData;
+ layerRecord.waitData--;
}
+ layerRecord.droppedFrames++;
}
void TimeStats::enable() {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 8318210..5ab3934 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -40,14 +40,18 @@
// static const size_t MAX_NUM_LAYER_RECORDS = 200;
static const size_t MAX_NUM_TIME_RECORDS = 64;
- struct TimeRecord {
- bool ready = false;
+ struct FrameTime {
uint64_t frameNumber = 0;
nsecs_t postTime = 0;
nsecs_t latchTime = 0;
nsecs_t acquireTime = 0;
nsecs_t desiredTime = 0;
nsecs_t presentTime = 0;
+ };
+
+ struct TimeRecord {
+ bool ready = false;
+ FrameTime frameTime;
std::shared_ptr<FenceTime> acquireFence;
std::shared_ptr<FenceTime> presentFence;
};
@@ -57,6 +61,7 @@
// specific frame are still not fully received. This is not waiting for
// fences to signal, but rather waiting to receive those fences/timestamps.
int32_t waitData = -1;
+ uint32_t droppedFrames = 0;
TimeRecord prevTimeRecord;
std::deque<TimeRecord> timeRecords;
};
@@ -77,8 +82,11 @@
void setPresentTime(const std::string& layerName, uint64_t frameNumber, nsecs_t presentTime);
void setPresentFence(const std::string& layerName, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& presentFence);
+ // On producer disconnect with BufferQueue.
void onDisconnect(const std::string& layerName);
+ // When SF is cleaning up the queue, clear the LayerRecord as well.
void clearLayerRecord(const std::string& layerName);
+ // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
void removeTimeRecord(const std::string& layerName, uint64_t frameNumber);
private:
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 21f3ef3..b7b2778 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -68,12 +68,11 @@
}
std::string TimeStatsHelper::TimeStatsLayer::toString() const {
- std::string result = "";
+ std::string result = "\n";
StringAppendF(&result, "layerName = %s\n", layerName.c_str());
StringAppendF(&result, "packageName = %s\n", packageName.c_str());
- StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
- StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
- StringAppendF(&result, "totalFrames= %d\n", totalFrames);
+ StringAppendF(&result, "totalFrames = %d\n", totalFrames);
+ StringAppendF(&result, "droppedFrames = %d\n", droppedFrames);
auto iter = deltas.find("present2present");
if (iter != deltas.end()) {
StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime());
@@ -90,10 +89,9 @@
std::string result = "SurfaceFlinger TimeStats:\n";
StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
- StringAppendF(&result, "totalFrames= %d\n", totalFrames);
- StringAppendF(&result, "missedFrames= %d\n", missedFrames);
- StringAppendF(&result, "clientCompositionFrames= %d\n", clientCompositionFrames);
- StringAppendF(&result, "TimeStats for each layer is as below:\n");
+ StringAppendF(&result, "totalFrames = %d\n", totalFrames);
+ StringAppendF(&result, "missedFrames = %d\n", missedFrames);
+ StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
const auto dumpStats = generateDumpStats(maxLayers);
for (auto& ele : dumpStats) {
StringAppendF(&result, "%s", ele->toString().c_str());
@@ -106,15 +104,14 @@
SFTimeStatsLayerProto layerProto;
layerProto.set_layer_name(layerName);
layerProto.set_package_name(packageName);
- layerProto.set_stats_start(statsStart);
- layerProto.set_stats_end(statsEnd);
layerProto.set_total_frames(totalFrames);
+ layerProto.set_dropped_frames(droppedFrames);
for (auto& ele : deltas) {
SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas();
deltaProto->set_delta_name(ele.first);
for (auto& histEle : ele.second.hist) {
SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms();
- histProto->set_render_millis(histEle.first);
+ histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
}
}
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 1798555..99c891b 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -42,9 +42,8 @@
public:
std::string layerName;
std::string packageName;
- int64_t statsStart = 0;
- int64_t statsEnd = 0;
int32_t totalFrames = 0;
+ int32_t droppedFrames = 0;
std::unordered_map<std::string, Histogram> deltas;
std::string toString() const;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index f29fbd1..b8f38c2 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -20,46 +20,60 @@
option optimize_for = LITE_RUNTIME;
+// //depot/google3/java/com/google/android/apps/graphics/stats/proto/
+// timestats.proto is based on this proto. Please only make valid protobuf
+// changes to these messages, and keep the other file in sync per Android
+// release. Please also do not include "option optimize_for = LITE_RUNTIME;" at
+// google3 side.
+
+// Next tag: 7
message SFTimeStatsGlobalProto {
- // The start & end timestamps in UTC as
- // milliseconds since January 1, 1970
+ // The stats start time in UTC as seconds since January 1, 1970
optional int64 stats_start = 1;
+ // The stats end time in UTC as seconds since January 1, 1970
optional int64 stats_end = 2;
- // Total frames
+ // Total number of frames presented during tracing period.
optional int32 total_frames = 3;
// Total missed frames of SurfaceFlinger.
optional int32 missed_frames = 4;
// Total frames fallback to client composition.
optional int32 client_composition_frames = 5;
-
+ // Stats per layer. Apps could have multiple layers.
repeated SFTimeStatsLayerProto stats = 6;
}
+// Next tag: 8
message SFTimeStatsLayerProto {
- // The layer name
+ // The name of the visible view layer.
optional string layer_name = 1;
- // The package name
+ // The package name of the application owning this layer.
optional string package_name = 2;
- // The start & end timestamps in UTC as
- // milliseconds since January 1, 1970
+ // The stats start time in UTC as seconds since January 1, 1970
optional int64 stats_start = 3;
+ // The stats end time in UTC as seconds since January 1, 1970
optional int64 stats_end = 4;
- // Distinct frame count.
+ // Total number of frames presented during tracing period.
optional int32 total_frames = 5;
-
+ // Total number of frames dropped by SurfaceFlinger.
+ optional int32 dropped_frames = 7;
+ // There are multiple timestamps tracked in SurfaceFlinger, and these are the
+ // histograms of deltas between different combinations of those timestamps.
repeated SFTimeStatsDeltaProto deltas = 6;
}
+// Next tag: 3
message SFTimeStatsDeltaProto {
// Name of the time interval
optional string delta_name = 1;
- // Histogram of the delta time
+ // Histogram of the delta time. There should be at most 85 buckets ranging
+ // from [0ms, 1ms) to [1000ms, infinity)
repeated SFTimeStatsHistogramBucketProto histograms = 2;
}
+// Next tag: 3
message SFTimeStatsHistogramBucketProto {
- // Lower bound of render time in milliseconds.
- optional int32 render_millis = 1;
+ // Lower bound of time interval in milliseconds.
+ optional int32 time_millis = 1;
// Number of frames in the bucket.
optional int32 frame_count = 2;
}
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
deleted file mode 100644
index b11d057..0000000
--- a/services/surfaceflinger/Transform.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef ANDROID_TRANSFORM_H
-#define ANDROID_TRANSFORM_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <ui/Point.h>
-#include <ui/Rect.h>
-#include <math/vec2.h>
-#include <math/vec3.h>
-
-#include <gui/ISurfaceComposer.h>
-
-#include <hardware/hardware.h>
-
-namespace android {
-
-class Region;
-
-// ---------------------------------------------------------------------------
-
-class Transform
-{
-public:
- Transform();
- Transform(const Transform& other);
- explicit Transform(uint32_t orientation);
- ~Transform();
-
- enum orientation_flags {
- ROT_0 = 0x00000000,
- FLIP_H = HAL_TRANSFORM_FLIP_H,
- FLIP_V = HAL_TRANSFORM_FLIP_V,
- ROT_90 = HAL_TRANSFORM_ROT_90,
- ROT_180 = FLIP_H|FLIP_V,
- ROT_270 = ROT_180|ROT_90,
- ROT_INVALID = 0x80
- };
-
- static orientation_flags fromRotation(ISurfaceComposer::Rotation rotation);
-
- enum type_mask {
- IDENTITY = 0,
- TRANSLATE = 0x1,
- ROTATE = 0x2,
- SCALE = 0x4,
- UNKNOWN = 0x8
- };
-
- // query the transform
- bool preserveRects() const;
- uint32_t getType() const;
- uint32_t getOrientation() const;
-
- const vec3& operator [] (size_t i) const; // returns column i
- float tx() const;
- float ty() const;
-
- // modify the transform
- void reset();
- void set(float tx, float ty);
- void set(float a, float b, float c, float d);
- status_t set(uint32_t flags, float w, float h);
-
- // transform data
- Rect makeBounds(int w, int h) const;
- vec2 transform(int x, int y) const;
- Region transform(const Region& reg) const;
- Rect transform(const Rect& bounds,
- bool roundOutwards = false) const;
- FloatRect transform(const FloatRect& bounds) const;
- Transform operator * (const Transform& rhs) const;
- // assumes the last row is < 0 , 0 , 1 >
- vec2 transform(const vec2& v) const;
- vec3 transform(const vec3& v) const;
-
- Transform inverse() const;
-
- // for debugging
- void dump(const char* name) const;
-
-private:
- struct mat33 {
- vec3 v[3];
- inline const vec3& operator [] (int i) const { return v[i]; }
- inline vec3& operator [] (int i) { return v[i]; }
- };
-
- enum { UNKNOWN_TYPE = 0x80000000 };
-
- uint32_t type() const;
- static bool absIsOne(float f);
- static bool isZero(float f);
-
- mat33 mMatrix;
- mutable uint32_t mType;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif /* ANDROID_TRANSFORM_H */
diff --git a/services/surfaceflinger/clz.h b/services/surfaceflinger/clz.h
deleted file mode 100644
index a4c5262..0000000
--- a/services/surfaceflinger/clz.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef ANDROID_SURFACE_FLINGER_CLZ_H
-
-#include <stdint.h>
-
-namespace android {
-
-int inline clz(int32_t x) {
- return __builtin_clz(x);
-}
-
-template <typename T>
-static inline T min(T a, T b) {
- return a<b ? a : b;
-}
-template <typename T>
-static inline T min(T a, T b, T c) {
- return min(a, min(b, c));
-}
-template <typename T>
-static inline T min(T a, T b, T c, T d) {
- return min(a, b, min(c, d));
-}
-
-template <typename T>
-static inline T max(T a, T b) {
- return a>b ? a : b;
-}
-template <typename T>
-static inline T max(T a, T b, T c) {
- return max(a, max(b, c));
-}
-template <typename T>
-static inline T max(T a, T b, T c, T d) {
- return max(a, b, max(c, d));
-}
-
-template <typename T>
-static inline
-void swap(T& a, T& b) {
- T t(a);
- a = b;
- b = t;
-}
-
-
-}; // namespace android
-
-#endif /* ANDROID_SURFACE_FLINGER_CLZ_H */
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index fcf42f0..a5bf9c1 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -101,7 +101,6 @@
layerProto.requested_position().y()};
layer->size = {layerProto.size().w(), layerProto.size().h()};
layer->crop = generateRect(layerProto.crop());
- layer->finalCrop = generateRect(layerProto.final_crop());
layer->isOpaque = layerProto.is_opaque();
layer->invalidate = layerProto.invalidate();
layer->dataspace = layerProto.dataspace();
@@ -114,6 +113,7 @@
layer->transform = generateTransform(layerProto.transform());
layer->requestedTransform = generateTransform(layerProto.requested_transform());
layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
+ layer->bufferTransform = generateTransform(layerProto.buffer_transform());
layer->queuedFrames = layerProto.queued_frames();
layer->refreshPending = layerProto.refresh_pending();
layer->hwcFrame = generateRect(layerProto.hwc_frame());
@@ -298,8 +298,7 @@
z, static_cast<double>(position.x), static_cast<double>(position.y), size.x,
size.y);
- StringAppendF(&result, "crop=%s, finalCrop=%s, ", crop.to_string().c_str(),
- finalCrop.to_string().c_str());
+ StringAppendF(&result, "crop=%s, ", crop.to_string().c_str());
StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate);
StringAppendF(&result, "dataspace=%s, ", dataspace.c_str());
StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str());
@@ -312,6 +311,7 @@
StringAppendF(&result, " zOrderRelativeOf=%s\n",
zOrderRelativeOf == nullptr ? "none" : zOrderRelativeOf->name.c_str());
StringAppendF(&result, " activeBuffer=%s,", activeBuffer.to_string().c_str());
+ StringAppendF(&result, " tr=%s", bufferTransform.to_string().c_str());
StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d,", queuedFrames, refreshPending);
StringAppendF(&result, " windowType=%d, appId=%d", windowType, appId);
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 74a6f28..b1610cf 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -92,7 +92,6 @@
float2 requestedPosition;
int2 size;
LayerProtoParser::Rect crop;
- LayerProtoParser::Rect finalCrop;
bool isOpaque;
bool invalidate;
std::string dataspace;
@@ -105,6 +104,7 @@
Layer* parent = 0;
Layer* zOrderRelativeOf = 0;
LayerProtoParser::ActiveBuffer activeBuffer;
+ Transform bufferTransform;
int32_t queuedFrames;
bool refreshPending;
LayerProtoParser::Rect hwcFrame;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index edf56ab..2a09634 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -41,7 +41,7 @@
// The layer's crop in it's own bounds.
optional RectProto crop = 14;
// The layer's crop in it's parent's bounds.
- optional RectProto final_crop = 15;
+ optional RectProto final_crop = 15 [deprecated=true];
optional bool is_opaque = 16;
optional bool invalidate = 17;
optional string dataspace = 18;
@@ -84,6 +84,8 @@
optional uint64 curr_frame = 37;
// A list of barriers that the layer is waiting to update state.
repeated BarrierLayerProto barrier_layer = 38;
+ // If active_buffer is not null, record its transform.
+ optional TransformProto buffer_transform = 39;
}
message PositionProto {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index c511c5e..604aa7d 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -17,6 +17,7 @@
defaults: ["surfaceflinger_defaults"],
test_suites: ["device-tests"],
srcs: [
+ "Credentials_test.cpp",
"Stress_test.cpp",
"SurfaceInterceptor_test.cpp",
"Transaction_test.cpp",
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
new file mode 100644
index 0000000..8e23eb8e
--- /dev/null
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -0,0 +1,331 @@
+#include <algorithm>
+#include <functional>
+#include <limits>
+#include <ostream>
+
+#include <gtest/gtest.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/gui/ComposerService.h>
+
+#include <ui/DisplayInfo.h>
+#include <utils/String8.h>
+
+namespace android {
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+namespace {
+const String8 DISPLAY_NAME("Credentials Display Test");
+const String8 SURFACE_NAME("Test Surface Name");
+const int32_t MIN_LAYER_Z = 0;
+const int32_t MAX_LAYER_Z = std::numeric_limits<int32_t>::max();
+const uint32_t ROTATION = 0;
+const float FRAME_SCALE = 1.0f;
+} // namespace
+
+/**
+ * This class tests the CheckCredentials method in SurfaceFlinger.
+ * Methods like EnableVsyncInjections and InjectVsync are not tested since they do not
+ * return anything meaningful.
+ */
+class CredentialsTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ // Start the tests as root.
+ seteuid(AID_ROOT);
+
+ ASSERT_NO_FATAL_FAILURE(initClient());
+ }
+
+ void TearDown() override {
+ mComposerClient->dispose();
+ mBGSurfaceControl.clear();
+ mComposerClient.clear();
+ // Finish the tests as root.
+ seteuid(AID_ROOT);
+ }
+
+ sp<IBinder> mDisplay;
+ sp<IBinder> mVirtualDisplay;
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<SurfaceControl> mBGSurfaceControl;
+ sp<SurfaceControl> mVirtualSurfaceControl;
+
+ void initClient() {
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+ }
+
+ void setupBackgroundSurface() {
+ mDisplay = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
+ const ssize_t displayWidth = info.w;
+ const ssize_t displayHeight = info.h;
+
+ // Background surface
+ mBGSurfaceControl =
+ mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mBGSurfaceControl != nullptr);
+ ASSERT_TRUE(mBGSurfaceControl->isValid());
+
+ Transaction t;
+ t.setDisplayLayerStack(mDisplay, 0);
+ ASSERT_EQ(NO_ERROR,
+ t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply());
+ }
+
+ void setupVirtualDisplay() {
+ mVirtualDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
+ const ssize_t displayWidth = 100;
+ const ssize_t displayHeight = 100;
+
+ // Background surface
+ mVirtualSurfaceControl =
+ mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mVirtualSurfaceControl != nullptr);
+ ASSERT_TRUE(mVirtualSurfaceControl->isValid());
+
+ Transaction t;
+ t.setDisplayLayerStack(mVirtualDisplay, 0);
+ ASSERT_EQ(NO_ERROR,
+ t.setLayer(mVirtualSurfaceControl, INT_MAX - 3)
+ .show(mVirtualSurfaceControl)
+ .apply());
+ }
+
+ /**
+ * Sets UID to imitate Graphic's process.
+ */
+ void setGraphicsUID() {
+ seteuid(AID_ROOT);
+ seteuid(AID_GRAPHICS);
+ }
+
+ /**
+ * Sets UID to imitate System's process.
+ */
+ void setSystemUID() {
+ seteuid(AID_ROOT);
+ seteuid(AID_SYSTEM);
+ }
+
+ /**
+ * Sets UID to imitate a process that doesn't have any special privileges in
+ * our code.
+ */
+ void setBinUID() {
+ seteuid(AID_ROOT);
+ seteuid(AID_BIN);
+ }
+
+ /**
+ * Template function the check a condition for different types of users: root
+ * graphics, system, and non-supported user. Root, graphics, and system should
+ * always equal privilegedValue, and non-supported user should equal unprivilegedValue.
+ */
+ template <typename T>
+ void checkWithPrivileges(std::function<T()> condition, T privilegedValue, T unprivilegedValue) {
+ // Check with root.
+ seteuid(AID_ROOT);
+ ASSERT_EQ(privilegedValue, condition());
+
+ // Check as a Graphics user.
+ setGraphicsUID();
+ ASSERT_EQ(privilegedValue, condition());
+
+ // Check as a system user.
+ setSystemUID();
+ ASSERT_EQ(privilegedValue, condition());
+
+ // Check as a non-supported user.
+ setBinUID();
+ ASSERT_EQ(unprivilegedValue, condition());
+ }
+};
+
+TEST_F(CredentialsTest, ClientInitTest) {
+ // Root can init can init the client.
+ ASSERT_NO_FATAL_FAILURE(initClient());
+
+ // Graphics can init the client.
+ setGraphicsUID();
+ ASSERT_NO_FATAL_FAILURE(initClient());
+
+ // System can init the client.
+ setSystemUID();
+ ASSERT_NO_FATAL_FAILURE(initClient());
+
+ // No one else can init the client.
+ setBinUID();
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_INIT, mComposerClient->initCheck());
+}
+
+TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) {
+ std::function<bool()> condition = [=]() {
+ sp<IBinder> display(
+ SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ return (display != nullptr);
+ };
+ // Anyone can access display information.
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true));
+}
+
+TEST_F(CredentialsTest, AllowedGetterMethodsTest) {
+ // The following methods are tested with a UID that is not root, graphics,
+ // or system, to show that anyone can access them.
+ setBinUID();
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ ASSERT_TRUE(display != nullptr);
+
+ DisplayInfo info;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+
+ Vector<DisplayInfo> configs;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveConfig(display));
+
+ ASSERT_NE(static_cast<ui::ColorMode>(BAD_VALUE),
+ SurfaceComposerClient::getActiveColorMode(display));
+}
+
+TEST_F(CredentialsTest, GetDisplayColorModesTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ Vector<ui::ColorMode> outColorModes;
+ return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
+}
+
+TEST_F(CredentialsTest, SetActiveConfigTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ return SurfaceComposerClient::setActiveConfig(display, 0);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
+}
+
+TEST_F(CredentialsTest, SetActiveColorModeTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
+}
+
+TEST_F(CredentialsTest, CreateSurfaceTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+ const ssize_t displayWidth = info.w;
+ const ssize_t displayHeight = info.h;
+
+ std::function<bool()> condition = [=]() {
+ mBGSurfaceControl =
+ mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ return mBGSurfaceControl != nullptr && mBGSurfaceControl->isValid();
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
+}
+
+TEST_F(CredentialsTest, CreateDisplayTest) {
+ std::function<bool()> condition = [=]() {
+ sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
+ return testDisplay.get() != nullptr;
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
+
+ condition = [=]() {
+ sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
+ return testDisplay.get() != nullptr;
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
+}
+
+TEST_F(CredentialsTest, DISABLED_DestroyDisplayTest) {
+ setupVirtualDisplay();
+
+ DisplayInfo info;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
+ SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
+ // This test currently fails. TODO(b/112002626): Find a way to properly create
+ // a display in the test environment, so that destroy display can remove it.
+ ASSERT_EQ(NAME_NOT_FOUND, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
+}
+
+TEST_F(CredentialsTest, CaptureTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ sp<GraphicBuffer> outBuffer;
+ return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/,
+ MIN_LAYER_Z, MAX_LAYER_Z, false, ROTATION, &outBuffer);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
+}
+
+TEST_F(CredentialsTest, CaptureLayersTest) {
+ setupBackgroundSurface();
+ sp<GraphicBuffer> outBuffer;
+ std::function<status_t()> condition = [=]() {
+ sp<GraphicBuffer> outBuffer;
+ return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), Rect(), FRAME_SCALE,
+ &outBuffer);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
+}
+
+/**
+ * The following tests are for methods accessible directly through SurfaceFlinger.
+ */
+
+/**
+ * An app can pass a buffer queue to the media server and ask the media server to decode a DRM video
+ * to that buffer queue. The media server is the buffer producer in this case. Because the app may create
+ * its own buffer queue and act as the buffer consumer, the media server wants to be careful to avoid
+ * sending decoded video frames to the app. This is where authenticateSurfaceTexture call comes in, to check
+ * the consumer of a buffer queue is SurfaceFlinger.
+ */
+TEST_F(CredentialsTest, AuthenticateSurfaceTextureTest) {
+ setupBackgroundSurface();
+ sp<IGraphicBufferProducer> producer =
+ mBGSurfaceControl->getSurface()->getIGraphicBufferProducer();
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+ std::function<bool()> condition = [=]() { return sf->authenticateSurfaceTexture(producer); };
+ // Anyone should be able to check if the consumer of the buffer queue is SF.
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true));
+}
+
+TEST_F(CredentialsTest, GetLayerDebugInfo) {
+ setupBackgroundSurface();
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+ // Historically, only root and shell can access the getLayerDebugInfo which
+ // is called when we call dumpsys. I don't see a reason why we should change this.
+ std::vector<LayerDebugInfo> outLayers;
+ // Check with root.
+ seteuid(AID_ROOT);
+ ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers));
+
+ // Check as a shell.
+ seteuid(AID_SHELL);
+ ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers));
+
+ // Check as anyone else.
+ seteuid(AID_ROOT);
+ seteuid(AID_BIN);
+ ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers));
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 36424b9..34d0fd7 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*"
+ "filter": "CredentialsTest.*:LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*"
}
}
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index de78c3f..740d2fa 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -42,13 +42,16 @@
constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
constexpr uint32_t SIZE_UPDATE = 134;
constexpr uint32_t STACK_UPDATE = 1;
-constexpr uint64_t DEFERRED_UPDATE = 13;
+constexpr uint64_t DEFERRED_UPDATE = 0;
constexpr float ALPHA_UPDATE = 0.29f;
constexpr float POSITION_UPDATE = 121;
const Rect CROP_UPDATE(16, 16, 32, 32);
const String8 DISPLAY_NAME("SurfaceInterceptor Display Test");
+constexpr auto TEST_SURFACE_NAME = "BG Interceptor Test Surface";
+constexpr auto UNIQUE_TEST_SURFACE_NAME = "BG Interceptor Test Surface#0";
constexpr auto LAYER_NAME = "Layer Create and Delete Test";
+constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
@@ -94,30 +97,21 @@
system("service call SurfaceFlinger 1020 i32 0 > /dev/null");
}
-int32_t getSurfaceId(const std::string& surfaceName) {
- enableInterceptor();
- disableInterceptor();
- Trace capturedTrace;
- readProtoFile(&capturedTrace);
+int32_t getSurfaceId(const Trace& capturedTrace, const std::string& surfaceName) {
int32_t layerId = 0;
- for (const auto& increment : *capturedTrace.mutable_increment()) {
+ for (const auto& increment : capturedTrace.increment()) {
if (increment.increment_case() == increment.kSurfaceCreation) {
if (increment.surface_creation().name() == surfaceName) {
layerId = increment.surface_creation().id();
- break;
}
}
}
return layerId;
}
-int32_t getDisplayId(const std::string& displayName) {
- enableInterceptor();
- disableInterceptor();
- Trace capturedTrace;
- readProtoFile(&capturedTrace);
+int32_t getDisplayId(const Trace& capturedTrace, const std::string& displayName) {
int32_t displayId = 0;
- for (const auto& increment : *capturedTrace.mutable_increment()) {
+ for (const auto& increment : capturedTrace.increment()) {
if (increment.increment_case() == increment.kDisplayCreation) {
if (increment.display_creation().name() == displayName) {
displayId = increment.display_creation().id();
@@ -130,36 +124,15 @@
class SurfaceInterceptorTest : public ::testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
// Allow SurfaceInterceptor write to /data
system("setenforce 0");
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
- DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
-
- // Background surface
- mBGSurfaceControl = mComposerClient->createSurface(
- String8("BG Interceptor Test Surface"), displayWidth, displayHeight,
- PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mBGSurfaceControl != nullptr);
- ASSERT_TRUE(mBGSurfaceControl->isValid());
- mBGLayerId = getSurfaceId("BG Interceptor Test Surface");
-
- Transaction t;
- t.setDisplayLayerStack(display, 0);
- ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
- .show(mBGSurfaceControl)
- .apply());
}
- virtual void TearDown() {
+ void TearDown() override {
mComposerClient->dispose();
mBGSurfaceControl.clear();
mComposerClient.clear();
@@ -168,18 +141,25 @@
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mBGSurfaceControl;
int32_t mBGLayerId;
- // Used to verify creation and destruction of surfaces and displays
- int32_t mTargetId;
public:
- void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
- bool (SurfaceInterceptorTest::* verification)(Trace *));
- void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
- SurfaceChange::SurfaceChangeCase changeCase);
- void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
- Increment::IncrementCase incrementCase);
- void runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
- bool intercepted = false);
+ using TestTransactionAction = void (SurfaceInterceptorTest::*)(Transaction&);
+ using TestAction = void (SurfaceInterceptorTest::*)();
+ using TestBooleanVerification = bool (SurfaceInterceptorTest::*)(const Trace&);
+ using TestVerification = void (SurfaceInterceptorTest::*)(const Trace&);
+
+ void setupBackgroundSurface();
+ void preProcessTrace(const Trace& trace);
+
+ // captureTest will enable SurfaceInterceptor, setup background surface,
+ // disable SurfaceInterceptor, collect the trace and process the trace for
+ // id of background surface before further verification.
+ void captureTest(TestTransactionAction action, TestBooleanVerification verification);
+ void captureTest(TestTransactionAction action, SurfaceChange::SurfaceChangeCase changeCase);
+ void captureTest(TestTransactionAction action, Increment::IncrementCase incrementCase);
+ void captureTest(TestAction action, TestBooleanVerification verification);
+ void captureTest(TestAction action, TestVerification verification);
+ void runInTransaction(TestTransactionAction action);
// Verification of changes to a surface
bool positionUpdateFound(const SurfaceChange& change, bool foundPosition);
@@ -187,7 +167,6 @@
bool alphaUpdateFound(const SurfaceChange& change, bool foundAlpha);
bool layerUpdateFound(const SurfaceChange& change, bool foundLayer);
bool cropUpdateFound(const SurfaceChange& change, bool foundCrop);
- bool finalCropUpdateFound(const SurfaceChange& change, bool foundFinalCrop);
bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -196,18 +175,22 @@
bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag);
bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag);
bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred);
- bool surfaceUpdateFound(Trace* trace, SurfaceChange::SurfaceChangeCase changeCase);
- void assertAllUpdatesFound(Trace* trace);
+ bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase);
+
+ // Find all of the updates in the single trace
+ void assertAllUpdatesFound(const Trace& trace);
// Verification of creation and deletion of a surface
bool surfaceCreationFound(const Increment& increment, bool foundSurface);
- bool surfaceDeletionFound(const Increment& increment, bool foundSurface);
+ bool surfaceDeletionFound(const Increment& increment, const int32_t targetId,
+ bool foundSurface);
bool displayCreationFound(const Increment& increment, bool foundDisplay);
- bool displayDeletionFound(const Increment& increment, bool foundDisplay);
- bool singleIncrementFound(Trace* trace, Increment::IncrementCase incrementCase);
+ bool displayDeletionFound(const Increment& increment, const int32_t targetId,
+ bool foundDisplay);
+ bool singleIncrementFound(const Trace& trace, Increment::IncrementCase incrementCase);
// Verification of buffer updates
- bool bufferUpdatesFound(Trace* trace);
+ bool bufferUpdatesFound(const Trace& trace);
// Perform each of the possible changes to a surface
void positionUpdate(Transaction&);
@@ -215,7 +198,6 @@
void alphaUpdate(Transaction&);
void layerUpdate(Transaction&);
void cropUpdate(Transaction&);
- void finalCropUpdate(Transaction&);
void matrixUpdate(Transaction&);
void overrideScalingModeUpdate(Transaction&);
void transparentRegionHintUpdate(Transaction&);
@@ -230,48 +212,93 @@
void nBufferUpdates();
void runAllUpdates();
+
+private:
+ void captureInTransaction(TestTransactionAction action, Trace*);
+ void capture(TestAction action, Trace*);
};
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
- bool (SurfaceInterceptorTest::* verification)(Trace *))
-{
- runInTransaction(action, true);
- Trace capturedTrace;
- ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- ASSERT_TRUE((this->*verification)(&capturedTrace));
+void SurfaceInterceptorTest::captureInTransaction(TestTransactionAction action, Trace* outTrace) {
+ enableInterceptor();
+ setupBackgroundSurface();
+ runInTransaction(action);
+ disableInterceptor();
+ ASSERT_EQ(NO_ERROR, readProtoFile(outTrace));
+ preProcessTrace(*outTrace);
}
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
- Increment::IncrementCase incrementCase)
-{
- runInTransaction(action, true);
- Trace capturedTrace;
- ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- ASSERT_TRUE(singleIncrementFound(&capturedTrace, incrementCase));
+void SurfaceInterceptorTest::capture(TestAction action, Trace* outTrace) {
+ enableInterceptor();
+ setupBackgroundSurface();
+ (this->*action)();
+ disableInterceptor();
+ ASSERT_EQ(NO_ERROR, readProtoFile(outTrace));
+ preProcessTrace(*outTrace);
}
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
- SurfaceChange::SurfaceChangeCase changeCase)
-{
- runInTransaction(action, true);
- Trace capturedTrace;
- ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- ASSERT_TRUE(surfaceUpdateFound(&capturedTrace, changeCase));
+void SurfaceInterceptorTest::setupBackgroundSurface() {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain));
+ DisplayInfo info;
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+ ssize_t displayWidth = info.w;
+ ssize_t displayHeight = info.h;
+
+ // Background surface
+ mBGSurfaceControl = mComposerClient->createSurface(
+ String8(TEST_SURFACE_NAME), displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mBGSurfaceControl != nullptr);
+ ASSERT_TRUE(mBGSurfaceControl->isValid());
+
+ Transaction t;
+ t.setDisplayLayerStack(display, 0);
+ ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
+ .show(mBGSurfaceControl)
+ .apply());
}
-void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
- bool intercepted)
-{
- if (intercepted) {
- enableInterceptor();
- }
+void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) {
+ mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_SURFACE_NAME);
+}
+
+void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
+ TestBooleanVerification verification) {
+ Trace capturedTrace;
+ captureInTransaction(action, &capturedTrace);
+ ASSERT_TRUE((this->*verification)(capturedTrace));
+}
+
+void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
+ Increment::IncrementCase incrementCase) {
+ Trace capturedTrace;
+ captureInTransaction(action, &capturedTrace);
+ ASSERT_TRUE(singleIncrementFound(capturedTrace, incrementCase));
+}
+
+void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
+ SurfaceChange::SurfaceChangeCase changeCase) {
+ Trace capturedTrace;
+ captureInTransaction(action, &capturedTrace);
+ ASSERT_TRUE(surfaceUpdateFound(capturedTrace, changeCase));
+}
+
+void SurfaceInterceptorTest::captureTest(TestAction action, TestBooleanVerification verification) {
+ Trace capturedTrace;
+ capture(action, &capturedTrace);
+ ASSERT_TRUE((this->*verification)(capturedTrace));
+}
+
+void SurfaceInterceptorTest::captureTest(TestAction action, TestVerification verification) {
+ Trace capturedTrace;
+ capture(action, &capturedTrace);
+ (this->*verification)(capturedTrace);
+}
+
+void SurfaceInterceptorTest::runInTransaction(TestTransactionAction action) {
Transaction t;
(this->*action)(t);
t.apply(true);
-
- if (intercepted) {
- disableInterceptor();
- }
}
void SurfaceInterceptorTest::positionUpdate(Transaction& t) {
@@ -291,11 +318,7 @@
}
void SurfaceInterceptorTest::cropUpdate(Transaction& t) {
- t.setCrop(mBGSurfaceControl, CROP_UPDATE);
-}
-
-void SurfaceInterceptorTest::finalCropUpdate(Transaction& t) {
- t.setFinalCrop(mBGSurfaceControl, CROP_UPDATE);
+ t.setCrop_legacy(mBGSurfaceControl, CROP_UPDATE);
}
void SurfaceInterceptorTest::matrixUpdate(Transaction& t) {
@@ -328,7 +351,8 @@
}
void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) {
- t.deferTransactionUntil(mBGSurfaceControl, mBGSurfaceControl->getHandle(), DEFERRED_UPDATE);
+ t.deferTransactionUntil_legacy(mBGSurfaceControl, mBGSurfaceControl->getHandle(),
+ DEFERRED_UPDATE);
}
void SurfaceInterceptorTest::displayCreation(Transaction&) {
@@ -338,7 +362,6 @@
void SurfaceInterceptorTest::displayDeletion(Transaction&) {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
- mTargetId = getDisplayId(DISPLAY_NAME.string());
SurfaceComposerClient::destroyDisplay(testDisplay);
}
@@ -348,7 +371,6 @@
runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
runInTransaction(&SurfaceInterceptorTest::layerUpdate);
runInTransaction(&SurfaceInterceptorTest::cropUpdate);
- runInTransaction(&SurfaceInterceptorTest::finalCropUpdate);
runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
runInTransaction(&SurfaceInterceptorTest::overrideScalingModeUpdate);
runInTransaction(&SurfaceInterceptorTest::transparentRegionHintUpdate);
@@ -380,9 +402,8 @@
bool hasY(change.position().y() == POSITION_UPDATE);
if (hasX && hasY && !foundPosition) {
foundPosition = true;
- }
- // Failed because the position update was found a second time
- else if (hasX && hasY && foundPosition) {
+ } else if (hasX && hasY && foundPosition) {
+ // Failed because the position update was found a second time
[] () { FAIL(); }();
}
return foundPosition;
@@ -393,8 +414,7 @@
bool hasHeight(change.size().w() == SIZE_UPDATE);
if (hasWidth && hasHeight && !foundSize) {
foundSize = true;
- }
- else if (hasWidth && hasHeight && foundSize) {
+ } else if (hasWidth && hasHeight && foundSize) {
[] () { FAIL(); }();
}
return foundSize;
@@ -404,8 +424,7 @@
bool hasAlpha(change.alpha().alpha() == ALPHA_UPDATE);
if (hasAlpha && !foundAlpha) {
foundAlpha = true;
- }
- else if (hasAlpha && foundAlpha) {
+ } else if (hasAlpha && foundAlpha) {
[] () { FAIL(); }();
}
return foundAlpha;
@@ -415,8 +434,7 @@
bool hasLayer(change.layer().layer() == LAYER_UPDATE);
if (hasLayer && !foundLayer) {
foundLayer = true;
- }
- else if (hasLayer && foundLayer) {
+ } else if (hasLayer && foundLayer) {
[] () { FAIL(); }();
}
return foundLayer;
@@ -429,59 +447,38 @@
bool hasBottom(change.crop().rectangle().bottom() == CROP_UPDATE.bottom);
if (hasLeft && hasRight && hasTop && hasBottom && !foundCrop) {
foundCrop = true;
- }
- else if (hasLeft && hasRight && hasTop && hasBottom && foundCrop) {
+ } else if (hasLeft && hasRight && hasTop && hasBottom && foundCrop) {
[] () { FAIL(); }();
}
return foundCrop;
}
-bool SurfaceInterceptorTest::finalCropUpdateFound(const SurfaceChange& change,
- bool foundFinalCrop)
-{
- bool hasLeft(change.final_crop().rectangle().left() == CROP_UPDATE.left);
- bool hasTop(change.final_crop().rectangle().top() == CROP_UPDATE.top);
- bool hasRight(change.final_crop().rectangle().right() == CROP_UPDATE.right);
- bool hasBottom(change.final_crop().rectangle().bottom() == CROP_UPDATE.bottom);
- if (hasLeft && hasRight && hasTop && hasBottom && !foundFinalCrop) {
- foundFinalCrop = true;
- }
- else if (hasLeft && hasRight && hasTop && hasBottom && foundFinalCrop) {
- [] () { FAIL(); }();
- }
- return foundFinalCrop;
-}
-
bool SurfaceInterceptorTest::matrixUpdateFound(const SurfaceChange& change, bool foundMatrix) {
bool hasSx((float)change.matrix().dsdx() == (float)M_SQRT1_2);
bool hasTx((float)change.matrix().dtdx() == (float)M_SQRT1_2);
- bool hasSy((float)change.matrix().dsdy() == (float)-M_SQRT1_2);
- bool hasTy((float)change.matrix().dtdy() == (float)M_SQRT1_2);
+ bool hasSy((float)change.matrix().dsdy() == (float)M_SQRT1_2);
+ bool hasTy((float)change.matrix().dtdy() == (float)-M_SQRT1_2);
if (hasSx && hasTx && hasSy && hasTy && !foundMatrix) {
foundMatrix = true;
- }
- else if (hasSx && hasTx && hasSy && hasTy && foundMatrix) {
+ } else if (hasSx && hasTx && hasSy && hasTy && foundMatrix) {
[] () { FAIL(); }();
}
return foundMatrix;
}
bool SurfaceInterceptorTest::scalingModeUpdateFound(const SurfaceChange& change,
- bool foundScalingMode)
-{
+ bool foundScalingMode) {
bool hasScalingUpdate(change.override_scaling_mode().override_scaling_mode() == SCALING_UPDATE);
if (hasScalingUpdate && !foundScalingMode) {
foundScalingMode = true;
- }
- else if (hasScalingUpdate && foundScalingMode) {
+ } else if (hasScalingUpdate && foundScalingMode) {
[] () { FAIL(); }();
}
return foundScalingMode;
}
bool SurfaceInterceptorTest::transparentRegionHintUpdateFound(const SurfaceChange& change,
- bool foundTransparentRegion)
-{
+ bool foundTransparentRegion) {
auto traceRegion = change.transparent_region_hint().region(0);
bool hasLeft(traceRegion.left() == CROP_UPDATE.left);
bool hasTop(traceRegion.top() == CROP_UPDATE.top);
@@ -489,84 +486,72 @@
bool hasBottom(traceRegion.bottom() == CROP_UPDATE.bottom);
if (hasLeft && hasRight && hasTop && hasBottom && !foundTransparentRegion) {
foundTransparentRegion = true;
- }
- else if (hasLeft && hasRight && hasTop && hasBottom && foundTransparentRegion) {
+ } else if (hasLeft && hasRight && hasTop && hasBottom && foundTransparentRegion) {
[] () { FAIL(); }();
}
return foundTransparentRegion;
}
bool SurfaceInterceptorTest::layerStackUpdateFound(const SurfaceChange& change,
- bool foundLayerStack)
-{
+ bool foundLayerStack) {
bool hasLayerStackUpdate(change.layer_stack().layer_stack() == STACK_UPDATE);
if (hasLayerStackUpdate && !foundLayerStack) {
foundLayerStack = true;
- }
- else if (hasLayerStackUpdate && foundLayerStack) {
+ } else if (hasLayerStackUpdate && foundLayerStack) {
[] () { FAIL(); }();
}
return foundLayerStack;
}
bool SurfaceInterceptorTest::hiddenFlagUpdateFound(const SurfaceChange& change,
- bool foundHiddenFlag)
-{
+ bool foundHiddenFlag) {
bool hasHiddenFlag(change.hidden_flag().hidden_flag());
if (hasHiddenFlag && !foundHiddenFlag) {
foundHiddenFlag = true;
- }
- else if (hasHiddenFlag && foundHiddenFlag) {
+ } else if (hasHiddenFlag && foundHiddenFlag) {
[] () { FAIL(); }();
}
return foundHiddenFlag;
}
bool SurfaceInterceptorTest::opaqueFlagUpdateFound(const SurfaceChange& change,
- bool foundOpaqueFlag)
-{
+ bool foundOpaqueFlag) {
bool hasOpaqueFlag(change.opaque_flag().opaque_flag());
if (hasOpaqueFlag && !foundOpaqueFlag) {
foundOpaqueFlag = true;
- }
- else if (hasOpaqueFlag && foundOpaqueFlag) {
+ } else if (hasOpaqueFlag && foundOpaqueFlag) {
[] () { FAIL(); }();
}
return foundOpaqueFlag;
}
bool SurfaceInterceptorTest::secureFlagUpdateFound(const SurfaceChange& change,
- bool foundSecureFlag)
-{
+ bool foundSecureFlag) {
bool hasSecureFlag(change.secure_flag().secure_flag());
if (hasSecureFlag && !foundSecureFlag) {
foundSecureFlag = true;
- }
- else if (hasSecureFlag && foundSecureFlag) {
+ } else if (hasSecureFlag && foundSecureFlag) {
[] () { FAIL(); }();
}
return foundSecureFlag;
}
bool SurfaceInterceptorTest::deferredTransactionUpdateFound(const SurfaceChange& change,
- bool foundDeferred)
-{
+ bool foundDeferred) {
bool hasId(change.deferred_transaction().layer_id() == mBGLayerId);
bool hasFrameNumber(change.deferred_transaction().frame_number() == DEFERRED_UPDATE);
if (hasId && hasFrameNumber && !foundDeferred) {
foundDeferred = true;
- }
- else if (hasId && hasFrameNumber && foundDeferred) {
+ } else if (hasId && hasFrameNumber && foundDeferred) {
[] () { FAIL(); }();
}
return foundDeferred;
}
-bool SurfaceInterceptorTest::surfaceUpdateFound(Trace* trace,
- SurfaceChange::SurfaceChangeCase changeCase)
-{
+bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace,
+ SurfaceChange::SurfaceChangeCase changeCase) {
bool foundUpdate = false;
- for (const auto& increment : *trace->mutable_increment()) {
+ for (const auto& increment : trace.increment()) {
if (increment.increment_case() == increment.kTransaction) {
for (const auto& change : increment.transaction().surface_change()) {
if (change.id() == mBGLayerId && change.SurfaceChange_case() == changeCase) {
@@ -587,9 +572,6 @@
case SurfaceChange::SurfaceChangeCase::kCrop:
foundUpdate = cropUpdateFound(change, foundUpdate);
break;
- case SurfaceChange::SurfaceChangeCase::kFinalCrop:
- foundUpdate = finalCropUpdateFound(change, foundUpdate);
- break;
case SurfaceChange::SurfaceChangeCase::kMatrix:
foundUpdate = matrixUpdateFound(change, foundUpdate);
break;
@@ -624,13 +606,12 @@
return foundUpdate;
}
-void SurfaceInterceptorTest::assertAllUpdatesFound(Trace* trace) {
+void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) {
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kPosition));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSize));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kAlpha));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayer));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kCrop));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kFinalCrop));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kMatrix));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOverrideScalingMode));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kTransparentRegionHint));
@@ -642,24 +623,23 @@
}
bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) {
- bool isMatch(increment.surface_creation().name() == LAYER_NAME &&
+ bool isMatch(increment.surface_creation().name() == UNIQUE_LAYER_NAME &&
increment.surface_creation().w() == SIZE_UPDATE &&
increment.surface_creation().h() == SIZE_UPDATE);
if (isMatch && !foundSurface) {
foundSurface = true;
- }
- else if (isMatch && foundSurface) {
+ } else if (isMatch && foundSurface) {
[] () { FAIL(); }();
}
return foundSurface;
}
-bool SurfaceInterceptorTest::surfaceDeletionFound(const Increment& increment, bool foundSurface) {
- bool isMatch(increment.surface_deletion().id() == mTargetId);
+bool SurfaceInterceptorTest::surfaceDeletionFound(const Increment& increment,
+ const int32_t targetId, bool foundSurface) {
+ bool isMatch(increment.surface_deletion().id() == targetId);
if (isMatch && !foundSurface) {
foundSurface = true;
- }
- else if (isMatch && foundSurface) {
+ } else if (isMatch && foundSurface) {
[] () { FAIL(); }();
}
return foundSurface;
@@ -670,42 +650,45 @@
increment.display_creation().is_secure());
if (isMatch && !foundDisplay) {
foundDisplay = true;
- }
- else if (isMatch && foundDisplay) {
+ } else if (isMatch && foundDisplay) {
[] () { FAIL(); }();
}
return foundDisplay;
}
-bool SurfaceInterceptorTest::displayDeletionFound(const Increment& increment, bool foundDisplay) {
- bool isMatch(increment.display_deletion().id() == mTargetId);
+bool SurfaceInterceptorTest::displayDeletionFound(const Increment& increment,
+ const int32_t targetId, bool foundDisplay) {
+ bool isMatch(increment.display_deletion().id() == targetId);
if (isMatch && !foundDisplay) {
foundDisplay = true;
- }
- else if (isMatch && foundDisplay) {
+ } else if (isMatch && foundDisplay) {
[] () { FAIL(); }();
}
return foundDisplay;
}
-bool SurfaceInterceptorTest::singleIncrementFound(Trace* trace,
- Increment::IncrementCase incrementCase)
-{
+bool SurfaceInterceptorTest::singleIncrementFound(const Trace& trace,
+ Increment::IncrementCase incrementCase) {
bool foundIncrement = false;
- for (const auto& increment : *trace->mutable_increment()) {
+ for (const auto& increment : trace.increment()) {
if (increment.increment_case() == incrementCase) {
+ int32_t targetId = 0;
switch (incrementCase) {
case Increment::IncrementCase::kSurfaceCreation:
foundIncrement = surfaceCreationFound(increment, foundIncrement);
break;
case Increment::IncrementCase::kSurfaceDeletion:
- foundIncrement = surfaceDeletionFound(increment, foundIncrement);
+ // Find the id of created surface.
+ targetId = getSurfaceId(trace, UNIQUE_LAYER_NAME);
+ foundIncrement = surfaceDeletionFound(increment, targetId, foundIncrement);
break;
case Increment::IncrementCase::kDisplayCreation:
foundIncrement = displayCreationFound(increment, foundIncrement);
break;
case Increment::IncrementCase::kDisplayDeletion:
- foundIncrement = displayDeletionFound(increment, foundIncrement);
+ // Find the id of created display.
+ targetId = getDisplayId(trace, DISPLAY_NAME.string());
+ foundIncrement = displayDeletionFound(increment, targetId, foundIncrement);
break;
default:
/* code */
@@ -716,9 +699,9 @@
return foundIncrement;
}
-bool SurfaceInterceptorTest::bufferUpdatesFound(Trace* trace) {
+bool SurfaceInterceptorTest::bufferUpdatesFound(const Trace& trace) {
uint32_t updates = 0;
- for (const auto& inc : *trace->mutable_increment()) {
+ for (const auto& inc : trace.increment()) {
if (inc.increment_case() == inc.kBufferUpdate && inc.buffer_update().id() == mBGLayerId) {
updates++;
}
@@ -747,11 +730,6 @@
captureTest(&SurfaceInterceptorTest::cropUpdate, SurfaceChange::SurfaceChangeCase::kCrop);
}
-TEST_F(SurfaceInterceptorTest, InterceptFinalCropUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::finalCropUpdate,
- SurfaceChange::SurfaceChangeCase::kFinalCrop);
-}
-
TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
}
@@ -792,14 +770,8 @@
}
TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) {
- enableInterceptor();
- runAllUpdates();
- disableInterceptor();
-
- // Find all of the updates in the single trace
- Trace capturedTrace;
- ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- assertAllUpdatesFound(&capturedTrace);
+ captureTest(&SurfaceInterceptorTest::runAllUpdates,
+ &SurfaceInterceptorTest::assertAllUpdatesFound);
}
TEST_F(SurfaceInterceptorTest, InterceptSurfaceCreationWorks) {
@@ -808,16 +780,15 @@
}
TEST_F(SurfaceInterceptorTest, InterceptSurfaceDeletionWorks) {
+ enableInterceptor();
sp<SurfaceControl> layerToDelete = mComposerClient->createSurface(String8(LAYER_NAME),
SIZE_UPDATE, SIZE_UPDATE, PIXEL_FORMAT_RGBA_8888, 0);
- this->mTargetId = getSurfaceId(LAYER_NAME);
- enableInterceptor();
mComposerClient->destroySurface(layerToDelete->getHandle());
disableInterceptor();
Trace capturedTrace;
ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- ASSERT_TRUE(singleIncrementFound(&capturedTrace, Increment::IncrementCase::kSurfaceDeletion));
+ ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceDeletion));
}
TEST_F(SurfaceInterceptorTest, InterceptDisplayCreationWorks) {
@@ -826,21 +797,24 @@
}
TEST_F(SurfaceInterceptorTest, InterceptDisplayDeletionWorks) {
- captureTest(&SurfaceInterceptorTest::displayDeletion,
- Increment::IncrementCase::kDisplayDeletion);
+ enableInterceptor();
+ runInTransaction(&SurfaceInterceptorTest::displayDeletion);
+ disableInterceptor();
+ Trace capturedTrace;
+ ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+ ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kDisplayDeletion));
}
TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) {
- nBufferUpdates();
- Trace capturedTrace;
- ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
+ captureTest(&SurfaceInterceptorTest::nBufferUpdates,
+ &SurfaceInterceptorTest::bufferUpdatesFound);
}
// If the interceptor is enabled while buffer updates are being pushed, the interceptor should
// first create a snapshot of the existing displays and surfaces and then start capturing
// the buffer updates
TEST_F(SurfaceInterceptorTest, InterceptWhileBufferUpdatesWorks) {
+ setupBackgroundSurface();
std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
enableInterceptor();
disableInterceptor();
@@ -854,6 +828,7 @@
TEST_F(SurfaceInterceptorTest, InterceptSimultaneousUpdatesWorks) {
enableInterceptor();
+ setupBackgroundSurface();
std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
std::thread surfaceUpdates(&SurfaceInterceptorTest::runAllUpdates, this);
runInTransaction(&SurfaceInterceptorTest::surfaceCreation);
@@ -863,10 +838,11 @@
Trace capturedTrace;
ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+ preProcessTrace(capturedTrace);
- assertAllUpdatesFound(&capturedTrace);
- ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
- ASSERT_TRUE(singleIncrementFound(&capturedTrace, Increment::IncrementCase::kSurfaceCreation));
+ assertAllUpdatesFound(capturedTrace);
+ ASSERT_TRUE(bufferUpdatesFound(capturedTrace));
+ ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
}
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 5108279..ed1529b 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -62,38 +62,28 @@
const Color Color::BLACK{0, 0, 0, 255};
const Color Color::TRANSPARENT{0, 0, 0, 0};
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
std::ostream& operator<<(std::ostream& os, const Color& color) {
os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
return os;
}
// Fill a region with the specified color.
-void fillBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect, const Color& color) {
- int32_t x = rect.left;
- int32_t y = rect.top;
- int32_t width = rect.right - rect.left;
- int32_t height = rect.bottom - rect.top;
-
- if (x < 0) {
- width += x;
- x = 0;
- }
- if (y < 0) {
- height += y;
- y = 0;
- }
- if (x + width > buffer.width) {
- x = std::min(x, buffer.width);
- width = buffer.width - x;
- }
- if (y + height > buffer.height) {
- y = std::min(y, buffer.height);
- height = buffer.height - y;
+void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
+ const Color& color) {
+ Rect r(0, 0, buffer.width, buffer.height);
+ if (!r.intersect(rect, &r)) {
+ return;
}
- for (int32_t j = 0; j < height; j++) {
- uint8_t* dst = static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (y + j) + x) * 4;
- for (int32_t i = 0; i < width; i++) {
+ int32_t width = r.right - r.left;
+ int32_t height = r.bottom - r.top;
+
+ for (int32_t row = 0; row < height; row++) {
+ uint8_t* dst =
+ static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (r.top + row) + r.left) * 4;
+ for (int32_t column = 0; column < width; column++) {
dst[0] = color.r;
dst[1] = color.g;
dst[2] = color.b;
@@ -103,6 +93,33 @@
}
}
+// Fill a region with the specified color.
+void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect, const Color& color) {
+ Rect r(0, 0, buffer->width, buffer->height);
+ if (!r.intersect(rect, &r)) {
+ return;
+ }
+
+ int32_t width = r.right - r.left;
+ int32_t height = r.bottom - r.top;
+
+ uint8_t* pixels;
+ buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+
+ for (int32_t row = 0; row < height; row++) {
+ uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
+ for (int32_t column = 0; column < width; column++) {
+ dst[0] = color.r;
+ dst[1] = color.g;
+ dst[2] = color.b;
+ dst[3] = color.a;
+ dst += 4;
+ }
+ }
+ buffer->unlock();
+}
+
// Check if a region has the specified color.
void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels, const Rect& rect,
const Color& color, uint8_t tolerance) {
@@ -301,8 +318,8 @@
ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
}
- sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
- uint32_t flags = 0) {
+ virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0) {
auto layer =
mClient->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
@@ -319,7 +336,7 @@
return layer;
}
- ANativeWindow_Buffer getLayerBuffer(const sp<SurfaceControl>& layer) {
+ ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
// wait for previous transactions (such as setSize) to complete
Transaction().apply(true);
@@ -329,35 +346,103 @@
return buffer;
}
- void postLayerBuffer(const sp<SurfaceControl>& layer) {
+ void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
// wait for the newly posted buffer to be latched
waitForLayerBuffers();
}
- void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color) {
+ virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
+ int32_t bufferWidth, int32_t bufferHeight) {
ANativeWindow_Buffer buffer;
- ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
- fillBufferColor(buffer, Rect(0, 0, buffer.width, buffer.height), color);
- postLayerBuffer(layer);
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ fillANativeWindowBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
+ postBufferQueueLayerBuffer(layer);
}
- void fillLayerQuadrant(const sp<SurfaceControl>& layer, const Color& topLeft,
+ virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color,
+ int32_t bufferWidth, int32_t bufferHeight) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
+ Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
+ }
+
+ void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color,
+ int32_t bufferWidth, int32_t bufferHeight) {
+ switch (mLayerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight);
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ fillBufferStateLayerColor(layer, color, bufferWidth, bufferHeight);
+ break;
+ default:
+ ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
+ }
+ }
+
+ void fillLayerQuadrant(uint32_t mLayerType, const sp<SurfaceControl>& layer,
+ int32_t bufferWidth, int32_t bufferHeight, const Color& topLeft,
const Color& topRight, const Color& bottomLeft,
const Color& bottomRight) {
+ switch (mLayerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ fillBufferQueueLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
+ bottomLeft, bottomRight);
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ fillBufferStateLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
+ bottomLeft, bottomRight);
+ break;
+ default:
+ ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
+ }
+ }
+
+ virtual void fillBufferQueueLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+ int32_t bufferHeight, const Color& topLeft,
+ const Color& topRight, const Color& bottomLeft,
+ const Color& bottomRight) {
ANativeWindow_Buffer buffer;
- ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
- ASSERT_TRUE(buffer.width % 2 == 0 && buffer.height % 2 == 0);
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
- const int32_t halfW = buffer.width / 2;
- const int32_t halfH = buffer.height / 2;
- fillBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
- fillBufferColor(buffer, Rect(halfW, 0, buffer.width, halfH), topRight);
- fillBufferColor(buffer, Rect(0, halfH, halfW, buffer.height), bottomLeft);
- fillBufferColor(buffer, Rect(halfW, halfH, buffer.width, buffer.height), bottomRight);
+ const int32_t halfW = bufferWidth / 2;
+ const int32_t halfH = bufferHeight / 2;
+ fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+ fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight);
+ fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft);
+ fillANativeWindowBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight),
+ bottomRight);
- postLayerBuffer(layer);
+ postBufferQueueLayerBuffer(layer);
+ }
+
+ virtual void fillBufferStateLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+ int32_t bufferHeight, const Color& topLeft,
+ const Color& topRight, const Color& bottomLeft,
+ const Color& bottomRight) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
+
+ const int32_t halfW = bufferWidth / 2;
+ const int32_t halfH = bufferHeight / 2;
+ fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+ fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight);
+ fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft);
+ fillGraphicBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight);
+
+ Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
}
sp<ScreenCapture> screenshot() {
@@ -376,6 +461,10 @@
// leave room for ~256 layers
const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
+ void setPositionWithResizeHelper(uint32_t layerType);
+ void setSizeBasicHelper(uint32_t layerType);
+ void setMatrixWithResizeHelper(uint32_t layerType);
+
private:
void SetUpDisplay() {
mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
@@ -404,10 +493,48 @@
int32_t mBufferPostDelay;
};
-TEST_F(LayerTransactionTest, SetPositionBasic) {
+class LayerTypeTransactionTest : public LayerTransactionTest,
+ public ::testing::WithParamInterface<uint32_t> {
+public:
+ LayerTypeTransactionTest() { mLayerType = GetParam(); }
+
+ sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0) override {
+ // if the flags already have a layer type specified, return an error
+ if (flags & ISurfaceComposerClient::eFXSurfaceMask) {
+ return nullptr;
+ }
+ return LayerTransactionTest::createLayer(name, width, height, flags | mLayerType);
+ }
+
+ void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, int32_t bufferWidth,
+ int32_t bufferHeight) {
+ ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color,
+ bufferWidth, bufferHeight));
+ }
+
+ void fillLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+ int32_t bufferHeight, const Color& topLeft, const Color& topRight,
+ const Color& bottomLeft, const Color& bottomRight) {
+ ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer,
+ bufferWidth, bufferHeight,
+ topLeft, topRight,
+ bottomLeft, bottomRight));
+ }
+
+protected:
+ uint32_t mLayerType;
+};
+
+INSTANTIATE_TEST_CASE_P(
+ LayerTypeTransactionTests, LayerTypeTransactionTest,
+ ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
+
+TEST_P(LayerTypeTransactionTest, SetPositionBasic) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
{
SCOPED_TRACE("default position");
@@ -425,10 +552,10 @@
}
}
-TEST_F(LayerTransactionTest, SetPositionRounding) {
+TEST_P(LayerTypeTransactionTest, SetPositionRounding) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
// GLES requires only 4 bits of subpixel precision during rasterization
// XXX GLES composition does not match HWC composition due to precision
@@ -447,10 +574,10 @@
}
}
-TEST_F(LayerTransactionTest, SetPositionOutOfBounds) {
+TEST_P(LayerTypeTransactionTest, SetPositionOutOfBounds) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
Transaction().setPosition(layer, -32, -32).apply();
{
@@ -465,10 +592,10 @@
}
}
-TEST_F(LayerTransactionTest, SetPositionPartiallyOutOfBounds) {
+TEST_P(LayerTypeTransactionTest, SetPositionPartiallyOutOfBounds) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
// partially out of bounds
Transaction().setPosition(layer, -30, -30).apply();
@@ -486,10 +613,10 @@
}
}
-TEST_F(LayerTransactionTest, SetPositionWithResize) {
+void LayerTransactionTest::setPositionWithResizeHelper(uint32_t layerType) {
sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 32, 32));
// setPosition is applied immediately by default, with or without resize
// pending
@@ -497,21 +624,43 @@
{
SCOPED_TRACE("resize pending");
auto shot = screenshot();
- shot->expectColor(Rect(5, 10, 37, 42), Color::RED);
- shot->expectBorder(Rect(5, 10, 37, 42), Color::BLACK);
+ Rect rect;
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ rect = {5, 10, 37, 42};
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ rect = {5, 10, 69, 74};
+ break;
+ default:
+ ASSERT_FALSE(true) << "Unsupported layer type";
+ }
+
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
}
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 64, 64));
{
SCOPED_TRACE("resize applied");
screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionWithNextResize) {
+TEST_F(LayerTransactionTest, SetPositionWithResize_BufferQueue) {
+ ASSERT_NO_FATAL_FAILURE(
+ setPositionWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_F(LayerTransactionTest, SetPositionWithResize_BufferState) {
+ ASSERT_NO_FATAL_FAILURE(
+ setPositionWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_F(LayerTransactionTest, SetPositionWithNextResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
// request setPosition to be applied with the next resize
Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply();
@@ -533,17 +682,17 @@
}
// finally resize and latch the buffer
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("new position applied");
screenshot()->expectColor(Rect(15, 20, 79, 84), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionWithNextResizeScaleToWindow) {
+TEST_F(LayerTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
// setPosition is not immediate even with SCALE_TO_WINDOW override
Transaction()
@@ -557,27 +706,38 @@
screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
}
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("new position applied");
screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetSizeBasic) {
+void LayerTransactionTest::setSizeBasicHelper(uint32_t layerType) {
sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 32, 32));
Transaction().setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ Rect rect;
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ rect = {0, 0, 32, 32};
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ rect = {0, 0, 64, 64};
+ break;
+ default:
+ ASSERT_FALSE(true) << "Unsupported layer type";
+ }
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
}
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 64, 64));
{
SCOPED_TRACE("resize applied");
auto shot = screenshot();
@@ -586,14 +746,22 @@
}
}
-TEST_F(LayerTransactionTest, SetSizeInvalid) {
+TEST_F(LayerTransactionTest, SetSizeBasic_BufferQueue) {
+ setSizeBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue);
+}
+
+TEST_F(LayerTransactionTest, SetSizeBasic_BufferState) {
+ setSizeBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState);
+}
+
+TEST_P(LayerTypeTransactionTest, SetSizeInvalid) {
// cannot test robustness against invalid sizes (zero or really huge)
}
-TEST_F(LayerTransactionTest, SetSizeWithScaleToWindow) {
+TEST_P(LayerTypeTransactionTest, SetSizeWithScaleToWindow) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
// setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
Transaction()
@@ -603,13 +771,13 @@
screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
}
-TEST_F(LayerTransactionTest, SetZBasic) {
+TEST_P(LayerTypeTransactionTest, SetZBasic) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
Transaction().setLayer(layerR, mLayerZBase + 1).apply();
{
@@ -624,13 +792,13 @@
}
}
-TEST_F(LayerTransactionTest, SetZNegative) {
+TEST_P(LayerTypeTransactionTest, SetZNegative) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
{
@@ -649,13 +817,13 @@
}
}
-TEST_F(LayerTransactionTest, SetRelativeZBasic) {
+TEST_P(LayerTypeTransactionTest, SetRelativeZBasic) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
Transaction()
.setPosition(layerG, 16, 16)
@@ -677,16 +845,16 @@
}
}
-TEST_F(LayerTransactionTest, SetRelativeZNegative) {
+TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
sp<SurfaceControl> layerB;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
// layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
@@ -697,16 +865,16 @@
screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
}
-TEST_F(LayerTransactionTest, SetRelativeZGroup) {
+TEST_P(LayerTypeTransactionTest, SetRelativeZGroup) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
sp<SurfaceControl> layerB;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
// layerR = 0, layerG = layerR + 3, layerB = 2
Transaction()
@@ -764,14 +932,14 @@
}
}
-TEST_F(LayerTransactionTest, SetRelativeZBug64572777) {
+TEST_P(LayerTypeTransactionTest, SetRelativeZBug64572777) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
Transaction()
.setPosition(layerG, 16, 16)
@@ -783,10 +951,10 @@
screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
-TEST_F(LayerTransactionTest, SetFlagsHidden) {
+TEST_P(LayerTypeTransactionTest, SetFlagsHidden) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
{
@@ -801,14 +969,14 @@
}
}
-TEST_F(LayerTransactionTest, SetFlagsOpaque) {
+TEST_P(LayerTypeTransactionTest, SetFlagsOpaque) {
const Color translucentRed = {100, 0, 0, 100};
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
Transaction()
.setLayer(layerR, mLayerZBase + 1)
@@ -827,10 +995,10 @@
}
}
-TEST_F(LayerTransactionTest, SetFlagsSecure) {
+TEST_P(LayerTypeTransactionTest, SetFlagsSecure) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
sp<ISurfaceComposer> composer = ComposerService::getComposerService();
sp<GraphicBuffer> outBuffer;
@@ -847,19 +1015,19 @@
false));
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic) {
+TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
const Rect top(0, 0, 32, 16);
const Rect bottom(0, 16, 32, 32);
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ANativeWindow_Buffer buffer;
- ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
- ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, top, Color::TRANSPARENT));
- ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, bottom, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT));
+ ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::RED));
// setTransparentRegionHint always applies to the following buffer
Transaction().setTransparentRegionHint(layer, Region(top)).apply();
- ASSERT_NO_FATAL_FAILURE(postLayerBuffer(layer));
+ ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
{
SCOPED_TRACE("top transparent");
auto shot = screenshot();
@@ -875,10 +1043,10 @@
shot->expectColor(bottom, Color::RED);
}
- ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
- ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, top, Color::RED));
- ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, bottom, Color::TRANSPARENT));
- ASSERT_NO_FATAL_FAILURE(postLayerBuffer(layer));
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT));
+ ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
{
SCOPED_TRACE("bottom transparent");
auto shot = screenshot();
@@ -887,7 +1055,58 @@
}
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds) {
+TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic_BufferState) {
+ const Rect top(0, 0, 32, 16);
+ const Rect bottom(0, 16, 32, 32);
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::TRANSPARENT));
+ ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::RED));
+ Transaction()
+ .setTransparentRegionHint(layer, Region(top))
+ .setBuffer(layer, buffer)
+ .setSize(layer, 32, 32)
+ .apply();
+ {
+ SCOPED_TRACE("top transparent");
+ auto shot = screenshot();
+ shot->expectColor(top, Color::BLACK);
+ shot->expectColor(bottom, Color::RED);
+ }
+
+ Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
+ {
+ SCOPED_TRACE("transparent region hint intermediate");
+ auto shot = screenshot();
+ shot->expectColor(top, Color::BLACK);
+ shot->expectColor(bottom, Color::BLACK);
+ }
+
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT));
+ Transaction().setBuffer(layer, buffer).setSize(layer, 32, 32).apply();
+ {
+ SCOPED_TRACE("bottom transparent");
+ auto shot = screenshot();
+ shot->expectColor(top, Color::RED);
+ shot->expectColor(bottom, Color::BLACK);
+ }
+}
+
+TEST_P(LayerTypeTransactionTest, SetTransparentRegionHintOutOfBounds) {
sp<SurfaceControl> layerTransparent;
sp<SurfaceControl> layerR;
ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
@@ -900,18 +1119,18 @@
.setPosition(layerR, 16, 16)
.setLayer(layerR, mLayerZBase + 1)
.apply();
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerTransparent, Color::TRANSPARENT));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED);
}
-TEST_F(LayerTransactionTest, SetAlphaBasic) {
+TEST_P(LayerTypeTransactionTest, SetAlphaBasic) {
sp<SurfaceControl> layer1;
sp<SurfaceControl> layer2;
ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32));
ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer1, {64, 0, 0, 255}));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer2, {0, 64, 0, 255}));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer1, {64, 0, 0, 255}, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer2, {0, 64, 0, 255}, 32, 32));
Transaction()
.setAlpha(layer1, 0.25f)
@@ -931,11 +1150,11 @@
}
}
-TEST_F(LayerTransactionTest, SetAlphaClamped) {
+TEST_P(LayerTypeTransactionTest, SetAlphaClamped) {
const Color color = {64, 0, 0, 255};
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color, 32, 32));
Transaction().setAlpha(layer, 2.0f).apply();
{
@@ -954,7 +1173,7 @@
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(
colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
@@ -989,7 +1208,7 @@
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(
colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
@@ -1014,7 +1233,7 @@
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer(
"childWithColor", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
@@ -1034,20 +1253,20 @@
tolerance);
}
-TEST_F(LayerTransactionTest, SetColorWithBuffer) {
+TEST_P(LayerTypeTransactionTest, SetColorWithBuffer) {
sp<SurfaceControl> bufferLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
// color is ignored
Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
-TEST_F(LayerTransactionTest, SetLayerStackBasic) {
+TEST_P(LayerTypeTransactionTest, SetLayerStackBasic) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
{
@@ -1062,11 +1281,11 @@
}
}
-TEST_F(LayerTransactionTest, SetMatrixBasic) {
+TEST_P(LayerTypeTransactionTest, SetMatrixBasic) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(
- fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+ fillLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
{
@@ -1104,11 +1323,11 @@
}
}
-TEST_F(LayerTransactionTest, SetMatrixRot45) {
+TEST_P(LayerTypeTransactionTest, SetMatrixRot45) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(
- fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+ fillLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
const float rot = M_SQRT1_2; // 45 degrees
const float trans = M_SQRT2 * 16.0f;
@@ -1127,31 +1346,52 @@
shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
}
-TEST_F(LayerTransactionTest, SetMatrixWithResize) {
+void LayerTransactionTest::setMatrixWithResizeHelper(uint32_t layerType) {
sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 32, 32));
// setMatrix is applied after any pending resize, unlike setPosition
Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ Rect rect;
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ rect = {0, 0, 32, 32};
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ rect = {0, 0, 128, 128};
+ break;
+ default:
+ ASSERT_FALSE(true) << "Unsupported layer type";
+ }
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
}
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 64, 64));
{
SCOPED_TRACE("resize applied");
screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetMatrixWithScaleToWindow) {
+TEST_F(LayerTransactionTest, SetMatrixWithResize_BufferQueue) {
+ ASSERT_NO_FATAL_FAILURE(
+ setMatrixWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_F(LayerTransactionTest, SetMatrixWithResize_BufferState) {
+ ASSERT_NO_FATAL_FAILURE(
+ setMatrixWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_P(LayerTypeTransactionTest, SetMatrixWithScaleToWindow) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
// setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
Transaction()
@@ -1162,11 +1402,11 @@
screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
}
-TEST_F(LayerTransactionTest, SetOverrideScalingModeBasic) {
+TEST_P(LayerTypeTransactionTest, SetOverrideScalingModeBasic) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(
- fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+ fillLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
// XXX SCALE_CROP is not respected; calling setSize and
// setOverrideScalingMode in separate transactions does not work
@@ -1182,10 +1422,36 @@
}
}
-TEST_F(LayerTransactionTest, SetCropBasic) {
+TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+ sp<IBinder> handle = layer->getHandle();
+ ASSERT_TRUE(handle != nullptr);
+
+ FrameStats frameStats;
+ mClient->getLayerFrameStats(handle, &frameStats);
+
+ ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0));
+}
+
+TEST_F(LayerTransactionTest, SetCropBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+ const Rect crop(8, 8, 24, 24);
+
+ Transaction().setCrop_legacy(layer, crop).apply();
+ auto shot = screenshot();
+ shot->expectColor(crop, Color::RED);
+ shot->expectBorder(crop, Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
const Rect crop(8, 8, 24, 24);
Transaction().setCrop(layer, crop).apply();
@@ -1194,10 +1460,29 @@
shot->expectBorder(crop, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropEmpty) {
+TEST_F(LayerTransactionTest, SetCropEmpty_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("empty rect");
+ Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
+ screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ {
+ SCOPED_TRACE("negative rect");
+ Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
+ screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+}
+
+TEST_F(LayerTransactionTest, SetCropEmpty_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
{
SCOPED_TRACE("empty rect");
@@ -1212,10 +1497,22 @@
}
}
-TEST_F(LayerTransactionTest, SetCropOutOfBounds) {
+TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
Transaction().setCrop(layer, Rect(-128, -64, 128, 64)).apply();
auto shot = screenshot();
@@ -1223,10 +1520,24 @@
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropWithTranslation) {
+TEST_F(LayerTransactionTest, SetCropWithTranslation_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ const Point position(32, 32);
+ const Rect crop(8, 8, 24, 24);
+ Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
+ auto shot = screenshot();
+ shot->expectColor(crop + position, Color::RED);
+ shot->expectBorder(crop + position, Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropWithTranslation_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
const Point position(32, 32);
const Rect crop(8, 8, 24, 24);
@@ -1236,10 +1547,26 @@
shot->expectBorder(crop + position, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropWithScale) {
+TEST_F(LayerTransactionTest, SetCropWithScale_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // crop is affected by matrix
+ Transaction()
+ .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+ .setCrop_legacy(layer, Rect(8, 8, 24, 24))
+ .apply();
+ auto shot = screenshot();
+ shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+ shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropWithScale_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
// crop is affected by matrix
Transaction()
@@ -1251,13 +1578,13 @@
shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropWithResize) {
+TEST_F(LayerTransactionTest, SetCropWithResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- // setCrop is applied immediately by default, with or without resize pending
- Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+ // setCrop_legacy is applied immediately by default, with or without resize pending
+ Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
{
SCOPED_TRACE("resize pending");
auto shot = screenshot();
@@ -1265,7 +1592,7 @@
shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
}
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
{
SCOPED_TRACE("resize applied");
auto shot = screenshot();
@@ -1274,19 +1601,46 @@
}
}
-TEST_F(LayerTransactionTest, SetCropWithNextResize) {
+TEST_F(LayerTransactionTest, SetCropWithResize_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ // setCrop_legacy is applied immediately by default, with or without resize pending
+ Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+ {
+ SCOPED_TRACE("new buffer pending");
+ auto shot = screenshot();
+ shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
+ shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 16, 16));
+ {
+ SCOPED_TRACE("new buffer");
+ auto shot = screenshot();
+ shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
+ shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
+ }
+}
+
+TEST_F(LayerTransactionTest, SetCropWithNextResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- // request setCrop to be applied with the next resize
- Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setGeometryAppliesWithResize(layer).apply();
+ // request setCrop_legacy to be applied with the next resize
+ Transaction()
+ .setCrop_legacy(layer, Rect(8, 8, 24, 24))
+ .setGeometryAppliesWithResize(layer)
+ .apply();
{
SCOPED_TRACE("waiting for next resize");
screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
- Transaction().setCrop(layer, Rect(4, 4, 12, 12)).apply();
+ Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply();
{
SCOPED_TRACE("pending crop modified");
screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
@@ -1299,7 +1653,7 @@
}
// finally resize
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
{
SCOPED_TRACE("new crop applied");
auto shot = screenshot();
@@ -1308,14 +1662,49 @@
}
}
-TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow) {
+TEST_F(LayerTransactionTest, SetCropWithNextResize_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ // request setCrop_legacy to be applied with the next resize
+ Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setGeometryAppliesWithResize(layer).apply();
+ {
+ SCOPED_TRACE("set crop 1");
+ screenshot()->expectColor(Rect(8, 8, 24, 24), Color::RED);
+ }
+
+ Transaction().setCrop(layer, Rect(4, 4, 12, 12)).apply();
+ {
+ SCOPED_TRACE("set crop 2");
+ screenshot()->expectColor(Rect(4, 4, 12, 12), Color::RED);
+ }
+
+ Transaction().setSize(layer, 16, 16).apply();
+ {
+ SCOPED_TRACE("resize");
+ screenshot()->expectColor(Rect(4, 4, 12, 12), Color::RED);
+ }
+
+ // finally resize
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 16, 16));
+ {
+ SCOPED_TRACE("new buffer");
+ auto shot = screenshot();
+ shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
+ shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+ }
+}
+
+TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- // setCrop is not immediate even with SCALE_TO_WINDOW override
+ // setCrop_legacy is not immediate even with SCALE_TO_WINDOW override
Transaction()
- .setCrop(layer, Rect(4, 4, 12, 12))
+ .setCrop_legacy(layer, Rect(4, 4, 12, 12))
.setSize(layer, 16, 16)
.setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
.setGeometryAppliesWithResize(layer)
@@ -1329,7 +1718,7 @@
// XXX crop is never latched without other geometry change (b/69315677)
Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
Transaction().setPosition(layer, 0, 0).apply();
{
SCOPED_TRACE("new crop applied");
@@ -1339,166 +1728,311 @@
}
}
-TEST_F(LayerTransactionTest, SetFinalCropBasic) {
+TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow_BufferState) {
sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
- const Rect crop(8, 8, 24, 24);
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
- // same as in SetCropBasic
- Transaction().setFinalCrop(layer, crop).apply();
- auto shot = screenshot();
- shot->expectColor(crop, Color::RED);
- shot->expectBorder(crop, Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropEmpty) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
-
- // same as in SetCropEmpty
- {
- SCOPED_TRACE("empty rect");
- Transaction().setFinalCrop(layer, Rect(8, 8, 8, 8)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- {
- SCOPED_TRACE("negative rect");
- Transaction().setFinalCrop(layer, Rect(8, 8, 0, 0)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropOutOfBounds) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
-
- // same as in SetCropOutOfBounds
- Transaction().setFinalCrop(layer, Rect(-128, -64, 128, 64)).apply();
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithTranslation) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
-
- // final crop is applied post-translation
- Transaction().setPosition(layer, 16, 16).setFinalCrop(layer, Rect(8, 8, 24, 24)).apply();
- auto shot = screenshot();
- shot->expectColor(Rect(16, 16, 24, 24), Color::RED);
- shot->expectBorder(Rect(16, 16, 24, 24), Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithScale) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
-
- // final crop is not affected by matrix
+ // all properties are applied immediate so setGeometryAppliesWithResize has no effect
Transaction()
- .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
- .setFinalCrop(layer, Rect(8, 8, 24, 24))
- .apply();
- auto shot = screenshot();
- shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
- shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithResize) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
-
- // same as in SetCropWithResize
- Transaction().setFinalCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = screenshot();
- shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
- shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
- {
- SCOPED_TRACE("resize applied");
- auto shot = screenshot();
- shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
- shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
- }
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithNextResize) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
-
- // same as in SetCropWithNextResize
- Transaction()
- .setFinalCrop(layer, Rect(8, 8, 24, 24))
- .setGeometryAppliesWithResize(layer)
- .apply();
- {
- SCOPED_TRACE("waiting for next resize");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setFinalCrop(layer, Rect(4, 4, 12, 12)).apply();
- {
- SCOPED_TRACE("pending final crop modified");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setSize(layer, 16, 16).apply();
- {
- SCOPED_TRACE("resize pending");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- // finally resize
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
- {
- SCOPED_TRACE("new final crop applied");
- auto shot = screenshot();
- shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
- shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
- }
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithNextResizeScaleToWindow) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
-
- // same as in SetCropWithNextResizeScaleToWindow
- Transaction()
- .setFinalCrop(layer, Rect(4, 4, 12, 12))
+ .setCrop(layer, Rect(4, 4, 12, 12))
.setSize(layer, 16, 16)
.setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
.setGeometryAppliesWithResize(layer)
.apply();
{
- SCOPED_TRACE("new final crop pending");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
- shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK);
- }
-
- // XXX final crop is never latched without other geometry change (b/69315677)
- Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
- Transaction().setPosition(layer, 0, 0).apply();
- {
- SCOPED_TRACE("new final crop applied");
+ SCOPED_TRACE("new crop pending");
auto shot = screenshot();
shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
}
+
+ Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 16, 16));
+ Transaction().setPosition(layer, 0, 0).apply();
+ {
+ SCOPED_TRACE("new crop applied");
+ auto shot = screenshot();
+ shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
+ shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+ }
+}
+
+TEST_F(LayerTransactionTest, SetBufferBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetBufferMultipleBuffers_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("set buffer 1");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
+
+ {
+ SCOPED_TRACE("set buffer 2");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("set buffer 3");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+}
+
+TEST_F(LayerTransactionTest, SetBufferMultipleLayers_BufferState) {
+ sp<SurfaceControl> layer1;
+ ASSERT_NO_FATAL_FAILURE(
+ layer1 = createLayer("test", 64, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<SurfaceControl> layer2;
+ ASSERT_NO_FATAL_FAILURE(
+ layer2 = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64));
+
+ {
+ SCOPED_TRACE("set layer 1 buffer red");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
+
+ {
+ SCOPED_TRACE("set layer 2 buffer blue");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectColor(Rect(0, 32, 64, 64), Color::RED);
+ shot->expectColor(Rect(0, 32, 32, 64), Color::RED);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::GREEN, 64, 64));
+ {
+ SCOPED_TRACE("set layer 1 buffer green");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
+ shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::WHITE, 32, 32));
+
+ {
+ SCOPED_TRACE("set layer 2 buffer white");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::WHITE);
+ shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
+ shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
+ }
+}
+
+TEST_F(LayerTransactionTest, SetTransformRotate90_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ Transaction().setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90).apply();
+
+ screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
+ Color::GREEN, true /* filtered */);
+}
+
+TEST_F(LayerTransactionTest, SetTransformFlipH_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ Transaction().setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H).apply();
+
+ screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
+ Color::BLUE, true /* filtered */);
+}
+
+TEST_F(LayerTransactionTest, SetTransformFlipV_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ Transaction().setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V).apply();
+
+ screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
+ Color::GREEN, true /* filtered */);
+}
+
+TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction().setTransformToDisplayInverse(layer, false).apply();
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::GREEN, 32, 32));
+
+ Transaction().setTransformToDisplayInverse(layer, true).apply();
+}
+
+TEST_F(LayerTransactionTest, SetFenceBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ sp<Fence> fence = new Fence(-1);
+
+ Transaction()
+ .setBuffer(layer, buffer)
+ .setAcquireFence(layer, fence)
+ .setSize(layer, 32, 32)
+ .apply();
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetDataspaceBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ Transaction()
+ .setBuffer(layer, buffer)
+ .setDataspace(layer, ui::Dataspace::UNKNOWN)
+ .setSize(layer, 32, 32)
+ .apply();
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetHdrMetadataBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ HdrMetadata hdrMetadata;
+ hdrMetadata.validTypes = 0;
+ Transaction()
+ .setBuffer(layer, buffer)
+ .setHdrMetadata(layer, hdrMetadata)
+ .setSize(layer, 32, 32)
+ .apply();
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ Region region;
+ region.set(32, 32);
+ Transaction()
+ .setBuffer(layer, buffer)
+ .setSurfaceDamageRegion(layer, region)
+ .setSize(layer, 32, 32)
+ .apply();
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetApiBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ Transaction()
+ .setBuffer(layer, buffer)
+ .setApi(layer, NATIVE_WINDOW_API_CPU)
+ .setSize(layer, 32, 32)
+ .apply();
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ // verify this doesn't cause a crash
+ Transaction().setSidebandStream(layer, nullptr).apply();
}
class LayerUpdateTest : public LayerTransactionTest {
@@ -1649,8 +2183,7 @@
asTransaction([&](Transaction& t) {
t.setSize(mFGSurfaceControl, 64, 64);
t.setPosition(mFGSurfaceControl, 64, 64);
- t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
- t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+ t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
});
EXPECT_INITIAL_STATE("After restoring initial state");
@@ -1679,43 +2212,6 @@
}
};
-// In this test we ensure that setGeometryAppliesWithResize actually demands
-// a buffer of the new size, and not just any size.
-TEST_F(CropLatchingTest, FinalCropLatchingBufferOldSize) {
- EXPECT_INITIAL_STATE("before anything");
- // Normally the crop applies immediately even while a resize is pending.
- asTransaction([&](Transaction& t) {
- t.setSize(mFGSurfaceControl, 128, 128);
- t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
- });
-
- EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
-
- restoreInitialState();
-
- // In order to prepare to submit a buffer at the wrong size, we acquire it prior to
- // initiating the resize.
- lockAndFillFGBuffer();
-
- asTransaction([&](Transaction& t) {
- t.setSize(mFGSurfaceControl, 128, 128);
- t.setGeometryAppliesWithResize(mFGSurfaceControl);
- t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
- });
-
- EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
-
- // We now submit our old buffer, at the old size, and ensure it doesn't
- // trigger geometry latching.
- unlockFGBuffer();
-
- EXPECT_INITIAL_STATE("after unlocking FG buffer (with geometryAppliesWithResize)");
-
- completeFGResize();
-
- EXPECT_CROPPED_STATE("after the resize finishes");
-}
-
TEST_F(LayerUpdateTest, DeferredTransactionTest) {
sp<ScreenCapture> sc;
{
@@ -1729,14 +2225,14 @@
// set up two deferred transactions on different frames
asTransaction([&](Transaction& t) {
t.setAlpha(mFGSurfaceControl, 0.75);
- t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
- mSyncSurfaceControl->getSurface()->getNextFrameNumber());
+ t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber());
});
asTransaction([&](Transaction& t) {
t.setPosition(mFGSurfaceControl, 128, 128);
- t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
- mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+ t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
});
{
@@ -1881,23 +2377,7 @@
t.show(mChild);
t.setPosition(mChild, 0, 0);
t.setPosition(mFGSurfaceControl, 0, 0);
- t.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
- });
-
- {
- ScreenCapture::captureScreen(&mCapture);
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(4, 4);
- mCapture->expectBGColor(5, 5);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerFinalCropping) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+ t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
});
{
@@ -2166,8 +2646,8 @@
// Show the child layer in a deferred transaction
asTransaction([&](Transaction& t) {
- t.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(),
- mFGSurfaceControl->getSurface()->getNextFrameNumber());
+ t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
+ mFGSurfaceControl->getSurface()->getNextFrameNumber());
t.show(mChild);
});
@@ -2465,8 +2945,9 @@
}
TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
-
- SurfaceComposerClient::Transaction().setCrop(mFGSurfaceControl, Rect(0, 0, 1, 1)).apply(true);
+ SurfaceComposerClient::Transaction()
+ .setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 1, 1))
+ .apply(true);
// Even though the parent is cropped out we should still capture the child.
verify();
@@ -2565,8 +3046,8 @@
mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888,
0, redLayer.get());
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(blueLayer, Color::BLUE));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
SurfaceComposerClient::Transaction()
.setLayer(redLayer, INT32_MAX - 1)
@@ -2599,8 +3080,8 @@
mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888,
0, redLayer.get());
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(blueLayer, Color::BLUE));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
SurfaceComposerClient::Transaction()
.setLayer(redLayer, INT32_MAX - 1)
@@ -2632,7 +3113,7 @@
sp<SurfaceControl> redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60,
PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
auto redLayerHandle = redLayer->getHandle();
mComposerClient->destroySurface(redLayerHandle);
@@ -2651,9 +3132,9 @@
void SetUp() override {
LayerTransactionTest::SetUp();
bgLayer = createLayer("BG layer", 20, 20);
- fillLayerColor(bgLayer, Color::RED);
+ fillBufferQueueLayerColor(bgLayer, Color::RED, 20, 20);
fgLayer = createLayer("FG layer", 20, 20);
- fillLayerColor(fgLayer, Color::BLUE);
+ fillBufferQueueLayerColor(fgLayer, Color::BLUE, 20, 20);
Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
{
SCOPED_TRACE("before anything");
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 6ad1b87..a5b522e 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -30,8 +30,9 @@
"libutils",
],
static_libs: [
+ "libgmock",
+ "librenderengine",
"libtrace_proto",
- "libgmock"
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 9b31985..356a880 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -624,7 +624,7 @@
{
TransactionScope ts(*sFakeComposer);
Rect cropRect(16, 16, 32, 32);
- ts.setCrop(mFGSurfaceControl, cropRect);
+ ts.setCrop_legacy(mFGSurfaceControl, cropRect);
}
ASSERT_EQ(2, sFakeComposer->getFrameCount());
@@ -634,40 +634,6 @@
EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
}
-TEST_F(TransactionTest, LayerFinalCrop) {
- // TODO: Add scaling to confirm that crop happens in display space?
- {
- TransactionScope ts(*sFakeComposer);
- Rect cropRect(32, 32, 32 + 64, 32 + 64);
- ts.setFinalCrop(mFGSurfaceControl, cropRect);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- // In display space we are cropping with [32, 32, 96, 96] against display rect
- // [64, 64, 128, 128]. Should yield display rect [64, 64, 96, 96]
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 32, 64 + 32};
-
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
-TEST_F(TransactionTest, LayerFinalCropEmpty) {
- // TODO: Add scaling to confirm that crop happens in display space?
- {
- TransactionScope ts(*sFakeComposer);
- Rect cropRect(16, 16, 32, 32);
- ts.setFinalCrop(mFGSurfaceControl, cropRect);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- // In display space we are cropping with [16, 16, 32, 32] against display rect
- // [64, 64, 128, 128]. The intersection is empty and only the background layer is composited.
- std::vector<RenderState> referenceFrame(1);
- referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
TEST_F(TransactionTest, LayerSetLayer) {
{
TransactionScope ts(*sFakeComposer);
@@ -847,18 +813,16 @@
{
TransactionScope ts(*sFakeComposer);
ts.setAlpha(mFGSurfaceControl, 0.75);
- ts.deferTransactionUntil(mFGSurfaceControl,
- syncSurfaceControl->getHandle(),
- syncSurfaceControl->getSurface()->getNextFrameNumber());
+ ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+ syncSurfaceControl->getSurface()->getNextFrameNumber());
}
EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
{
TransactionScope ts(*sFakeComposer);
ts.setPosition(mFGSurfaceControl, 128, 128);
- ts.deferTransactionUntil(mFGSurfaceControl,
- syncSurfaceControl->getHandle(),
- syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+ ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+ syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
}
EXPECT_EQ(4, sFakeComposer->getFrameCount());
EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
@@ -981,7 +945,7 @@
ts.show(mChild);
ts.setPosition(mChild, 0, 0);
ts.setPosition(mFGSurfaceControl, 0, 0);
- ts.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+ ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
}
// NOTE: The foreground surface would be occluded by the child
// now, but is included in the stack because the child is
@@ -994,22 +958,6 @@
EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
}
-TEST_F(ChildLayerTest, FinalCropping) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
- }
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
- referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
- referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
TEST_F(ChildLayerTest, Constraints) {
{
TransactionScope ts(*sFakeComposer);
@@ -1095,7 +1043,7 @@
EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
}
-TEST_F(ChildLayerTest, DetachChildren) {
+TEST_F(ChildLayerTest, DetachChildrenSameClient) {
{
TransactionScope ts(*sFakeComposer);
ts.show(mChild);
@@ -1111,14 +1059,59 @@
{
TransactionScope ts(*sFakeComposer);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
ts.detachChildren(mFGSurfaceControl);
}
{
TransactionScope ts(*sFakeComposer);
+ ts.setPosition(mFGSurfaceControl, 64, 64);
ts.hide(mChild);
}
+ std::vector<RenderState> refFrame(2);
+ refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ refFrame[FG_LAYER] = mBaseFrame[FG_LAYER];
+
+ EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ ASSERT_TRUE(childNewClient != nullptr);
+ ASSERT_TRUE(childNewClient->isValid());
+ fillSurfaceRGBA8(childNewClient, LIGHT_GRAY);
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.hide(mChild);
+ ts.show(childNewClient);
+ ts.setPosition(childNewClient, 10, 10);
+ ts.setPosition(mFGSurfaceControl, 64, 64);
+ }
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.detachChildren(mFGSurfaceControl);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ }
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setPosition(mFGSurfaceControl, 64, 64);
+ ts.setPosition(childNewClient, 0, 0);
+ ts.hide(childNewClient);
+ }
+
// Nothing should have changed. The child control becomes a no-op
// zombie on detach. See comments for detachChildren in the
// SurfaceControl.h file.
@@ -1193,8 +1186,8 @@
// Show the child layer in a deferred transaction
{
TransactionScope ts(*sFakeComposer);
- ts.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(),
- mFGSurfaceControl->getSurface()->getNextFrameNumber());
+ ts.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
+ mFGSurfaceControl->getSurface()->getNextFrameNumber());
ts.show(mChild);
}
@@ -1217,6 +1210,81 @@
sFakeComposer->runVSyncAndWait();
}
+class ChildColorLayerTest : public ChildLayerTest {
+protected:
+ void SetUp() override {
+ TransactionTest::SetUp();
+ mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ mFGSurfaceControl.get());
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setColor(mChild,
+ {LIGHT_GRAY.r / 255.0f, LIGHT_GRAY.g / 255.0f, LIGHT_GRAY.b / 255.0f});
+ }
+
+ sFakeComposer->runVSyncAndWait();
+ mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
+ mBaseFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.0f, 0.0f, 0.0f, 0.0f};
+ mBaseFrame[CHILD_LAYER].mSwapCount = 0;
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+ }
+};
+
+TEST_F(ChildColorLayerTest, LayerAlpha) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ ts.setAlpha(mChild, 0.5);
+ }
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setAlpha(mFGSurfaceControl, 0.5);
+ }
+
+ auto referenceFrame2 = referenceFrame;
+ referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f;
+ referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildColorLayerTest, LayerZeroAlpha) {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(mFGSurfaceControl, 0, 0);
+ ts.setAlpha(mChild, 0.5);
+ }
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setAlpha(mFGSurfaceControl, 0.0f);
+ }
+
+ std::vector<RenderState> refFrame(1);
+ refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+
+ EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
class LatchingTest : public TransactionTest {
protected:
void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); }
@@ -1235,8 +1303,7 @@
TransactionScope ts(*sFakeComposer);
ts.setSize(mFGSurfaceControl, 64, 64);
ts.setPosition(mFGSurfaceControl, 64, 64);
- ts.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
- ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+ ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
}
};
@@ -1280,7 +1347,7 @@
{
TransactionScope ts(*sFakeComposer);
ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+ ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63));
}
auto referenceFrame1 = mBaseFrame;
@@ -1294,7 +1361,7 @@
TransactionScope ts(*sFakeComposer);
ts.setSize(mFGSurfaceControl, 128, 128);
ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+ ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63));
}
EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
@@ -1307,111 +1374,6 @@
EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
}
-TEST_F(LatchingTest, FinalCropLatching) {
- // Normally the crop applies immediately even while a resize is pending.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
-
- auto referenceFrame1 = mBaseFrame;
- referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
- referenceFrame1[FG_LAYER].mSourceCrop =
- hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
- EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
-
- restoreInitialState();
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
- completeFGResize();
-
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
- referenceFrame2[FG_LAYER].mSourceCrop =
- hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
- referenceFrame2[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
-}
-
-// In this test we ensure that setGeometryAppliesWithResize actually demands
-// a buffer of the new size, and not just any size.
-TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) {
- // Normally the crop applies immediately even while a resize is pending.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
-
- auto referenceFrame1 = mBaseFrame;
- referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
- referenceFrame1[FG_LAYER].mSourceCrop =
- hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
- EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
-
- restoreInitialState();
-
- // In order to prepare to submit a buffer at the wrong size, we acquire it prior to
- // initiating the resize.
- lockAndFillFGBuffer();
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
- // We now submit our old buffer, at the old size, and ensure it doesn't
- // trigger geometry latching.
- unlockFGBuffer();
-
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
-
- completeFGResize();
- auto referenceFrame3 = referenceFrame2;
- referenceFrame3[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
- referenceFrame3[FG_LAYER].mSourceCrop =
- hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
- referenceFrame3[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame3, sFakeComposer->getLatestFrame()));
-}
-
-TEST_F(LatchingTest, FinalCropLatchingRegressionForb37531386) {
- // In this scenario, we attempt to set the final crop a second time while the resize
- // is still pending, and ensure we are successful. Success meaning the second crop
- // is the one which eventually latches and not the first.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
- completeFGResize();
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
} // namespace
int main(int argc, char** argv) {
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 9949bfa..6fe52d3 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2018 The Android Open Source Project
+// Copyright 2018 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,16 +16,26 @@
name: "libsurfaceflinger_unittest",
defaults: ["libsurfaceflinger_defaults"],
test_suites: ["device-tests"],
+ sanitize: {
+ // Using the address sanitizer not only helps uncover issues in the code
+ // covered by the tests, but also covers some of the tricky injection of
+ // fakes the unit tests currently do.
+ address: true,
+ },
srcs: [
":libsurfaceflinger_sources",
+ "CompositionTest.cpp",
+ "DisplayIdentificationTest.cpp",
"DisplayTransactionTest.cpp",
"EventControlThreadTest.cpp",
"EventThreadTest.cpp",
+ "SchedulerTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockDisplaySurface.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
"mock/gui/MockGraphicBufferConsumer.cpp",
"mock/gui/MockGraphicBufferProducer.cpp",
+ "mock/MockDispSync.cpp",
"mock/MockEventControlThread.cpp",
"mock/MockEventThread.cpp",
"mock/MockMessageQueue.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
new file mode 100644
index 0000000..5aa6e27
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -0,0 +1,1275 @@
+/*
+ * Copyright 2018 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 "CompositionTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <gui/IProducerListener.h>
+#include <log/log.h>
+#include <system/window.h>
+#include <utils/String8.h>
+
+#include "BufferQueueLayer.h"
+#include "ColorLayer.h"
+#include "Layer.h"
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+#include "mock/RenderEngine/MockRenderEngine.h"
+
+namespace android {
+namespace {
+
+using testing::_;
+using testing::ByMove;
+using testing::DoAll;
+using testing::IsNull;
+using testing::Mock;
+using testing::NotNull;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgPointee;
+
+using android::Hwc2::Error;
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+using android::Hwc2::Transform;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+constexpr hwc2_display_t HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr hwc2_layer_t HWC_LAYER = 5000;
+constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
+
+constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+
+constexpr int DEFAULT_CONFIG_ID = 0;
+constexpr int DEFAULT_TEXTURE_ID = 6000;
+constexpr int DEFAULT_LAYER_STACK = 7000;
+
+constexpr int DEFAULT_DISPLAY_MAX_LUMINANCE = 500;
+
+constexpr int DEFAULT_SIDEBAND_STREAM = 51;
+
+class CompositionTest : public testing::Test {
+public:
+ CompositionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ mFlinger.mutableEventControlThread().reset(mEventControlThread);
+ mFlinger.mutableEventThread().reset(mEventThread);
+ mFlinger.mutableEventQueue().reset(mMessageQueue);
+
+ mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
+ EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*mPrimaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+
+ mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+ setupComposer(0);
+ }
+
+ ~CompositionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ void setupComposer(int virtualDisplayCount) {
+ mComposer = new Hwc2::mock::Composer();
+ EXPECT_CALL(*mComposer, getCapabilities())
+ .WillOnce(Return(std::vector<IComposer::Capability>()));
+ EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ Mock::VerifyAndClear(mComposer);
+ }
+
+ void setupForceGeometryDirty() {
+ // TODO: This requires the visible region and other related
+ // state to be set, and is problematic for BufferLayers since they are
+ // not visible without a buffer (and setting up a buffer looks like a
+ // pain)
+ // mFlinger.mutableVisibleRegionsDirty() = true;
+
+ mFlinger.mutableGeometryInvalid() = true;
+ }
+
+ template <typename Case>
+ void displayRefreshCompositionDirtyGeometry();
+
+ template <typename Case>
+ void displayRefreshCompositionDirtyFrame();
+
+ template <typename Case>
+ void captureScreenComposition();
+
+ std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
+
+ TestableSurfaceFlinger mFlinger;
+ sp<DisplayDevice> mDisplay;
+ sp<DisplayDevice> mExternalDisplay;
+ sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
+ renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface();
+
+ mock::EventThread* mEventThread = new mock::EventThread();
+ mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+
+ Hwc2::mock::Composer* mComposer = nullptr;
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+ mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+ renderengine::mock::Image* mReImage = new renderengine::mock::Image();
+ renderengine::mock::Framebuffer* mReFrameBuffer = new renderengine::mock::Framebuffer();
+
+ sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
+
+ sp<GraphicBuffer> mCaptureScreenBuffer;
+};
+
+template <typename LayerCase>
+void CompositionTest::displayRefreshCompositionDirtyGeometry() {
+ setupForceGeometryDirty();
+ LayerCase::setupForDirtyGeometry(this);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+ mFlinger.onMessageReceived(MessageQueue::REFRESH);
+
+ LayerCase::cleanup(this);
+}
+
+template <typename LayerCase>
+void CompositionTest::displayRefreshCompositionDirtyFrame() {
+ LayerCase::setupForDirtyFrame(this);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+ mFlinger.onMessageReceived(MessageQueue::REFRESH);
+
+ LayerCase::cleanup(this);
+}
+
+template <typename LayerCase>
+void CompositionTest::captureScreenComposition() {
+ LayerCase::setupForScreenCapture(this);
+
+ const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
+ constexpr int32_t minLayerZ = -1;
+ constexpr int32_t maxLayerZ = 1000;
+ constexpr bool useIdentityTransform = true;
+ constexpr bool forSystem = true;
+
+ DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT, ui::Transform::ROT_0);
+
+ auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
+ return mFlinger.traverseLayersInDisplay(mDisplay, minLayerZ, maxLayerZ, visitor);
+ };
+
+ // TODO: Eliminate expensive/real allocation if possible.
+ const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+ mCaptureScreenBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+ HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+
+ int fd = -1;
+ status_t result =
+ mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(),
+ useIdentityTransform, forSystem, &fd);
+ if (fd >= 0) {
+ close(fd);
+ }
+
+ EXPECT_EQ(NO_ERROR, result);
+
+ LayerCase::cleanup(this);
+}
+
+/* ------------------------------------------------------------------------
+ * Variants for each display configuration which can be tested
+ */
+
+template <typename Derived>
+struct BaseDisplayVariant {
+ static constexpr bool IS_SECURE = true;
+ static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+
+ static void setupPreconditions(CompositionTest* test) {
+ FakeHwcDisplayInjector(DisplayDevice::DISPLAY_PRIMARY, HWC2::DisplayType::Physical)
+ .setCapabilities(&test->mDefaultCapabilities)
+ .inject(&test->mFlinger, test->mComposer);
+
+ test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DisplayDevice::DISPLAY_PRIMARY,
+ DisplayDevice::DISPLAY_PRIMARY)
+ .setDisplaySize(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
+ .setDisplaySurface(test->mDisplaySurface)
+ .setRenderSurface(std::unique_ptr<renderengine::Surface>(
+ test->mRenderSurface))
+ .setSecure(Derived::IS_SECURE)
+ .setPowerMode(Derived::INIT_POWER_MODE)
+ .inject();
+ test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
+ }
+
+ template <typename Case>
+ static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
+ .Times(1);
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+ EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
+ EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
+ EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
+ EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
+
+ EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+
+ EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*test->mRenderEngine,
+ setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+ Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Transform::ROT_0))
+ .Times(1);
+
+ EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
+ EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
+
+ Case::CompositionType::setupHwcSetCallExpectations(test);
+ Case::CompositionType::setupHwcGetCallExpectations(test);
+ }
+
+ template <typename Case>
+ static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
+ // Called once with a non-null value to set a framebuffer, and then
+ // again with nullptr to clear it.
+ EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true));
+ EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true));
+
+ EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
+ EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
+ .WillOnce(Return(
+ ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
+ EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, clearWithColor(0, 0, 0, 1)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true));
+
+ EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::SRGB)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
+ .Times(1);
+ // This expectation retires on saturation as setViewportAndProjection is
+ // called an extra time for the code path this setup is for.
+ // TODO: Investigate this extra call
+ EXPECT_CALL(*test->mRenderEngine,
+ setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+ Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Transform::ROT_0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1);
+ }
+
+ static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mDisplaySurface, beginFrame(true)).Times(1);
+ }
+
+ static void setupEmptyFrameCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mDisplaySurface, beginFrame(false)).Times(1);
+ }
+
+ static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
+
+ EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+ }
+
+ static void setupRECompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+ .Times(1);
+ EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
+ .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
+
+ EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
+ .Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setupColorTransform(_)).Times(2);
+ // These expectations retire on saturation as the code path these
+ // expectations are for appears to make an extra call to them.
+ // TODO: Investigate this extra call
+ EXPECT_CALL(*test->mRenderEngine,
+ setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+ Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Transform::ROT_0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
+ .WillOnce(Return(true))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*test->mRenderSurface, swapBuffers()).Times(1);
+ }
+
+ template <typename Case>
+ static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
+ Case::Layer::setupRECompositionCallExpectations(test);
+ }
+
+ template <typename Case>
+ static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
+ Case::Layer::setupREScreenshotCompositionCallExpectations(test);
+
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+ }
+};
+
+struct DefaultDisplaySetupVariant : public BaseDisplayVariant<DefaultDisplaySetupVariant> {};
+
+struct InsecureDisplaySetupVariant : public BaseDisplayVariant<InsecureDisplaySetupVariant> {
+ static constexpr bool IS_SECURE = false;
+
+ template <typename Case>
+ static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
+ Case::Layer::setupInsecureRECompositionCallExpectations(test);
+
+ // TODO: Investigate this extra call
+ EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+ }
+
+ template <typename Case>
+ static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
+ Case::Layer::setupInsecureREScreenshotCompositionCallExpectations(test);
+
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+ }
+};
+
+struct PoweredOffDisplaySetupVariant : public BaseDisplayVariant<PoweredOffDisplaySetupVariant> {
+ static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_OFF;
+
+ template <typename Case>
+ static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+ // TODO: This seems like an unnecessary call if display is powered off.
+ EXPECT_CALL(*test->mComposer,
+ setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
+ .Times(1);
+
+ // TODO: This seems like an unnecessary call if display is powered off.
+ Case::CompositionType::setupHwcSetCallExpectations(test);
+ }
+
+ static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+
+ static void setupRECompositionCallExpectations(CompositionTest* test) {
+ // TODO: This seems like an unnecessary call if display is powered off.
+ EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
+ .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
+ }
+
+ template <typename Case>
+ static void setupRELayerCompositionCallExpectations(CompositionTest*) {}
+};
+
+/* ------------------------------------------------------------------------
+ * Variants for each layer configuration which can be tested
+ */
+
+template <typename LayerProperties>
+struct BaseLayerProperties {
+ static constexpr uint32_t WIDTH = 100;
+ static constexpr uint32_t HEIGHT = 100;
+ static constexpr PixelFormat FORMAT = PIXEL_FORMAT_RGBA_8888;
+ static constexpr uint64_t USAGE =
+ GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_SW_WRITE_NEVER;
+ static constexpr android_dataspace DATASPACE = HAL_DATASPACE_UNKNOWN;
+ static constexpr uint32_t SCALING_MODE = 0;
+ static constexpr uint32_t TRANSFORM = 0;
+ static constexpr uint32_t LAYER_FLAGS = 0;
+ static constexpr float COLOR[] = {1.f, 1.f, 1.f, 1.f};
+ static constexpr IComposerClient::BlendMode BLENDMODE =
+ IComposerClient::BlendMode::PREMULTIPLIED;
+
+ static void enqueueBuffer(CompositionTest*, sp<BufferQueueLayer> layer) {
+ auto producer = layer->getProducer();
+
+ IGraphicBufferProducer::QueueBufferOutput qbo;
+ status_t result = producer->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &qbo);
+ if (result != NO_ERROR) {
+ ALOGE("Failed to connect() (%d)", result);
+ return;
+ }
+
+ int slot;
+ sp<Fence> fence;
+ result = producer->dequeueBuffer(&slot, &fence, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT, LayerProperties::FORMAT,
+ LayerProperties::USAGE, nullptr, nullptr);
+ if (result != IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+ ALOGE("Failed to dequeueBuffer() (%d)", result);
+ return;
+ }
+
+ sp<GraphicBuffer> buffer;
+ result = producer->requestBuffer(slot, &buffer);
+ if (result != NO_ERROR) {
+ ALOGE("Failed to requestBuffer() (%d)", result);
+ return;
+ }
+
+ IGraphicBufferProducer::QueueBufferInput qbi(systemTime(), false /* isAutoTimestamp */,
+ LayerProperties::DATASPACE,
+ Rect(LayerProperties::WIDTH,
+ LayerProperties::HEIGHT),
+ LayerProperties::SCALING_MODE,
+ LayerProperties::TRANSFORM, Fence::NO_FENCE);
+ result = producer->queueBuffer(slot, qbi, &qbo);
+ if (result != NO_ERROR) {
+ ALOGE("Failed to queueBuffer (%d)", result);
+ return;
+ }
+ }
+
+ static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) {
+ // TODO: Eliminate the complexity of actually creating a buffer
+ EXPECT_CALL(*test->mRenderEngine, getMaxTextureSize()).WillOnce(Return(16384));
+ EXPECT_CALL(*test->mRenderEngine, getMaxViewportDims()).WillOnce(Return(16384));
+ status_t err =
+ layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT,
+ LayerProperties::FORMAT);
+ ASSERT_EQ(NO_ERROR, err);
+ Mock::VerifyAndClear(test->mRenderEngine);
+
+ EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+ enqueueBuffer(test, layer);
+ Mock::VerifyAndClear(test->mMessageQueue);
+
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*test->mRenderEngine, createImage())
+ .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
+ EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, checkErrors()).Times(1);
+ EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, false)).WillOnce(Return(true));
+ bool ignoredRecomputeVisibleRegions;
+ layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+ Mock::VerifyAndClear(test->mRenderEngine);
+ Mock::VerifyAndClear(test->mReImage);
+ }
+
+ static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+ setupLatchedBuffer(test, layer);
+ }
+
+ static void setupBufferLayerPostFrameCallExpectations(CompositionTest* test) {
+ // BufferLayer::onPostComposition(), when there is no present fence
+ EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY, _))
+ .WillOnce(DoAll(SetArgPointee<1>(DEFAULT_CONFIG_ID), Return(Error::NONE)));
+ }
+
+ static void setupHwcSetGeometryCallExpectations(CompositionTest* test) {
+ // TODO: Coverage of other values
+ EXPECT_CALL(*test->mComposer,
+ setLayerBlendMode(HWC_DISPLAY, HWC_LAYER, LayerProperties::BLENDMODE))
+ .Times(1);
+ // TODO: Coverage of other values for origin
+ EXPECT_CALL(*test->mComposer,
+ setLayerDisplayFrame(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::Rect({0, 0, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT})))
+ .Times(1);
+ EXPECT_CALL(*test->mComposer,
+ setLayerPlaneAlpha(HWC_DISPLAY, HWC_LAYER, LayerProperties::COLOR[3]))
+ .Times(1);
+ // TODO: Coverage of other values
+ EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
+ // TODO: Coverage of other values
+ EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
+
+ // These expectations retire on saturation as the code path these
+ // expectations are for appears to make an extra call to them.
+ // TODO: Investigate this extra call
+ EXPECT_CALL(*test->mComposer, setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+
+ static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::FRect({0.f, 0.f, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT})))
+ .Times(1);
+ }
+
+ static void setupHwcSetSourceCropColorCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::FRect({0.f, 0.f, 0.f, 0.f})))
+ .Times(1);
+ }
+
+ static void setupHwcSetPerFrameCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerVisibleRegion(HWC_DISPLAY, HWC_LAYER,
+ std::vector<IComposerClient::Rect>({IComposerClient::Rect(
+ {0, 0, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT})})))
+ .Times(1);
+ }
+
+ static void setupHwcSetPerFrameColorCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+
+ // TODO: use COLOR
+ EXPECT_CALL(*test->mComposer,
+ setLayerColor(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
+ .Times(1);
+
+ // TODO: ColorLayer::onPreComposition() always returns true, triggering an
+ // extra layer update in SurfaceFlinger::preComposition(). This seems
+ // wrong on the surface.
+ EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+ }
+
+ static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+ EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
+
+ setupBufferLayerPostFrameCallExpectations(test);
+ }
+
+ static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine,
+ setupLayerBlending(true, false, false,
+ half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+ LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+ .Times(1);
+
+ EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setupLayerTexturing(_)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
+ // This call retires on saturation as the code that renders a texture disables the state,
+ // along with a top-level disable to ensure it is disabled for non-buffer layers.
+ EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+ }
+
+ static void setupREBufferCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+
+ // TODO - Investigate and eliminate these differences between display
+ // composition and screenshot composition.
+ EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+ }
+
+ static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
+ setupREBufferCompositionCallExpectations(test);
+ }
+
+ static void setupREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+ }
+
+ static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+ }
+
+ static void setupREColorCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+ }
+
+ static void setupREColorCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine,
+ setupLayerBlending(true, false, true,
+ half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+ LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+ .Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+ }
+
+ static void setupREColorScreenshotCompositionCallExpectations(CompositionTest* test) {
+ setupREColorCompositionCallExpectations(test);
+ }
+};
+
+struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
+
+struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {};
+
+struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerProperties> {
+ using Base = BaseLayerProperties<SidebandLayerProperties>;
+ static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
+
+ static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+ sp<NativeHandle> stream =
+ NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
+ false);
+ test->mFlinger.setLayerSidebandStream(layer, stream);
+ }
+
+ static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::FRect({0.f, 0.f, -1.f, -1.f})))
+ .Times(1);
+ }
+
+ static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSidebandStream(HWC_DISPLAY, HWC_LAYER,
+ reinterpret_cast<native_handle_t*>(
+ DEFAULT_SIDEBAND_STREAM)))
+ .WillOnce(Return(Error::NONE));
+
+ EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+ }
+
+ static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, setupFillWithColor(0, 0, 0, 1)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+ }
+};
+
+struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> {
+ using Base = BaseLayerProperties<SecureLayerProperties>;
+
+ static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure;
+
+ static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setupLayerBlackedOut()).Times(1);
+
+ EXPECT_CALL(*test->mRenderEngine,
+ setupLayerBlending(true, false, false,
+ half4(Base::COLOR[0], Base::COLOR[1], Base::COLOR[2],
+ Base::COLOR[3])))
+ .Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
+ // This call retires on saturation as the code that renders a texture disables the state,
+ // along with a top-level disable to ensure it is disabled for non-buffer layers.
+ EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+ }
+
+ static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
+ setupInsecureREBufferCompositionCommonCallExpectations(test);
+ Base::setupBufferLayerPostFrameCallExpectations(test);
+ }
+
+ static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+ setupInsecureREBufferCompositionCommonCallExpectations(test);
+ }
+};
+
+struct CursorLayerProperties : public BaseLayerProperties<CursorLayerProperties> {
+ using Base = BaseLayerProperties<CursorLayerProperties>;
+
+ static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+ Base::setupLayerState(test, layer);
+ test->mFlinger.setLayerPotentialCursor(layer, true);
+ }
+};
+
+struct NoLayerVariant {
+ using FlingerLayerType = sp<BufferQueueLayer>;
+
+ static FlingerLayerType createLayer(CompositionTest*) { return FlingerLayerType(); }
+ static void injectLayer(CompositionTest*, FlingerLayerType) {}
+ static void cleanupInjectedLayers(CompositionTest*) {}
+
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+ static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+template <typename LayerProperties>
+struct BaseLayerVariant {
+ template <typename L, typename F>
+ static sp<L> createLayerWithFactory(CompositionTest* test, F factory) {
+ EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(0);
+
+ sp<L> layer = factory();
+
+ Mock::VerifyAndClear(test->mComposer);
+ Mock::VerifyAndClear(test->mRenderEngine);
+ Mock::VerifyAndClear(test->mMessageQueue);
+
+ auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
+ layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
+ layerDrawingState.active.w = 100;
+ layerDrawingState.active.h = 100;
+ layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+ LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
+
+ layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
+
+ return layer;
+ }
+
+ static void injectLayer(CompositionTest* test, sp<Layer> layer) {
+ EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
+ .WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
+
+ layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), test->mDisplay->getId());
+
+ Mock::VerifyAndClear(test->mComposer);
+
+ Vector<sp<Layer>> layers;
+ layers.add(layer);
+ test->mDisplay->setVisibleLayersSortedByZ(layers);
+ test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
+ }
+
+ static void cleanupInjectedLayers(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
+ .WillOnce(Return(Error::NONE));
+ for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
+ layer->destroyHwcLayer(test->mDisplay->getId());
+ }
+ test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
+ }
+};
+
+template <typename LayerProperties>
+struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> {
+ using Base = BaseLayerVariant<LayerProperties>;
+ using FlingerLayerType = sp<ColorLayer>;
+
+ static FlingerLayerType createLayer(CompositionTest* test) {
+ FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
+ return new ColorLayer(test->mFlinger.mFlinger.get(), sp<Client>(),
+ String8("test-layer"), LayerProperties::WIDTH,
+ LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS);
+ });
+ return layer;
+ }
+
+ static void setupRECompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREColorCompositionCommonCallExpectations(test);
+ LayerProperties::setupREColorCompositionCallExpectations(test);
+ }
+
+ static void setupREScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREColorScreenshotCompositionCallExpectations(test);
+ }
+
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+ LayerProperties::setupHwcSetGeometryCallExpectations(test);
+ LayerProperties::setupHwcSetSourceCropColorCallExpectations(test);
+ }
+
+ static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+ LayerProperties::setupHwcSetPerFrameCallExpectations(test);
+ LayerProperties::setupHwcSetPerFrameColorCallExpectations(test);
+ }
+};
+
+template <typename LayerProperties>
+struct BufferLayerVariant : public BaseLayerVariant<LayerProperties> {
+ using Base = BaseLayerVariant<LayerProperties>;
+ using FlingerLayerType = sp<BufferQueueLayer>;
+
+ static FlingerLayerType createLayer(CompositionTest* test) {
+ test->mFlinger.mutableTexturePool().push_back(DEFAULT_TEXTURE_ID);
+
+ FlingerLayerType layer =
+ Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
+ return new BufferQueueLayer(test->mFlinger.mFlinger.get(), sp<Client>(),
+ String8("test-layer"), LayerProperties::WIDTH,
+ LayerProperties::HEIGHT,
+ LayerProperties::LAYER_FLAGS);
+ });
+
+ LayerProperties::setupLayerState(test, layer);
+
+ return layer;
+ }
+
+ static void cleanupInjectedLayers(CompositionTest* test) {
+ EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(2);
+ Base::cleanupInjectedLayers(test);
+ }
+
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+ LayerProperties::setupHwcSetGeometryCallExpectations(test);
+ LayerProperties::setupHwcSetSourceCropBufferCallExpectations(test);
+ }
+
+ static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+ LayerProperties::setupHwcSetPerFrameCallExpectations(test);
+ LayerProperties::setupHwcSetPerFrameBufferCallExpectations(test);
+ }
+
+ static void setupRECompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferCompositionCallExpectations(test);
+ }
+
+ static void setupInsecureRECompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupInsecureREBufferCompositionCallExpectations(test);
+ }
+
+ static void setupREScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferScreenshotCompositionCallExpectations(test);
+ }
+
+ static void setupInsecureREScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupInsecureREBufferScreenshotCompositionCallExpectations(test);
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * Variants to control how the composition type is changed
+ */
+
+struct NoCompositionTypeVariant {
+ static void setupHwcSetCallExpectations(CompositionTest*) {}
+
+ static void setupHwcGetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _)).Times(1);
+ }
+};
+
+template <IComposerClient::Composition CompositionType>
+struct KeepCompositionTypeVariant {
+ static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(CompositionType);
+
+ static void setupHwcSetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, CompositionType))
+ .Times(1);
+ }
+
+ static void setupHwcGetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _)).Times(1);
+ }
+};
+
+template <IComposerClient::Composition InitialCompositionType,
+ IComposerClient::Composition FinalCompositionType>
+struct ChangeCompositionTypeVariant {
+ static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(FinalCompositionType);
+
+ static void setupHwcSetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, InitialCompositionType))
+ .Times(1);
+ }
+
+ static void setupHwcGetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::Layer>{
+ static_cast<Hwc2::Layer>(HWC_LAYER)}),
+ SetArgPointee<2>(std::vector<IComposerClient::Composition>{
+ FinalCompositionType}),
+ Return(Error::NONE)));
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * Variants to select how the composition is expected to be handled
+ */
+
+struct CompositionResultBaseVariant {
+ static void setupLayerState(CompositionTest*, sp<Layer>) {}
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+ Case::Layer::setupCallExpectationsForDirtyGeometry(test);
+ }
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+ Case::Layer::setupCallExpectationsForDirtyFrame(test);
+ }
+};
+
+struct NoCompositionResultVariant : public CompositionResultBaseVariant {
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcCompositionCallExpectations(test);
+ }
+};
+
+struct HwcCompositionResultVariant : public CompositionResultBaseVariant {
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcCompositionCallExpectations(test);
+ }
+};
+
+struct RECompositionResultVariant : public CompositionResultBaseVariant {
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupRECompositionCallExpectations(test);
+ Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+ }
+};
+
+struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+ static void setupLayerState(CompositionTest*, sp<Layer> layer) {
+ layer->forceClientComposition(DisplayDevice::DISPLAY_PRIMARY);
+ }
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+struct EmptyScreenshotResultVariant {
+ static void setupLayerState(CompositionTest*, sp<Layer>) {}
+
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest*) {}
+};
+
+struct REScreenshotResultVariant : public EmptyScreenshotResultVariant {
+ using Base = EmptyScreenshotResultVariant;
+
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Base::template setupCallExpectations<Case>(test);
+ Case::Display::template setupRELayerScreenshotCompositionCallExpectations<Case>(test);
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * Composition test case, containing all the variants being tested
+ */
+
+template <typename DisplayCase, typename LayerCase, typename CompositionTypeCase,
+ typename CompositionResultCase>
+struct CompositionCase {
+ using ThisCase =
+ CompositionCase<DisplayCase, LayerCase, CompositionTypeCase, CompositionResultCase>;
+ using Display = DisplayCase;
+ using Layer = LayerCase;
+ using CompositionType = CompositionTypeCase;
+ using CompositionResult = CompositionResultCase;
+
+ static void setupCommon(CompositionTest* test) {
+ Display::setupPreconditions(test);
+
+ auto layer = Layer::createLayer(test);
+ Layer::injectLayer(test, layer);
+ CompositionResult::setupLayerState(test, layer);
+ }
+
+ static void setupForDirtyGeometry(CompositionTest* test) {
+ setupCommon(test);
+
+ Display::template setupCommonCompositionCallExpectations<ThisCase>(test);
+ CompositionResult::template setupCallExpectationsForDirtyGeometry<ThisCase>(test);
+ CompositionResult::template setupCallExpectationsForDirtyFrame<ThisCase>(test);
+ CompositionResult::template setupCallExpectations<ThisCase>(test);
+ }
+
+ static void setupForDirtyFrame(CompositionTest* test) {
+ setupCommon(test);
+
+ Display::template setupCommonCompositionCallExpectations<ThisCase>(test);
+ CompositionResult::template setupCallExpectationsForDirtyFrame<ThisCase>(test);
+ CompositionResult::template setupCallExpectations<ThisCase>(test);
+ }
+
+ static void setupForScreenCapture(CompositionTest* test) {
+ setupCommon(test);
+
+ Display::template setupCommonScreensCaptureCallExpectations<ThisCase>(test);
+ CompositionResult::template setupCallExpectations<ThisCase>(test);
+ }
+
+ static void cleanup(CompositionTest* test) {
+ Layer::cleanupInjectedLayers(test);
+
+ for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) {
+ hwcDisplay->mutableLayers().clear();
+ }
+
+ test->mDisplay->setVisibleLayersSortedByZ(Vector<sp<android::Layer>>());
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * Composition cases to test
+ */
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+ NoCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+ NoCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkToCaptureScreen) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+ EmptyScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Simple buffer layers
+ */
+
+TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedNormalBufferLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenNormalBufferLayer) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Single-color layers
+ */
+
+TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedColorLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenColorLayer) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Layers with sideband buffers
+ */
+
+TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::SIDEBAND>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::SIDEBAND>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedSidebandBufferLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::SIDEBAND,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSidebandBufferLayer) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Layers with ISurfaceComposerClient::eSecure, on a secure display
+ */
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedSecureBufferLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSecureBufferLayerOnSecureDisplay) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Layers with ISurfaceComposerClient::eSecure, on a non-secure display
+ */
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+ ForcedClientCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+ ForcedClientCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSecureBufferLayerOnInsecureDisplay) {
+ captureScreenComposition<
+ CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Cursor layers
+ */
+
+TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CURSOR>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CURSOR>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedCursorLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::CURSOR,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenCursorLayer) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Simple buffer layer on a display which is powered off.
+ */
+
+TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<CompositionCase<
+ PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<CompositionCase<
+ PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, displayOffREComposedNormalBufferLayer) {
+ displayRefreshCompositionDirtyFrame<CompositionCase<
+ PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenNormalBufferLayerOnPoweredOffDisplay) {
+ captureScreenComposition<CompositionCase<
+ PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
new file mode 100644
index 0000000..4f1c99e
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android {
+namespace {
+
+const unsigned char kInternalEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x4c\xa3\x42\x31\x00\x00\x00\x00"
+ "\x00\x15\x01\x03\x80\x1a\x10\x78\x0a\xd3\xe5\x95\x5c\x60\x90\x27"
+ "\x19\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
+ "\x01\x01\x01\x01\x01\x01\x9e\x1b\x00\xa0\x50\x20\x12\x30\x10\x30"
+ "\x13\x00\x05\xa3\x10\x00\x00\x19\x00\x00\x00\x0f\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x23\x87\x02\x64\x00\x00\x00\x00\xfe\x00\x53"
+ "\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x00\x00\x00\xfe"
+ "\x00\x31\x32\x31\x41\x54\x31\x31\x2d\x38\x30\x31\x0a\x20\x00\x45";
+
+const unsigned char kExternalEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x22\xf0\x6c\x28\x01\x01\x01\x01"
+ "\x02\x16\x01\x04\xb5\x40\x28\x78\xe2\x8d\x85\xad\x4f\x35\xb1\x25"
+ "\x0e\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
+ "\x01\x01\x01\x01\x01\x01\xe2\x68\x00\xa0\xa0\x40\x2e\x60\x30\x20"
+ "\x36\x00\x81\x90\x21\x00\x00\x1a\xbc\x1b\x00\xa0\x50\x20\x17\x30"
+ "\x30\x20\x36\x00\x81\x90\x21\x00\x00\x1a\x00\x00\x00\xfc\x00\x48"
+ "\x50\x20\x5a\x52\x33\x30\x77\x0a\x20\x20\x20\x20\x00\x00\x00\xff"
+ "\x00\x43\x4e\x34\x32\x30\x32\x31\x33\x37\x51\x0a\x20\x20\x00\x71";
+
+// Extended EDID with timing extension.
+const unsigned char kExternalEedid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x4c\x2d\xfe\x08\x00\x00\x00\x00"
+ "\x29\x15\x01\x03\x80\x10\x09\x78\x0a\xee\x91\xa3\x54\x4c\x99\x26"
+ "\x0f\x50\x54\xbd\xef\x80\x71\x4f\x81\xc0\x81\x00\x81\x80\x95\x00"
+ "\xa9\xc0\xb3\x00\x01\x01\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c"
+ "\x45\x00\xa0\x5a\x00\x00\x00\x1e\x66\x21\x56\xaa\x51\x00\x1e\x30"
+ "\x46\x8f\x33\x00\xa0\x5a\x00\x00\x00\x1e\x00\x00\x00\xfd\x00\x18"
+ "\x4b\x0f\x51\x17\x00\x0a\x20\x20\x20\x20\x20\x20\x00\x00\x00\xfc"
+ "\x00\x53\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x01\x1d"
+ "\x02\x03\x1f\xf1\x47\x90\x04\x05\x03\x20\x22\x07\x23\x09\x07\x07"
+ "\x83\x01\x00\x00\xe2\x00\x0f\x67\x03\x0c\x00\x20\x00\xb8\x2d\x01"
+ "\x1d\x80\x18\x71\x1c\x16\x20\x58\x2c\x25\x00\xa0\x5a\x00\x00\x00"
+ "\x9e\x01\x1d\x00\x72\x51\xd0\x1e\x20\x6e\x28\x55\x00\xa0\x5a\x00"
+ "\x00\x00\x1e\x8c\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\xa0"
+ "\x5a\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6";
+
+template <size_t N>
+DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&bytes)[N]) {
+ return DisplayIdentificationData(bytes, bytes + N - 1);
+}
+
+} // namespace
+
+TEST(DisplayIdentificationTest, isEdid) {
+ EXPECT_FALSE(isEdid({}));
+
+ EXPECT_TRUE(isEdid(asDisplayIdentificationData(kInternalEdid)));
+ EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEdid)));
+ EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEedid)));
+}
+
+TEST(DisplayIdentificationTest, parseEdid) {
+ auto data = asDisplayIdentificationData(kInternalEdid);
+ auto edid = parseEdid(data);
+ ASSERT_TRUE(edid);
+ EXPECT_EQ(0x4ca3u, edid->manufacturerId);
+ EXPECT_STREQ("SEC", edid->pnpId.data());
+ // ASCII text should be used as fallback if display name and serial number are missing.
+ EXPECT_EQ("121AT11-801", edid->displayName);
+
+ data = asDisplayIdentificationData(kExternalEdid);
+ edid = parseEdid(data);
+ ASSERT_TRUE(edid);
+ EXPECT_EQ(0x22f0u, edid->manufacturerId);
+ EXPECT_STREQ("HWP", edid->pnpId.data());
+ EXPECT_EQ("HP ZR30w", edid->displayName);
+
+ data = asDisplayIdentificationData(kExternalEedid);
+ edid = parseEdid(data);
+ ASSERT_TRUE(edid);
+ EXPECT_EQ(0x4c2du, edid->manufacturerId);
+ EXPECT_STREQ("SAM", edid->pnpId.data());
+ EXPECT_EQ("SAMSUNG", edid->displayName);
+}
+
+TEST(DisplayIdentificationTest, parseInvalidEdid) {
+ EXPECT_FALSE(isEdid({}));
+ EXPECT_FALSE(parseEdid({}));
+
+ // Display name must be printable.
+ auto data = asDisplayIdentificationData(kExternalEdid);
+ data[97] = '\x1b';
+ auto edid = parseEdid(data);
+ ASSERT_TRUE(edid);
+ // Serial number should be used as fallback if display name is invalid.
+ EXPECT_EQ("CN4202137Q", edid->displayName);
+
+ // Parsing should succeed even if EDID is truncated.
+ data.pop_back();
+ edid = parseEdid(data);
+ ASSERT_TRUE(edid);
+ EXPECT_EQ("CN4202137Q", edid->displayName);
+}
+
+TEST(DisplayIdentificationTest, getPnpId) {
+ EXPECT_FALSE(getPnpId(0));
+ EXPECT_FALSE(getPnpId(static_cast<uint16_t>(-1)));
+
+ EXPECT_STREQ("SEC", getPnpId(0x4ca3u).value_or(PnpId{}).data());
+ EXPECT_STREQ("HWP", getPnpId(0x22f0u).value_or(PnpId{}).data());
+ EXPECT_STREQ("SAM", getPnpId(0x4c2du).value_or(PnpId{}).data());
+}
+
+TEST(DisplayIdentificationTest, generateDisplayId) {
+ const auto primaryId = generateDisplayId(0, asDisplayIdentificationData(kInternalEdid));
+ ASSERT_TRUE(primaryId);
+
+ const auto secondaryId = generateDisplayId(1, asDisplayIdentificationData(kExternalEdid));
+ ASSERT_TRUE(secondaryId);
+
+ const auto tertiaryId = generateDisplayId(2, asDisplayIdentificationData(kExternalEedid));
+ ASSERT_TRUE(tertiaryId);
+
+ // Display IDs should be unique.
+ EXPECT_NE(primaryId, secondaryId);
+ EXPECT_NE(primaryId, tertiaryId);
+ EXPECT_NE(secondaryId, tertiaryId);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 9ac5f3b..aa377af 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -25,6 +25,7 @@
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
#include "mock/MockMessageQueue.h"
@@ -115,17 +116,18 @@
// These mocks are created by the test, but are destroyed by SurfaceFlinger
// by virtue of being stored into a std::unique_ptr. However we still need
// to keep a reference to them for use in setting up call expectations.
- RE::mock::RenderEngine* mRenderEngine = new RE::mock::RenderEngine();
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
Hwc2::mock::Composer* mComposer = nullptr;
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync();
// These mocks are created only when expected to be created via a factory.
sp<mock::GraphicBufferConsumer> mConsumer;
sp<mock::GraphicBufferProducer> mProducer;
mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
sp<mock::NativeWindow> mNativeWindow;
- RE::mock::Surface* mRenderSurface = nullptr;
+ renderengine::mock::Surface* mRenderSurface = nullptr;
};
DisplayTransactionTest::DisplayTransactionTest() {
@@ -135,6 +137,7 @@
// Default to no wide color display support configured
mFlinger.mutableHasWideColorDisplay() = false;
+ mFlinger.mutableUseColorManagement() = false;
mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
// Default to using HWC virtual displays
@@ -152,8 +155,9 @@
mFlinger.mutableEventControlThread().reset(mEventControlThread);
mFlinger.mutableEventThread().reset(mEventThread);
mFlinger.mutableEventQueue().reset(mMessageQueue);
- mFlinger.setupRenderEngine(std::unique_ptr<RE::RenderEngine>(mRenderEngine));
+ mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
+ mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
injectMockComposer(0);
}
@@ -207,11 +211,11 @@
}
bool DisplayTransactionTest::hasDisplayDevice(sp<IBinder> displayToken) {
- return mFlinger.mutableDisplays().indexOfKey(displayToken) >= 0;
+ return mFlinger.mutableDisplays().count(displayToken) == 1;
}
sp<DisplayDevice> DisplayTransactionTest::getDisplayDevice(sp<IBinder> displayToken) {
- return mFlinger.mutableDisplays().valueFor(displayToken);
+ return mFlinger.mutableDisplays()[displayToken];
}
bool DisplayTransactionTest::hasCurrentDisplayState(sp<IBinder> displayToken) {
@@ -234,8 +238,8 @@
*
*/
-template <DisplayDevice::DisplayType type, DisplayDevice::DisplayType hwcId, int width, int height,
- Critical critical, Async async, Secure secure, int grallocUsage>
+template <DisplayDevice::DisplayType type, DisplayDevice::DisplayType displayId, int width,
+ int height, Critical critical, Async async, Secure secure, int grallocUsage>
struct DisplayVariant {
// The display width and height
static constexpr int WIDTH = width;
@@ -245,7 +249,9 @@
// The type for this display
static constexpr DisplayDevice::DisplayType TYPE = type;
- static constexpr DisplayDevice::DisplayType HWCOMPOSER_ID = hwcId;
+ static_assert(TYPE != DisplayDevice::DISPLAY_ID_INVALID);
+
+ static constexpr DisplayDevice::DisplayType DISPLAY_ID = displayId;
// When creating native window surfaces for the framebuffer, whether those should be critical
static constexpr Critical CRITICAL = critical;
@@ -257,7 +263,7 @@
static constexpr Secure SECURE = secure;
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
- auto injector = FakeDisplayDeviceInjector(test->mFlinger, TYPE, HWCOMPOSER_ID);
+ auto injector = FakeDisplayDeviceInjector(test->mFlinger, TYPE, DISPLAY_ID);
injector.setSecure(static_cast<bool>(SECURE));
return injector;
}
@@ -271,9 +277,10 @@
// For simplicity, we only expect to create a single render surface for
// each test.
ASSERT_TRUE(test->mRenderSurface == nullptr);
- test->mRenderSurface = new RE::mock::Surface();
+ test->mRenderSurface = new renderengine::mock::Surface();
EXPECT_CALL(*test->mRenderEngine, createSurface())
- .WillOnce(Return(ByMove(std::unique_ptr<RE::Surface>(test->mRenderSurface))));
+ .WillOnce(Return(ByMove(
+ std::unique_ptr<renderengine::Surface>(test->mRenderSurface))));
EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast<bool>(ASYNC))).Times(1);
EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast<bool>(CRITICAL))).Times(1);
EXPECT_CALL(*test->mRenderSurface, setNativeWindow(test->mNativeWindow.get())).Times(1);
@@ -353,6 +360,8 @@
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::DPI_Y, _))
.WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+ .WillRepeatedly(Return(Error::UNSUPPORTED));
}
// Called by tests to set up HWC call expectations
@@ -383,11 +392,6 @@
DisplayVariant<type, type, width, height, critical, Async::FALSE,
Secure::TRUE, GRALLOC_USAGE_PHYSICAL_DISPLAY>> {};
-// An invalid display
-using InvalidDisplayVariant =
- DisplayVariant<DisplayDevice::DISPLAY_ID_INVALID, DisplayDevice::DISPLAY_ID_INVALID, 0, 0,
- Critical::FALSE, Async::FALSE, Secure::FALSE, 0>;
-
// A primary display is a physical display that is critical
using PrimaryDisplayVariant =
PhysicalDisplayVariant<1001, DisplayDevice::DISPLAY_PRIMARY, 3840, 2160, Critical::TRUE>;
@@ -453,6 +457,7 @@
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableHasWideColorDisplay() = false;
+ test->mFlinger.mutableUseColorManagement() = false;
test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
}
@@ -471,6 +476,7 @@
static constexpr bool WIDE_COLOR_SUPPORTED = true;
static void injectConfigChange(DisplayTransactionTest* test) {
+ test->mFlinger.mutableUseColorManagement() = true;
test->mFlinger.mutableHasWideColorDisplay() = true;
test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
}
@@ -499,6 +505,7 @@
static constexpr bool WIDE_COLOR_SUPPORTED = false;
static void injectConfigChange(DisplayTransactionTest* test) {
+ test->mFlinger.mutableUseColorManagement() = true;
test->mFlinger.mutableHasWideColorDisplay() = true;
}
@@ -578,7 +585,7 @@
struct NonHwcPerFrameMetadataSupportVariant {
static constexpr int PER_FRAME_METADATA_KEYS = 0;
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_, _)).Times(0);
+ EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_)).Times(0);
}
};
@@ -586,9 +593,8 @@
struct NoPerFrameMetadataSupportVariant {
static constexpr int PER_FRAME_METADATA_KEYS = 0;
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<PerFrameMetadataKey>()),
- Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+ .WillOnce(Return(std::vector<PerFrameMetadataKey>()));
}
};
@@ -596,8 +602,8 @@
struct Smpte2086PerFrameMetadataSupportVariant {
static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::SMPTE2086;
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<PerFrameMetadataKey>({
+ EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+ .WillOnce(Return(std::vector<PerFrameMetadataKey>({
PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X,
PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y,
PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X,
@@ -608,8 +614,7 @@
PerFrameMetadataKey::WHITE_POINT_Y,
PerFrameMetadataKey::MAX_LUMINANCE,
PerFrameMetadataKey::MIN_LUMINANCE,
- })),
- Return(Error::NONE)));
+ })));
}
};
@@ -617,12 +622,11 @@
struct Cta861_3_PerFrameMetadataSupportVariant {
static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::CTA861_3;
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<PerFrameMetadataKey>({
+ EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+ .WillOnce(Return(std::vector<PerFrameMetadataKey>({
PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL,
PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL,
- })),
- Return(Error::NONE)));
+ })));
}
};
@@ -658,7 +662,8 @@
using SimpleHwcVirtualDisplayVariant = HwcVirtualDisplayVariant<1024, 768, Secure::TRUE>;
using HwcVirtualDisplayCase =
Case<SimpleHwcVirtualDisplayVariant, WideColorSupportNotConfiguredVariant,
- NonHwcDisplayHdrSupportVariant, NonHwcPerFrameMetadataSupportVariant>;
+ HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>,
+ NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>;
using WideColorP3ColorimetricDisplayCase =
Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>,
HdrNotSupportedVariant<PrimaryDisplayVariant>,
@@ -683,9 +688,7 @@
Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
HdrNotSupportedVariant<PrimaryDisplayVariant>,
Cta861_3_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using InvalidDisplayCase = Case<InvalidDisplayVariant, WideColorSupportNotConfiguredVariant,
- NonHwcDisplayHdrSupportVariant,
- NoPerFrameMetadataSupportVariant<InvalidDisplayVariant>>;
+
/* ------------------------------------------------------------------------
*
* SurfaceFlinger::onHotplugReceived
@@ -693,8 +696,8 @@
TEST_F(DisplayTransactionTest, hotplugEnqueuesEventsForDisplayTransaction) {
constexpr int currentSequenceId = 123;
- constexpr hwc2_display_t displayId1 = 456;
- constexpr hwc2_display_t displayId2 = 654;
+ constexpr hwc2_display_t hwcDisplayId1 = 456;
+ constexpr hwc2_display_t hwcDisplayId2 = 654;
// --------------------------------------------------------------------
// Preconditions
@@ -717,8 +720,8 @@
// Invocation
// Simulate two hotplug events (a connect and a disconnect)
- mFlinger.onHotplugReceived(currentSequenceId, displayId1, HWC2::Connection::Connected);
- mFlinger.onHotplugReceived(currentSequenceId, displayId2, HWC2::Connection::Disconnected);
+ mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, HWC2::Connection::Connected);
+ mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, HWC2::Connection::Disconnected);
// --------------------------------------------------------------------
// Postconditions
@@ -729,9 +732,9 @@
// All events should be in the pending event queue.
const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
ASSERT_EQ(2u, pendingEvents.size());
- EXPECT_EQ(displayId1, pendingEvents[0].display);
+ EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId);
EXPECT_EQ(HWC2::Connection::Connected, pendingEvents[0].connection);
- EXPECT_EQ(displayId2, pendingEvents[1].display);
+ EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId);
EXPECT_EQ(HWC2::Connection::Disconnected, pendingEvents[1].connection);
}
@@ -967,6 +970,9 @@
// The call clears the current render engine surface
EXPECT_CALL(*mRenderEngine, resetCurrentSurface());
+ // The call ends any display resyncs
+ EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1);
+
// --------------------------------------------------------------------
// Invocation
@@ -1031,7 +1037,10 @@
// --------------------------------------------------------------------
// Invocation
- auto state = DisplayDeviceState(Case::Display::TYPE, static_cast<bool>(Case::Display::SECURE));
+ DisplayDeviceState state;
+ state.type = Case::Display::TYPE;
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
+
auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::TYPE, state,
displaySurface, producer);
@@ -1159,13 +1168,23 @@
Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
- EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::TYPE, true)).Times(1);
+ EXPECT_CALL(*mEventThread,
+ onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+ ? EventThread::DisplayType::Primary
+ : EventThread::DisplayType::External,
+ true))
+ .Times(1);
}
template <typename Case>
void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
- EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::TYPE, false)).Times(1);
+ EXPECT_CALL(*mEventThread,
+ onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+ ? EventThread::DisplayType::Primary
+ : EventThread::DisplayType::External,
+ false))
+ .Times(1);
}
template <typename Case>
@@ -1196,7 +1215,7 @@
static_assert(0 <= Case::Display::TYPE &&
Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
"Must use a valid physical display type index for the fixed-size array");
- auto& displayToken = mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE];
+ auto& displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
ASSERT_TRUE(displayToken != nullptr);
verifyDisplayIsConnected<Case>(displayToken);
@@ -1285,6 +1304,8 @@
// Call Expectations
EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _))
+ .Times(0);
setupCommonCallExpectationsForDisconnectProcessing<Case>();
@@ -1302,7 +1323,7 @@
// The display should not be set up as a built-in display.
ASSERT_TRUE(0 <= Case::Display::TYPE &&
Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
- auto displayToken = mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE];
+ auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
EXPECT_TRUE(displayToken == nullptr);
// The existing token should have been removed
@@ -1395,7 +1416,7 @@
// The display should not be set up as a primary built-in display.
ASSERT_TRUE(0 <= Case::Display::TYPE &&
Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
- auto displayToken = mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE];
+ auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
EXPECT_TRUE(displayToken == nullptr);
}
@@ -1438,7 +1459,7 @@
static_assert(0 <= Case::Display::TYPE &&
Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
"Display type must be a built-in display");
- EXPECT_NE(existing.token(), mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE]);
+ EXPECT_NE(existing.token(), mFlinger.mutableDisplayTokens()[Case::Display::TYPE]);
// A new display should be connected in its place
@@ -1467,7 +1488,11 @@
// A virtual display was added to the current state, and it has a
// surface(producer)
sp<BBinder> displayToken = new BBinder();
- DisplayDeviceState info(Case::Display::TYPE, static_cast<bool>(Case::Display::SECURE));
+
+ DisplayDeviceState info;
+ info.type = Case::Display::TYPE;
+ info.isSecure = static_cast<bool>(Case::Display::SECURE);
+
sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
info.surface = surface;
mFlinger.mutableCurrentState().displays.add(displayToken, info);
@@ -1531,7 +1556,11 @@
// A virtual display was added to the current state, but it does not have a
// surface.
sp<BBinder> displayToken = new BBinder();
- DisplayDeviceState info(Case::Display::TYPE, static_cast<bool>(Case::Display::SECURE));
+
+ DisplayDeviceState info;
+ info.type = Case::Display::TYPE;
+ info.isSecure = static_cast<bool>(Case::Display::SECURE);
+
mFlinger.mutableCurrentState().displays.add(displayToken, info);
// --------------------------------------------------------------------
@@ -1709,11 +1738,11 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
- auto renderSurface = new RE::mock::Surface();
+ auto renderSurface = new renderengine::mock::Surface();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
- display.setRenderSurface(std::unique_ptr<RE::Surface>(renderSurface));
+ display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
display.inject();
// There is a change to the viewport state
@@ -1750,11 +1779,11 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
- auto renderSurface = new RE::mock::Surface();
+ auto renderSurface = new renderengine::mock::Surface();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
- display.setRenderSurface(std::unique_ptr<RE::Surface>(renderSurface));
+ display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
display.inject();
// There is a change to the viewport state
@@ -1810,40 +1839,6 @@
EXPECT_FALSE(hasCurrentDisplayState(displayToken));
}
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWithInvalidDisplay) {
- using Case = InvalidDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // An invalid display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The invalid display has some state
- display.mutableCurrentDisplayState().layerStack = 654u;
-
- // The requested display state tries to change the display state.
- DisplayState state;
- state.what = DisplayState::eLayerStackChanged;
- state.token = display.token();
- state.layerStack = 456;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags are empty
- EXPECT_EQ(0u, flags);
-
- // The current display layer stack value is unchanged.
- EXPECT_EQ(654u, getCurrentDisplayState(display.token()).layerStack);
-}
-
TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWhenNoChanges) {
using Case = SimplePrimaryDisplayCase;
@@ -2419,6 +2414,24 @@
}
};
+struct DispSyncIsSupportedVariant {
+ static void setupBeginResyncCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mPrimaryDispSync, reset()).Times(1);
+ EXPECT_CALL(*test->mPrimaryDispSync, setPeriod(DEFAULT_REFRESH_RATE)).Times(1);
+ EXPECT_CALL(*test->mPrimaryDispSync, beginResync()).Times(1);
+ }
+
+ static void setupEndResyncCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mPrimaryDispSync, endResync()).Times(1);
+ }
+};
+
+struct DispSyncNotSupportedVariant {
+ static void setupBeginResyncCallExpectations(DisplayTransactionTest* /* test */) {}
+
+ static void setupEndResyncCallExpectations(DisplayTransactionTest* /* test */) {}
+};
+
// --------------------------------------------------------------------
// Note:
//
@@ -2440,6 +2453,7 @@
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::DispSync::setupBeginResyncCallExpectations(test);
Case::setupRepaintEverythingCallExpectations(test);
}
@@ -2469,6 +2483,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+ Case::DispSync::setupEndResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
}
@@ -2504,6 +2519,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::DispSync::setupBeginResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
}
};
@@ -2522,6 +2538,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::DispSync::setupBeginResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
}
};
@@ -2531,6 +2548,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+ Case::DispSync::setupEndResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
}
};
@@ -2553,11 +2571,12 @@
// --------------------------------------------------------------------
template <typename DisplayVariant, typename DozeVariant, typename EventThreadVariant,
- typename TransitionVariant>
+ typename DispSyncVariant, typename TransitionVariant>
struct DisplayPowerCase {
using Display = DisplayVariant;
using Doze = DozeVariant;
using EventThread = EventThreadVariant;
+ using DispSync = DispSyncVariant;
using Transition = TransitionVariant;
static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, int mode) {
@@ -2605,15 +2624,16 @@
// In addition to having event thread support, we emulate doze support.
template <typename TransitionVariant>
using PrimaryDisplayPowerCase = DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant,
- EventThreadIsSupportedVariant, TransitionVariant>;
+ EventThreadIsSupportedVariant,
+ DispSyncIsSupportedVariant, TransitionVariant>;
// A sample configuration for the external display.
// In addition to not having event thread support, we emulate not having doze
// support.
template <typename TransitionVariant>
-using ExternalDisplayPowerCase =
- DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant,
- EventThreadNotSupportedVariant, TransitionVariant>;
+using ExternalDisplayPowerCase = DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant,
+ EventThreadNotSupportedVariant,
+ DispSyncNotSupportedVariant, TransitionVariant>;
class SetPowerModeInternalTest : public DisplayTransactionTest {
public:
@@ -2670,7 +2690,7 @@
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.inject();
- // The diplay is already set to HWC_POWER_MODE_NORMAL
+ // The display is already set to HWC_POWER_MODE_NORMAL
display.mutableDisplayDevice()->setPowerMode(HWC_POWER_MODE_NORMAL);
// --------------------------------------------------------------------
@@ -2684,7 +2704,7 @@
EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
}
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalJustSetsInternalStateIfVirtualDisplay) {
+TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
@@ -2699,13 +2719,13 @@
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.inject();
- // The display is set to HWC_POWER_MODE_OFF
- getDisplayDevice(display.token())->setPowerMode(HWC_POWER_MODE_OFF);
+ // The display is set to HWC_POWER_MODE_NORMAL
+ getDisplayDevice(display.token())->setPowerMode(HWC_POWER_MODE_NORMAL);
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_NORMAL);
+ mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_OFF);
// --------------------------------------------------------------------
// Postconditions
diff --git a/services/surfaceflinger/tests/unittests/EventControlThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventControlThreadTest.cpp
index b346454..9dc4193 100644
--- a/services/surfaceflinger/tests/unittests/EventControlThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventControlThreadTest.cpp
@@ -23,7 +23,7 @@
#include <log/log.h>
#include "AsyncCallRecorder.h"
-#include "EventControlThread.h"
+#include "Scheduler/EventControlThread.h"
namespace android {
namespace {
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 80fdb80..fb3b7a2 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -25,7 +25,7 @@
#include <utils/Errors.h>
#include "AsyncCallRecorder.h"
-#include "EventThread.h"
+#include "Scheduler/EventThread.h"
using namespace std::chrono_literals;
using namespace std::placeholders;
@@ -71,7 +71,8 @@
ConnectionEventRecorder& connectionEventRecorder,
nsecs_t expectedTimestamp, unsigned expectedCount);
void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
- void expectHotplugEventReceivedByConnection(int expectedDisplayType, bool expectedConnected);
+ void expectHotplugEventReceivedByConnection(EventThread::DisplayType expectedDisplayType,
+ bool expectedConnected);
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -169,13 +170,16 @@
expectedCount);
}
-void EventThreadTest::expectHotplugEventReceivedByConnection(int expectedDisplayType,
- bool expectedConnected) {
+void EventThreadTest::expectHotplugEventReceivedByConnection(
+ EventThread::DisplayType expectedDisplayType, bool expectedConnected) {
+ const uint32_t expectedDisplayId =
+ expectedDisplayType == EventThread::DisplayType::Primary ? 0 : 1;
+
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
- EXPECT_EQ(static_cast<unsigned>(expectedDisplayType), event.header.id);
+ EXPECT_EQ(expectedDisplayId, event.header.id);
EXPECT_EQ(expectedConnected, event.hotplug.connected);
}
@@ -394,28 +398,23 @@
}
TEST_F(EventThreadTest, postHotplugPrimaryDisconnect) {
- mThread->onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, false);
- expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_PRIMARY, false);
+ mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+ expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
}
TEST_F(EventThreadTest, postHotplugPrimaryConnect) {
- mThread->onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, true);
- expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_PRIMARY, true);
+ mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
+ expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
}
TEST_F(EventThreadTest, postHotplugExternalDisconnect) {
- mThread->onHotplugReceived(DisplayDevice::DISPLAY_EXTERNAL, false);
- expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_EXTERNAL, false);
+ mThread->onHotplugReceived(EventThread::DisplayType::External, false);
+ expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, false);
}
TEST_F(EventThreadTest, postHotplugExternalConnect) {
- mThread->onHotplugReceived(DisplayDevice::DISPLAY_EXTERNAL, true);
- expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_EXTERNAL, true);
-}
-
-TEST_F(EventThreadTest, postHotplugVirtualDisconnectIsFilteredOut) {
- mThread->onHotplugReceived(DisplayDevice::DISPLAY_VIRTUAL, false);
- EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
+ mThread->onHotplugReceived(EventThread::DisplayType::External, true);
+ expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, true);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
new file mode 100644
index 0000000..df0d982
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -0,0 +1,186 @@
+#undef LOG_TAG
+#define LOG_TAG "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+
+#include "AsyncCallRecorder.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/Scheduler.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventThread.h"
+
+using testing::_;
+using testing::Return;
+
+namespace android {
+
+class SchedulerTest : public testing::Test {
+protected:
+ class MockEventThreadConnection : public BnDisplayEventConnection {
+ public:
+ MockEventThreadConnection() = default;
+ ~MockEventThreadConnection() = default;
+
+ MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
+ MOCK_METHOD1(setVsyncRate, status_t(uint32_t count));
+ MOCK_METHOD0(requestNextVsync, void());
+ };
+
+ /**
+ * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else
+ * the same.
+ */
+ class MockScheduler : public android::Scheduler {
+ public:
+ MockScheduler(std::unique_ptr<EventThread> eventThread)
+ : mEventThread(std::move(eventThread)) {}
+
+ std::unique_ptr<EventThread> makeEventThread(
+ const std::string& /* connectionName */, DispSync* /* dispSync */,
+ nsecs_t /* phaseOffsetNs */,
+ impl::EventThread::ResyncWithRateLimitCallback /* resyncCallback */,
+ impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
+ return std::move(mEventThread);
+ }
+
+ MockScheduler() = default;
+ ~MockScheduler() override = default;
+
+ std::unique_ptr<EventThread> mEventThread;
+ };
+
+ SchedulerTest();
+ ~SchedulerTest() override;
+
+ sp<Scheduler::ConnectionHandle> mConnectionHandle;
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+ mock::EventThread* mEventThread;
+ std::unique_ptr<MockScheduler> mScheduler;
+ sp<MockEventThreadConnection> mEventThreadConnection;
+
+ AsyncCallRecorder<void (*)()> mResyncCallRecorder;
+ AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
+};
+
+SchedulerTest::SchedulerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>();
+ mEventThread = eventThread.get();
+ mScheduler = std::make_unique<MockScheduler>(std::move(eventThread));
+ mEventThreadConnection = new MockEventThreadConnection();
+
+ // createConnection call to scheduler makes a createEventConnection call to EventThread. Make
+ // sure that call gets executed and returns an EventThread::Connection object.
+ EXPECT_CALL(*mEventThread, createEventConnection())
+ .WillRepeatedly(Return(mEventThreadConnection));
+
+ mConnectionHandle = mScheduler->createConnection("appConnection", mPrimaryDispSync, 16,
+ mResyncCallRecorder.getInvocable(),
+ mInterceptVSyncCallRecorder.getInvocable());
+}
+
+SchedulerTest::~SchedulerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(SchedulerTest, canCreateAndDestroyTest) {
+ EXPECT_FALSE(mResyncCallRecorder.waitForCall().has_value());
+ EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall().has_value());
+ EXPECT_EQ(0, mConnectionHandle->id);
+}
+
+TEST_F(SchedulerTest, testNullPtr) {
+ // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any
+ // exceptions, just gracefully continues.
+ sp<IDisplayEventConnection> returnedValue;
+ ASSERT_NO_FATAL_FAILURE(returnedValue = mScheduler->createDisplayEventConnection(nullptr));
+ EXPECT_TRUE(returnedValue == nullptr);
+ EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
+ EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
+ ASSERT_NO_FATAL_FAILURE(
+ mScheduler->hotplugReceived(nullptr, EventThread::DisplayType::Primary, false));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr));
+ String8 testString;
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString));
+ EXPECT_TRUE(testString == "");
+ ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10));
+}
+
+TEST_F(SchedulerTest, invalidConnectionHandle) {
+ // Passing an invalid ConnectionHandle is a valid argument. The code doesn't throw any
+ // exceptions, just gracefully continues.
+ sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20);
+
+ sp<IDisplayEventConnection> returnedValue;
+ ASSERT_NO_FATAL_FAILURE(returnedValue =
+ mScheduler->createDisplayEventConnection(connectionHandle));
+ EXPECT_TRUE(returnedValue == nullptr);
+ EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
+ EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
+
+ // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads.
+ EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(connectionHandle,
+ EventThread::DisplayType::Primary, false));
+
+ EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle));
+
+ EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle));
+
+ String8 testString;
+ EXPECT_CALL(*mEventThread, dump(_)).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString));
+ EXPECT_TRUE(testString == "");
+
+ EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(connectionHandle, 10));
+}
+
+TEST_F(SchedulerTest, validConnectionHandle) {
+ sp<IDisplayEventConnection> returnedValue;
+ ASSERT_NO_FATAL_FAILURE(returnedValue =
+ mScheduler->createDisplayEventConnection(mConnectionHandle));
+ EXPECT_TRUE(returnedValue != nullptr);
+ ASSERT_EQ(returnedValue, mEventThreadConnection);
+
+ EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr);
+ EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr);
+
+ EXPECT_CALL(*mEventThread, onHotplugReceived(EventThread::DisplayType::Primary, false))
+ .Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(mConnectionHandle,
+ EventThread::DisplayType::Primary, false));
+
+ EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle));
+
+ EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle));
+
+ String8 testString("dump");
+ EXPECT_CALL(*mEventThread, dump(testString)).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString));
+ EXPECT_TRUE(testString != "");
+
+ EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10));
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index acd16fe..341734c 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,13 +17,14 @@
#pragma once
#include "DisplayDevice.h"
+#include "Layer.h"
#include "SurfaceFlinger.h"
namespace android {
class EventThread;
-namespace RE {
+namespace renderengine {
class RenderEngine;
}
@@ -36,7 +37,7 @@
// Extend this as needed for accessing SurfaceFlinger private (and public)
// functions.
- void setupRenderEngine(std::unique_ptr<RE::RenderEngine> renderEngine) {
+ void setupRenderEngine(std::unique_ptr<renderengine::RenderEngine> renderEngine) {
mFlinger->getBE().mRenderEngine = std::move(renderEngine);
}
@@ -56,6 +57,21 @@
using HotplugEvent = SurfaceFlinger::HotplugEvent;
+ auto& mutableLayerCurrentState(sp<Layer> layer) { return layer->mCurrentState; }
+ auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
+
+ void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
+ layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
+ }
+
+ void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
+ layer->getBE().mHwcLayers[DisplayDevice::DISPLAY_PRIMARY].compositionType = type;
+ };
+
+ void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
+ layer->mPotentialCursor = potentialCursor;
+ }
+
/* ------------------------------------------------------------------------
* Forwarding for functions being tested
*/
@@ -64,15 +80,17 @@
return mFlinger->createDisplay(displayName, secure);
}
- auto destroyDisplay(const sp<IBinder>& display) { return mFlinger->destroyDisplay(display); }
+ auto destroyDisplay(const sp<IBinder>& displayToken) {
+ return mFlinger->destroyDisplay(displayToken);
+ }
auto resetDisplayState() { return mFlinger->resetDisplayState(); }
- auto setupNewDisplayDeviceInternal(const wp<IBinder>& display, int hwcId,
+ auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken, int32_t displayId,
const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
- return mFlinger->setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface,
+ return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface,
producer);
}
@@ -89,8 +107,24 @@
auto onInitializeDisplays() { return mFlinger->onInitializeDisplays(); }
- auto setPowerModeInternal(const sp<DisplayDevice>& hw, int mode, bool stateLockHeld = false) {
- return mFlinger->setPowerModeInternal(hw, mode, stateLockHeld);
+ auto setPowerModeInternal(const sp<DisplayDevice>& display, int mode,
+ bool stateLockHeld = false) {
+ return mFlinger->setPowerModeInternal(display, mode, stateLockHeld);
+ }
+
+ auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what); }
+
+ auto captureScreenImplLocked(const RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers, ANativeWindowBuffer* buffer,
+ bool useIdentityTransform, bool forSystem, int* outSyncFd) {
+ return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer,
+ useIdentityTransform, forSystem, outSyncFd);
+ }
+
+ auto traverseLayersInDisplay(const sp<const DisplayDevice>& display, int32_t minLayerZ,
+ int32_t maxLayerZ, const LayerVector::Visitor& visitor) {
+ return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, minLayerZ, maxLayerZ,
+ visitor);
}
/* ------------------------------------------------------------------------
@@ -110,20 +144,25 @@
*/
auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
+ auto& mutablePrimaryDisplayOrientation() { return SurfaceFlinger::primaryDisplayOrientation; }
+ auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
- auto& mutableBuiltinDisplays() { return mFlinger->mBuiltinDisplays; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
- auto& mutableDisplays() { return mFlinger->mDisplays; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
+ auto& mutableDisplays() { return mFlinger->mDisplays; }
+ auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
auto& mutableEventQueue() { return mFlinger->mEventQueue; }
auto& mutableEventThread() { return mFlinger->mEventThread; }
+ auto& mutableGeometryInvalid() { return mFlinger->mGeometryInvalid; }
auto& mutableHWVsyncAvailable() { return mFlinger->mHWVsyncAvailable; }
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+ auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
+ auto& mutableTexturePool() { return mFlinger->mTexturePool; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
@@ -141,6 +180,7 @@
mutableEventQueue().reset();
mutableEventThread().reset();
mutableInterceptor().reset();
+ mutablePrimaryDispSync().reset();
mFlinger->getBE().mHwc.reset();
mFlinger->getBE().mRenderEngine.reset();
}
@@ -168,6 +208,7 @@
auto& mutableIsConnected() { return this->mIsConnected; }
auto& mutableConfigs() { return this->mConfigs; }
+ auto& mutableLayers() { return this->mLayers; }
};
class FakeHwcDisplayInjector {
@@ -217,13 +258,27 @@
return *this;
}
- auto& addCapability(HWC2::Capability cap) {
- mCapabilities.emplace(cap);
+ auto& setCapabilities(const std::unordered_set<HWC2::Capability>* capabilities) {
+ mCapabilities = capabilities;
+ return *this;
+ }
+
+ auto& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
+ mPowerAdvisor = powerAdvisor;
return *this;
}
void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
- auto display = std::make_unique<HWC2Display>(*composer, mPowerAdvisor, mCapabilities,
+ static FakePowerAdvisor defaultPowerAdvisor;
+ if (mPowerAdvisor == nullptr) mPowerAdvisor = &defaultPowerAdvisor;
+ static const std::unordered_set<HWC2::Capability> defaultCapabilities;
+ if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
+
+ // Caution - Make sure that any values passed by reference here do
+ // not refer to an instance owned by FakeHwcDisplayInjector. This
+ // class has temporary lifetime, while the constructed HWC2::Display
+ // is much longer lived.
+ auto display = std::make_unique<HWC2Display>(*composer, *mPowerAdvisor, *mCapabilities,
mHwcDisplayId, mHwcDisplayType);
auto config = HWC2::Display::Config::Builder(*display, mActiveConfig);
@@ -236,7 +291,7 @@
display->mutableIsConnected() = true;
ASSERT_TRUE(flinger->mutableHwcDisplayData().size() > static_cast<size_t>(mType));
- flinger->mutableHwcDisplayData()[mType].reset();
+ flinger->mutableHwcDisplayData()[mType] = HWComposer::DisplayData();
flinger->mutableHwcDisplayData()[mType].hwcDisplay = display.get();
flinger->mutableHwcDisplaySlots().emplace(mHwcDisplayId, mType);
@@ -253,15 +308,15 @@
int32_t mDpiX = DEFAULT_DPI;
int32_t mDpiY = DEFAULT_DPI;
int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
- std::unordered_set<HWC2::Capability> mCapabilities;
- FakePowerAdvisor mPowerAdvisor;
+ const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
+ Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
};
class FakeDisplayDeviceInjector {
public:
FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, DisplayDevice::DisplayType type,
- int hwcId)
- : mFlinger(flinger), mType(type), mHwcId(hwcId) {}
+ int32_t displayId)
+ : mFlinger(flinger), mType(type), mDisplayId(displayId) {}
sp<IBinder> token() const { return mDisplayToken; }
@@ -281,7 +336,7 @@
return mFlinger.mutableCurrentState().displays.valueFor(mDisplayToken);
}
- auto& mutableDisplayDevice() { return mFlinger.mutableDisplays().valueFor(mDisplayToken); }
+ auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; }
auto& setNativeWindow(const sp<ANativeWindow>& nativeWindow) {
mNativeWindow = nativeWindow;
@@ -293,7 +348,7 @@
return *this;
}
- auto& setRenderSurface(std::unique_ptr<RE::Surface> renderSurface) {
+ auto& setRenderSurface(std::unique_ptr<renderengine::Surface> renderSurface) {
mRenderSurface = std::move(renderSurface);
return *this;
}
@@ -303,21 +358,35 @@
return *this;
}
+ auto& setDisplaySize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ return *this;
+ }
+
+ auto& setPowerMode(int mode) {
+ mPowerMode = mode;
+ return *this;
+ }
+
sp<DisplayDevice> inject() {
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hdrAndRenderIntents;
sp<DisplayDevice> device =
- new DisplayDevice(mFlinger.mFlinger.get(), mType, mHwcId, mSecure, mDisplayToken,
- mNativeWindow, mDisplaySurface, std::move(mRenderSurface), 0,
- 0, false, HdrCapabilities(), 0, hdrAndRenderIntents,
- HWC_POWER_MODE_NORMAL);
- mFlinger.mutableDisplays().add(mDisplayToken, device);
+ new DisplayDevice(mFlinger.mFlinger.get(), mType, mDisplayId, mSecure,
+ mDisplayToken, mNativeWindow, mDisplaySurface,
+ std::move(mRenderSurface), mWidth, mHeight,
+ DisplayState::eOrientationDefault, false, HdrCapabilities(),
+ 0, hdrAndRenderIntents, mPowerMode);
+ mFlinger.mutableDisplays().emplace(mDisplayToken, device);
- DisplayDeviceState state(mType, mSecure);
+ DisplayDeviceState state;
+ state.type = mType;
+ state.isSecure = mSecure;
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
if (mType >= DisplayDevice::DISPLAY_PRIMARY && mType < DisplayDevice::DISPLAY_VIRTUAL) {
- mFlinger.mutableBuiltinDisplays()[mType] = mDisplayToken;
+ mFlinger.mutableDisplayTokens()[mType] = mDisplayToken;
}
return device;
@@ -327,11 +396,14 @@
TestableSurfaceFlinger& mFlinger;
sp<BBinder> mDisplayToken = new BBinder();
DisplayDevice::DisplayType mType;
- int mHwcId;
+ const int32_t mDisplayId;
sp<ANativeWindow> mNativeWindow;
sp<DisplaySurface> mDisplaySurface;
- std::unique_ptr<RE::Surface> mRenderSurface;
+ std::unique_ptr<renderengine::Surface> mRenderSurface;
bool mSecure = false;
+ int mWidth = 0;
+ int mHeight = 0;
+ int mPowerMode = HWC_POWER_MODE_NORMAL;
};
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(SurfaceFlinger::SkipInitialization);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 267670a..ecf3181 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -74,9 +74,10 @@
MOCK_METHOD2(getDisplayType, Error(Display, IComposerClient::DisplayType*));
MOCK_METHOD2(getDozeSupport, Error(Display, bool*));
MOCK_METHOD5(getHdrCapabilities, Error(Display, std::vector<Hdr>*, float*, float*, float*));
- MOCK_METHOD2(getPerFrameMetadataKeys,
- Error(Display, std::vector<IComposerClient::PerFrameMetadataKey>*));
+ MOCK_METHOD1(getPerFrameMetadataKeys,
+ std::vector<IComposerClient::PerFrameMetadataKey>(Display));
MOCK_METHOD2(getDataspaceSaturationMatrix, Error(Dataspace, mat4*));
+ MOCK_METHOD3(getDisplayIdentificationData, Error(Display, uint8_t*, std::vector<uint8_t>*));
MOCK_METHOD3(getReleaseFences, Error(Display, std::vector<Layer>*, std::vector<int>*));
MOCK_METHOD2(presentDisplay, Error(Display, int*));
MOCK_METHOD2(setActiveConfig, Error(Display, Config));
@@ -111,6 +112,7 @@
MOCK_METHOD3(setLayerZOrder, Error(Display, Layer, uint32_t));
MOCK_METHOD4(setLayerInfo, Error(Display, Layer, uint32_t, uint32_t));
MOCK_METHOD3(getRenderIntents, Error(Display, ColorMode, std::vector<RenderIntent>*));
+ MOCK_METHOD3(setLayerColorTransform, Error(Display, Layer, const float*));
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
new file mode 100644
index 0000000..2f7e5ea
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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 "mock/MockDispSync.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+DispSync::DispSync() = default;
+DispSync::~DispSync() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
new file mode 100644
index 0000000..46d6558
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 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 <gmock/gmock.h>
+
+#include <utils/String8.h>
+#include "Scheduler/DispSync.h"
+
+namespace android {
+namespace mock {
+
+class DispSync : public android::DispSync {
+public:
+ DispSync();
+ ~DispSync() override;
+
+ MOCK_METHOD0(reset, void());
+ MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD0(beginResync, void());
+ MOCK_METHOD1(addResyncSample, bool(nsecs_t));
+ MOCK_METHOD0(endResync, void());
+ MOCK_METHOD1(setPeriod, void(nsecs_t));
+ MOCK_METHOD1(scalePeriod, void(HWC2::Device::FrequencyScaler));
+ MOCK_METHOD0(getPeriod, nsecs_t());
+ MOCK_METHOD1(setRefreshSkipCount, void(int));
+ MOCK_METHOD3(addEventListener, status_t(const char*, nsecs_t, Callback*));
+ MOCK_METHOD1(removeEventListener, status_t(Callback*));
+ MOCK_METHOD2(changePhaseOffset, status_t(Callback*, nsecs_t));
+ MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
+ MOCK_METHOD1(setIgnorePresentFences, void(bool));
+
+ MOCK_CONST_METHOD1(dump, void(String8&));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventControlThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventControlThread.h
index 8ac09a9..6ef352a 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventControlThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventControlThread.h
@@ -18,7 +18,7 @@
#include <gmock/gmock.h>
-#include "EventControlThread.h"
+#include "Scheduler/EventControlThread.h"
namespace android {
namespace mock {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index e6ea663..ad2463d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -18,7 +18,7 @@
#include <gmock/gmock.h>
-#include "EventThread.h"
+#include "Scheduler/EventThread.h"
namespace android {
namespace mock {
@@ -31,7 +31,7 @@
MOCK_CONST_METHOD0(createEventConnection, sp<BnDisplayEventConnection>());
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
- MOCK_METHOD2(onHotplugReceived, void(int, bool));
+ MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
MOCK_CONST_METHOD1(dump, void(String8&));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index cf07cf7..f2f3675 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -18,7 +18,7 @@
#include <gmock/gmock.h>
-#include "MessageQueue.h"
+#include "Scheduler/MessageQueue.h"
namespace android {
namespace mock {
@@ -30,6 +30,7 @@
MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
MOCK_METHOD1(setEventThread, void(android::EventThread*));
+ MOCK_METHOD1(setEventConnection, void(const sp<BnDisplayEventConnection>& connection));
MOCK_METHOD0(waitMessage, void());
MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
MOCK_METHOD0(invalidate, void());
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
index a98bece..af54df6 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
@@ -16,8 +16,10 @@
#include "mock/RenderEngine/MockRenderEngine.h"
+#include <ui/Region.h>
+
namespace android {
-namespace RE {
+namespace renderengine {
namespace mock {
// Explicit default instantiation is recommended.
@@ -30,6 +32,9 @@
Image::Image() = default;
Image::~Image() = default;
+Framebuffer::Framebuffer() = default;
+Framebuffer::~Framebuffer() = default;
+
} // namespace mock
-} // namespace RE
+} // namespace renderengine
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index ac08293..39ed622 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -18,44 +18,47 @@
#include <gmock/gmock.h>
-#include "RenderEngine/Image.h"
-#include "RenderEngine/Mesh.h"
-#include "RenderEngine/RenderEngine.h"
-#include "RenderEngine/Surface.h"
-#include "RenderEngine/Texture.h"
+#include <renderengine/Framebuffer.h>
+#include <renderengine/Image.h>
+#include <renderengine/Mesh.h>
+#include <renderengine/RenderEngine.h>
+#include <renderengine/Surface.h>
+#include <renderengine/Texture.h>
namespace android {
-namespace RE {
+namespace renderengine {
namespace mock {
-class RenderEngine : public RE::RenderEngine {
+class RenderEngine : public renderengine::RenderEngine {
public:
RenderEngine();
~RenderEngine() override;
- MOCK_METHOD0(createSurface, std::unique_ptr<RE::Surface>());
- MOCK_METHOD0(createImage, std::unique_ptr<RE::Image>());
+ MOCK_METHOD0(createFramebuffer, std::unique_ptr<Framebuffer>());
+ MOCK_METHOD0(createSurface, std::unique_ptr<renderengine::Surface>());
+ MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
MOCK_CONST_METHOD0(primeCache, void());
MOCK_METHOD1(dump, void(String8&));
- MOCK_CONST_METHOD0(supportsImageCrop, bool());
+ MOCK_CONST_METHOD0(useNativeFenceSync, bool());
+ MOCK_CONST_METHOD0(useWaitSync, bool());
MOCK_CONST_METHOD0(isCurrent, bool());
- MOCK_METHOD1(setCurrentSurface, bool(const RE::Surface&));
+ MOCK_METHOD1(setCurrentSurface, bool(const renderengine::Surface&));
MOCK_METHOD0(resetCurrentSurface, void());
MOCK_METHOD0(flush, base::unique_fd());
MOCK_METHOD0(finish, bool());
MOCK_METHOD1(waitFence, bool(base::unique_fd*));
bool waitFence(base::unique_fd fd) override { return waitFence(&fd); };
MOCK_METHOD4(clearWithColor, void(float, float, float, float));
- MOCK_METHOD6(fillRegionWithColor, void(const Region&, uint32_t, float, float, float, float));
+ MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float));
MOCK_METHOD4(setScissor, void(uint32_t, uint32_t, uint32_t, uint32_t));
MOCK_METHOD0(disableScissor, void());
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
- MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const RE::Image&));
+ MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
MOCK_METHOD5(readPixels, void(size_t, size_t, size_t, size_t, uint32_t*));
MOCK_CONST_METHOD0(checkErrors, void());
- MOCK_METHOD6(setViewportAndProjection,
- void(size_t, size_t, Rect, size_t, bool, Transform::orientation_flags));
+ MOCK_METHOD4(setViewportAndProjection,
+ void(size_t, size_t, Rect, ui::Transform::orientation_flags));
MOCK_METHOD4(setupLayerBlending, void(bool, bool, bool, const half4&));
MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
MOCK_METHOD0(setupLayerBlackedOut, void());
@@ -68,15 +71,14 @@
MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace));
MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace));
MOCK_METHOD1(setDisplayMaxLuminance, void(const float));
- MOCK_METHOD2(bindNativeBufferAsFrameBuffer,
- void(ANativeWindowBuffer*, RE::BindNativeBufferAsFramebuffer*));
- MOCK_METHOD1(unbindNativeBufferAsFrameBuffer, void(RE::BindNativeBufferAsFramebuffer*));
+ MOCK_METHOD1(bindFrameBuffer, status_t(Framebuffer*));
+ MOCK_METHOD1(unbindFrameBuffer, void(Framebuffer*));
MOCK_METHOD1(drawMesh, void(const Mesh&));
MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
};
-class Surface : public RE::Surface {
+class Surface : public renderengine::Surface {
public:
Surface();
~Surface() override;
@@ -93,16 +95,23 @@
MOCK_CONST_METHOD0(queryHeight, int32_t());
};
-class Image : public RE::Image {
+class Image : public renderengine::Image {
public:
Image();
~Image() override;
- MOCK_METHOD4(setNativeWindowBuffer,
- bool(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
- int32_t cropHeight));
+ MOCK_METHOD2(setNativeWindowBuffer,
+ bool(ANativeWindowBuffer* buffer, bool isProtected));
+};
+
+class Framebuffer : public renderengine::Framebuffer {
+public:
+ Framebuffer();
+ ~Framebuffer() override;
+
+ MOCK_METHOD1(setNativeWindowBuffer, bool(ANativeWindowBuffer*));
};
} // namespace mock
-} // namespace RE
+} // namespace renderengine
} // namespace android
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 6122846..499a8f6 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -13,11 +13,12 @@
// limitations under the License.
sourceFiles = [
+ "buffer_channel.cpp",
"buffer_hub.cpp",
+ "buffer_node.cpp",
"bufferhubd.cpp",
"consumer_channel.cpp",
"producer_channel.cpp",
- "detached_buffer_channel.cpp",
"consumer_queue_channel.cpp",
"producer_queue_channel.cpp",
]
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
new file mode 100644
index 0000000..2150d62
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -0,0 +1,206 @@
+#include "buffer_channel.h"
+#include "producer_channel.h"
+
+using android::pdx::BorrowedHandle;
+using android::pdx::ErrorStatus;
+using android::pdx::Message;
+using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+
+namespace android {
+namespace dvr {
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+ int channel_id, IonBuffer buffer,
+ IonBuffer metadata_buffer,
+ size_t user_metadata_size)
+ : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+ buffer_node_(std::make_shared<BufferNode>(
+ std::move(buffer), std::move(metadata_buffer), user_metadata_size)),
+ buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+ buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+ uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t user_metadata_size)
+ : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
+ buffer_node_(std::make_shared<BufferNode>(
+ width, height, layer_count, format, usage, user_metadata_size)),
+ buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+ buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+ int channel_id,
+ std::shared_ptr<BufferNode> buffer_node,
+ uint64_t buffer_state_bit)
+ : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+ buffer_node_(buffer_node),
+ buffer_state_bit_(buffer_state_bit) {
+ buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::~BufferChannel() {
+ ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
+ channel_id(), buffer_id());
+ Hangup();
+}
+
+BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
+ return BufferInfo(
+ buffer_id(), /*consumer_count=*/0, buffer_node_->buffer().width(),
+ buffer_node_->buffer().height(), buffer_node_->buffer().layer_count(),
+ buffer_node_->buffer().format(), buffer_node_->buffer().usage(),
+ /*pending_count=*/0, /*state=*/0, /*signaled_mask=*/0,
+ /*index=*/0);
+}
+
+void BufferChannel::HandleImpulse(Message& /*message*/) {
+ ATRACE_NAME("BufferChannel::HandleImpulse");
+}
+
+bool BufferChannel::HandleMessage(Message& message) {
+ ATRACE_NAME("BufferChannel::HandleMessage");
+ switch (message.GetOp()) {
+ case DetachedBufferRPC::Import::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Import>(
+ *this, &BufferChannel::OnImport, message);
+ return true;
+
+ case DetachedBufferRPC::Duplicate::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Duplicate>(
+ *this, &BufferChannel::OnDuplicate, message);
+ return true;
+
+ case DetachedBufferRPC::Promote::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Promote>(
+ *this, &BufferChannel::OnPromote, message);
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+Status<BufferDescription<BorrowedHandle>> BufferChannel::OnImport(
+ Message& /*message*/) {
+ ATRACE_NAME("BufferChannel::OnImport");
+ ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.",
+ buffer_id());
+
+ return BufferDescription<BorrowedHandle>{buffer_node_->buffer(),
+ buffer_node_->metadata_buffer(),
+ buffer_id(),
+ channel_id(),
+ buffer_state_bit_,
+ BorrowedHandle{},
+ BorrowedHandle{}};
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnDuplicate(
+ Message& message) {
+ ATRACE_NAME("BufferChannel::OnDuplicate");
+ ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.",
+ buffer_id());
+
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
+ status.GetErrorMessage().c_str());
+ return ErrorStatus(ENOMEM);
+ }
+
+ // Try find the next buffer state bit which has not been claimed by any
+ // other buffers yet.
+ uint64_t buffer_state_bit =
+ BufferHubDefs::FindNextClearedBit(buffer_node_->active_buffer_bit_mask() |
+ BufferHubDefs::kProducerStateBit);
+ if (buffer_state_bit == 0ULL) {
+ ALOGE(
+ "BufferChannel::OnDuplicate: reached the maximum mumber of channels "
+ "per buffer node: 63.");
+ return ErrorStatus(E2BIG);
+ }
+
+ auto channel =
+ std::shared_ptr<BufferChannel>(new BufferChannel(
+ service(), buffer_id(), channel_id, buffer_node_, buffer_state_bit));
+ if (!channel) {
+ ALOGE("BufferChannel::OnDuplicate: Invalid buffer.");
+ return ErrorStatus(EINVAL);
+ }
+
+ const auto channel_status =
+ service()->SetChannel(channel_id, std::move(channel));
+ if (!channel_status) {
+ // Technically, this should never fail, as we just pushed the channel. Note
+ // that LOG_FATAL will be stripped out in non-debug build.
+ LOG_FATAL(
+ "BufferChannel::OnDuplicate: Failed to set new buffer channel: %s.",
+ channel_status.GetErrorMessage().c_str());
+ }
+
+ return status;
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnPromote(
+ Message& message) {
+ ATRACE_NAME("BufferChannel::OnPromote");
+ ALOGD_IF(TRACE, "BufferChannel::OnPromote: buffer_id=%d", buffer_id());
+
+ // Check whether this is the channel exclusive owner of the buffer_node_.
+ if (buffer_state_bit_ != buffer_node_->active_buffer_bit_mask()) {
+ ALOGE(
+ "BufferChannel::OnPromote: Cannot promote this BufferChannel as its "
+ "BufferNode is shared between multiple channels. This channel's state "
+ "bit=0x%" PRIx64 ", acitve_buffer_bit_mask=0x%" PRIx64 ".",
+ buffer_state_bit_, buffer_node_->active_buffer_bit_mask());
+ return ErrorStatus(EINVAL);
+ }
+
+ // Note that the new ProducerChannel will have different channel_id, but
+ // inherits the buffer_id from the DetachedBuffer.
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "BufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
+ status.GetErrorMessage().c_str());
+ return ErrorStatus(ENOMEM);
+ }
+
+ IonBuffer buffer = std::move(buffer_node_->buffer());
+ IonBuffer metadata_buffer = std::move(buffer_node_->metadata_buffer());
+ size_t user_metadata_size = buffer_node_->user_metadata_size();
+
+ std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
+ service(), buffer_id(), channel_id, std::move(buffer),
+ std::move(metadata_buffer), user_metadata_size);
+ if (!channel) {
+ ALOGE(
+ "BufferChannel::OnPromote: Failed to create ProducerChannel from a "
+ "BufferChannel, buffer_id=%d.",
+ buffer_id());
+ }
+
+ const auto channel_status =
+ service()->SetChannel(channel_id, std::move(channel));
+ if (!channel_status) {
+ // Technically, this should never fail, as we just pushed the channel. Note
+ // that LOG_FATAL will be stripped out in non-debug build.
+ LOG_FATAL(
+ "BufferChannel::OnPromote: Failed to set new producer buffer channel: "
+ "%s.",
+ channel_status.GetErrorMessage().c_str());
+ }
+
+ return status;
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/bufferhubd/buffer_channel.h b/services/vr/bufferhubd/buffer_channel.h
new file mode 100644
index 0000000..ac99a73
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.h
@@ -0,0 +1,66 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+
+#include "buffer_hub.h"
+#include "buffer_node.h"
+
+#include <pdx/channel_handle.h>
+#include <pdx/file_handle.h>
+
+namespace android {
+namespace dvr {
+
+class BufferChannel : public BufferHubChannel {
+ public:
+ ~BufferChannel() override;
+
+ template <typename... Args>
+ static std::unique_ptr<BufferChannel> Create(Args&&... args) {
+ auto buffer = std::unique_ptr<BufferChannel>(
+ new BufferChannel(std::forward<Args>(args)...));
+ return buffer->IsValid() ? std::move(buffer) : nullptr;
+ }
+
+ // Returns whether the object holds a valid graphic buffer.
+ bool IsValid() const {
+ return buffer_node_ != nullptr && buffer_node_->IsValid();
+ }
+
+ // Captures buffer info for use by BufferHubService::DumpState().
+ BufferInfo GetBufferInfo() const override;
+
+ bool HandleMessage(pdx::Message& message) override;
+ void HandleImpulse(pdx::Message& message) override;
+
+ private:
+ // Creates a detached buffer from existing IonBuffers.
+ BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
+ IonBuffer buffer, IonBuffer metadata_buffer,
+ size_t user_metadata_size);
+
+ // Allocates a new detached buffer.
+ BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
+ uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t user_metadata_size);
+
+ // Creates a detached buffer from an existing BufferNode.
+ BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
+ std::shared_ptr<BufferNode> buffer_node,
+ uint64_t buffer_state_bit);
+
+ pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
+ pdx::Message& message);
+ pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
+ pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
+
+ // The concrete implementation of the Buffer object.
+ std::shared_ptr<BufferNode> buffer_node_;
+
+ // The state bit of this buffer. Must be one the lower 63 bits.
+ uint64_t buffer_state_bit_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index e57c8ed..c0ee31b 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -13,8 +13,8 @@
#include <pdx/default_transport/service_endpoint.h>
#include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
#include "consumer_channel.h"
-#include "detached_buffer_channel.h"
#include "producer_channel.h"
#include "producer_queue_channel.h"
@@ -267,7 +267,7 @@
return {};
case DetachedBufferRPC::Promote::Opcode:
- // In addition to the message handler in the DetachedBufferChannel's
+ // In addition to the message handler in the BufferChannel's
// HandleMessage method, we also need to invalid the channel. Note that
// this has to be done after HandleMessage returns to make sure the IPC
// request has went back to the client first.
@@ -332,9 +332,9 @@
return ErrorStatus(EALREADY);
}
- std::unique_ptr<DetachedBufferChannel> channel =
- DetachedBufferChannel::Create(this, buffer_id, width, height, layer_count,
- format, usage, user_metadata_size);
+ std::unique_ptr<BufferChannel> channel =
+ BufferChannel::Create(this, buffer_id, width, height, layer_count, format,
+ usage, user_metadata_size);
if (!channel) {
ALOGE(
"BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
new file mode 100644
index 0000000..de22bba
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -0,0 +1,53 @@
+#include "buffer_node.h"
+
+#include <private/dvr/buffer_hub_defs.h>
+
+namespace android {
+namespace dvr {
+
+BufferNode::BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
+ size_t user_metadata_size)
+ : buffer_(std::move(buffer)),
+ metadata_buffer_(std::move(metadata_buffer)),
+ user_metadata_size_(user_metadata_size) {}
+
+// Allocates a new BufferNode.
+BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
+ uint32_t format, uint64_t usage,
+ size_t user_metadata_size)
+ : user_metadata_size_(user_metadata_size) {
+ // The size the of metadata buffer is used as the "width" parameter during
+ // allocation. Thus it cannot overflow uint32_t.
+ if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
+ BufferHubDefs::kMetadataHeaderSize)) {
+ ALOGE(
+ "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
+ return;
+ }
+
+ if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
+ ALOGE(
+ "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+ "buffer: %s",
+ strerror(-ret));
+ return;
+ }
+
+ // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
+ // user requested metadata.
+ const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
+ if (int ret = metadata_buffer_.Alloc(size,
+ /*height=*/1,
+ /*layer_count=*/1,
+ BufferHubDefs::kMetadataFormat,
+ BufferHubDefs::kMetadataUsage)) {
+ ALOGE(
+ "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+ "metadata: %s",
+ strerror(-ret));
+ return;
+ }
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.h b/services/vr/bufferhubd/buffer_node.h
new file mode 100644
index 0000000..4bcf4e3
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.h
@@ -0,0 +1,55 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+
+#include <private/dvr/ion_buffer.h>
+
+namespace android {
+namespace dvr {
+
+class BufferNode {
+ public:
+ // Creates a BufferNode from existing IonBuffers, i.e. creating from an
+ // existing ProducerChannel.
+ BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
+ size_t user_metadata_size);
+
+ // Allocates a new BufferNode.
+ BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
+ uint32_t format, uint64_t usage, size_t user_metadata_size);
+
+ // Returns whether the object holds a valid graphic buffer.
+ bool IsValid() const {
+ return buffer_.IsValid() && metadata_buffer_.IsValid();
+ }
+
+ size_t user_metadata_size() const { return user_metadata_size_; }
+ uint64_t active_buffer_bit_mask() const { return active_buffer_bit_mask_; }
+ void set_buffer_state_bit(uint64_t buffer_state_bit) {
+ active_buffer_bit_mask_ |= buffer_state_bit;
+ }
+
+ // Used to take out IonBuffers.
+ IonBuffer& buffer() { return buffer_; }
+ IonBuffer& metadata_buffer() { return metadata_buffer_; }
+
+ // Used to access IonBuffers.
+ const IonBuffer& buffer() const { return buffer_; }
+ const IonBuffer& metadata_buffer() const { return metadata_buffer_; }
+
+ private:
+ // Gralloc buffer handles.
+ IonBuffer buffer_;
+ IonBuffer metadata_buffer_;
+
+ // Size of user requested metadata.
+ const size_t user_metadata_size_;
+
+ // All active buffer bits. Valid bits are the lower 63 bits, while the
+ // highest bit is reserved for the exclusive writing and should not be set.
+ uint64_t active_buffer_bit_mask_ = 0ULL;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
deleted file mode 100644
index a5cf68d..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-#include "detached_buffer_channel.h"
-#include "producer_channel.h"
-
-using android::pdx::BorrowedHandle;
-using android::pdx::ErrorStatus;
-using android::pdx::Message;
-using android::pdx::RemoteChannelHandle;
-using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
- int buffer_id, int channel_id,
- IonBuffer buffer,
- IonBuffer metadata_buffer,
- size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
- buffer_(std::move(buffer)),
- metadata_buffer_(std::move(metadata_buffer)),
- user_metadata_size_(user_metadata_size) {
-}
-
-DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
- int buffer_id, uint32_t width,
- uint32_t height,
- uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
- user_metadata_size_(user_metadata_size) {
- // The size the of metadata buffer is used as the "width" parameter during
- // allocation. Thus it cannot overflow uint32_t.
- if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
- BufferHubDefs::kMetadataHeaderSize)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
- return;
- }
-
- if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
- "buffer: %s",
- strerror(-ret));
- return;
- }
-
- // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
- // user requested metadata.
- const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
- if (int ret = metadata_buffer_.Alloc(size,
- /*height=*/1,
- /*layer_count=*/1,
- BufferHubDefs::kMetadataFormat,
- BufferHubDefs::kMetadataUsage)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
- "metadata: %s",
- strerror(-ret));
- return;
- }
-}
-
-DetachedBufferChannel::~DetachedBufferChannel() {
- ALOGD_IF(TRACE,
- "DetachedBufferChannel::~DetachedBufferChannel: channel_id=%d "
- "buffer_id=%d.",
- channel_id(), buffer_id());
- Hangup();
-}
-
-BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
- return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
- buffer_.height(), buffer_.layer_count(), buffer_.format(),
- buffer_.usage(), /*pending_count=*/0, /*state=*/0,
- /*signaled_mask=*/0, /*index=*/0);
-}
-
-void DetachedBufferChannel::HandleImpulse(Message& /*message*/) {
- ATRACE_NAME("DetachedBufferChannel::HandleImpulse");
-}
-
-bool DetachedBufferChannel::HandleMessage(Message& message) {
- ATRACE_NAME("DetachedBufferChannel::HandleMessage");
- switch (message.GetOp()) {
- case DetachedBufferRPC::Import::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Import>(
- *this, &DetachedBufferChannel::OnImport, message);
- return true;
-
- case DetachedBufferRPC::Promote::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Promote>(
- *this, &DetachedBufferChannel::OnPromote, message);
- return true;
-
- default:
- return false;
- }
-}
-
-Status<BufferDescription<BorrowedHandle>> DetachedBufferChannel::OnImport(
- Message& /*message*/) {
- ATRACE_NAME("DetachedBufferChannel::OnGetBuffer");
- ALOGD_IF(TRACE, "DetachedBufferChannel::OnGetBuffer: buffer=%d.",
- buffer_id());
-
- return BufferDescription<BorrowedHandle>{buffer_,
- metadata_buffer_,
- buffer_id(),
- /*buffer_state_bit=*/0,
- BorrowedHandle{},
- BorrowedHandle{}};
-}
-
-Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
- Message& message) {
- ATRACE_NAME("DetachedBufferChannel::OnPromote");
- ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
- buffer_id());
-
- // Note that the new ProducerChannel will have different channel_id, but
- // inherits the buffer_id from the DetachedBuffer.
- int channel_id;
- auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status) {
- ALOGE(
- "DetachedBufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
- status.GetErrorMessage().c_str());
- return ErrorStatus(ENOMEM);
- }
-
- std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
- service(), buffer_id(), channel_id, std::move(buffer_),
- std::move(metadata_buffer_), user_metadata_size_);
- if (!channel) {
- ALOGE(
- "DetachedBufferChannel::OnPromote: Failed to create ProducerChannel "
- "from a DetachedBufferChannel, buffer_id=%d.",
- buffer_id());
- }
-
- const auto channel_status =
- service()->SetChannel(channel_id, std::move(channel));
- if (!channel_status) {
- // Technically, this should never fail, as we just pushed the channel. Note
- // that LOG_FATAL will be stripped out in non-debug build.
- LOG_FATAL(
- "DetachedBufferChannel::OnPromote: Failed to set new producer buffer "
- "channel: %s.",
- channel_status.GetErrorMessage().c_str());
- }
-
- return status;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
deleted file mode 100644
index 8b6dab8..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-#define ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-
-#include "buffer_hub.h"
-
-#include <pdx/channel_handle.h>
-#include <pdx/file_handle.h>
-
-namespace android {
-namespace dvr {
-
-class DetachedBufferChannel : public BufferHubChannel {
- public:
- ~DetachedBufferChannel() override;
-
- template <typename... Args>
- static std::unique_ptr<DetachedBufferChannel> Create(Args&&... args) {
- auto buffer = std::unique_ptr<DetachedBufferChannel>(
- new DetachedBufferChannel(std::forward<Args>(args)...));
- return buffer->IsValid() ? std::move(buffer) : nullptr;
- }
-
- // Returns whether the object holds a valid graphic buffer.
- bool IsValid() const {
- return buffer_.IsValid() && metadata_buffer_.IsValid();
- }
-
- size_t user_metadata_size() const { return user_metadata_size_; }
-
- // Captures buffer info for use by BufferHubService::DumpState().
- BufferInfo GetBufferInfo() const override;
-
- bool HandleMessage(pdx::Message& message) override;
- void HandleImpulse(pdx::Message& message) override;
-
- private:
- // Creates a detached buffer from existing IonBuffers.
- DetachedBufferChannel(BufferHubService* service, int buffer_id,
- int channel_id, IonBuffer buffer,
- IonBuffer metadata_buffer, size_t user_metadata_size);
-
- // Allocates a new detached buffer.
- DetachedBufferChannel(BufferHubService* service, int buffer_id,
- uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size);
-
- pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
- pdx::Message& message);
- pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
-
- // Gralloc buffer handles.
- IonBuffer buffer_;
- IonBuffer metadata_buffer_;
-
- // Size of user requested metadata.
- const size_t user_metadata_size_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b6977aa..19d48f2 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -12,8 +12,8 @@
#include <thread>
#include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
#include "consumer_channel.h"
-#include "detached_buffer_channel.h"
using android::pdx::BorrowedHandle;
using android::pdx::ErrorStatus;
@@ -27,14 +27,6 @@
namespace android {
namespace dvr {
-namespace {
-
-static inline uint64_t FindNextClearedBit(uint64_t bits) {
- return ~bits - (~bits & (~bits - 1));
-}
-
-} // namespace
-
ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
int channel_id, IonBuffer buffer,
IonBuffer metadata_buffer,
@@ -236,9 +228,13 @@
BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
uint64_t buffer_state_bit) {
- return {
- buffer_, metadata_buffer_, buffer_id(),
- buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()};
+ return {buffer_,
+ metadata_buffer_,
+ buffer_id(),
+ channel_id(),
+ buffer_state_bit,
+ acquire_fence_fd_.Borrow(),
+ release_fence_fd_.Borrow()};
}
Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
@@ -266,7 +262,7 @@
// Try find the next consumer state bit which has not been claimed by any
// consumer yet.
- uint64_t consumer_state_bit = FindNextClearedBit(
+ uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
BufferHubDefs::kProducerStateBit);
if (consumer_state_bit == 0ULL) {
@@ -415,10 +411,9 @@
return ErrorStatus(-ret);
};
- std::unique_ptr<DetachedBufferChannel> channel =
- DetachedBufferChannel::Create(
- service(), buffer_id(), channel_id, std::move(buffer_),
- std::move(metadata_buffer_), user_metadata_size_);
+ std::unique_ptr<BufferChannel> channel = BufferChannel::Create(
+ service(), buffer_id(), channel_id, std::move(buffer_),
+ std::move(metadata_buffer_), user_metadata_size_);
if (!channel) {
ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
return ErrorStatus(EINVAL);
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h
index 67fdf15..10a4ce7 100644
--- a/services/vr/bufferhubd/producer_channel.h
+++ b/services/vr/bufferhubd/producer_channel.h
@@ -43,6 +43,8 @@
~ProducerChannel() override;
+ uint64_t buffer_state() const { return buffer_state_->load(); }
+
bool HandleMessage(Message& message) override;
void HandleImpulse(Message& message) override;
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index c0c48c2..88f5508 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -76,6 +76,11 @@
message);
return true;
+ case BufferHubRPC::ProducerQueueInsertBuffer::Opcode:
+ DispatchRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>(
+ *this, &ProducerQueueChannel::OnProducerQueueInsertBuffer, message);
+ return true;
+
case BufferHubRPC::ProducerQueueRemoveBuffer::Opcode:
DispatchRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(
*this, &ProducerQueueChannel::OnProducerQueueRemoveBuffer, message);
@@ -278,6 +283,81 @@
return {{std::move(buffer_handle), slot}};
}
+Status<size_t> ProducerQueueChannel::OnProducerQueueInsertBuffer(
+ pdx::Message& message, int buffer_cid) {
+ ATRACE_NAME("ProducerQueueChannel::InsertBuffer");
+ ALOGD_IF(TRACE,
+ "ProducerQueueChannel::InsertBuffer: channel_id=%d, buffer_cid=%d",
+ channel_id(), buffer_cid);
+
+ if (capacity_ >= BufferHubRPC::kMaxQueueCapacity) {
+ ALOGE("ProducerQueueChannel::InsertBuffer: reaches kMaxQueueCapacity.");
+ return ErrorStatus(E2BIG);
+ }
+ auto producer_channel = std::static_pointer_cast<ProducerChannel>(
+ service()->GetChannel(buffer_cid));
+ if (producer_channel == nullptr ||
+ producer_channel->channel_type() != BufferHubChannel::kProducerType) {
+ // Rejects the request if the requested buffer channel is invalid and/or
+ // it's not a ProducerChannel.
+ ALOGE(
+ "ProducerQueueChannel::InsertBuffer: Invalid buffer_cid=%d, "
+ "producer_buffer=0x%p, channel_type=%d.",
+ buffer_cid, producer_channel.get(),
+ producer_channel == nullptr ? -1 : producer_channel->channel_type());
+ return ErrorStatus(EINVAL);
+ }
+ if (producer_channel->GetActiveProcessId() != message.GetProcessId()) {
+ // Rejects the request if the requested buffer channel is not currently
+ // connected to the caller this is IPC request. This effectively prevents
+ // fake buffer_cid from being injected.
+ ALOGE(
+ "ProducerQueueChannel::InsertBuffer: Requested buffer channel "
+ "(buffer_cid=%d) is not connected to the calling process (pid=%d). "
+ "It's connected to a different process (pid=%d).",
+ buffer_cid, message.GetProcessId(),
+ producer_channel->GetActiveProcessId());
+ return ErrorStatus(EINVAL);
+ }
+ uint64_t buffer_state = producer_channel->buffer_state();
+ if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+ // Rejects the request if the requested buffer is not in Gained state.
+ ALOGE(
+ "ProducerQueueChannel::InsertBuffer: The buffer (cid=%d, "
+ "state=0x%" PRIx64 ") is not in gained state.",
+ buffer_cid, buffer_state);
+ return ErrorStatus(EINVAL);
+ }
+
+ // Register the to-be-inserted buffer's channel_id into the first empty
+ // buffer slot.
+ size_t slot = 0;
+ for (; slot < BufferHubRPC::kMaxQueueCapacity; slot++) {
+ if (buffers_[slot].expired())
+ break;
+ }
+ if (slot == BufferHubRPC::kMaxQueueCapacity) {
+ ALOGE(
+ "ProducerQueueChannel::AllocateBuffer: Cannot find empty slot for new "
+ "buffer allocation.");
+ return ErrorStatus(E2BIG);
+ }
+
+ buffers_[slot] = producer_channel;
+ capacity_++;
+
+ // Notify each consumer channel about the new buffer.
+ for (auto* consumer_channel : consumer_channels_) {
+ ALOGD(
+ "ProducerQueueChannel::AllocateBuffer: Notified consumer with new "
+ "buffer, buffer_cid=%d",
+ buffer_cid);
+ consumer_channel->RegisterNewBuffer(producer_channel, slot);
+ }
+
+ return {slot};
+}
+
Status<void> ProducerQueueChannel::OnProducerQueueRemoveBuffer(
Message& /*message*/, size_t slot) {
if (buffers_[slot].expired()) {
diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h
index e825f47..e4fa243 100644
--- a/services/vr/bufferhubd/producer_queue_channel.h
+++ b/services/vr/bufferhubd/producer_queue_channel.h
@@ -38,8 +38,12 @@
uint32_t format, uint64_t usage,
size_t buffer_count);
- // Detach a BufferHubProducer indicated by |slot|. Note that the buffer must
- // be in Gain'ed state for the producer queue to detach.
+ // Inserts a BufferProducer into the queue. Note that the buffer must be in
+ // Gain'ed state for the operation to succeed.
+ pdx::Status<size_t> OnProducerQueueInsertBuffer(pdx::Message& message, int buffer_cid);
+
+ // Removes a BufferProducer indicated by |slot|. Note that the buffer must be
+ // in Gain'ed state for the operation to succeed.
pdx::Status<void> OnProducerQueueRemoveBuffer(pdx::Message& message,
size_t slot);
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 90edf69..003775b 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -39,6 +39,10 @@
"android.hardware.graphics.composer@2.1-hal",
],
+ export_static_lib_headers: [
+ "libdisplay",
+ ],
+
export_shared_lib_headers: [
"android.frameworks.vr.composer@1.0",
"android.hardware.graphics.composer@2.1",
@@ -48,6 +52,7 @@
cflags: [
"-DLOG_TAG=\"vr_hwc\"",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
"-Wall",
"-Werror",
// mVrClient unused in vr_composer_client.cpp
@@ -115,6 +120,7 @@
cc_binary {
name: "vr_hwc",
+ vintf_fragments: ["manifest_vr_hwc.xml"],
srcs: [
"vr_hardware_composer_service.cpp"
],
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 4af47d2..417460c 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -16,9 +16,11 @@
#include "impl/vr_hwc.h"
#include "android-base/stringprintf.h"
+#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <private/dvr/display_client.h>
#include <ui/Fence.h>
+#include <utils/Trace.h>
#include <mutex>
@@ -244,29 +246,38 @@
////////////////////////////////////////////////////////////////////////////////
// VrHwcClient
-VrHwc::VrHwc() {}
+VrHwc::VrHwc() {
+ vsync_callback_ = new VsyncCallback;
+}
-VrHwc::~VrHwc() {}
+VrHwc::~VrHwc() {
+ vsync_callback_->SetEventCallback(nullptr);
+}
bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
void VrHwc::registerEventCallback(EventCallback* callback) {
- {
- std::lock_guard<std::mutex> guard(mutex_);
- event_callback_ = callback;
- int32_t width, height;
- GetPrimaryDisplaySize(&width, &height);
- // Create the primary display late to avoid initialization issues between
- // VR HWC and SurfaceFlinger.
- displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
- }
+ std::unique_lock<std::mutex> lock(mutex_);
+ event_callback_ = callback;
+ int32_t width, height;
+ GetPrimaryDisplaySize(&width, &height);
+ // Create the primary display late to avoid initialization issues between
+ // VR HWC and SurfaceFlinger.
+ displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
+
+ // Surface flinger will make calls back into vr_hwc when it receives the
+ // onHotplug() call, so it's important to release mutex_ here.
+ lock.unlock();
event_callback_->onHotplug(kDefaultDisplayId,
IComposerCallback::Connection::CONNECTED);
+ lock.lock();
+ UpdateVsyncCallbackEnabledLocked();
}
void VrHwc::unregisterEventCallback() {
std::lock_guard<std::mutex> guard(mutex_);
event_callback_ = nullptr;
+ UpdateVsyncCallbackEnabledLocked();
}
uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
@@ -321,10 +332,14 @@
return Error::NONE;
}
-Error VrHwc::getClientTargetSupport(Display /* display */, uint32_t /* width */,
+Error VrHwc::getClientTargetSupport(Display display, uint32_t /* width */,
uint32_t /* height */,
PixelFormat /* format */,
Dataspace /* dataspace */) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
+
return Error::NONE;
}
@@ -455,16 +470,37 @@
if (!display_ptr)
return Error::BAD_DISPLAY;
+ if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3)
+ return Error::BAD_PARAMETER;
+
display_ptr->set_color_mode(mode);
return Error::NONE;
}
Error VrHwc::setPowerMode(Display display, IComposerClient::PowerMode mode) {
+ bool dozeSupported = false;
+
+ Error dozeSupportError = getDozeSupport(display, &dozeSupported);
+
+ if (dozeSupportError != Error::NONE)
+ return dozeSupportError;
+
std::lock_guard<std::mutex> guard(mutex_);
auto display_ptr = FindDisplay(display);
if (!display_ptr)
return Error::BAD_DISPLAY;
+ if (mode < IComposerClient::PowerMode::OFF ||
+ mode > IComposerClient::PowerMode::DOZE_SUSPEND) {
+ return Error::BAD_PARAMETER;
+ }
+
+ if (!dozeSupported &&
+ (mode == IComposerClient::PowerMode::DOZE ||
+ mode == IComposerClient::PowerMode::DOZE_SUSPEND)) {
+ return Error::UNSUPPORTED;
+ }
+
display_ptr->set_power_mode(mode);
return Error::NONE;
}
@@ -475,8 +511,45 @@
if (!display_ptr)
return Error::BAD_DISPLAY;
- display_ptr->set_vsync_enabled(enabled);
- return Error::NONE;
+ if (enabled != IComposerClient::Vsync::ENABLE &&
+ enabled != IComposerClient::Vsync::DISABLE) {
+ return Error::BAD_PARAMETER;
+ }
+
+ Error set_vsync_result = Error::NONE;
+ if (display == kDefaultDisplayId) {
+ sp<IVsyncService> vsync_service = interface_cast<IVsyncService>(
+ defaultServiceManager()->getService(
+ String16(IVsyncService::GetServiceName())));
+ if (vsync_service == nullptr) {
+ ALOGE("Failed to get vsync service");
+ return Error::NO_RESOURCES;
+ }
+
+ if (enabled == IComposerClient::Vsync::ENABLE) {
+ ALOGI("Enable vsync");
+ display_ptr->set_vsync_enabled(true);
+ status_t result = vsync_service->registerCallback(vsync_callback_);
+ if (result != OK) {
+ ALOGE("%s service registerCallback() failed: %s (%d)",
+ IVsyncService::GetServiceName(), strerror(-result), result);
+ set_vsync_result = Error::NO_RESOURCES;
+ }
+ } else if (enabled == IComposerClient::Vsync::DISABLE) {
+ ALOGI("Disable vsync");
+ display_ptr->set_vsync_enabled(false);
+ status_t result = vsync_service->unregisterCallback(vsync_callback_);
+ if (result != OK) {
+ ALOGE("%s service unregisterCallback() failed: %s (%d)",
+ IVsyncService::GetServiceName(), strerror(-result), result);
+ set_vsync_result = Error::NO_RESOURCES;
+ }
+ }
+
+ UpdateVsyncCallbackEnabledLocked();
+ }
+
+ return set_vsync_result;
}
Error VrHwc::setColorTransform(Display display, const float* matrix,
@@ -559,7 +632,8 @@
frame.display_height = display_ptr->height();
frame.active_config = display_ptr->active_config();
frame.power_mode = display_ptr->power_mode();
- frame.vsync_enabled = display_ptr->vsync_enabled();
+ frame.vsync_enabled = display_ptr->vsync_enabled() ?
+ IComposerClient::Vsync::ENABLE : IComposerClient::Vsync::DISABLE;
frame.color_transform_hint = display_ptr->color_transform_hint();
frame.color_mode = display_ptr->color_mode();
memcpy(frame.color_transform, display_ptr->color_transform(),
@@ -911,6 +985,15 @@
return iter == displays_.end() ? nullptr : iter->second.get();
}
+void VrHwc::UpdateVsyncCallbackEnabledLocked() {
+ auto primary_display = FindDisplay(kDefaultDisplayId);
+ LOG_ALWAYS_FATAL_IF(event_callback_ != nullptr && primary_display == nullptr,
+ "Should have created the primary display by now");
+ bool send_vsync =
+ event_callback_ != nullptr && primary_display->vsync_enabled();
+ vsync_callback_->SetEventCallback(send_vsync ? event_callback_ : nullptr);
+}
+
void HwcLayer::dumpDebugInfo(std::string* result) const {
if (!result) {
return;
@@ -928,5 +1011,18 @@
buffer_metadata.layerCount, buffer_metadata.format);
}
+status_t VrHwc::VsyncCallback::onVsync(int64_t vsync_timestamp) {
+ ATRACE_NAME("vr_hwc onVsync");
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (callback_ != nullptr)
+ callback_->onVsync(kDefaultDisplayId, vsync_timestamp);
+ return NO_ERROR;
+}
+
+void VrHwc::VsyncCallback::SetEventCallback(EventCallback* callback) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ callback_ = callback;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index 85e587a..f9872b2 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -20,6 +20,7 @@
#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
#include <android/hardware/graphics/composer/2.1/IComposer.h>
#include <composer-hal/2.1/ComposerHal.h>
+#include <private/dvr/vsync_service.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>
@@ -156,10 +157,8 @@
IComposerClient::PowerMode power_mode() const { return power_mode_; }
void set_power_mode(IComposerClient::PowerMode mode) { power_mode_ = mode; }
- IComposerClient::Vsync vsync_enabled() const { return vsync_enabled_; }
- void set_vsync_enabled(IComposerClient::Vsync vsync) {
- vsync_enabled_ = vsync;
- }
+ bool vsync_enabled() const { return vsync_enabled_; }
+ void set_vsync_enabled(bool vsync) {vsync_enabled_ = vsync;}
const float* color_transform() const { return color_transform_; }
int32_t color_transform_hint() const { return color_transform_hint_; }
@@ -187,7 +186,7 @@
Config active_config_;
ColorMode color_mode_;
IComposerClient::PowerMode power_mode_;
- IComposerClient::Vsync vsync_enabled_;
+ bool vsync_enabled_ = false;
float color_transform_[16];
int32_t color_transform_hint_;
@@ -299,8 +298,23 @@
void UnregisterObserver(Observer* observer) override;
private:
+ class VsyncCallback : public BnVsyncCallback {
+ public:
+ status_t onVsync(int64_t vsync_timestamp) override;
+ void SetEventCallback(EventCallback* callback);
+ private:
+ std::mutex mutex_;
+ EventCallback* callback_;
+ };
+
HwcDisplay* FindDisplay(Display display);
+ // Re-evaluate whether or not we should start making onVsync() callbacks to
+ // the client. We need enableCallback(true) to have been called, and
+ // setVsyncEnabled() to have been called for the primary display. The caller
+ // must have mutex_ locked already.
+ void UpdateVsyncCallbackEnabledLocked();
+
wp<VrComposerClient> client_;
// Guard access to internal state from binder threads.
@@ -312,6 +326,8 @@
EventCallback* event_callback_ = nullptr;
Observer* observer_ = nullptr;
+ sp<VsyncCallback> vsync_callback_;
+
VrHwc(const VrHwc&) = delete;
void operator=(const VrHwc&) = delete;
};
diff --git a/services/vr/hardware_composer/manifest_vr_hwc.xml b/services/vr/hardware_composer/manifest_vr_hwc.xml
new file mode 100644
index 0000000..1068cac
--- /dev/null
+++ b/services/vr/hardware_composer/manifest_vr_hwc.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.hardware.graphics.composer</name>
+ <transport>hwbinder</transport>
+ <version>2.1</version>
+ <interface>
+ <name>IComposer</name>
+ <instance>vr</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/services/vr/performanced/cpu_set.cpp b/services/vr/performanced/cpu_set.cpp
index 1a7264c..d940b79 100644
--- a/services/vr/performanced/cpu_set.cpp
+++ b/services/vr/performanced/cpu_set.cpp
@@ -106,7 +106,7 @@
return sets;
}
-std::string CpuSetManager::DumpState() const {
+void CpuSetManager::DumpState(std::ostringstream& stream) const {
size_t max_path = 0;
std::vector<CpuSet*> sets;
@@ -119,8 +119,6 @@
return a->path() < b->path();
});
- std::ostringstream stream;
-
stream << std::left;
stream << std::setw(max_path) << "Path";
stream << " ";
@@ -146,8 +144,6 @@
stream << std::setw(6) << set->GetTasks().size();
stream << std::endl;
}
-
- return stream.str();
}
void CpuSetManager::MoveUnboundTasks(const std::string& target_set) {
diff --git a/services/vr/performanced/cpu_set.h b/services/vr/performanced/cpu_set.h
index 6879272..4c25e9e 100644
--- a/services/vr/performanced/cpu_set.h
+++ b/services/vr/performanced/cpu_set.h
@@ -5,6 +5,7 @@
#include <memory>
#include <mutex>
+#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
@@ -83,7 +84,7 @@
// to shield the system from interference from unbound kernel threads.
void MoveUnboundTasks(const std::string& target_set);
- std::string DumpState() const;
+ void DumpState(std::ostringstream& stream) const;
operator bool() const { return root_set_ != nullptr; }
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 4c26671..73dcf76 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -1,5 +1,7 @@
#include "performance_service.h"
+#include <sstream>
+
#include <sched.h>
#include <sys/prctl.h>
#include <unistd.h>
@@ -31,6 +33,10 @@
const char kRootCpuSet[] = "/";
+const char kVrAppRenderPolicy[] = "vr:app:render";
+
+const bool kAllowAppsToRequestVrAppRenderPolicy = false;
+
constexpr unsigned long kTimerSlackForegroundNs = 50000;
constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
@@ -124,9 +130,6 @@
// TODO(eieio): Replace this witha device-specific config file. This is just a
// hack for now to put some form of permission logic in place while a longer
// term solution is developed.
- using AllowRootSystem =
- CheckAnd<SameProcess,
- CheckOr<UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>>;
using AllowRootSystemGraphics =
CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
@@ -136,6 +139,17 @@
using AllowRootSystemTrusted =
CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>;
+ auto vr_app_render_permission_check = [](
+ const pdx::Message& sender, const Task& task) {
+ // For vr:app:render, in addition to system/root apps and VrCore, we
+ // also allow apps to request vr:app:render if
+ // kAllowAppsToRequestVrAppRenderPolicy == true, but not for other
+ // apps, only for themselves.
+ return (task && task.thread_group_id() == sender.GetProcessId() &&
+ kAllowAppsToRequestVrAppRenderPolicy)
+ || AllowRootSystemTrusted::Check(sender, task);
+ };
+
partition_permission_check_ = AllowRootSystemTrusted::Check;
// Setup the scheduler classes.
@@ -170,28 +184,28 @@
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_low,
- .permission_check = AllowRootSystem::Check}},
+ .permission_check = AllowRootSystemTrusted::Check}},
{"sensors:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_low,
- .permission_check = AllowRootSystem::Check}},
+ .permission_check = AllowRootSystemTrusted::Check}},
{"sensors:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_low + 1,
- .permission_check = AllowRootSystem::Check}},
+ .permission_check = AllowRootSystemTrusted::Check}},
{"vr:system:arp",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_medium + 2,
.permission_check = AllowRootSystemTrusted::Check,
"/system/performance"}},
- {"vr:app:render",
+ {kVrAppRenderPolicy,
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_medium + 1,
- .permission_check = AllowRootSystemTrusted::Check,
+ .permission_check = vr_app_render_permission_check,
"/application/performance"}},
{"normal",
{.timer_slack = kTimerSlackForegroundNs,
@@ -218,7 +232,10 @@
}
std::string PerformanceService::DumpState(size_t /*max_length*/) {
- return cpuset_.DumpState();
+ std::ostringstream stream;
+ stream << "vr_app_render_thread: " << vr_app_render_thread_ << std::endl;
+ cpuset_.DumpState(stream);
+ return stream.str();
}
Status<void> PerformanceService::OnSetSchedulerPolicy(
@@ -244,7 +261,12 @@
// Make sure the sending process is allowed to make the requested change to
// this task.
if (!config.IsAllowed(message, task))
- return ErrorStatus(EINVAL);
+ return ErrorStatus(EPERM);
+
+ if (scheduler_policy == kVrAppRenderPolicy) {
+ // We only allow one vr:app:render thread at a time
+ SetVrAppRenderThread(task_id);
+ }
// Get the thread group's cpu set. Policies that do not specify a cpuset
// should default to this cpuset.
@@ -302,14 +324,16 @@
Status<void> PerformanceService::OnSetCpuPartition(
Message& message, pid_t task_id, const std::string& partition) {
Task task(task_id);
- if (!task || task.thread_group_id() != message.GetProcessId())
+ if (!task)
return ErrorStatus(EINVAL);
+ if (task.thread_group_id() != message.GetProcessId())
+ return ErrorStatus(EPERM);
// Temporary permission check.
// TODO(eieio): Replace this with a configuration file.
if (partition_permission_check_ &&
!partition_permission_check_(message, task)) {
- return ErrorStatus(EINVAL);
+ return ErrorStatus(EPERM);
}
auto target_set = cpuset_.Lookup(partition);
@@ -336,7 +360,12 @@
// Make sure the sending process is allowed to make the requested change to
// this task.
if (!config.IsAllowed(message, task))
- return ErrorStatus(EINVAL);
+ return ErrorStatus(EPERM);
+
+ if (scheduler_class == kVrAppRenderPolicy) {
+ // We only allow one vr:app:render thread at a time
+ SetVrAppRenderThread(task_id);
+ }
struct sched_param param;
param.sched_priority = config.priority;
@@ -359,8 +388,10 @@
pid_t task_id) {
// Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
- if (!task || task.thread_group_id() != message.GetProcessId())
+ if (!task)
return ErrorStatus(EINVAL);
+ if (task.thread_group_id() != message.GetProcessId())
+ return ErrorStatus(EPERM);
return task.GetCpuSetPath();
}
@@ -393,5 +424,38 @@
}
}
+void PerformanceService::SetVrAppRenderThread(pid_t new_vr_app_render_thread) {
+ ALOGI("SetVrAppRenderThread old=%d new=%d",
+ vr_app_render_thread_, new_vr_app_render_thread);
+
+ if (vr_app_render_thread_ >= 0 &&
+ vr_app_render_thread_ != new_vr_app_render_thread) {
+ // Restore the default scheduler policy and priority on the previous
+ // vr:app:render thread.
+ struct sched_param param;
+ param.sched_priority = 0;
+ if (sched_setscheduler(vr_app_render_thread_, SCHED_NORMAL, ¶m) < 0) {
+ if (errno == ESRCH) {
+ ALOGI("Failed to revert %s scheduler policy. Couldn't find thread %d."
+ " Was the app killed?", kVrAppRenderPolicy, vr_app_render_thread_);
+ } else {
+ ALOGE("Failed to revert %s scheduler policy: %s",
+ kVrAppRenderPolicy, strerror(errno));
+ }
+ }
+
+ // Restore the default timer slack on the previous vr:app:render thread.
+ prctl(PR_SET_TIMERSLACK_PID, kTimerSlackForegroundNs,
+ vr_app_render_thread_);
+ }
+
+ // We could also reset the thread's cpuset here, but the cpuset is already
+ // managed by Android. Better to let Android adjust the cpuset as the app
+ // moves to the background, rather than adjust it ourselves here, and risk
+ // stomping on the value set by Android.
+
+ vr_app_render_thread_ = new_vr_app_render_thread;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index 6b519ab..fe63756 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -39,6 +39,14 @@
pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message,
pid_t task_id);
+ // Set which thread gets the vr:app:render policy. Only one thread at a time
+ // is allowed to have vr:app:render. If multiple threads are allowed
+ // vr:app:render, and those threads busy loop, the system can freeze. When
+ // SetVrAppRenderThread() is called, the thread which we had previously
+ // assigned vr:app:render will have its scheduling policy reset to default
+ // values.
+ void SetVrAppRenderThread(pid_t new_vr_app_render_thread);
+
CpuSetManager cpuset_;
int sched_fifo_min_priority_;
@@ -70,6 +78,8 @@
std::function<bool(const pdx::Message& message, const Task& task)>
partition_permission_check_;
+ pid_t vr_app_render_thread_ = -1;
+
PerformanceService(const PerformanceService&) = delete;
void operator=(const PerformanceService&) = delete;
};
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 56bc35e..4c2d223 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -984,7 +984,7 @@
uint32_t icd_api_version;
PFN_vkEnumerateInstanceVersion pfn_enumerate_instance_version =
reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
- Hal::Device().GetInstanceProcAddr(NULL,
+ Hal::Device().GetInstanceProcAddr(nullptr,
"vkEnumerateInstanceVersion"));
if (!pfn_enumerate_instance_version) {
icd_api_version = VK_API_VERSION_1_0;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3db8a39..915de45 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -335,15 +335,15 @@
swapchain.surface.window.get(), ti.native_frame_id_,
&desired_present_time, &render_complete_time,
&composition_latch_time,
- NULL, //&first_composition_start_time,
- NULL, //&last_composition_start_time,
- NULL, //&composition_finish_time,
+ nullptr, //&first_composition_start_time,
+ nullptr, //&last_composition_start_time,
+ nullptr, //&composition_finish_time,
// TODO(ianelliott): Maybe ask if this one is
// supported, at startup time (since it may not be
// supported):
&actual_present_time,
- NULL, //&dequeue_ready_time,
- NULL /*&reads_done_time*/);
+ nullptr, //&dequeue_ready_time,
+ nullptr /*&reads_done_time*/);
if (ret != android::NO_ERROR) {
continue;
@@ -575,15 +575,10 @@
break;
}
- // USAGE_CPU_READ_MASK 0xFUL
- // USAGE_CPU_WRITE_MASK (0xFUL << 4)
- // The currently used bits are as below:
- // USAGE_CPU_READ_RARELY = 2UL
- // USAGE_CPU_READ_OFTEN = 3UL
- // USAGE_CPU_WRITE_RARELY = (2UL << 4)
- // USAGE_CPU_WRITE_OFTEN = (3UL << 4)
- *supported = static_cast<VkBool32>(format_supported ||
- (surface->consumer_usage & 0xFFUL) == 0);
+ *supported = static_cast<VkBool32>(
+ format_supported || (surface->consumer_usage &
+ (AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) == 0);
return VK_SUCCESS;
}
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
index e387165..7fbe315 100644
--- a/vulkan/vkjson/Android.bp
+++ b/vulkan/vkjson/Android.bp
@@ -9,7 +9,6 @@
"-Werror",
],
cppflags: [
- "-std=c++11",
"-Wno-sign-compare",
],
export_include_dirs: [
@@ -35,7 +34,6 @@
"-Werror",
],
cppflags: [
- "-std=c++11",
"-Wno-sign-compare",
],
export_include_dirs: [