Merge "Revert "Partial revert of "Fix Surface slot caching""" into nyc-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 128681f..e15a0c5 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -485,7 +485,8 @@
/* adds a new entry to the existing zip file. */
static bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
if (!zip_writer) {
- MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n", entry_name.c_str());
+ MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
+ entry_name.c_str());
return false;
}
// Logging statement below is useful to time how long each entry takes, but it's too verbose.
@@ -545,6 +546,7 @@
MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
return;
}
+ MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
DurationReporter duration_reporter(dir, NULL);
dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
}
@@ -598,7 +600,6 @@
dump_file("BUDDYINFO", "/proc/buddyinfo");
dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
- dump_file("KERNEL WAKELOCKS", "/proc/wakelocks");
dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
dump_file("KERNEL SYNC", "/d/sync");
@@ -1065,6 +1066,7 @@
}
/* parse arguments */
+ log_args("Dumpstate command line", argc, const_cast<const char **>(argv));
int c;
while ((c = getopt(argc, argv, "dho:svqzpPBRV:")) != -1) {
switch (c) {
@@ -1277,14 +1279,6 @@
dumpstate(do_early_screenshot ? "": screenshot_path, version);
- /* done */
- if (vibrator) {
- for (int i = 0; i < 3; i++) {
- vibrate(vibrator.get(), 75);
- usleep((75 + 50) * 1000);
- }
- }
-
/* close output if needed */
if (is_redirecting) {
fclose(stdout);
@@ -1326,17 +1320,29 @@
bool do_text_file = true;
if (do_zip_file) {
- MYLOGD("Adding text entry to .zip bugreport\n");
- if (!finish_zip_file(base_name + "-" + suffix + ".txt", tmp_path, now)) {
+ std::string entry_name = base_name + "-" + suffix + ".txt";
+ MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
+ if (!finish_zip_file(entry_name, tmp_path, now)) {
MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
do_text_file = true;
} else {
do_text_file = false;
+ // Since zip file is already created, it needs to be renamed.
+ std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
+ if (path != new_path) {
+ MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
+ if (rename(path.c_str(), new_path.c_str())) {
+ MYLOGE("rename(%s, %s): %s\n", path.c_str(),
+ new_path.c_str(), strerror(errno));
+ } else {
+ path = new_path;
+ }
+ }
}
}
if (do_text_file) {
- MYLOGD("Generating .txt bugreport\n");
path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
+ MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
if (rename(tmp_path.c_str(), path.c_str())) {
MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
path.clear();
@@ -1344,6 +1350,14 @@
}
}
+ /* vibrate a few but shortly times to let user know it's finished */
+ if (vibrator) {
+ for (int i = 0; i < 3; i++) {
+ vibrate(vibrator.get(), 75);
+ usleep((75 + 50) * 1000);
+ }
+ }
+
/* tell activity manager we're done */
if (do_broadcast) {
if (!path.empty()) {
@@ -1352,6 +1366,7 @@
"--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
"--ei", "android.intent.extra.ID", std::to_string(id),
"--ei", "android.intent.extra.PID", std::to_string(getpid()),
+ "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
"--es", "android.intent.extra.BUGREPORT", path,
"--es", "android.intent.extra.DUMPSTATE_LOG", log_path
};
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index a8aea42..9c975d2 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -171,6 +171,9 @@
/* dump eMMC Extended CSD data */
void dump_emmc_ecsd(const char *ext_csd_path);
+/** logs command-line arguments */
+void log_args(const std::string& message, int argc, const char *argv[]);
+
/*
* Helper class used to report how long it takes for a section to finish.
*
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 282a772..f0ae325 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -713,6 +713,7 @@
}
// Always terminate with NULL.
am_args[am_index + 1] = NULL;
+ log_args("send_broadcast arguments", am_index, am_args);
run_command_always(NULL, 5, am_args);
}
@@ -1187,3 +1188,12 @@
printf("\n");
}
+
+void log_args(const std::string& message, int argc, const char *argv[]) {
+ std::string args;
+ for (int i = 0; i < argc; i++) {
+ args.append(argv[i]);
+ args.append(" ");
+ }
+ MYLOGI("%s: %s\n", message.c_str(), args.c_str());
+}
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 2c5bb1c..e31c6e2 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -24,6 +24,7 @@
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
@@ -56,6 +57,17 @@
#define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M
+typedef int fd_t;
+
+static bool property_get_bool(const char* property_name, bool default_value = false) {
+ char tmp_property_value[kPropertyValueMax];
+ bool have_property = get_property(property_name, tmp_property_value, nullptr) > 0;
+ if (!have_property) {
+ return default_value;
+ }
+ return strcmp(tmp_property_value, "true") == 0;
+}
+
int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
appid_t appid, const char* seinfo, int target_sdk_version) {
uid_t uid = multiuser_get_uid(userid, appid);
@@ -83,6 +95,24 @@
// TODO: include result once 25796509 is fixed
return 0;
}
+
+ if (property_get_bool("dalvik.vm.usejitprofiles")) {
+ const std::string profile_path = create_data_user_profile_package_path(userid, pkgname);
+ // read-write-execute only for the app user.
+ if (fs_prepare_dir_strict(profile_path.c_str(), 0700, uid, uid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << profile_path;
+ return -1;
+ }
+ const std::string ref_profile_path = create_data_ref_profile_package_path(pkgname);
+ // dex2oat/profman runs under the shared app gid and it needs to read/write reference
+ // profiles.
+ appid_t shared_app_gid = multiuser_get_shared_app_gid(uid);
+ if (fs_prepare_dir_strict(
+ ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << ref_profile_path;
+ return -1;
+ }
+ }
}
return 0;
}
@@ -125,6 +155,36 @@
return 0;
}
+// Keep profile paths in sync with ActivityThread.
+constexpr const char* PRIMARY_PROFILE_NAME = "primary.prof";
+static std::string create_primary_profile(const std::string& profile_dir) {
+ return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
+}
+
+static void unlink_reference_profile(const char* pkgname) {
+ std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
+ std::string reference_profile = create_primary_profile(reference_profile_dir);
+ if (unlink(reference_profile.c_str()) != 0) {
+ PLOG(WARNING) << "Could not unlink " << reference_profile;
+ }
+}
+
+static void unlink_current_profiles(const char* pkgname) {
+ std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
+ for (auto user : users) {
+ std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
+ std::string profile = create_primary_profile(profile_dir);
+ if (unlink(profile.c_str()) != 0) {
+ PLOG(WARNING) << "Could not unlink " << profile;
+ }
+ }
+}
+
+static void unlink_all_profiles(const char* pkgname) {
+ unlink_reference_profile(pkgname);
+ unlink_current_profiles(pkgname);
+}
+
int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) {
std::string suffix = "";
if (flags & FLAG_CLEAR_CACHE_ONLY) {
@@ -146,6 +206,7 @@
// TODO: include result once 25796509 is fixed
delete_dir_contents(path);
}
+ unlink_all_profiles(pkgname);
}
return res;
}
@@ -160,6 +221,7 @@
// TODO: include result once 25796509 is fixed
delete_dir_contents_and_dir(
create_data_user_de_package_path(uuid, userid, pkgname));
+ unlink_all_profiles(pkgname);
}
return res;
}
@@ -289,11 +351,13 @@
std::string data_path(create_data_user_path(uuid, userid));
std::string data_de_path(create_data_user_de_path(uuid, userid));
std::string media_path(create_data_media_path(uuid, userid));
+ std::string profiles_path(create_data_user_profiles_path(userid));
res |= delete_dir_contents_and_dir(data_path);
// TODO: include result once 25796509 is fixed
delete_dir_contents_and_dir(data_de_path);
res |= delete_dir_contents_and_dir(media_path);
+ res |= delete_dir_contents_and_dir(profiles_path);
// Config paths only exist on internal storage
if (uuid == nullptr) {
@@ -630,19 +694,10 @@
ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno));
}
-static bool check_boolean_property(const char* property_name, bool default_value = false) {
- char tmp_property_value[kPropertyValueMax];
- bool have_property = get_property(property_name, tmp_property_value, nullptr) > 0;
- if (!have_property) {
- return default_value;
- }
- return strcmp(tmp_property_value, "true") == 0;
-}
-
static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_file_name,
- const char* output_file_name, int swap_fd, const char *instruction_set,
- bool vm_safe_mode, bool debuggable, bool post_bootcomplete, bool extract_only,
- const std::vector<int>& profile_files_fd, const std::vector<int>& reference_profile_files_fd) {
+ const char* output_file_name, int swap_fd, const char *instruction_set,
+ bool vm_safe_mode, bool debuggable, bool post_bootcomplete, bool extract_only,
+ int profile_fd) {
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -651,12 +706,6 @@
return;
}
- if (profile_files_fd.size() != reference_profile_files_fd.size()) {
- ALOGE("Invalid configuration of profile files: pf_size (%zu) != rpf_size (%zu)",
- profile_files_fd.size(), reference_profile_files_fd.size());
- return;
- }
-
char dex2oat_Xms_flag[kPropertyValueMax];
bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;
@@ -705,7 +754,7 @@
(strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
(strcmp(vold_decrypt, "1") == 0)));
- bool generate_debug_info = check_boolean_property("debug.generate-debug-info");
+ bool generate_debug_info = property_get_bool("debug.generate-debug-info");
char app_image_format[kPropertyValueMax];
char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
@@ -779,18 +828,12 @@
(get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
(prop_buf[0] == '1');
}
- std::vector<std::string> profile_file_args(profile_files_fd.size());
- std::vector<std::string> reference_profile_file_args(profile_files_fd.size());
- // "reference-profile-file-fd" is longer than "profile-file-fd" so we can
- // use it to set the max length.
- char profile_buf[strlen("--reference-profile-file-fd=") + MAX_INT_LEN];
- for (size_t k = 0; k < profile_files_fd.size(); k++) {
- sprintf(profile_buf, "--profile-file-fd=%d", profile_files_fd[k]);
- profile_file_args[k].assign(profile_buf);
- sprintf(profile_buf, "--reference-profile-file-fd=%d", reference_profile_files_fd[k]);
- reference_profile_file_args[k].assign(profile_buf);
+ char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
+ if (profile_fd != -1) {
+ sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
}
+
ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
const char* argv[7 // program name, mandatory arguments and the final NULL
@@ -807,8 +850,7 @@
+ (debuggable ? 1 : 0)
+ (have_app_image_format ? 1 : 0)
+ dex2oat_flags_count
- + profile_files_fd.size()
- + reference_profile_files_fd.size()];
+ + (profile_fd == -1 ? 0 : 1)];
int i = 0;
argv[i++] = DEX2OAT_BIN;
argv[i++] = zip_fd_arg;
@@ -858,9 +900,8 @@
argv[i++] = RUNTIME_ARG;
argv[i++] = dex2oat_norelocation;
}
- for (size_t k = 0; k < profile_file_args.size(); k++) {
- argv[i++] = profile_file_args[k].c_str();
- argv[i++] = reference_profile_file_args[k].c_str();
+ if (profile_fd != -1) {
+ argv[i++] = profile_arg;
}
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
@@ -906,7 +947,7 @@
return true;
}
- bool is_low_mem = check_boolean_property("ro.config.low_ram");
+ bool is_low_mem = property_get_bool("ro.config.low_ram");
if (is_low_mem) {
return true;
}
@@ -928,10 +969,7 @@
}
}
-constexpr const char* PROFILE_FILE_EXTENSION = ".prof";
-constexpr const char* REFERENCE_PROFILE_FILE_EXTENSION = ".prof.ref";
-
-static void close_all_fds(const std::vector<int>& fds, const char* description) {
+static void close_all_fds(const std::vector<fd_t>& fds, const char* description) {
for (size_t i = 0; i < fds.size(); i++) {
if (close(fds[i]) != 0) {
PLOG(WARNING) << "Failed to close fd for " << description << " at index " << i;
@@ -939,92 +977,224 @@
}
}
-static int open_code_cache_for_user(userid_t user, const char* volume_uuid, const char* pkgname) {
- std::string code_cache_path =
- create_data_user_de_package_path(volume_uuid, user, pkgname) + CODE_CACHE_DIR_POSTFIX;
-
+static fd_t open_profile_dir(const std::string& profile_dir) {
struct stat buffer;
- // Check that the code cache exists. If not, return and don't log an error.
- if (TEMP_FAILURE_RETRY(lstat(code_cache_path.c_str(), &buffer)) == -1) {
+ if (TEMP_FAILURE_RETRY(lstat(profile_dir.c_str(), &buffer)) == -1) {
+ PLOG(ERROR) << "Failed to lstat profile_dir: " << profile_dir;
+ return -1;
+ }
+
+ fd_t profile_dir_fd = TEMP_FAILURE_RETRY(open(profile_dir.c_str(),
+ O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW));
+ if (profile_dir_fd < 0) {
+ PLOG(ERROR) << "Failed to open profile_dir: " << profile_dir;
+ }
+ return profile_dir_fd;
+}
+
+static fd_t open_primary_profile_file_from_dir(const std::string& profile_dir, mode_t open_mode) {
+ fd_t profile_dir_fd = open_profile_dir(profile_dir);
+ if (profile_dir_fd < 0) {
+ return -1;
+ }
+
+ fd_t profile_fd = -1;
+ std::string profile_file = create_primary_profile(profile_dir);
+
+ profile_fd = TEMP_FAILURE_RETRY(open(profile_file.c_str(), open_mode | O_NOFOLLOW));
+ if (profile_fd == -1) {
+ // It's not an error if the profile file does not exist.
if (errno != ENOENT) {
- PLOG(ERROR) << "Failed to lstat code_cache: " << code_cache_path;
+ PLOG(ERROR) << "Failed to lstat profile_dir: " << profile_dir;
+ }
+ }
+ // TODO(calin): use AutoCloseFD instead of closing the fd manually.
+ if (close(profile_dir_fd) != 0) {
+ PLOG(WARNING) << "Could not close profile dir " << profile_dir;
+ }
+ return profile_fd;
+}
+
+static fd_t open_primary_profile_file(userid_t user, const char* pkgname) {
+ std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
+ return open_primary_profile_file_from_dir(profile_dir, O_RDONLY);
+}
+
+static fd_t open_reference_profile(uid_t uid, const char* pkgname, bool read_write) {
+ std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
+ int flags = read_write ? O_RDWR | O_CREAT : O_RDONLY;
+ fd_t fd = open_primary_profile_file_from_dir(reference_profile_dir, flags);
+ if (fd < 0) {
+ return -1;
+ }
+ if (read_write) {
+ // Fix the owner.
+ if (fchown(fd, uid, uid) < 0) {
+ close(fd);
return -1;
}
}
-
- int code_cache_fd = open(code_cache_path.c_str(),
- O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW);
- if (code_cache_fd < 0) {
- PLOG(ERROR) << "Failed to open code_cache: " << code_cache_path;
- }
- return code_cache_fd;
+ return fd;
}
-// Keep profile paths in sync with ActivityThread.
-static void open_profile_files_for_user(uid_t uid, const char* pkgname, int code_cache_fd,
- /*out*/ int* profile_fd, /*out*/ int* reference_profile_fd) {
- *profile_fd = -1;
- *reference_profile_fd = -1;
- std::string profile_file(pkgname);
- profile_file += PROFILE_FILE_EXTENSION;
-
- // Check if the profile exists. If not, early return and don't log an error.
- struct stat buffer;
- if (TEMP_FAILURE_RETRY(fstatat(
- code_cache_fd, profile_file.c_str(), &buffer, AT_SYMLINK_NOFOLLOW)) == -1) {
- if (errno != ENOENT) {
- PLOG(ERROR) << "Failed to fstatat profile file: " << profile_file;
- return;
- }
- }
-
- // Open in read-write to allow transfer of information from the current profile
- // to the reference profile.
- *profile_fd = openat(code_cache_fd, profile_file.c_str(), O_RDWR | O_NOFOLLOW);
- if (*profile_fd < 0) {
- PLOG(ERROR) << "Failed to open profile file: " << profile_file;
- return;
- }
-
- std::string reference_profile(pkgname);
- reference_profile += REFERENCE_PROFILE_FILE_EXTENSION;
- // Give read-write permissions just for the user (changed with fchown after opening).
- // We need write permission because dex2oat will update the reference profile files
- // with the content of the corresponding current profile files.
- *reference_profile_fd = openat(code_cache_fd, reference_profile.c_str(),
- O_CREAT | O_RDWR | O_NOFOLLOW, S_IWUSR | S_IRUSR);
+static void open_profile_files(uid_t uid, const char* pkgname,
+ /*out*/ std::vector<fd_t>* profiles_fd, /*out*/ fd_t* reference_profile_fd) {
+ // Open the reference profile in read-write mode as profman might need to save the merge.
+ *reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ true);
if (*reference_profile_fd < 0) {
- close(*profile_fd);
+ // We can't access the reference profile file.
return;
}
- if (fchown(*reference_profile_fd, uid, uid) < 0) {
- PLOG(ERROR) << "Cannot change reference profile file owner: " << reference_profile;
- close(*profile_fd);
- *profile_fd = -1;
- *reference_profile_fd = -1;
+
+ std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
+ for (auto user : users) {
+ fd_t profile_fd = open_primary_profile_file(user, pkgname);
+ // Add to the lists only if both fds are valid.
+ if (profile_fd >= 0) {
+ profiles_fd->push_back(profile_fd);
+ }
}
}
-static void open_profile_files(const char* volume_uuid, uid_t uid, const char* pkgname,
- std::vector<int>* profile_fds, std::vector<int>* reference_profile_fds) {
- std::vector<userid_t> users = get_known_users(volume_uuid);
- for (auto user : users) {
- int code_cache_fd = open_code_cache_for_user(user, volume_uuid, pkgname);
- if (code_cache_fd < 0) {
- continue;
- }
- int profile_fd = -1;
- int reference_profile_fd = -1;
- open_profile_files_for_user(
- uid, pkgname, code_cache_fd, &profile_fd, &reference_profile_fd);
- close(code_cache_fd);
+static void drop_capabilities(uid_t uid) {
+ if (setgid(uid) != 0) {
+ ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
+ exit(64);
+ }
+ if (setuid(uid) != 0) {
+ ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
+ exit(65);
+ }
+ // drop capabilities
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ if (capset(&capheader, &capdata[0]) < 0) {
+ ALOGE("capset failed: %s\n", strerror(errno));
+ exit(66);
+ }
+}
- // Add to the lists only if both fds are valid.
- if ((profile_fd >= 0) && (reference_profile_fd >= 0)) {
- profile_fds->push_back(profile_fd);
- reference_profile_fds->push_back(reference_profile_fd);
+static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0;
+static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1;
+static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2;
+static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
+static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
+
+static void run_profman(const std::vector<fd_t>& profiles_fd, fd_t reference_profile_fd) {
+ static const size_t MAX_INT_LEN = 32;
+ static const char* PROFMAN_BIN = "/system/bin/profman";
+
+ std::vector<std::string> profile_args(profiles_fd.size());
+ char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN];
+ for (size_t k = 0; k < profiles_fd.size(); k++) {
+ sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k]);
+ profile_args[k].assign(profile_buf);
+ }
+ char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN];
+ sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd);
+
+ // program name, reference profile fd, the final NULL and the profile fds
+ const char* argv[3 + profiles_fd.size()];
+ int i = 0;
+ argv[i++] = PROFMAN_BIN;
+ argv[i++] = reference_profile_arg;
+ for (size_t k = 0; k < profile_args.size(); k++) {
+ argv[i++] = profile_args[k].c_str();
+ }
+ // Do not add after dex2oat_flags, they should override others for debugging.
+ argv[i] = NULL;
+
+ execv(PROFMAN_BIN, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
+ exit(68); /* only get here on exec failure */
+}
+
+// Decides if profile guided compilation is needed or not based on existing profiles.
+// Returns true if there is enough information in the current profiles that worth
+// a re-compilation of the package.
+// If the return value is true all the current profiles would have been merged into
+// the reference profiles accessible with open_reference_profile().
+static bool analyse_profiles(uid_t uid, const char* pkgname) {
+ std::vector<fd_t> profiles_fd;
+ fd_t reference_profile_fd = -1;
+ open_profile_files(uid, pkgname, &profiles_fd, &reference_profile_fd);
+ if (profiles_fd.empty() || (reference_profile_fd == -1)) {
+ // Skip profile guided compilation because no profiles were found.
+ // Or if the reference profile info couldn't be opened.
+ close_all_fds(profiles_fd, "profiles_fd");
+ if ((reference_profile_fd != - 1) && (close(reference_profile_fd) != 0)) {
+ PLOG(WARNING) << "Failed to close fd for reference profile";
+ }
+ return false;
+ }
+
+ ALOGV("PROFMAN: --- BEGIN '%s' ---\n", pkgname);
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ drop_capabilities(uid);
+ run_profman(profiles_fd, reference_profile_fd);
+ exit(68); /* only get here on exec failure */
+ }
+ /* parent */
+ int return_code = wait_child(pid);
+ bool need_to_compile = false;
+ bool delete_current_profiles = false;
+ bool delete_reference_profile = false;
+ if (!WIFEXITED(return_code)) {
+ LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code;
+ } else {
+ return_code = WEXITSTATUS(return_code);
+ switch (return_code) {
+ case PROFMAN_BIN_RETURN_CODE_COMPILE:
+ need_to_compile = true;
+ delete_current_profiles = true;
+ delete_reference_profile = false;
+ break;
+ case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION:
+ need_to_compile = false;
+ delete_current_profiles = false;
+ delete_reference_profile = false;
+ break;
+ case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES:
+ LOG(WARNING) << "Bad profiles for package " << pkgname;
+ need_to_compile = false;
+ delete_current_profiles = true;
+ delete_reference_profile = true;
+ break;
+ case PROFMAN_BIN_RETURN_CODE_ERROR_IO: // fall-through
+ case PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING:
+ // Temporary IO problem (e.g. locking). Ignore but log a warning.
+ LOG(WARNING) << "IO error while reading profiles for package " << pkgname;
+ need_to_compile = false;
+ delete_current_profiles = false;
+ delete_reference_profile = false;
+ break;
+ default:
+ // Unknown return code or error. Unlink profiles.
+ LOG(WARNING) << "Unknown error code while processing profiles for package " << pkgname
+ << ": " << return_code;
+ need_to_compile = false;
+ delete_current_profiles = true;
+ delete_reference_profile = true;
+ break;
}
}
+ close_all_fds(profiles_fd, "profiles_fd");
+ if (close(reference_profile_fd) != 0) {
+ PLOG(WARNING) << "Failed to close fd for reference profile";
+ }
+ if (delete_current_profiles) {
+ unlink_current_profiles(pkgname);
+ }
+ if (delete_reference_profile) {
+ unlink_reference_profile(pkgname);
+ }
+ return need_to_compile;
}
static void trim_extension(char* path) {
@@ -1066,9 +1236,36 @@
return true;
}
+static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
+ const char* oat_dir, /*out*/ char* out_path) {
+ // Early best-effort check whether we can fit the the path into our buffers.
+ // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
+ // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
+ // extension to the cache path (5 bytes).
+ if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
+ ALOGE("apk_path too long '%s'\n", apk_path);
+ return false;
+ }
+
+ if (oat_dir != NULL && oat_dir[0] != '!') {
+ if (validate_apk_path(oat_dir)) {
+ ALOGE("invalid oat_dir '%s'\n", oat_dir);
+ return false;
+ }
+ if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) {
+ return false;
+ }
+ } else {
+ if (!create_cache_path(out_path, apk_path, instruction_set)) {
+ return false;
+ }
+ }
+ return true;
+}
+
int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
- int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* volume_uuid,
- bool use_profiles)
+ int dexopt_needed, const char* oat_dir, int dexopt_flags,
+ const char* volume_uuid ATTRIBUTE_UNUSED, bool use_profiles)
{
struct utimbuf ut;
struct stat input_stat;
@@ -1077,19 +1274,25 @@
char image_path[PKG_PATH_MAX];
const char *input_file;
char in_odex_path[PKG_PATH_MAX];
- int res, input_fd=-1, out_fd=-1, image_fd=-1, swap_fd=-1;
+ int res;
+ fd_t input_fd=-1, out_fd=-1, image_fd=-1, swap_fd=-1;
bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
bool extract_only = (dexopt_flags & DEXOPT_EXTRACTONLY) != 0;
- std::vector<int> profile_files_fd;
- std::vector<int> reference_profile_files_fd;
+ fd_t reference_profile_fd = -1;
if (use_profiles) {
- open_profile_files(volume_uuid, uid, pkgname,
- &profile_files_fd, &reference_profile_files_fd);
- if (profile_files_fd.empty()) {
- // Skip profile guided compilation because no profiles were found.
+ if (analyse_profiles(uid, pkgname)) {
+ // Open again reference profile in read only mode as dex2oat does not get write
+ // permissions.
+ reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ false);
+ if (reference_profile_fd == -1) {
+ PLOG(WARNING) << "Couldn't open reference profile in read only mode " << pkgname;
+ exit(72);
+ }
+ } else {
+ // No need to (re)compile. Return early.
return 0;
}
}
@@ -1098,26 +1301,8 @@
LOG_FATAL("dexopt flags contains unknown fields\n");
}
- // Early best-effort check whether we can fit the the path into our buffers.
- // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
- // without a swap file, if necessary.
- if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
- ALOGE("apk_path too long '%s'\n", apk_path);
- return -1;
- }
-
- if (oat_dir != NULL && oat_dir[0] != '!') {
- if (validate_apk_path(oat_dir)) {
- ALOGE("invalid oat_dir '%s'\n", oat_dir);
- return -1;
- }
- if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) {
- return -1;
- }
- } else {
- if (!create_cache_path(out_path, apk_path, instruction_set)) {
- return -1;
- }
+ if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) {
+ return false;
}
switch (dexopt_needed) {
@@ -1207,24 +1392,8 @@
pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
- if (setgid(uid) != 0) {
- ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
- exit(64);
- }
- if (setuid(uid) != 0) {
- ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
- exit(65);
- }
- // drop capabilities
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata[2];
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- if (capset(&capheader, &capdata[0]) < 0) {
- ALOGE("capset failed: %s\n", strerror(errno));
- exit(66);
- }
+ drop_capabilities(uid);
+
SetDex2OatAndPatchOatScheduling(boot_complete);
if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) {
ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno));
@@ -1244,7 +1413,7 @@
}
run_dex2oat(input_fd, out_fd, image_fd, input_file_name, out_path, swap_fd,
instruction_set, vm_safe_mode, debuggable, boot_complete, extract_only,
- profile_files_fd, reference_profile_files_fd);
+ reference_profile_fd);
} else {
ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
exit(73);
@@ -1269,9 +1438,8 @@
if (swap_fd >= 0) {
close(swap_fd);
}
- if (use_profiles != 0) {
- close_all_fds(profile_files_fd, "profile_files_fd");
- close_all_fds(reference_profile_files_fd, "reference_profile_files_fd");
+ if (reference_profile_fd >= 0) {
+ close(reference_profile_fd);
}
if (image_fd >= 0) {
close(image_fd);
@@ -1286,9 +1454,11 @@
if (input_fd >= 0) {
close(input_fd);
}
- if (use_profiles != 0) {
- close_all_fds(profile_files_fd, "profile_files_fd");
- close_all_fds(reference_profile_files_fd, "reference_profile_files_fd");
+ if (reference_profile_fd >= 0) {
+ close(reference_profile_fd);
+ // We failed to compile. Unlink the reference profile. Current profiles are already unlinked
+ // when profmoan advises compilation.
+ unlink_reference_profile(pkgname);
}
if (swap_fd >= 0) {
close(swap_fd);
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index bee2790..6a67e29 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -39,6 +39,7 @@
dir_rec_t android_data_dir;
dir_rec_t android_media_dir;
dir_rec_t android_mnt_expand_dir;
+dir_rec_t android_profiles_dir;
dir_rec_array_t android_system_dirs;
@@ -99,6 +100,11 @@
return false;
}
+ // Get the android profiles directory.
+ if (copy_and_append(&android_profiles_dir, &android_data_dir, PROFILES_SUBDIR) < 0) {
+ return false;
+ }
+
// Take note of the system and vendor directories.
android_system_dirs.count = 4;
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index 2e61f85..3e52346 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -43,6 +43,7 @@
extern dir_rec_t android_data_dir;
extern dir_rec_t android_media_dir;
extern dir_rec_t android_mnt_expand_dir;
+extern dir_rec_t android_profiles_dir;
extern dir_rec_array_t android_system_dirs;
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 4e1d38f..8f6e928 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -4,7 +4,7 @@
**
** 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
+** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
@@ -41,6 +41,8 @@
constexpr const char* MEDIA_SUBDIR = "media/"; // sub-directory under ANDROID_DATA
+constexpr const char* PROFILES_SUBDIR = "misc/profiles"; // sub-directory under ANDROID_DATA
+
/* other handy constants */
constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under ANDROID_DATA
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index d25bf71..74f4264 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -59,6 +59,11 @@
}
}
+static void check_package_name(const char* package_name) {
+ CHECK(is_valid_filename(package_name));
+ CHECK(is_valid_package_name(package_name) == 0);
+}
+
/**
* Create the path name where package app contents should be stored for
* the given volume UUID and package name. An empty UUID is assumed to
@@ -66,9 +71,7 @@
*/
std::string create_data_app_package_path(const char* volume_uuid,
const char* package_name) {
- CHECK(is_valid_filename(package_name));
- CHECK(is_valid_package_name(package_name) == 0);
-
+ check_package_name(package_name);
return StringPrintf("%s/%s",
create_data_app_path(volume_uuid).c_str(), package_name);
}
@@ -80,18 +83,14 @@
*/
std::string create_data_user_package_path(const char* volume_uuid,
userid_t user, const char* package_name) {
- CHECK(is_valid_filename(package_name));
- CHECK(is_valid_package_name(package_name) == 0);
-
+ check_package_name(package_name);
return StringPrintf("%s/%s",
create_data_user_path(volume_uuid, user).c_str(), package_name);
}
std::string create_data_user_de_package_path(const char* volume_uuid,
userid_t user, const char* package_name) {
- CHECK(is_valid_filename(package_name));
- CHECK(is_valid_package_name(package_name) == 0);
-
+ check_package_name(package_name);
return StringPrintf("%s/%s",
create_data_user_de_path(volume_uuid, user).c_str(), package_name);
}
@@ -161,6 +160,20 @@
return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
}
+std::string create_data_user_profiles_path(userid_t userid) {
+ return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
+}
+
+std::string create_data_user_profile_package_path(userid_t user, const char* package_name) {
+ check_package_name(package_name);
+ return StringPrintf("%s/%s",create_data_user_profiles_path(user).c_str(), package_name);
+}
+
+std::string create_data_ref_profile_package_path(const char* package_name) {
+ check_package_name(package_name);
+ return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name);
+}
+
std::vector<userid_t> get_known_users(const char* volume_uuid) {
std::vector<userid_t> users;
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 2d9573e..9bbddca 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -84,6 +84,10 @@
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
+std::string create_data_user_profiles_path(userid_t userid);
+std::string create_data_user_profile_package_path(userid_t user, const char* package_name);
+std::string create_data_ref_profile_package_path(const char* package_name);
+
std::vector<userid_t> get_known_users(const char* volume_uuid);
int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
@@ -135,6 +139,7 @@
char *build_string3(const char *s1, const char *s2, const char *s3);
int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
+int ensure_media_user_dirs(const char* uuid, userid_t userid);
int ensure_config_user_dirs(userid_t userid);
int wait_child(pid_t pid);
diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk
index 7ee0dd1..73c0367 100644
--- a/cmds/servicemanager/Android.mk
+++ b/cmds/servicemanager/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
svc_c_flags = \
- -Wall -Wextra \
+ -Wall -Wextra -Werror \
ifneq ($(TARGET_USES_64_BIT_BINDER),true)
ifneq ($(TARGET_IS_64_BIT),true)
diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c
index fd91633..6466654 100644
--- a/cmds/servicemanager/bctest.c
+++ b/cmds/servicemanager/bctest.c
@@ -58,7 +58,6 @@
int main(int argc, char **argv)
{
- int fd;
struct binder_state *bs;
uint32_t svcmgr = BINDER_SERVICE_MANAGER;
uint32_t handle;
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index 3d14451..9e99085 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -449,7 +449,7 @@
}
void binder_done(struct binder_state *bs,
- struct binder_io *msg,
+ __unused struct binder_io *msg,
struct binder_io *reply)
{
struct {
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 8596f96..21fdff0 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -178,7 +178,7 @@
};
-uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid)
+uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
struct svcinfo *si = find_svc(s, len);
@@ -304,7 +304,7 @@
if (s == NULL) {
return -1;
}
- handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
+ handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
@@ -349,7 +349,7 @@
}
-static int audit_callback(void *data, security_class_t cls, char *buf, size_t len)
+static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len)
{
struct audit_data *ad = (struct audit_data *)data;
@@ -362,7 +362,7 @@
return 0;
}
-int main(int argc, char **argv)
+int main()
{
struct binder_state *bs;
diff --git a/data/etc/android.hardware.vulkan.level-0.xml b/data/etc/android.hardware.vulkan.level-0.xml
new file mode 100644
index 0000000..39c65ac
--- /dev/null
+++ b/data/etc/android.hardware.vulkan.level-0.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device supports Vulkan
+ hardware level 0. -->
+<permissions>
+ <feature name="android.hardware.vulkan.level" version="0" />
+</permissions>
diff --git a/data/etc/android.hardware.vulkan.level-1.xml b/data/etc/android.hardware.vulkan.level-1.xml
new file mode 100644
index 0000000..c3f5513
--- /dev/null
+++ b/data/etc/android.hardware.vulkan.level-1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device supports Vulkan
+ hardware level 1. -->
+<permissions>
+ <feature name="android.hardware.vulkan.level" version="1" />
+</permissions>
diff --git a/data/etc/android.hardware.vulkan.version-1_0_3.xml b/data/etc/android.hardware.vulkan.version-1_0_3.xml
new file mode 100644
index 0000000..adc5a5d
--- /dev/null
+++ b/data/etc/android.hardware.vulkan.version-1_0_3.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device has a Vulkan
+ driver that supports API version 1.0.3 (0x00400003) -->
+<permissions>
+ <feature name="android.hardware.vulkan.version" version="4194307" />
+</permissions>
diff --git a/include/binder/IProcessInfoService.h b/include/binder/IProcessInfoService.h
index 34ce0f0..69dc9a7 100644
--- a/include/binder/IProcessInfoService.h
+++ b/include/binder/IProcessInfoService.h
@@ -44,16 +44,6 @@
// ----------------------------------------------------------------------
-class BnProcessInfoService : public BnInterface<IProcessInfoService> {
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
}; // namespace android
#endif // ANDROID_I_PROCESS_INFO_SERVICE_H
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index a515f39..6f45181 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -119,8 +119,10 @@
// previous frame
Region mSurfaceDamage;
- // Indicates that the BufferQueue is in single buffer mode
- bool mSingleBufferMode;
+ // Indicates that the consumer should acquire the next frame as soon as it
+ // can and not wait for a frame to become available. This is only relevant
+ // in single buffer mode.
+ bool mAutoRefresh;
// Indicates that this buffer was queued by the producer. When in single
// buffer mode acquire() can return a BufferItem that wasn't in the queue.
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 7b90aa1..2645d09 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -294,6 +294,11 @@
// consumer and producer to access the same buffer simultaneously.
bool mSingleBufferMode;
+ // When single buffer mode is enabled, this indicates whether the consumer
+ // should acquire buffers even if BufferQueue doesn't indicate that they are
+ // available.
+ bool mAutoRefresh;
+
// When single buffer mode is enabled, this tracks which slot contains the
// shared buffer.
int mSingleBufferSlot;
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index dc05e98..312f323 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -176,6 +176,9 @@
// See IGraphicBufferProducer::setSingleBufferMode
virtual status_t setSingleBufferMode(bool singleBufferMode) override;
+ // See IGraphicBufferProducer::setAutoRefresh
+ virtual status_t setAutoRefresh(bool autoRefresh) override;
+
// See IGraphicBufferProducer::setDequeueTimeout
virtual status_t setDequeueTimeout(nsecs_t timeout) override;
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 9307a26..1b63552 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -26,6 +26,8 @@
#include <utils/threads.h>
#include <gui/IConsumerListener.h>
+#include <queue>
+
namespace android {
// ----------------------------------------------------------------------------
@@ -108,18 +110,18 @@
// from the derived class.
virtual void onLastStrongRef(const void* id);
- // Implementation of the IConsumerListener interface. These
- // calls are used to notify the ConsumerBase of asynchronous events in the
- // BufferQueue. The onFrameAvailable, onFrameReplaced, and
- // onBuffersReleased methods should not need to be overridden by derived
- // classes, but if they are overridden the ConsumerBase implementation must
- // be called from the derived class. The ConsumerBase version of
- // onSidebandStreamChanged does nothing and can be overriden by derived
- // classes if they want the notification.
- virtual void onFrameAvailable(const BufferItem& item) override;
- virtual void onFrameReplaced(const BufferItem& item) override;
- virtual void onBuffersReleased() override;
- virtual void onSidebandStreamChanged() override;
+ // Handlers for the IConsumerListener interface, these will be called from
+ // the message queue thread. These calls are used to notify the ConsumerBase
+ // of asynchronous events in the BufferQueue. The onFrameAvailableHandler,
+ // onFrameReplacedHandler, and onBuffersReleasedHandler methods should not
+ // need to be overridden by derived classes, but if they are overridden the
+ // ConsumerBase implementation must be called from the derived class. The
+ // ConsumerBase version of onSidebandStreamChangedHandler does nothing and
+ // can be overriden by derived classes if they want the notification.
+ virtual void onFrameAvailableHandler(const BufferItem& item);
+ virtual void onFrameReplacedHandler(const BufferItem& item);
+ virtual void onBuffersReleasedHandler();
+ virtual void onSidebandStreamChangedHandler();
// freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in that
@@ -244,6 +246,35 @@
//
// This mutex is intended to be locked by derived classes.
mutable Mutex mMutex;
+
+ // Implements the ConsumerListener interface
+ virtual void onFrameAvailable(const BufferItem& item) override;
+ virtual void onFrameReplaced(const BufferItem& item) override;
+ virtual void onBuffersReleased() override;
+ virtual void onSidebandStreamChanged() override;
+
+ enum MessageType {
+ ON_FRAME_AVAILABLE,
+ ON_FRAME_REPLACED,
+ ON_BUFFERS_RELEASED,
+ ON_SIDEBAND_STREAM_CHANGED,
+ EXIT,
+ };
+
+ mutable Mutex mMessageQueueLock;
+ Condition mMessageAvailable;
+ std::queue<std::pair<MessageType, BufferItem>> mMessageQueue;
+
+ class MessageThread : public Thread {
+ public:
+ MessageThread(ConsumerBase* consumerBase) :
+ mConsumerBase(consumerBase) {};
+ protected:
+ virtual bool threadLoop() override;
+ ConsumerBase* mConsumerBase;
+ };
+
+ sp<MessageThread> mMessageThread;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 0e4acee..61f631f 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -253,10 +253,25 @@
static bool isExternalFormat(PixelFormat format);
+ struct PendingRelease {
+ PendingRelease() : isPending(false), currentTexture(-1),
+ graphicBuffer(), display(nullptr), fence(nullptr) {}
+
+ bool isPending;
+ int currentTexture;
+ sp<GraphicBuffer> graphicBuffer;
+ EGLDisplay display;
+ EGLSyncKHR fence;
+ };
+
// This releases the buffer in the slot referenced by mCurrentTexture,
// then updates state to refer to the BufferItem, which must be a
- // newly-acquired buffer.
- status_t updateAndReleaseLocked(const BufferItem& item);
+ // newly-acquired buffer. If pendingRelease is not null, the parameters
+ // which would have been passed to releaseBufferLocked upon the successful
+ // completion of the method will instead be returned to the caller, so that
+ // it may call releaseBufferLocked itself later.
+ status_t updateAndReleaseLocked(const BufferItem& item,
+ PendingRelease* pendingRelease = nullptr);
// Binds mTexName and the current buffer to mTexTarget. Uses
// mCurrentTexture if it's set, mCurrentTextureImage if not. If the
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 265728f..f6b4230 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -531,6 +531,14 @@
// the producer and consumer to simultaneously access the same buffer.
virtual status_t setSingleBufferMode(bool singleBufferMode) = 0;
+ // Used to enable/disable auto-refresh.
+ //
+ // Auto refresh has no effect outside of single buffer mode. In single
+ // buffer mode, when enabled, it indicates to the consumer that it should
+ // attempt to acquire buffers even if it is not aware of any being
+ // available.
+ virtual status_t setAutoRefresh(bool autoRefresh) = 0;
+
// Sets how long dequeueBuffer will wait for a buffer to become available
// before returning an error (TIMED_OUT).
//
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index f79210b..3afdaae 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -168,6 +168,7 @@
int dispatchSetBuffersDataSpace(va_list args);
int dispatchSetSurfaceDamage(va_list args);
int dispatchSetSingleBufferMode(va_list args);
+ int dispatchSetAutoRefresh(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
@@ -197,6 +198,7 @@
virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers);
virtual int setAsyncMode(bool async);
virtual int setSingleBufferMode(bool singleBufferMode);
+ virtual int setAutoRefresh(bool autoRefresh);
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
virtual int unlockAndPost();
@@ -331,6 +333,19 @@
// Stores the current generation number. See setGenerationNumber and
// IGraphicBufferProducer::setGenerationNumber for more information.
uint32_t mGenerationNumber;
+
+ // Caches the values that have been passed to the producer.
+ bool mSingleBufferMode;
+ bool mAutoRefresh;
+
+ // If in single buffer mode and auto refresh is enabled, store the shared
+ // buffer slot and return it for all calls to queue/dequeue without going
+ // over Binder.
+ int mSharedBufferSlot;
+
+ // This is true if the shared buffer has already been queued/canceled. It's
+ // used to prevent a mismatch between the number of queue/dequeue calls.
+ bool mSharedBufferHasBeenQueued;
};
}; // namespace android
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index e4d8201..9a061a0 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -28,7 +28,7 @@
static const sp<IBinder>& getToken(const sp<IAppOpsService>& service) {
pthread_mutex_lock(&gTokenMutex);
- if (gToken == NULL) {
+ if (gToken == NULL || gToken->pingBinder() != NO_ERROR) {
gToken = service->getToken(new BBinder());
}
pthread_mutex_unlock(&gTokenMutex);
diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp
index c37920d..76508b8 100644
--- a/libs/binder/IProcessInfoService.cpp
+++ b/libs/binder/IProcessInfoService.cpp
@@ -88,72 +88,4 @@
// ----------------------------------------------------------------------
-status_t BnProcessInfoService::onTransact( uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags) {
- switch(code) {
- case GET_PROCESS_STATES_FROM_PIDS: {
- CHECK_INTERFACE(IProcessInfoService, data, reply);
- int32_t arrayLen = data.readInt32();
- if (arrayLen <= 0) {
- reply->writeNoException();
- reply->writeInt32(0);
- reply->writeInt32(NOT_ENOUGH_DATA);
- return NO_ERROR;
- }
-
- size_t len = static_cast<size_t>(arrayLen);
- int32_t pids[len];
- status_t res = data.read(pids, len * sizeof(*pids));
-
- // Ignore output array length returned in the parcel here, as the states array must
- // always be the same length as the input PIDs array.
- int32_t states[len];
- for (size_t i = 0; i < len; i++) states[i] = -1;
- if (res == NO_ERROR) {
- res = getProcessStatesFromPids(len, /*in*/ pids, /*out*/ states);
- }
- reply->writeNoException();
- reply->writeInt32Array(len, states);
- reply->writeInt32(res);
- return NO_ERROR;
- } break;
- case GET_PROCESS_STATES_AND_OOM_SCORES_FROM_PIDS: {
- CHECK_INTERFACE(IProcessInfoService, data, reply);
- int32_t arrayLen = data.readInt32();
- if (arrayLen <= 0) {
- reply->writeNoException();
- reply->writeInt32(0);
- reply->writeInt32(NOT_ENOUGH_DATA);
- return NO_ERROR;
- }
-
- size_t len = static_cast<size_t>(arrayLen);
- int32_t pids[len];
- status_t res = data.read(pids, len * sizeof(*pids));
-
- // Ignore output array length returned in the parcel here, as the
- // states array must always be the same length as the input PIDs array.
- int32_t states[len];
- int32_t scores[len];
- for (size_t i = 0; i < len; i++) {
- states[i] = -1;
- scores[i] = -10000;
- }
- if (res == NO_ERROR) {
- res = getProcessStatesAndOomScoresFromPids(
- len, /*in*/ pids, /*out*/ states, /*out*/ scores);
- }
- reply->writeNoException();
- reply->writeInt32Array(len, states);
- reply->writeInt32Array(len, scores);
- reply->writeInt32(res);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------
-
}; // namespace android
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 036ef1e..5e3924a 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -38,7 +38,7 @@
mAcquireCalled(false),
mTransformToDisplayInverse(false),
mSurfaceDamage(),
- mSingleBufferMode(false),
+ mAutoRefresh(false),
mQueuedBuffer(true),
mIsStale(false) {
}
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index b025280..aacbed5 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -32,6 +32,10 @@
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
@@ -67,7 +71,7 @@
}
bool sharedBufferAvailable = mCore->mSingleBufferMode &&
- mCore->mSingleBufferSlot !=
+ mCore->mAutoRefresh && mCore->mSingleBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT;
// In asynchronous mode the list is guaranteed to be one buffer deep,
@@ -214,16 +218,15 @@
(mCore->mSingleBufferCache.transform &
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
outBuffer->mSurfaceDamage = Region::INVALID_REGION;
- outBuffer->mSingleBufferMode = true;
outBuffer->mQueuedBuffer = false;
outBuffer->mIsStale = false;
+ outBuffer->mAutoRefresh = mCore->mSingleBufferMode &&
+ mCore->mAutoRefresh;
} else {
slot = front->mSlot;
*outBuffer = *front;
}
- outBuffer->mSingleBufferMode = mCore->mSingleBufferMode;
-
ATRACE_BUFFER_INDEX(slot);
BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
@@ -748,7 +751,18 @@
}
void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
- mCore->dump(result, prefix);
+ const IPCThreadState* ipc = IPCThreadState::self();
+ const pid_t pid = ipc->getCallingPid();
+ const uid_t uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL)
+ && !PermissionCache::checkPermission(String16(
+ "android.permission.DUMP"), pid, uid)) {
+ result.appendFormat("Permission Denial: can't dump BufferQueueConsumer "
+ "from pid=%d, uid=%d\n", pid, uid);
+ android_errorWriteWithInfoLog(0x534e4554, "27046057", uid, NULL, 0);
+ } else {
+ mCore->dump(result, prefix);
+ }
}
} // namespace android
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index df7376e..fc3ffed 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -79,6 +79,7 @@
mGenerationNumber(0),
mAsyncMode(false),
mSingleBufferMode(false),
+ mAutoRefresh(false),
mSingleBufferSlot(INVALID_BUFFER_SLOT),
mSingleBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
HAL_DATASPACE_UNKNOWN)
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 46e7591..cb5d773 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -870,8 +870,8 @@
mCore->mDequeueBufferCannotBlock ||
(mCore->mSingleBufferMode && mCore->mSingleBufferSlot == slot);
item.mSurfaceDamage = surfaceDamage;
- item.mSingleBufferMode = mCore->mSingleBufferMode;
item.mQueuedBuffer = true;
+ item.mAutoRefresh = mCore->mSingleBufferMode && mCore->mAutoRefresh;
mStickyTransform = stickyTransform;
@@ -1393,6 +1393,16 @@
return NO_ERROR;
}
+status_t BufferQueueProducer::setAutoRefresh(bool autoRefresh) {
+ ATRACE_CALL();
+ BQ_LOGV("setAutoRefresh: %d", autoRefresh);
+
+ Mutex::Autolock lock(mCore->mMutex);
+
+ mCore->mAutoRefresh = autoRefresh;
+ return NO_ERROR;
+}
+
status_t BufferQueueProducer::setDequeueTimeout(nsecs_t timeout) {
ATRACE_CALL();
BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index d01187f..a22b81b 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -74,12 +74,26 @@
} else {
mConsumer->setConsumerName(mName);
}
+
+ mMessageThread = new MessageThread(this);
+ mMessageThread->run();
}
ConsumerBase::~ConsumerBase() {
CB_LOGV("~ConsumerBase");
- Mutex::Autolock lock(mMutex);
+ mMessageThread->requestExit();
+ {
+ Mutex::Autolock lock(mMessageQueueLock);
+ mMessageQueue.emplace(std::piecewise_construct,
+ std::forward_as_tuple(EXIT),
+ std::forward_as_tuple());
+ mMessageAvailable.signal();
+ }
+
+ mMessageThread->join();
+
+ Mutex::Autolock lock(mMutex);
// Verify that abandon() has been called before we get here. This should
// be done by ConsumerBase::onLastStrongRef(), but it's possible for a
// derived class to override that method and not call
@@ -100,6 +114,13 @@
}
void ConsumerBase::onFrameAvailable(const BufferItem& item) {
+ Mutex::Autolock lock(mMessageQueueLock);
+ mMessageQueue.emplace(std::piecewise_construct,
+ std::forward_as_tuple(ON_FRAME_AVAILABLE),
+ std::forward_as_tuple(item));
+ mMessageAvailable.signal();
+}
+void ConsumerBase::onFrameAvailableHandler(const BufferItem& item) {
CB_LOGV("onFrameAvailable");
sp<FrameAvailableListener> listener;
@@ -115,6 +136,14 @@
}
void ConsumerBase::onFrameReplaced(const BufferItem &item) {
+ Mutex::Autolock lock(mMessageQueueLock);
+ mMessageQueue.emplace(std::piecewise_construct,
+ std::forward_as_tuple(ON_FRAME_REPLACED),
+ std::forward_as_tuple(item));
+ mMessageAvailable.signal();
+}
+
+void ConsumerBase::onFrameReplacedHandler(const BufferItem &item) {
CB_LOGV("onFrameReplaced");
sp<FrameAvailableListener> listener;
@@ -130,6 +159,14 @@
}
void ConsumerBase::onBuffersReleased() {
+ Mutex::Autolock lock(mMessageQueueLock);
+ mMessageQueue.emplace(std::piecewise_construct,
+ std::forward_as_tuple(ON_BUFFERS_RELEASED),
+ std::forward_as_tuple());
+ mMessageAvailable.signal();
+}
+
+void ConsumerBase::onBuffersReleasedHandler() {
Mutex::Autolock lock(mMutex);
CB_LOGV("onBuffersReleased");
@@ -149,6 +186,45 @@
}
void ConsumerBase::onSidebandStreamChanged() {
+ Mutex::Autolock lock(mMessageQueueLock);
+ mMessageQueue.emplace(std::piecewise_construct,
+ std::forward_as_tuple(ON_SIDEBAND_STREAM_CHANGED),
+ std::forward_as_tuple());
+ mMessageAvailable.signal();
+}
+
+void ConsumerBase::onSidebandStreamChangedHandler() {
+}
+
+bool ConsumerBase::MessageThread::threadLoop() {
+ Mutex::Autolock lock(mConsumerBase->mMessageQueueLock);
+
+ if (mConsumerBase->mMessageQueue.empty()) {
+ mConsumerBase->mMessageAvailable.wait(mConsumerBase->mMessageQueueLock);
+ }
+
+ while (!mConsumerBase->mMessageQueue.empty()) {
+ auto nextMessage = mConsumerBase->mMessageQueue.front();
+
+ switch (nextMessage.first) {
+ case ON_FRAME_AVAILABLE:
+ mConsumerBase->onFrameAvailableHandler(nextMessage.second);
+ break;
+ case ON_FRAME_REPLACED:
+ mConsumerBase->onFrameReplacedHandler(nextMessage.second);
+ break;
+ case ON_BUFFERS_RELEASED:
+ mConsumerBase->onBuffersReleasedHandler();
+ break;
+ case ON_SIDEBAND_STREAM_CHANGED:
+ mConsumerBase->onSidebandStreamChangedHandler();
+ break;
+ case EXIT:
+ break;
+ }
+ mConsumerBase->mMessageQueue.pop();
+ }
+ return true;
}
void ConsumerBase::abandon() {
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index e1abd45..149f5bd 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -370,7 +370,8 @@
return err;
}
-status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item)
+status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item,
+ PendingRelease* pendingRelease)
{
status_t err = NO_ERROR;
@@ -407,7 +408,7 @@
}
// Do whatever sync ops we need to do before releasing the old slot.
- if (!item.mSingleBufferMode || slot != mCurrentTexture) {
+ if (slot != mCurrentTexture) {
err = syncForReleaseLocked(mEglDisplay);
if (err != NO_ERROR) {
// Release the buffer we just acquired. It's not safe to
@@ -432,14 +433,23 @@
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- status_t status = releaseBufferLocked(
- mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
- mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
- if (status < NO_ERROR) {
- GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
- strerror(-status), status);
- err = status;
- // keep going, with error raised [?]
+ if (pendingRelease == nullptr) {
+ status_t status = releaseBufferLocked(
+ mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
+ mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
+ if (status < NO_ERROR) {
+ GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
+ strerror(-status), status);
+ err = status;
+ // keep going, with error raised [?]
+ }
+ } else {
+ pendingRelease->currentTexture = mCurrentTexture;
+ pendingRelease->graphicBuffer =
+ mCurrentTextureImage->graphicBuffer();
+ pendingRelease->display = mEglDisplay;
+ pendingRelease->fence = mEglSlots[mCurrentTexture].mEglFence;
+ pendingRelease->isPending = true;
}
}
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 2478601..c66694d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -52,6 +52,7 @@
SET_ASYNC_MODE,
GET_NEXT_FRAME_NUMBER,
SET_SINGLE_BUFFER_MODE,
+ SET_AUTO_REFRESH,
SET_DEQUEUE_TIMEOUT,
};
@@ -355,6 +356,18 @@
return result;
}
+ virtual status_t setAutoRefresh(bool autoRefresh) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeInt32(autoRefresh);
+ status_t result = remote()->transact(SET_AUTO_REFRESH, data, &reply);
+ if (result == NO_ERROR) {
+ result = reply.readInt32();
+ }
+ return result;
+ }
+
virtual status_t setDequeueTimeout(nsecs_t timeout) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
@@ -562,6 +575,13 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case SET_AUTO_REFRESH: {
+ CHECK_INTERFACE(IGraphicBuffer, data, reply);
+ bool autoRefresh = data.readInt32();
+ status_t result = setAutoRefresh(autoRefresh);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
case SET_DEQUEUE_TIMEOUT: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
nsecs_t timeout = data.readInt64();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index ebbeae6..c295684 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -44,7 +44,11 @@
bool controlledByApp)
: mGraphicBufferProducer(bufferProducer),
mCrop(Rect::EMPTY_RECT),
- mGenerationNumber(0)
+ mGenerationNumber(0),
+ mSingleBufferMode(false),
+ mAutoRefresh(false),
+ mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
+ mSharedBufferHasBeenQueued(false)
{
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
@@ -232,6 +236,16 @@
reqFormat = mReqFormat;
reqUsage = mReqUsage;
+
+ if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot !=
+ BufferItem::INVALID_BUFFER_SLOT) {
+ sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
+ if (gbuf != NULL) {
+ *buffer = gbuf.get();
+ *fenceFd = -1;
+ return OK;
+ }
+ }
} // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer
int buf = -1;
@@ -279,6 +293,15 @@
}
*buffer = gbuf.get();
+
+ if (mSingleBufferMode && mAutoRefresh) {
+ mSharedBufferSlot = buf;
+ mSharedBufferHasBeenQueued = false;
+ } else if (mSharedBufferSlot == buf) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ mSharedBufferHasBeenQueued = false;
+ }
+
return OK;
}
@@ -294,8 +317,19 @@
}
return i;
}
+ if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) {
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
mGraphicBufferProducer->cancelBuffer(i, fence);
+
+ if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot == i) {
+ mSharedBufferHasBeenQueued = true;
+ }
+
return OK;
}
@@ -323,6 +357,7 @@
Mutex::Autolock lock(mMutex);
int64_t timestamp;
bool isAutoTimestamp = false;
+
if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
isAutoTimestamp = true;
@@ -338,6 +373,12 @@
}
return i;
}
+ if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) {
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
// Make sure the crop rectangle is entirely inside the buffer.
@@ -417,6 +458,7 @@
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
}
+
uint32_t numPendingBuffers = 0;
uint32_t hint = 0;
output.deflate(&mDefaultWidth, &mDefaultHeight, &hint,
@@ -434,6 +476,10 @@
mDirtyRegion = Region::INVALID_REGION;
}
+ if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot == i) {
+ mSharedBufferHasBeenQueued = true;
+ }
+
return err;
}
@@ -557,6 +603,9 @@
case NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE:
res = dispatchSetSingleBufferMode(args);
break;
+ case NATIVE_WINDOW_SET_AUTO_REFRESH:
+ res = dispatchSetAutoRefresh(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -669,8 +718,12 @@
int Surface::dispatchSetSingleBufferMode(va_list args) {
bool singleBufferMode = va_arg(args, int);
- setSingleBufferMode(singleBufferMode);
- return NO_ERROR;
+ return setSingleBufferMode(singleBufferMode);
+}
+
+int Surface::dispatchSetAutoRefresh(va_list args) {
+ bool autoRefresh = va_arg(args, int);
+ return setAutoRefresh(autoRefresh);
}
int Surface::connect(int api) {
@@ -714,6 +767,8 @@
ATRACE_CALL();
ALOGV("Surface::disconnect");
Mutex::Autolock lock(mMutex);
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ mSharedBufferHasBeenQueued = false;
freeAllBuffers();
int err = mGraphicBufferProducer->disconnect(api);
if (!err) {
@@ -796,6 +851,9 @@
{
ALOGV("Surface::setUsage");
Mutex::Autolock lock(mMutex);
+ if (reqUsage != mReqUsage) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mReqUsage = reqUsage;
return OK;
}
@@ -876,12 +934,29 @@
status_t err = mGraphicBufferProducer->setSingleBufferMode(
singleBufferMode);
- ALOGE_IF(err, "IGraphicsBufferProducer::setSingleBufferMode(%d) returned"
+ if (err == NO_ERROR) {
+ mSingleBufferMode = singleBufferMode;
+ }
+ ALOGE_IF(err, "IGraphicBufferProducer::setSingleBufferMode(%d) returned"
"%s", singleBufferMode, strerror(-err));
return err;
}
+int Surface::setAutoRefresh(bool autoRefresh) {
+ ATRACE_CALL();
+ ALOGV("Surface::setAutoRefresh (%d)", autoRefresh);
+ Mutex::Autolock lock(mMutex);
+
+ status_t err = mGraphicBufferProducer->setAutoRefresh(autoRefresh);
+ if (err == NO_ERROR) {
+ mAutoRefresh = autoRefresh;
+ }
+ ALOGE_IF(err, "IGraphicBufferProducer::setAutoRefresh(%d) returned %s",
+ autoRefresh, strerror(-err));
+ return err;
+}
+
int Surface::setBuffersDimensions(uint32_t width, uint32_t height)
{
ATRACE_CALL();
@@ -891,6 +966,9 @@
return BAD_VALUE;
Mutex::Autolock lock(mMutex);
+ if (width != mReqWidth || height != mReqHeight) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mReqWidth = width;
mReqHeight = height;
return NO_ERROR;
@@ -905,6 +983,9 @@
return BAD_VALUE;
Mutex::Autolock lock(mMutex);
+ if (width != mUserWidth || height != mUserHeight) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mUserWidth = width;
mUserHeight = height;
return NO_ERROR;
@@ -915,6 +996,9 @@
ALOGV("Surface::setBuffersFormat");
Mutex::Autolock lock(mMutex);
+ if (format != mReqFormat) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mReqFormat = format;
return NO_ERROR;
}
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index f4c47ed..b6af166 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -65,6 +65,27 @@
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
}
+ void testBufferItem(const IGraphicBufferProducer::QueueBufferInput& input,
+ const BufferItem& item) {
+ int64_t timestamp;
+ bool isAutoTimestamp;
+ android_dataspace dataSpace;
+ Rect crop;
+ int scalingMode;
+ uint32_t transform;
+ sp<Fence> fence;
+
+ input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop,
+ &scalingMode, &transform, &fence, NULL);
+ ASSERT_EQ(timestamp, item.mTimestamp);
+ ASSERT_EQ(isAutoTimestamp, item.mIsAutoTimestamp);
+ ASSERT_EQ(dataSpace, item.mDataSpace);
+ ASSERT_EQ(crop, item.mCrop);
+ ASSERT_EQ(static_cast<uint32_t>(scalingMode), item.mScalingMode);
+ ASSERT_EQ(transform, item.mTransform);
+ ASSERT_EQ(fence, item.mFence);
+ }
+
sp<IGraphicBufferProducer> mProducer;
sp<IGraphicBufferConsumer> mConsumer;
};
@@ -521,7 +542,7 @@
ASSERT_EQ(OK, mConsumer->attachBuffer(&outSlot, buffer));
}
-TEST_F(BufferQueueTest, TestSingleBufferMode) {
+TEST_F(BufferQueueTest, TestSingleBufferModeWithoutAutoRefresh) {
createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
@@ -545,19 +566,66 @@
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+ // Repeatedly queue and dequeue a buffer from the producer side, it should
+ // always return the same one. And we won't run out of buffers because it's
+ // always the same one and because async mode gets enabled.
+ int slot;
+ for (int i = 0; i < 5; i++) {
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+ ASSERT_EQ(singleSlot, slot);
+ ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+ }
+
+ // acquire the buffer
+ BufferItem item;
+ ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+ ASSERT_EQ(singleSlot, item.mSlot);
+ testBufferItem(input, item);
+ ASSERT_EQ(true, item.mQueuedBuffer);
+ ASSERT_EQ(false, item.mAutoRefresh);
+
+ ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+ // attempt to acquire a second time should return no buffer available
+ ASSERT_EQ(IGraphicBufferConsumer::NO_BUFFER_AVAILABLE,
+ mConsumer->acquireBuffer(&item, 0));
+}
+
+TEST_F(BufferQueueTest, TestSingleBufferModeWithAutoRefresh) {
+ createBufferQueue();
+ sp<DummyConsumer> dc(new DummyConsumer);
+ ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+ NATIVE_WINDOW_API_CPU, true, &output));
+
+ ASSERT_EQ(OK, mProducer->setSingleBufferMode(true));
+ ASSERT_EQ(OK, mProducer->setAutoRefresh(true));
+
+ // Get a buffer
+ int singleSlot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buffer;
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(&singleSlot, &fence, 0, 0, 0, 0));
+ ASSERT_EQ(OK, mProducer->requestBuffer(singleSlot, &buffer));
+
+ // Queue the buffer
+ IGraphicBufferProducer::QueueBufferInput input(0, false,
+ HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+ ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+
// Repeatedly acquire and release a buffer from the consumer side, it should
// always return the same one.
BufferItem item;
for (int i = 0; i < 5; i++) {
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
ASSERT_EQ(singleSlot, item.mSlot);
- ASSERT_EQ(0, item.mTimestamp);
- ASSERT_EQ(false, item.mIsAutoTimestamp);
- ASSERT_EQ(HAL_DATASPACE_UNKNOWN, item.mDataSpace);
- ASSERT_EQ(Rect(0, 0, 1, 1), item.mCrop);
- ASSERT_EQ(NATIVE_WINDOW_SCALING_MODE_FREEZE, item.mScalingMode);
- ASSERT_EQ(0u, item.mTransform);
- ASSERT_EQ(Fence::NO_FENCE, item.mFence);
+ testBufferItem(input, item);
+ ASSERT_EQ(i == 0, item.mQueuedBuffer);
+ ASSERT_EQ(true, item.mAutoRefresh);
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
@@ -585,6 +653,8 @@
ASSERT_EQ(NATIVE_WINDOW_SCALING_MODE_FREEZE, item.mScalingMode);
ASSERT_EQ(0u, item.mTransform);
ASSERT_EQ(Fence::NO_FENCE, item.mFence);
+ ASSERT_EQ(i == 0, item.mQueuedBuffer);
+ ASSERT_EQ(true, item.mAutoRefresh);
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
index c28b4d1..b8a7a90 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
@@ -192,6 +192,10 @@
ASSERT_EQ(EGL_SUCCESS, eglGetError());
mProducerEglSurface = EGL_NO_SURFACE;
+ // sleep for 10ms to allow any asynchronous operations to complete before
+ // checking the reference counts
+ usleep(10000);
+
// This test should have the only reference to buffer 0.
EXPECT_EQ(1, buffers[0]->getStrongCount());
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index fe649fb..0627ca6 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -608,7 +608,7 @@
return NULL;
}
if (numKeys > MAX_KEYS) {
- ALOGE("Too many keys in KeyCharacterMap (%d > %d)", numKeys, MAX_KEYS);
+ ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
return NULL;
}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index e593a72..49f501d 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -92,7 +92,7 @@
return -1;
/* We are in the emulator, get GPU status value */
- property_get("ro.kernel.qemu.gles",prop,"0");
+ property_get("qemu.gles",prop,"0");
return atoi(prop);
}
@@ -174,11 +174,45 @@
#endif
#endif
+static void setEmulatorGlesValue(void) {
+ char prop[PROPERTY_VALUE_MAX];
+ property_get("ro.kernel.qemu", prop, "0");
+ if (atoi(prop) != 1) return;
+
+ property_get("ro.kernel.qemu.gles",prop,"0");
+ if (atoi(prop) == 1) {
+ ALOGD("Emulator has host GPU support, qemu.gles is set to 1.");
+ property_set("qemu.gles", "1");
+ return;
+ }
+
+ // for now, checking the following
+ // directory is good enough for emulator system images
+ const char* vendor_lib_path =
+#if defined(__LP64__)
+ "/vendor/lib64/egl";
+#else
+ "/vendor/lib/egl";
+#endif
+
+ const bool has_vendor_lib = (access(vendor_lib_path, R_OK) == 0);
+ if (has_vendor_lib) {
+ ALOGD("Emulator has vendor provided software renderer, qemu.gles is set to 2.");
+ property_set("qemu.gles", "2");
+ } else {
+ ALOGD("Emulator without GPU support detected. "
+ "Fallback to legacy software renderer, qemu.gles is set to 0.");
+ property_set("qemu.gles", "0");
+ }
+}
+
void* Loader::open(egl_connection_t* cnx)
{
void* dso;
driver_t* hnd = 0;
+ setEmulatorGlesValue();
+
dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2);
if (dso) {
hnd = new driver_t(dso);
@@ -280,8 +314,6 @@
int emulationStatus = checkGlesEmulationStatus();
switch (emulationStatus) {
case 0:
- ALOGD("Emulator without GPU support detected. "
- "Fallback to legacy software renderer.");
#if defined(__LP64__)
result.setTo("/system/lib64/egl/libGLES_android.so");
#else
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index c7e2afb..05700f8 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1197,6 +1197,7 @@
//XXX: temporary hack for the EGL hook-up for single buffer mode
if (attribute == EGL_RENDER_BUFFER && (value == EGL_BACK_BUFFER ||
value == EGL_SINGLE_BUFFER)) {
+ native_window_set_auto_refresh(s->win.get(), true);
return (native_window_set_single_buffer_mode(s->win.get(),
value == EGL_SINGLE_BUFFER)) ? EGL_TRUE : EGL_FALSE;
}
diff --git a/opengl/tools/glgen/specs/gles11/GLES30.spec b/opengl/tools/glgen/specs/gles11/GLES30.spec
index a426eb0..f190fc0 100644
--- a/opengl/tools/glgen/specs/gles11/GLES30.spec
+++ b/opengl/tools/glgen/specs/gles11/GLES30.spec
@@ -108,3 +108,4 @@
void glTexStorage2D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height )
void glTexStorage3D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth )
void glGetInternalformativ ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params )
+void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint offset )
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
index 47f232d..aa0d2a4 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
@@ -118,22 +118,35 @@
static void
android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
(JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "deprecated");
+}
+
+/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
+static void
+android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2
+ (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jobject name_buf) {
jintArray _lengthArray = (jintArray) 0;
jint _lengthBufferOffset = (jint) 0;
jintArray _sizeArray = (jintArray) 0;
jint _sizeBufferOffset = (jint) 0;
jintArray _typeArray = (jintArray) 0;
jint _typeBufferOffset = (jint) 0;
+ jbyteArray _nameArray = (jbyteArray)0;
+ jint _nameBufferOffset = (jint)0;
jint _lengthRemaining;
GLsizei *length = (GLsizei *) 0;
jint _sizeRemaining;
GLint *size = (GLint *) 0;
jint _typeRemaining;
GLenum *type = (GLenum *) 0;
+ jint _nameRemaining;
+ GLchar* name = (GLchar*)0;
+
length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
+ name = (GLchar*)getPointer(_env, name_buf, (jarray*)&_nameArray, &_nameRemaining, &_nameBufferOffset);
if (length == NULL) {
char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
@@ -146,6 +159,10 @@
char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
type = (GLenum *) (_typeBase + _typeBufferOffset);
}
+ if (name == NULL) {
+ char* _nameBase = (char *)_env->GetByteArrayElements(_nameArray, (jboolean*)0);
+ name = (GLchar *) (_nameBase + _nameBufferOffset);
+ }
glGetTransformFeedbackVarying(
(GLuint)program,
(GLuint)index,
@@ -153,11 +170,7 @@
(GLsizei *)length,
(GLint *)size,
(GLenum *)type,
- // The cast below is incorrect. The driver will end up writing to the
- // address specified by name, which will always crash the process since
- // it is guaranteed to be in low memory. The additional static_cast
- // suppresses the warning for now. http://b/19478262
- (char *)static_cast<uintptr_t>(name)
+ (GLchar*)name
);
if (_typeArray) {
releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
@@ -168,6 +181,9 @@
if (_lengthArray) {
releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
}
+ if (_nameArray) {
+ releaseArrayPointer<jbyteArray, jbyte*, ByteArrayReleaser>(_env, _nameArray, (jbyte*)name, JNI_TRUE);
+ }
}
/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java
index f73bbfe..e54359d 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java
@@ -15,7 +15,10 @@
);
// C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
-
+ /**
+ * @deprecated
+ * Use the version that takes a ByteBuffer as the last argument, or the versions that return a String.
+ * */
public static native void glGetTransformFeedbackVarying(
int program,
int index,
@@ -28,6 +31,18 @@
// C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+ public static native void glGetTransformFeedbackVarying(
+ int program,
+ int index,
+ int bufsize,
+ java.nio.IntBuffer length,
+ java.nio.IntBuffer size,
+ java.nio.IntBuffer type,
+ java.nio.ByteBuffer name
+ );
+
+ // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+
public static native String glGetTransformFeedbackVarying(
int program,
int index,
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg
index 412d04c..7f5829b 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg
@@ -1,4 +1,5 @@
{"glGetTransformFeedbackVarying", "(III[II[II[II[BI)V", (void *) android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI },
{"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B },
+{"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 },
{"glGetTransformFeedbackVarying", "(II[II[II)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying1 },
{"glGetTransformFeedbackVarying", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying2 },
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index d84ce42..ef17630 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -20,6 +20,8 @@
LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
+LOCAL_CFLAGS += -Wall -Werror
+
LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_SHARED_LIBRARIES := \
diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp
index 359d289..e92b23d 100644
--- a/services/sensorservice/Fusion.cpp
+++ b/services/sensorservice/Fusion.cpp
@@ -72,8 +72,6 @@
*/
static const float NOMINAL_GRAVITY = 9.81f;
static const float FREE_FALL_THRESHOLD = 0.1f * (NOMINAL_GRAVITY);
-static const float FREE_FALL_THRESHOLD_SQ =
- FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD;
/*
* The geomagnetic-field should be between 30uT and 60uT.
@@ -104,7 +102,6 @@
static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ =
MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG;
-static const float W_EPS = 1e-4f;
static const float SQRT_3 = 1.732f;
static const float WVEC_EPS = 1e-4f/SQRT_3;
// -----------------------------------------------------------------------
diff --git a/services/sensorservice/MostRecentEventLogger.cpp b/services/sensorservice/MostRecentEventLogger.cpp
index 0bd0e17..a5d8456 100644
--- a/services/sensorservice/MostRecentEventLogger.cpp
+++ b/services/sensorservice/MostRecentEventLogger.cpp
@@ -16,10 +16,12 @@
#include "MostRecentEventLogger.h"
+#include <inttypes.h>
+
namespace android {
SensorService::MostRecentEventLogger::MostRecentEventLogger(int sensorType) :
- mSensorType(sensorType), mNextInd(0) {
+ mNextInd(0), mSensorType(sensorType) {
mBufSize = (sensorType == SENSOR_TYPE_STEP_COUNTER ||
sensorType == SENSOR_TYPE_SIGNIFICANT_MOTION ||
@@ -61,13 +63,13 @@
}
result.appendFormat("%d) ", eventNum++);
if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
- result.appendFormat("%llu,", mTrimmedSensorEventArr[i]->mStepCounter);
+ result.appendFormat("%" PRIu64 ",", mTrimmedSensorEventArr[i]->mStepCounter);
} else {
for (int j = 0; j < numData; ++j) {
result.appendFormat("%5.1f,", mTrimmedSensorEventArr[i]->mData[j]);
}
}
- result.appendFormat("%lld %02d:%02d:%02d ", mTrimmedSensorEventArr[i]->mTimestamp,
+ result.appendFormat("%" PRId64 " %02d:%02d:%02d ", mTrimmedSensorEventArr[i]->mTimestamp,
mTrimmedSensorEventArr[i]->mHour, mTrimmedSensorEventArr[i]->mMin,
mTrimmedSensorEventArr[i]->mSec);
i = (i + 1) % mBufSize;
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index d70b069..3d71aa8 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -19,6 +19,8 @@
SurfaceFlingerConsumer.cpp \
Transform.cpp \
DisplayHardware/FramebufferSurface.cpp \
+ DisplayHardware/HWC2.cpp \
+ DisplayHardware/HWC2On1Adapter.cpp \
DisplayHardware/HWComposer.cpp \
DisplayHardware/PowerHAL.cpp \
DisplayHardware/VirtualDisplaySurface.cpp \
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index bdf8f74..e9cbbca 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -82,7 +82,6 @@
mFlags(),
mPageFlipCount(),
mIsSecure(isSecure),
- mSecureLayerVisible(false),
mLayerStack(NO_LAYER_STACK),
mOrientation(),
mPowerMode(HWC_POWER_MODE_OFF),
@@ -307,24 +306,12 @@
void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers) {
mVisibleLayersSortedByZ = layers;
- mSecureLayerVisible = false;
- size_t count = layers.size();
- for (size_t i=0 ; i<count ; i++) {
- const sp<Layer>& layer(layers[i]);
- if (layer->isSecure()) {
- mSecureLayerVisible = true;
- }
- }
}
const Vector< sp<Layer> >& DisplayDevice::getVisibleLayersSortedByZ() const {
return mVisibleLayersSortedByZ;
}
-bool DisplayDevice::getSecureLayerVisible() const {
- return mSecureLayerVisible;
-}
-
Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
Region dirty;
if (repaintEverything) {
@@ -506,13 +493,13 @@
result.appendFormat(
"+ DisplayDevice: %s\n"
" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), "
- "flips=%u, isSecure=%d, secureVis=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n"
+ "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n"
" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
"transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
mDisplayName.string(), mType, mHwcDisplayId,
mLayerStack, mDisplayWidth, mDisplayHeight, mNativeWindow.get(),
mOrientation, tr.getType(), getPageFlipCount(),
- mIsSecure, mSecureLayerVisible, mPowerMode, mActiveConfig,
+ mIsSecure, mPowerMode, mActiveConfig,
mVisibleLayersSortedByZ.size(),
mViewport.left, mViewport.top, mViewport.right, mViewport.bottom,
mFrame.left, mFrame.top, mFrame.right, mFrame.bottom,
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8695a44..6d380d1 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -106,7 +106,6 @@
void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
- bool getSecureLayerVisible() const;
Region getDirtyRegion(bool repaintEverything) const;
void setLayerStack(uint32_t stack);
@@ -202,10 +201,6 @@
// list of visible layers on that display
Vector< sp<Layer> > mVisibleLayersSortedByZ;
- // Whether we have a visible secure layer on this display
- bool mSecureLayerVisible;
-
-
/*
* Transaction state
*/
diff --git a/services/surfaceflinger/DisplayHardware/FloatRect.h b/services/surfaceflinger/DisplayHardware/FloatRect.h
index 3b75cc0..9ad1040 100644
--- a/services/surfaceflinger/DisplayHardware/FloatRect.h
+++ b/services/surfaceflinger/DisplayHardware/FloatRect.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SF_FLOAT_RECT
#define ANDROID_SF_FLOAT_RECT
+#include <ui/Rect.h>
#include <utils/TypeHelpers.h>
namespace android {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
new file mode 100644
index 0000000..0e97a53
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -0,0 +1,992 @@
+/*
+ * Copyright 2015 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 "HWC2"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "HWC2.h"
+
+#include "FloatRect.h"
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+
+#include <android/configuration.h>
+
+#include <inttypes.h>
+
+extern "C" {
+ static void hotplug_hook(hwc2_callback_data_t callbackData,
+ hwc2_display_t displayId, int32_t intConnected) {
+ auto device = static_cast<HWC2::Device*>(callbackData);
+ auto display = device->getDisplayById(displayId);
+ if (display) {
+ auto connected = static_cast<HWC2::Connection>(intConnected);
+ device->callHotplug(std::move(display), connected);
+ } else {
+ ALOGE("Hotplug callback called with unknown display %" PRIu64,
+ displayId);
+ }
+ }
+
+ static void refresh_hook(hwc2_callback_data_t callbackData,
+ hwc2_display_t displayId) {
+ auto device = static_cast<HWC2::Device*>(callbackData);
+ auto display = device->getDisplayById(displayId);
+ if (display) {
+ device->callRefresh(std::move(display));
+ } else {
+ ALOGE("Refresh callback called with unknown display %" PRIu64,
+ displayId);
+ }
+ }
+
+ static void vsync_hook(hwc2_callback_data_t callbackData,
+ hwc2_display_t displayId, int64_t timestamp) {
+ auto device = static_cast<HWC2::Device*>(callbackData);
+ auto display = device->getDisplayById(displayId);
+ if (display) {
+ device->callVsync(std::move(display), timestamp);
+ } else {
+ ALOGE("Vsync callback called with unknown display %" PRIu64,
+ displayId);
+ }
+ }
+}
+
+using android::Fence;
+using android::FloatRect;
+using android::GraphicBuffer;
+using android::Rect;
+using android::Region;
+using android::sp;
+
+namespace HWC2 {
+
+// Device methods
+
+Device::Device(hwc2_device_t* device)
+ : mHwcDevice(device),
+ mCreateVirtualDisplay(nullptr),
+ mDestroyVirtualDisplay(nullptr),
+ mDump(nullptr),
+ mGetMaxVirtualDisplayCount(nullptr),
+ mRegisterCallback(nullptr),
+ mAcceptDisplayChanges(nullptr),
+ mCreateLayer(nullptr),
+ mDestroyLayer(nullptr),
+ mGetActiveConfig(nullptr),
+ mGetChangedCompositionTypes(nullptr),
+ mGetDisplayAttribute(nullptr),
+ mGetDisplayConfigs(nullptr),
+ mGetDisplayName(nullptr),
+ mGetDisplayRequests(nullptr),
+ mGetDisplayType(nullptr),
+ mGetDozeSupport(nullptr),
+ mGetReleaseFences(nullptr),
+ mPresentDisplay(nullptr),
+ mSetActiveConfig(nullptr),
+ mSetClientTarget(nullptr),
+ mSetOutputBuffer(nullptr),
+ mSetPowerMode(nullptr),
+ mSetVsyncEnabled(nullptr),
+ mValidateDisplay(nullptr),
+ mSetCursorPosition(nullptr),
+ mSetLayerBuffer(nullptr),
+ mSetLayerSurfaceDamage(nullptr),
+ mSetLayerBlendMode(nullptr),
+ mSetLayerColor(nullptr),
+ mSetLayerCompositionType(nullptr),
+ mSetLayerDisplayFrame(nullptr),
+ mSetLayerPlaneAlpha(nullptr),
+ mSetLayerSidebandStream(nullptr),
+ mSetLayerSourceCrop(nullptr),
+ mSetLayerTransform(nullptr),
+ mSetLayerVisibleRegion(nullptr),
+ mSetLayerZOrder(nullptr),
+ mCapabilities(),
+ mDisplays(),
+ mHotplug(),
+ mPendingHotplugs(),
+ mRefresh(),
+ mPendingRefreshes(),
+ mVsync(),
+ mPendingVsyncs()
+{
+ loadCapabilities();
+ loadFunctionPointers();
+ registerCallbacks();
+}
+
+Device::~Device()
+{
+ if (mHwcDevice == nullptr) {
+ return;
+ }
+
+ for (auto element : mDisplays) {
+ auto display = element.second;
+
+ DisplayType displayType = HWC2::DisplayType::Invalid;
+ auto error = display->getType(&displayType);
+ if (error != Error::None) {
+ ALOGE("~Device: Failed to determine type of display %" PRIu64
+ ": %s (%d)", display->getId(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ continue;
+ }
+
+ if (displayType == HWC2::DisplayType::Physical) {
+ error = display->setVsyncEnabled(HWC2::Vsync::Disable);
+ if (error != Error::None) {
+ ALOGE("~Device: Failed to disable vsync for display %" PRIu64
+ ": %s (%d)", display->getId(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+ }
+ }
+
+ hwc2_close(mHwcDevice);
+}
+
+// Required by HWC2 device
+
+std::string Device::dump() const
+{
+ uint32_t numBytes = 0;
+ mDump(mHwcDevice, &numBytes, nullptr);
+
+ std::vector<char> buffer(numBytes);
+ mDump(mHwcDevice, &numBytes, buffer.data());
+
+ return std::string(buffer.data(), buffer.size());
+}
+
+uint32_t Device::getMaxVirtualDisplayCount() const
+{
+ return mGetMaxVirtualDisplayCount(mHwcDevice);
+}
+
+Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
+ std::shared_ptr<Display>* outDisplay)
+{
+ ALOGI("Creating virtual display");
+
+ hwc2_display_t displayId = 0;
+ int32_t intError = mCreateVirtualDisplay(mHwcDevice, width, height,
+ &displayId);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ ALOGI("Created virtual display");
+ *outDisplay = getDisplayById(displayId);
+ (*outDisplay)->setVirtual();
+ return Error::None;
+}
+
+void Device::registerHotplugCallback(HotplugCallback hotplug)
+{
+ ALOGV("registerHotplugCallback");
+ mHotplug = hotplug;
+ for (auto& pending : mPendingHotplugs) {
+ auto& display = pending.first;
+ auto connected = pending.second;
+ ALOGV("Sending pending hotplug(%" PRIu64 ", %s)", display->getId(),
+ to_string(connected).c_str());
+ mHotplug(std::move(display), connected);
+ }
+}
+
+void Device::registerRefreshCallback(RefreshCallback refresh)
+{
+ mRefresh = refresh;
+ for (auto& pending : mPendingRefreshes) {
+ mRefresh(std::move(pending));
+ }
+}
+
+void Device::registerVsyncCallback(VsyncCallback vsync)
+{
+ mVsync = vsync;
+ for (auto& pending : mPendingVsyncs) {
+ auto& display = pending.first;
+ auto timestamp = pending.second;
+ mVsync(std::move(display), timestamp);
+ }
+}
+
+// For use by Device callbacks
+
+void Device::callHotplug(std::shared_ptr<Display> display, Connection connected)
+{
+ if (connected == Connection::Connected) {
+ if (!display->isConnected()) {
+ display->loadConfigs();
+ display->setConnected(true);
+ }
+ } else {
+ display->setConnected(false);
+ mDisplays.erase(display->getId());
+ }
+
+ if (mHotplug) {
+ mHotplug(std::move(display), connected);
+ } else {
+ ALOGV("callHotplug called, but no valid callback registered, storing");
+ mPendingHotplugs.emplace_back(std::move(display), connected);
+ }
+}
+
+void Device::callRefresh(std::shared_ptr<Display> display)
+{
+ if (mRefresh) {
+ mRefresh(std::move(display));
+ } else {
+ ALOGV("callRefresh called, but no valid callback registered, storing");
+ mPendingRefreshes.emplace_back(std::move(display));
+ }
+}
+
+void Device::callVsync(std::shared_ptr<Display> display, nsecs_t timestamp)
+{
+ if (mVsync) {
+ mVsync(std::move(display), timestamp);
+ } else {
+ ALOGV("callVsync called, but no valid callback registered, storing");
+ mPendingVsyncs.emplace_back(std::move(display), timestamp);
+ }
+}
+
+// Other Device methods
+
+std::shared_ptr<Display> Device::getDisplayById(hwc2_display_t id) {
+ if (mDisplays.count(id) != 0) {
+ return mDisplays.at(id);
+ }
+
+ auto display = std::make_shared<Display>(*this, id);
+ mDisplays.emplace(id, display);
+ return display;
+}
+
+// Device initialization methods
+
+void Device::loadCapabilities()
+{
+ static_assert(sizeof(Capability) == sizeof(int32_t),
+ "Capability size has changed");
+ uint32_t numCapabilities = 0;
+ mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, nullptr);
+ mCapabilities.resize(numCapabilities);
+ auto asInt = reinterpret_cast<int32_t*>(mCapabilities.data());
+ mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, asInt);
+}
+
+void Device::loadFunctionPointers()
+{
+ // For all of these early returns, we log an error message inside
+ // loadFunctionPointer specifying which function failed to load
+
+ // Display function pointers
+ if(!loadFunctionPointer(FunctionDescriptor::CreateVirtualDisplay,
+ mCreateVirtualDisplay)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::DestroyVirtualDisplay,
+ mDestroyVirtualDisplay)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::Dump, mDump)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetMaxVirtualDisplayCount,
+ mGetMaxVirtualDisplayCount)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::RegisterCallback,
+ mRegisterCallback)) return;
+
+ // Device function pointers
+ if(!loadFunctionPointer(FunctionDescriptor::AcceptDisplayChanges,
+ mAcceptDisplayChanges)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::CreateLayer,
+ mCreateLayer)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::DestroyLayer,
+ mDestroyLayer)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetActiveConfig,
+ mGetActiveConfig)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetChangedCompositionTypes,
+ mGetChangedCompositionTypes)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetDisplayAttribute,
+ mGetDisplayAttribute)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetDisplayConfigs,
+ mGetDisplayConfigs)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetDisplayName,
+ mGetDisplayName)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetDisplayRequests,
+ mGetDisplayRequests)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetDisplayType,
+ mGetDisplayType)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetDozeSupport,
+ mGetDozeSupport)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::GetReleaseFences,
+ mGetReleaseFences)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::PresentDisplay,
+ mPresentDisplay)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetActiveConfig,
+ mSetActiveConfig)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetClientTarget,
+ mSetClientTarget)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetOutputBuffer,
+ mSetOutputBuffer)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetPowerMode,
+ mSetPowerMode)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetVsyncEnabled,
+ mSetVsyncEnabled)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::ValidateDisplay,
+ mValidateDisplay)) return;
+
+ // Layer function pointers
+ if(!loadFunctionPointer(FunctionDescriptor::SetCursorPosition,
+ mSetCursorPosition)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerBuffer,
+ mSetLayerBuffer)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerSurfaceDamage,
+ mSetLayerSurfaceDamage)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerBlendMode,
+ mSetLayerBlendMode)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerColor,
+ mSetLayerColor)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerCompositionType,
+ mSetLayerCompositionType)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerDisplayFrame,
+ mSetLayerDisplayFrame)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerPlaneAlpha,
+ mSetLayerPlaneAlpha)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerSidebandStream,
+ mSetLayerSidebandStream)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerSourceCrop,
+ mSetLayerSourceCrop)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerTransform,
+ mSetLayerTransform)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerVisibleRegion,
+ mSetLayerVisibleRegion)) return;
+ if(!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder,
+ mSetLayerZOrder)) return;
+}
+
+void Device::registerCallbacks()
+{
+ registerCallback<HWC2_PFN_HOTPLUG>(Callback::Hotplug, hotplug_hook);
+ registerCallback<HWC2_PFN_REFRESH>(Callback::Refresh, refresh_hook);
+ registerCallback<HWC2_PFN_VSYNC>(Callback::Vsync, vsync_hook);
+}
+
+
+// For use by Display
+
+void Device::destroyVirtualDisplay(hwc2_display_t display)
+{
+ ALOGI("Destroying virtual display");
+ int32_t intError = mDestroyVirtualDisplay(mHwcDevice, display);
+ auto error = static_cast<Error>(intError);
+ ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:"
+ " %s (%d)", display, to_string(error).c_str(), intError);
+}
+
+// Display methods
+
+Display::Display(Device& device, hwc2_display_t id)
+ : mDevice(device),
+ mId(id),
+ mIsConnected(false),
+ mIsVirtual(false)
+{
+ ALOGV("Created display %" PRIu64, id);
+}
+
+Display::~Display()
+{
+ ALOGV("Destroyed display %" PRIu64, mId);
+ if (mIsVirtual) {
+ mDevice.destroyVirtualDisplay(mId);
+ }
+}
+
+Display::Config::Config(Display& display, hwc2_config_t id)
+ : mDisplay(display),
+ mId(id),
+ mWidth(-1),
+ mHeight(-1),
+ mVsyncPeriod(-1),
+ mDpiX(-1),
+ mDpiY(-1) {}
+
+Display::Config::Builder::Builder(Display& display, hwc2_config_t id)
+ : mConfig(new Config(display, id)) {}
+
+float Display::Config::Builder::getDefaultDensity() {
+ // Default density is based on TVs: 1080p displays get XHIGH density, lower-
+ // resolution displays get TV density. Maybe eventually we'll need to update
+ // it for 4k displays, though hopefully those will just report accurate DPI
+ // information to begin with. This is also used for virtual displays and
+ // older HWC implementations, so be careful about orientation.
+
+ auto longDimension = std::max(mConfig->mWidth, mConfig->mHeight);
+ if (longDimension >= 1080) {
+ return ACONFIGURATION_DENSITY_XHIGH;
+ } else {
+ return ACONFIGURATION_DENSITY_TV;
+ }
+}
+
+// Required by HWC2 display
+
+Error Display::acceptChanges()
+{
+ int32_t intError = mDevice.mAcceptDisplayChanges(mDevice.mHwcDevice, mId);
+ return static_cast<Error>(intError);
+}
+
+Error Display::createLayer(std::shared_ptr<Layer>* outLayer)
+{
+ hwc2_layer_t layerId = 0;
+ int32_t intError = mDevice.mCreateLayer(mDevice.mHwcDevice, mId, &layerId);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ auto layer = std::make_shared<Layer>(shared_from_this(), layerId);
+ mLayers.emplace(layerId, layer);
+ *outLayer = std::move(layer);
+ return Error::None;
+}
+
+Error Display::getActiveConfig(
+ std::shared_ptr<const Display::Config>* outConfig) const
+{
+ ALOGV("[%" PRIu64 "] getActiveConfig", mId);
+ hwc2_config_t configId = 0;
+ int32_t intError = mDevice.mGetActiveConfig(mDevice.mHwcDevice, mId,
+ &configId);
+ auto error = static_cast<Error>(intError);
+
+ if (error != Error::None) {
+ return error;
+ }
+
+ if (mConfigs.count(configId) != 0) {
+ *outConfig = mConfigs.at(configId);
+ } else {
+ ALOGE("[%" PRIu64 "] getActiveConfig returned unknown config %u", mId,
+ configId);
+ // Return no error, but the caller needs to check for a null pointer to
+ // detect this case
+ *outConfig = nullptr;
+ }
+
+ return Error::None;
+}
+
+Error Display::getChangedCompositionTypes(
+ std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes)
+{
+ uint32_t numElements = 0;
+ int32_t intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice,
+ mId, &numElements, nullptr, nullptr);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ std::vector<hwc2_layer_t> layerIds(numElements);
+ std::vector<int32_t> types(numElements);
+ intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice, mId,
+ &numElements, layerIds.data(), types.data());
+ error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ outTypes->clear();
+ outTypes->reserve(numElements);
+ for (uint32_t element = 0; element < numElements; ++element) {
+ auto layer = getLayerById(layerIds[element]);
+ if (layer) {
+ auto type = static_cast<Composition>(types[element]);
+ ALOGV("getChangedCompositionTypes: adding %" PRIu64 " %s",
+ layer->getId(), to_string(type).c_str());
+ outTypes->emplace(layer, type);
+ } else {
+ ALOGE("getChangedCompositionTypes: invalid layer %" PRIu64 " found"
+ " on display %" PRIu64, layerIds[element], mId);
+ }
+ }
+
+ return Error::None;
+}
+
+std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const
+{
+ std::vector<std::shared_ptr<const Config>> configs;
+ for (const auto& element : mConfigs) {
+ configs.emplace_back(element.second);
+ }
+ return configs;
+}
+
+Error Display::getName(std::string* outName) const
+{
+ uint32_t size;
+ int32_t intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size,
+ nullptr);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ std::vector<char> rawName(size);
+ intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size,
+ rawName.data());
+ error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ *outName = std::string(rawName.cbegin(), rawName.cend());
+ return Error::None;
+}
+
+Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests,
+ std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
+ outLayerRequests)
+{
+ int32_t intDisplayRequests = 0;
+ uint32_t numElements = 0;
+ int32_t intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId,
+ &intDisplayRequests, &numElements, nullptr, nullptr);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ std::vector<hwc2_layer_t> layerIds(numElements);
+ std::vector<int32_t> layerRequests(numElements);
+ intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId,
+ &intDisplayRequests, &numElements, layerIds.data(),
+ layerRequests.data());
+ error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ *outDisplayRequests = static_cast<DisplayRequest>(intDisplayRequests);
+ outLayerRequests->clear();
+ outLayerRequests->reserve(numElements);
+ for (uint32_t element = 0; element < numElements; ++element) {
+ auto layer = getLayerById(layerIds[element]);
+ if (layer) {
+ auto layerRequest =
+ static_cast<LayerRequest>(layerRequests[element]);
+ outLayerRequests->emplace(layer, layerRequest);
+ } else {
+ ALOGE("getRequests: invalid layer %" PRIu64 " found on display %"
+ PRIu64, layerIds[element], mId);
+ }
+ }
+
+ return Error::None;
+}
+
+Error Display::getType(DisplayType* outType) const
+{
+ int32_t intType = 0;
+ int32_t intError = mDevice.mGetDisplayType(mDevice.mHwcDevice, mId,
+ &intType);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ *outType = static_cast<DisplayType>(intType);
+ return Error::None;
+}
+
+Error Display::supportsDoze(bool* outSupport) const
+{
+ int32_t intSupport = 0;
+ int32_t intError = mDevice.mGetDozeSupport(mDevice.mHwcDevice, mId,
+ &intSupport);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+ *outSupport = static_cast<bool>(intSupport);
+ return Error::None;
+}
+
+Error Display::getReleaseFences(
+ std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const
+{
+ uint32_t numElements = 0;
+ int32_t intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId,
+ &numElements, nullptr, nullptr);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ std::vector<hwc2_layer_t> layerIds(numElements);
+ std::vector<int32_t> fenceFds(numElements);
+ intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId, &numElements,
+ layerIds.data(), fenceFds.data());
+ error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ std::unordered_map<std::shared_ptr<Layer>, sp<Fence>> releaseFences;
+ releaseFences.reserve(numElements);
+ for (uint32_t element = 0; element < numElements; ++element) {
+ auto layer = getLayerById(layerIds[element]);
+ if (layer) {
+ sp<Fence> fence(new Fence(fenceFds[element]));
+ releaseFences.emplace(std::move(layer), fence);
+ } else {
+ ALOGE("getReleaseFences: invalid layer %" PRIu64
+ " found on display %" PRIu64, layerIds[element], mId);
+ return Error::BadLayer;
+ }
+ }
+
+ *outFences = std::move(releaseFences);
+ return Error::None;
+}
+
+Error Display::present(sp<Fence>* outRetireFence)
+{
+ int32_t retireFenceFd = 0;
+ int32_t intError = mDevice.mPresentDisplay(mDevice.mHwcDevice, mId,
+ &retireFenceFd);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ return error;
+ }
+
+ *outRetireFence = new Fence(retireFenceFd);
+ return Error::None;
+}
+
+Error Display::setActiveConfig(const std::shared_ptr<const Config>& config)
+{
+ if (config->getDisplayId() != mId) {
+ ALOGE("setActiveConfig received config %u for the wrong display %"
+ PRIu64 " (expected %" PRIu64 ")", config->getId(),
+ config->getDisplayId(), mId);
+ return Error::BadConfig;
+ }
+ int32_t intError = mDevice.mSetActiveConfig(mDevice.mHwcDevice, mId,
+ config->getId());
+ return static_cast<Error>(intError);
+}
+
+Error Display::setClientTarget(buffer_handle_t target,
+ const sp<Fence>& acquireFence, android_dataspace_t dataspace)
+{
+ int32_t fenceFd = acquireFence->dup();
+ int32_t intError = mDevice.mSetClientTarget(mDevice.mHwcDevice, mId, target,
+ fenceFd, static_cast<int32_t>(dataspace));
+ return static_cast<Error>(intError);
+}
+
+Error Display::setOutputBuffer(const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& releaseFence)
+{
+ int32_t fenceFd = releaseFence->dup();
+ auto handle = buffer->getNativeBuffer()->handle;
+ int32_t intError = mDevice.mSetOutputBuffer(mDevice.mHwcDevice, mId, handle,
+ fenceFd);
+ return static_cast<Error>(intError);
+}
+
+Error Display::setPowerMode(PowerMode mode)
+{
+ auto intMode = static_cast<int32_t>(mode);
+ int32_t intError = mDevice.mSetPowerMode(mDevice.mHwcDevice, mId, intMode);
+ return static_cast<Error>(intError);
+}
+
+Error Display::setVsyncEnabled(Vsync enabled)
+{
+ auto intEnabled = static_cast<int32_t>(enabled);
+ int32_t intError = mDevice.mSetVsyncEnabled(mDevice.mHwcDevice, mId,
+ intEnabled);
+ return static_cast<Error>(intError);
+}
+
+Error Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests)
+{
+ uint32_t numTypes = 0;
+ uint32_t numRequests = 0;
+ int32_t intError = mDevice.mValidateDisplay(mDevice.mHwcDevice, mId,
+ &numTypes, &numRequests);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None && error != Error::HasChanges) {
+ return error;
+ }
+
+ *outNumTypes = numTypes;
+ *outNumRequests = numRequests;
+ return error;
+}
+
+// For use by Device
+
+int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
+{
+ int32_t value = 0;
+ int32_t intError = mDevice.mGetDisplayAttribute(mDevice.mHwcDevice, mId,
+ configId, static_cast<int32_t>(attribute), &value);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ ALOGE("getDisplayAttribute(%" PRIu64 ", %u, %s) failed: %s (%d)", mId,
+ configId, to_string(attribute).c_str(),
+ to_string(error).c_str(), intError);
+ return -1;
+ }
+ return value;
+}
+
+void Display::loadConfig(hwc2_config_t configId)
+{
+ ALOGV("[%" PRIu64 "] loadConfig(%u)", mId, configId);
+
+ auto config = Config::Builder(*this, configId)
+ .setWidth(getAttribute(configId, Attribute::Width))
+ .setHeight(getAttribute(configId, Attribute::Height))
+ .setVsyncPeriod(getAttribute(configId, Attribute::VsyncPeriod))
+ .setDpiX(getAttribute(configId, Attribute::DpiX))
+ .setDpiY(getAttribute(configId, Attribute::DpiY))
+ .build();
+ mConfigs.emplace(configId, std::move(config));
+}
+
+void Display::loadConfigs()
+{
+ ALOGV("[%" PRIu64 "] loadConfigs", mId);
+
+ uint32_t numConfigs = 0;
+ int32_t intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId,
+ &numConfigs, nullptr);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ ALOGE("[%" PRIu64 "] getDisplayConfigs [1] failed: %s (%d)", mId,
+ to_string(error).c_str(), intError);
+ return;
+ }
+
+ std::vector<hwc2_config_t> configIds(numConfigs);
+ intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId, &numConfigs,
+ configIds.data());
+ error = static_cast<Error>(intError);
+ if (error != Error::None) {
+ ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId,
+ to_string(error).c_str(), intError);
+ return;
+ }
+
+ for (auto configId : configIds) {
+ loadConfig(configId);
+ }
+}
+
+// For use by Layer
+
+void Display::destroyLayer(hwc2_layer_t layerId)
+{
+ int32_t intError = mDevice.mDestroyLayer(mDevice.mHwcDevice, mId, layerId);
+ auto error = static_cast<Error>(intError);
+ ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
+ " failed: %s (%d)", mId, layerId, to_string(error).c_str(),
+ intError);
+ mLayers.erase(layerId);
+}
+
+// Other Display methods
+
+std::shared_ptr<Layer> Display::getLayerById(hwc2_layer_t id) const
+{
+ if (mLayers.count(id) == 0) {
+ return nullptr;
+ }
+
+ auto layer = mLayers.at(id).lock();
+ return layer;
+}
+
+// Layer methods
+
+Layer::Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id)
+ : mDisplay(display),
+ mDisplayId(display->getId()),
+ mDevice(display->getDevice()),
+ mId(id)
+{
+ ALOGV("Created layer %" PRIu64 " on display %" PRIu64, id,
+ display->getId());
+}
+
+Layer::~Layer()
+{
+ auto display = mDisplay.lock();
+ if (display) {
+ display->destroyLayer(mId);
+ }
+}
+
+Error Layer::setCursorPosition(int32_t x, int32_t y)
+{
+ int32_t intError = mDevice.mSetCursorPosition(mDevice.mHwcDevice,
+ mDisplayId, mId, x, y);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setBuffer(buffer_handle_t buffer,
+ const sp<Fence>& acquireFence)
+{
+ int32_t fenceFd = acquireFence->dup();
+ int32_t intError = mDevice.mSetLayerBuffer(mDevice.mHwcDevice, mDisplayId,
+ mId, buffer, fenceFd);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setSurfaceDamage(const Region& damage)
+{
+ // We encode default full-screen damage as INVALID_RECT upstream, but as 0
+ // rects for HWC
+ int32_t intError = 0;
+ if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) {
+ intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice,
+ mDisplayId, mId, {0, nullptr});
+ } else {
+ size_t rectCount = 0;
+ auto rectArray = damage.getArray(&rectCount);
+
+ std::vector<hwc_rect_t> hwcRects;
+ for (size_t rect = 0; rect < rectCount; ++rect) {
+ hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
+ rectArray[rect].right, rectArray[rect].bottom});
+ }
+
+ hwc_region_t hwcRegion = {};
+ hwcRegion.numRects = rectCount;
+ hwcRegion.rects = hwcRects.data();
+
+ intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice,
+ mDisplayId, mId, hwcRegion);
+ }
+
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setBlendMode(BlendMode mode)
+{
+ auto intMode = static_cast<int32_t>(mode);
+ int32_t intError = mDevice.mSetLayerBlendMode(mDevice.mHwcDevice,
+ mDisplayId, mId, intMode);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setColor(hwc_color_t color)
+{
+ int32_t intError = mDevice.mSetLayerColor(mDevice.mHwcDevice, mDisplayId,
+ mId, color);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setCompositionType(Composition type)
+{
+ auto intType = static_cast<int32_t>(type);
+ int32_t intError = mDevice.mSetLayerCompositionType(mDevice.mHwcDevice,
+ mDisplayId, mId, intType);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setDisplayFrame(const Rect& frame)
+{
+ hwc_rect_t hwcRect{frame.left, frame.top, frame.right, frame.bottom};
+ int32_t intError = mDevice.mSetLayerDisplayFrame(mDevice.mHwcDevice,
+ mDisplayId, mId, hwcRect);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setPlaneAlpha(float alpha)
+{
+ int32_t intError = mDevice.mSetLayerPlaneAlpha(mDevice.mHwcDevice,
+ mDisplayId, mId, alpha);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setSidebandStream(const native_handle_t* stream)
+{
+ int32_t intError = mDevice.mSetLayerSidebandStream(mDevice.mHwcDevice,
+ mDisplayId, mId, stream);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setSourceCrop(const FloatRect& crop)
+{
+ hwc_frect_t hwcRect{crop.left, crop.top, crop.right, crop.bottom};
+ int32_t intError = mDevice.mSetLayerSourceCrop(mDevice.mHwcDevice,
+ mDisplayId, mId, hwcRect);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setTransform(Transform transform)
+{
+ auto intTransform = static_cast<int32_t>(transform);
+ int32_t intError = mDevice.mSetLayerTransform(mDevice.mHwcDevice,
+ mDisplayId, mId, intTransform);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setVisibleRegion(const Region& region)
+{
+ size_t rectCount = 0;
+ auto rectArray = region.getArray(&rectCount);
+
+ std::vector<hwc_rect_t> hwcRects;
+ for (size_t rect = 0; rect < rectCount; ++rect) {
+ hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
+ rectArray[rect].right, rectArray[rect].bottom});
+ }
+
+ hwc_region_t hwcRegion = {};
+ hwcRegion.numRects = rectCount;
+ hwcRegion.rects = hwcRects.data();
+
+ int32_t intError = mDevice.mSetLayerVisibleRegion(mDevice.mHwcDevice,
+ mDisplayId, mId, hwcRegion);
+ return static_cast<Error>(intError);
+}
+
+Error Layer::setZOrder(uint32_t z)
+{
+ int32_t intError = mDevice.mSetLayerZOrder(mDevice.mHwcDevice, mDisplayId,
+ mId, z);
+ return static_cast<Error>(intError);
+}
+
+} // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
new file mode 100644
index 0000000..a7bd28c
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2015 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_HWC2_H
+#define ANDROID_SF_HWC2_H
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+#include <functional>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+ class Fence;
+ class FloatRect;
+ class GraphicBuffer;
+ class Rect;
+ class Region;
+}
+
+namespace HWC2 {
+
+class Display;
+class Layer;
+
+typedef std::function<void(std::shared_ptr<Display>, Connection)>
+ HotplugCallback;
+typedef std::function<void(std::shared_ptr<Display>)> RefreshCallback;
+typedef std::function<void(std::shared_ptr<Display>, nsecs_t)> VsyncCallback;
+
+class Device
+{
+public:
+ Device(hwc2_device_t* device);
+ ~Device();
+
+ friend class HWC2::Display;
+ friend class HWC2::Layer;
+
+ // Required by HWC2
+
+ std::string dump() const;
+
+ const std::vector<Capability>& getCapabilities() const {
+ return mCapabilities;
+ };
+
+ uint32_t getMaxVirtualDisplayCount() const;
+ Error createVirtualDisplay(uint32_t width, uint32_t height,
+ std::shared_ptr<Display>* outDisplay);
+
+ void registerHotplugCallback(HotplugCallback hotplug);
+ void registerRefreshCallback(RefreshCallback refresh);
+ void registerVsyncCallback(VsyncCallback vsync);
+
+ // For use by callbacks
+
+ void callHotplug(std::shared_ptr<Display> display, Connection connected);
+ void callRefresh(std::shared_ptr<Display> display);
+ void callVsync(std::shared_ptr<Display> display, nsecs_t timestamp);
+
+ // Other Device methods
+
+ // This will create a Display if one is not found, but it will not be marked
+ // as connected
+ std::shared_ptr<Display> getDisplayById(hwc2_display_t id);
+
+private:
+ // Initialization methods
+
+ template <typename PFN>
+ [[clang::warn_unused_result]] bool loadFunctionPointer(
+ FunctionDescriptor desc, PFN& outPFN) {
+ auto intDesc = static_cast<int32_t>(desc);
+ auto pfn = mHwcDevice->getFunction(mHwcDevice, intDesc);
+ if (pfn != nullptr) {
+ outPFN = reinterpret_cast<PFN>(pfn);
+ return true;
+ } else {
+ ALOGE("Failed to load function %s", to_string(desc).c_str());
+ return false;
+ }
+ }
+
+ template <typename PFN, typename HOOK>
+ void registerCallback(Callback callback, HOOK hook) {
+ static_assert(std::is_same<PFN, HOOK>::value,
+ "Incompatible function pointer");
+ auto intCallback = static_cast<int32_t>(callback);
+ auto callbackData = static_cast<hwc2_callback_data_t>(this);
+ auto pfn = reinterpret_cast<hwc2_function_pointer_t>(hook);
+ mRegisterCallback(mHwcDevice, intCallback, callbackData, pfn);
+ }
+
+ void loadCapabilities();
+ void loadFunctionPointers();
+ void registerCallbacks();
+
+ // For use by Display
+
+ void destroyVirtualDisplay(hwc2_display_t display);
+
+ // Member variables
+
+ hwc2_device_t* mHwcDevice;
+
+ // Device function pointers
+ HWC2_PFN_CREATE_VIRTUAL_DISPLAY mCreateVirtualDisplay;
+ HWC2_PFN_DESTROY_VIRTUAL_DISPLAY mDestroyVirtualDisplay;
+ HWC2_PFN_DUMP mDump;
+ HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT mGetMaxVirtualDisplayCount;
+ HWC2_PFN_REGISTER_CALLBACK mRegisterCallback;
+
+ // Display function pointers
+ HWC2_PFN_ACCEPT_DISPLAY_CHANGES mAcceptDisplayChanges;
+ HWC2_PFN_CREATE_LAYER mCreateLayer;
+ HWC2_PFN_DESTROY_LAYER mDestroyLayer;
+ HWC2_PFN_GET_ACTIVE_CONFIG mGetActiveConfig;
+ HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES mGetChangedCompositionTypes;
+ HWC2_PFN_GET_DISPLAY_ATTRIBUTE mGetDisplayAttribute;
+ HWC2_PFN_GET_DISPLAY_CONFIGS mGetDisplayConfigs;
+ HWC2_PFN_GET_DISPLAY_NAME mGetDisplayName;
+ HWC2_PFN_GET_DISPLAY_REQUESTS mGetDisplayRequests;
+ HWC2_PFN_GET_DISPLAY_TYPE mGetDisplayType;
+ HWC2_PFN_GET_DOZE_SUPPORT mGetDozeSupport;
+ HWC2_PFN_GET_RELEASE_FENCES mGetReleaseFences;
+ HWC2_PFN_PRESENT_DISPLAY mPresentDisplay;
+ HWC2_PFN_SET_ACTIVE_CONFIG mSetActiveConfig;
+ HWC2_PFN_SET_CLIENT_TARGET mSetClientTarget;
+ HWC2_PFN_SET_OUTPUT_BUFFER mSetOutputBuffer;
+ HWC2_PFN_SET_POWER_MODE mSetPowerMode;
+ HWC2_PFN_SET_VSYNC_ENABLED mSetVsyncEnabled;
+ HWC2_PFN_VALIDATE_DISPLAY mValidateDisplay;
+
+ // Layer function pointers
+ HWC2_PFN_SET_CURSOR_POSITION mSetCursorPosition;
+ HWC2_PFN_SET_LAYER_BUFFER mSetLayerBuffer;
+ HWC2_PFN_SET_LAYER_SURFACE_DAMAGE mSetLayerSurfaceDamage;
+ HWC2_PFN_SET_LAYER_BLEND_MODE mSetLayerBlendMode;
+ HWC2_PFN_SET_LAYER_COLOR mSetLayerColor;
+ HWC2_PFN_SET_LAYER_COMPOSITION_TYPE mSetLayerCompositionType;
+ HWC2_PFN_SET_LAYER_DISPLAY_FRAME mSetLayerDisplayFrame;
+ HWC2_PFN_SET_LAYER_PLANE_ALPHA mSetLayerPlaneAlpha;
+ HWC2_PFN_SET_LAYER_SIDEBAND_STREAM mSetLayerSidebandStream;
+ HWC2_PFN_SET_LAYER_SOURCE_CROP mSetLayerSourceCrop;
+ HWC2_PFN_SET_LAYER_TRANSFORM mSetLayerTransform;
+ HWC2_PFN_SET_LAYER_VISIBLE_REGION mSetLayerVisibleRegion;
+ HWC2_PFN_SET_LAYER_Z_ORDER mSetLayerZOrder;
+
+ std::vector<Capability> mCapabilities;
+ std::unordered_map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+
+ HotplugCallback mHotplug;
+ std::vector<std::pair<std::shared_ptr<Display>, Connection>>
+ mPendingHotplugs;
+ RefreshCallback mRefresh;
+ std::vector<std::shared_ptr<Display>> mPendingRefreshes;
+ VsyncCallback mVsync;
+ std::vector<std::pair<std::shared_ptr<Display>, nsecs_t>> mPendingVsyncs;
+};
+
+class Display : public std::enable_shared_from_this<Display>
+{
+public:
+ Display(Device& device, hwc2_display_t id);
+ ~Display();
+
+ friend class HWC2::Device;
+ friend class HWC2::Layer;
+
+ class Config
+ {
+ public:
+ class Builder
+ {
+ public:
+ Builder(Display& display, hwc2_config_t id);
+
+ std::shared_ptr<const Config> build() {
+ return std::const_pointer_cast<const Config>(
+ std::move(mConfig));
+ }
+
+ Builder& setWidth(int32_t width) {
+ mConfig->mWidth = width;
+ return *this;
+ }
+ Builder& setHeight(int32_t height) {
+ mConfig->mHeight = height;
+ return *this;
+ }
+ Builder& setVsyncPeriod(int32_t vsyncPeriod) {
+ mConfig->mVsyncPeriod = vsyncPeriod;
+ return *this;
+ }
+ Builder& setDpiX(int32_t dpiX) {
+ if (dpiX == -1) {
+ mConfig->mDpiX = getDefaultDensity();
+ } else {
+ mConfig->mDpiX = dpiX / 1000.0f;
+ }
+ return *this;
+ }
+ Builder& setDpiY(int32_t dpiY) {
+ if (dpiY == -1) {
+ mConfig->mDpiY = getDefaultDensity();
+ } else {
+ mConfig->mDpiY = dpiY / 1000.0f;
+ }
+ return *this;
+ }
+
+ private:
+ float getDefaultDensity();
+ std::shared_ptr<Config> mConfig;
+ };
+
+ hwc2_display_t getDisplayId() const { return mDisplay.getId(); }
+ hwc2_config_t getId() const { return mId; }
+
+ int32_t getWidth() const { return mWidth; }
+ int32_t getHeight() const { return mHeight; }
+ nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
+ float getDpiX() const { return mDpiX; }
+ float getDpiY() const { return mDpiY; }
+
+ private:
+ Config(Display& display, hwc2_config_t id);
+
+ Display& mDisplay;
+ hwc2_config_t mId;
+
+ int32_t mWidth;
+ int32_t mHeight;
+ nsecs_t mVsyncPeriod;
+ float mDpiX;
+ float mDpiY;
+ };
+
+ // Required by HWC2
+
+ [[clang::warn_unused_result]] Error acceptChanges();
+ [[clang::warn_unused_result]] Error createLayer(
+ std::shared_ptr<Layer>* outLayer);
+ [[clang::warn_unused_result]] Error getActiveConfig(
+ std::shared_ptr<const Config>* outConfig) const;
+ [[clang::warn_unused_result]] Error getChangedCompositionTypes(
+ std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes);
+
+ // Doesn't call into the HWC2 device, so no errors are possible
+ std::vector<std::shared_ptr<const Config>> getConfigs() const;
+
+ [[clang::warn_unused_result]] Error getName(std::string* outName) const;
+ [[clang::warn_unused_result]] Error getRequests(
+ DisplayRequest* outDisplayRequests,
+ std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
+ outLayerRequests);
+ [[clang::warn_unused_result]] Error getType(DisplayType* outType) const;
+ [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const;
+ [[clang::warn_unused_result]] Error getReleaseFences(
+ std::unordered_map<std::shared_ptr<Layer>,
+ android::sp<android::Fence>>* outFences) const;
+ [[clang::warn_unused_result]] Error present(
+ android::sp<android::Fence>* outRetireFence);
+ [[clang::warn_unused_result]] Error setActiveConfig(
+ const std::shared_ptr<const Config>& config);
+ [[clang::warn_unused_result]] Error setClientTarget(
+ buffer_handle_t target,
+ const android::sp<android::Fence>& acquireFence,
+ android_dataspace_t dataspace);
+ [[clang::warn_unused_result]] Error setOutputBuffer(
+ const android::sp<android::GraphicBuffer>& buffer,
+ const android::sp<android::Fence>& releaseFence);
+ [[clang::warn_unused_result]] Error setPowerMode(PowerMode mode);
+ [[clang::warn_unused_result]] Error setVsyncEnabled(Vsync enabled);
+ [[clang::warn_unused_result]] Error validate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests);
+
+ // Other Display methods
+
+ Device& getDevice() const { return mDevice; }
+ hwc2_display_t getId() const { return mId; }
+ bool isConnected() const { return mIsConnected; }
+
+private:
+ // For use by Device
+
+ // Virtual displays are always connected
+ void setVirtual() {
+ mIsVirtual = true;
+ mIsConnected = true;
+ }
+
+ void setConnected(bool connected) { mIsConnected = connected; }
+ int32_t getAttribute(hwc2_config_t configId, Attribute attribute);
+ void loadConfig(hwc2_config_t configId);
+ void loadConfigs();
+
+ // For use by Layer
+ void destroyLayer(hwc2_layer_t layerId);
+
+ // This may fail (and return a null pointer) if no layer with this ID exists
+ // on this display
+ std::shared_ptr<Layer> getLayerById(hwc2_layer_t id) const;
+
+ // Member variables
+
+ Device& mDevice;
+ hwc2_display_t mId;
+ bool mIsConnected;
+ bool mIsVirtual;
+ std::unordered_map<hwc2_layer_t, std::weak_ptr<Layer>> mLayers;
+ std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
+};
+
+class Layer
+{
+public:
+ Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id);
+ ~Layer();
+
+ bool isAbandoned() const { return mDisplay.expired(); }
+ hwc2_layer_t getId() const { return mId; }
+
+ [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y);
+ [[clang::warn_unused_result]] Error setBuffer(buffer_handle_t buffer,
+ const android::sp<android::Fence>& acquireFence);
+ [[clang::warn_unused_result]] Error setSurfaceDamage(
+ const android::Region& damage);
+
+ [[clang::warn_unused_result]] Error setBlendMode(BlendMode mode);
+ [[clang::warn_unused_result]] Error setColor(hwc_color_t color);
+ [[clang::warn_unused_result]] Error setCompositionType(Composition type);
+ [[clang::warn_unused_result]] Error setDisplayFrame(
+ const android::Rect& frame);
+ [[clang::warn_unused_result]] Error setPlaneAlpha(float alpha);
+ [[clang::warn_unused_result]] Error setSidebandStream(
+ const native_handle_t* stream);
+ [[clang::warn_unused_result]] Error setSourceCrop(
+ const android::FloatRect& crop);
+ [[clang::warn_unused_result]] Error setTransform(Transform transform);
+ [[clang::warn_unused_result]] Error setVisibleRegion(
+ const android::Region& region);
+ [[clang::warn_unused_result]] Error setZOrder(uint32_t z);
+
+private:
+ std::weak_ptr<Display> mDisplay;
+ hwc2_display_t mDisplayId;
+ Device& mDevice;
+ hwc2_layer_t mId;
+};
+
+} // namespace HWC2
+
+#endif // ANDROID_SF_HWC2_H
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
new file mode 100644
index 0000000..8cbd718
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
@@ -0,0 +1,2323 @@
+/*
+ * Copyright 2015 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 "HWC2On1Adapter"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "HWC2On1Adapter.h"
+
+#include <hardware/hwcomposer.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <cstdlib>
+#include <chrono>
+#include <inttypes.h>
+#include <sstream>
+
+using namespace std::chrono_literals;
+
+static bool operator==(const hwc_color_t& lhs, const hwc_color_t& rhs) {
+ return lhs.r == rhs.r &&
+ lhs.g == rhs.g &&
+ lhs.b == rhs.b &&
+ lhs.a == rhs.a;
+}
+
+static bool operator==(const hwc_rect_t& lhs, const hwc_rect_t& rhs) {
+ return lhs.left == rhs.left &&
+ lhs.top == rhs.top &&
+ lhs.right == rhs.right &&
+ lhs.bottom == rhs.bottom;
+}
+
+static bool operator==(const hwc_frect_t& lhs, const hwc_frect_t& rhs) {
+ return lhs.left == rhs.left &&
+ lhs.top == rhs.top &&
+ lhs.right == rhs.right &&
+ lhs.bottom == rhs.bottom;
+}
+
+template <typename T>
+static inline bool operator!=(const T& lhs, const T& rhs)
+{
+ return !(lhs == rhs);
+}
+
+static uint8_t getMinorVersion(struct hwc_composer_device_1* device)
+{
+ auto version = device->common.version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
+ return (version >> 16) & 0xF;
+}
+
+template <typename PFN, typename T>
+static hwc2_function_pointer_t asFP(T function)
+{
+ static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+ return reinterpret_cast<hwc2_function_pointer_t>(function);
+}
+
+using namespace HWC2;
+
+namespace android {
+
+void HWC2On1Adapter::DisplayContentsDeleter::operator()(
+ hwc_display_contents_1_t* contents)
+{
+ if (contents != nullptr) {
+ for (size_t l = 0; l < contents->numHwLayers; ++l) {
+ auto& layer = contents->hwLayers[l];
+ std::free(const_cast<hwc_rect_t*>(layer.visibleRegionScreen.rects));
+ }
+ }
+ std::free(contents);
+}
+
+class HWC2On1Adapter::Callbacks : public hwc_procs_t {
+ public:
+ Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
+ invalidate = &invalidateHook;
+ vsync = &vsyncHook;
+ hotplug = &hotplugHook;
+ }
+
+ static void invalidateHook(const hwc_procs_t* procs) {
+ auto callbacks = static_cast<const Callbacks*>(procs);
+ callbacks->mAdapter.hwc1Invalidate();
+ }
+
+ static void vsyncHook(const hwc_procs_t* procs, int display,
+ int64_t timestamp) {
+ auto callbacks = static_cast<const Callbacks*>(procs);
+ callbacks->mAdapter.hwc1Vsync(display, timestamp);
+ }
+
+ static void hotplugHook(const hwc_procs_t* procs, int display,
+ int connected) {
+ auto callbacks = static_cast<const Callbacks*>(procs);
+ callbacks->mAdapter.hwc1Hotplug(display, connected);
+ }
+
+ private:
+ HWC2On1Adapter& mAdapter;
+};
+
+static int closeHook(hw_device_t* /*device*/)
+{
+ // Do nothing, since the real work is done in the class destructor, but we
+ // need to provide a valid function pointer for hwc2_close to call
+ return 0;
+}
+
+HWC2On1Adapter::HWC2On1Adapter(hwc_composer_device_1_t* hwc1Device)
+ : mDumpString(),
+ mHwc1Device(hwc1Device),
+ mHwc1MinorVersion(getMinorVersion(hwc1Device)),
+ mHwc1SupportsVirtualDisplays(false),
+ mHwc1Callbacks(std::make_unique<Callbacks>(*this)),
+ mCapabilities(),
+ mLayers(),
+ mHwc1VirtualDisplay(),
+ mStateMutex(),
+ mCallbacks(),
+ mHasPendingInvalidate(false),
+ mPendingVsyncs(),
+ mPendingHotplugs(),
+ mDisplays(),
+ mHwc1DisplayMap()
+{
+ common.close = closeHook;
+ getCapabilities = getCapabilitiesHook;
+ getFunction = getFunctionHook;
+ populateCapabilities();
+ populatePrimary();
+ mHwc1Device->registerProcs(mHwc1Device,
+ static_cast<const hwc_procs_t*>(mHwc1Callbacks.get()));
+}
+
+HWC2On1Adapter::~HWC2On1Adapter() {
+ hwc_close_1(mHwc1Device);
+}
+
+void HWC2On1Adapter::doGetCapabilities(uint32_t* outCount,
+ int32_t* outCapabilities)
+{
+ if (outCapabilities == nullptr) {
+ *outCount = mCapabilities.size();
+ return;
+ }
+
+ auto capabilityIter = mCapabilities.cbegin();
+ for (size_t written = 0; written < *outCount; ++written) {
+ if (capabilityIter == mCapabilities.cend()) {
+ return;
+ }
+ outCapabilities[written] = static_cast<int32_t>(*capabilityIter);
+ ++capabilityIter;
+ }
+}
+
+hwc2_function_pointer_t HWC2On1Adapter::doGetFunction(
+ FunctionDescriptor descriptor)
+{
+ switch (descriptor) {
+ // Device functions
+ case FunctionDescriptor::CreateVirtualDisplay:
+ return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
+ createVirtualDisplayHook);
+ case FunctionDescriptor::DestroyVirtualDisplay:
+ return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
+ destroyVirtualDisplayHook);
+ case FunctionDescriptor::Dump:
+ return asFP<HWC2_PFN_DUMP>(dumpHook);
+ case FunctionDescriptor::GetMaxVirtualDisplayCount:
+ return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
+ getMaxVirtualDisplayCountHook);
+ case FunctionDescriptor::RegisterCallback:
+ return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
+
+ // Display functions
+ case FunctionDescriptor::AcceptDisplayChanges:
+ return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
+ displayHook<decltype(&Display::acceptChanges),
+ &Display::acceptChanges>);
+ case FunctionDescriptor::CreateLayer:
+ return asFP<HWC2_PFN_CREATE_LAYER>(
+ displayHook<decltype(&Display::createLayer),
+ &Display::createLayer, hwc2_layer_t*>);
+ case FunctionDescriptor::DestroyLayer:
+ return asFP<HWC2_PFN_DESTROY_LAYER>(
+ displayHook<decltype(&Display::destroyLayer),
+ &Display::destroyLayer, hwc2_layer_t>);
+ case FunctionDescriptor::GetActiveConfig:
+ return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(
+ displayHook<decltype(&Display::getActiveConfig),
+ &Display::getActiveConfig, hwc2_config_t*>);
+ case FunctionDescriptor::GetChangedCompositionTypes:
+ return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
+ displayHook<decltype(&Display::getChangedCompositionTypes),
+ &Display::getChangedCompositionTypes, uint32_t*,
+ hwc2_layer_t*, int32_t*>);
+ case FunctionDescriptor::GetDisplayAttribute:
+ return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
+ getDisplayAttributeHook);
+ case FunctionDescriptor::GetDisplayConfigs:
+ return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(
+ displayHook<decltype(&Display::getConfigs),
+ &Display::getConfigs, uint32_t*, hwc2_config_t*>);
+ case FunctionDescriptor::GetDisplayName:
+ return asFP<HWC2_PFN_GET_DISPLAY_NAME>(
+ displayHook<decltype(&Display::getName),
+ &Display::getName, uint32_t*, char*>);
+ case FunctionDescriptor::GetDisplayRequests:
+ return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(
+ displayHook<decltype(&Display::getRequests),
+ &Display::getRequests, int32_t*, uint32_t*, hwc2_layer_t*,
+ int32_t*>);
+ case FunctionDescriptor::GetDisplayType:
+ return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(
+ displayHook<decltype(&Display::getType),
+ &Display::getType, int32_t*>);
+ case FunctionDescriptor::GetDozeSupport:
+ return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(
+ displayHook<decltype(&Display::getDozeSupport),
+ &Display::getDozeSupport, int32_t*>);
+ case FunctionDescriptor::GetReleaseFences:
+ return asFP<HWC2_PFN_GET_RELEASE_FENCES>(
+ displayHook<decltype(&Display::getReleaseFences),
+ &Display::getReleaseFences, uint32_t*, hwc2_layer_t*,
+ int32_t*>);
+ case FunctionDescriptor::PresentDisplay:
+ return asFP<HWC2_PFN_PRESENT_DISPLAY>(
+ displayHook<decltype(&Display::present),
+ &Display::present, int32_t*>);
+ case FunctionDescriptor::SetActiveConfig:
+ return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(
+ displayHook<decltype(&Display::setActiveConfig),
+ &Display::setActiveConfig, hwc2_config_t>);
+ case FunctionDescriptor::SetClientTarget:
+ return asFP<HWC2_PFN_SET_CLIENT_TARGET>(
+ displayHook<decltype(&Display::setClientTarget),
+ &Display::setClientTarget, buffer_handle_t, int32_t,
+ int32_t>);
+ case FunctionDescriptor::SetOutputBuffer:
+ return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(
+ displayHook<decltype(&Display::setOutputBuffer),
+ &Display::setOutputBuffer, buffer_handle_t, int32_t>);
+ case FunctionDescriptor::SetPowerMode:
+ return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook);
+ case FunctionDescriptor::SetVsyncEnabled:
+ return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook);
+ case FunctionDescriptor::ValidateDisplay:
+ return asFP<HWC2_PFN_VALIDATE_DISPLAY>(
+ displayHook<decltype(&Display::validate),
+ &Display::validate, uint32_t*, uint32_t*>);
+
+ // Layer functions
+ case FunctionDescriptor::SetCursorPosition:
+ return asFP<HWC2_PFN_SET_CURSOR_POSITION>(
+ layerHook<decltype(&Layer::setCursorPosition),
+ &Layer::setCursorPosition, int32_t, int32_t>);
+ case FunctionDescriptor::SetLayerBuffer:
+ return asFP<HWC2_PFN_SET_LAYER_BUFFER>(
+ layerHook<decltype(&Layer::setBuffer), &Layer::setBuffer,
+ buffer_handle_t, int32_t>);
+ case FunctionDescriptor::SetLayerSurfaceDamage:
+ return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
+ layerHook<decltype(&Layer::setSurfaceDamage),
+ &Layer::setSurfaceDamage, hwc_region_t>);
+
+ // Layer state functions
+ case FunctionDescriptor::SetLayerBlendMode:
+ return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(
+ setLayerBlendModeHook);
+ case FunctionDescriptor::SetLayerColor:
+ return asFP<HWC2_PFN_SET_LAYER_COLOR>(
+ layerHook<decltype(&Layer::setColor), &Layer::setColor,
+ hwc_color_t>);
+ case FunctionDescriptor::SetLayerCompositionType:
+ return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
+ setLayerCompositionTypeHook);
+ case FunctionDescriptor::SetLayerDisplayFrame:
+ return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
+ layerHook<decltype(&Layer::setDisplayFrame),
+ &Layer::setDisplayFrame, hwc_rect_t>);
+ case FunctionDescriptor::SetLayerPlaneAlpha:
+ return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
+ layerHook<decltype(&Layer::setPlaneAlpha),
+ &Layer::setPlaneAlpha, float>);
+ case FunctionDescriptor::SetLayerSidebandStream:
+ return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
+ layerHook<decltype(&Layer::setSidebandStream),
+ &Layer::setSidebandStream, const native_handle_t*>);
+ case FunctionDescriptor::SetLayerSourceCrop:
+ return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
+ layerHook<decltype(&Layer::setSourceCrop),
+ &Layer::setSourceCrop, hwc_frect_t>);
+ case FunctionDescriptor::SetLayerTransform:
+ return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerTransformHook);
+ case FunctionDescriptor::SetLayerVisibleRegion:
+ return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
+ layerHook<decltype(&Layer::setVisibleRegion),
+ &Layer::setVisibleRegion, hwc_region_t>);
+ case FunctionDescriptor::SetLayerZOrder:
+ return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerZOrderHook);
+
+ default:
+ ALOGE("doGetFunction: Unknown function descriptor: %d (%s)",
+ static_cast<int32_t>(descriptor),
+ to_string(descriptor).c_str());
+ return nullptr;
+ }
+}
+
+// Device functions
+
+Error HWC2On1Adapter::createVirtualDisplay(uint32_t width,
+ uint32_t height, hwc2_display_t* outDisplay)
+{
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ if (mHwc1VirtualDisplay) {
+ // We have already allocated our only HWC1 virtual display
+ ALOGE("createVirtualDisplay: HWC1 virtual display already allocated");
+ return Error::NoResources;
+ }
+
+ if (MAX_VIRTUAL_DISPLAY_DIMENSION != 0 &&
+ (width > MAX_VIRTUAL_DISPLAY_DIMENSION ||
+ height > MAX_VIRTUAL_DISPLAY_DIMENSION)) {
+ ALOGE("createVirtualDisplay: Can't create a virtual display with"
+ " a dimension > %u (tried %u x %u)",
+ MAX_VIRTUAL_DISPLAY_DIMENSION, width, height);
+ return Error::NoResources;
+ }
+
+ mHwc1VirtualDisplay = std::make_shared<HWC2On1Adapter::Display>(*this,
+ HWC2::DisplayType::Virtual);
+ mHwc1VirtualDisplay->populateConfigs(width, height);
+ const auto displayId = mHwc1VirtualDisplay->getId();
+ mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL] = displayId;
+ mHwc1VirtualDisplay->setHwc1Id(HWC_DISPLAY_VIRTUAL);
+ mDisplays.emplace(displayId, mHwc1VirtualDisplay);
+ *outDisplay = displayId;
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::destroyVirtualDisplay(hwc2_display_t displayId)
+{
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ if (!mHwc1VirtualDisplay || (mHwc1VirtualDisplay->getId() != displayId)) {
+ return Error::BadDisplay;
+ }
+
+ mHwc1VirtualDisplay.reset();
+ mHwc1DisplayMap.erase(HWC_DISPLAY_VIRTUAL);
+ mDisplays.erase(displayId);
+
+ return Error::None;
+}
+
+void HWC2On1Adapter::dump(uint32_t* outSize, char* outBuffer)
+{
+ if (outBuffer != nullptr) {
+ auto copiedBytes = mDumpString.copy(outBuffer, *outSize);
+ *outSize = static_cast<uint32_t>(copiedBytes);
+ return;
+ }
+
+ std::stringstream output;
+
+ output << "-- HWC2On1Adapter --\n";
+
+ output << "Adapting to a HWC 1." << static_cast<int>(mHwc1MinorVersion) <<
+ " device\n";
+
+ // Attempt to acquire the lock for 1 second, but proceed without the lock
+ // after that, so we can still get some information if we're deadlocked
+ std::unique_lock<std::timed_mutex> lock(mStateMutex, std::defer_lock);
+ lock.try_lock_for(1s);
+
+ if (mCapabilities.empty()) {
+ output << "Capabilities: None\n";
+ } else {
+ output << "Capabilities:\n";
+ for (auto capability : mCapabilities) {
+ output << " " << to_string(capability) << '\n';
+ }
+ }
+
+ output << "Displays:\n";
+ for (const auto& element : mDisplays) {
+ const auto& display = element.second;
+ output << display->dump();
+ }
+ output << '\n';
+
+ if (mHwc1Device->dump) {
+ output << "HWC1 dump:\n";
+ std::vector<char> hwc1Dump(4096);
+ // Call with size - 1 to preserve a null character at the end
+ mHwc1Device->dump(mHwc1Device, hwc1Dump.data(),
+ static_cast<int>(hwc1Dump.size() - 1));
+ output << hwc1Dump.data();
+ }
+
+ mDumpString = output.str();
+ *outSize = static_cast<uint32_t>(mDumpString.size());
+}
+
+uint32_t HWC2On1Adapter::getMaxVirtualDisplayCount()
+{
+ return mHwc1SupportsVirtualDisplays ? 1 : 0;
+}
+
+static bool isValid(Callback descriptor) {
+ switch (descriptor) {
+ case Callback::Hotplug: // Fall-through
+ case Callback::Refresh: // Fall-through
+ case Callback::Vsync: return true;
+ default: return false;
+ }
+}
+
+Error HWC2On1Adapter::registerCallback(Callback descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer)
+{
+ if (!isValid(descriptor)) {
+ return Error::BadParameter;
+ }
+
+ ALOGV("registerCallback(%s, %p, %p)", to_string(descriptor).c_str(),
+ callbackData, pointer);
+
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ mCallbacks[descriptor] = {callbackData, pointer};
+
+ bool hasPendingInvalidate = false;
+ std::vector<hwc2_display_t> displayIds;
+ std::vector<std::pair<hwc2_display_t, int64_t>> pendingVsyncs;
+ std::vector<std::pair<hwc2_display_t, int>> pendingHotplugs;
+
+ if (descriptor == Callback::Refresh) {
+ hasPendingInvalidate = mHasPendingInvalidate;
+ if (hasPendingInvalidate) {
+ for (auto& displayPair : mDisplays) {
+ displayIds.emplace_back(displayPair.first);
+ }
+ }
+ mHasPendingInvalidate = false;
+ } else if (descriptor == Callback::Vsync) {
+ for (auto pending : mPendingVsyncs) {
+ auto hwc1DisplayId = pending.first;
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d",
+ hwc1DisplayId);
+ continue;
+ }
+ auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+ auto timestamp = pending.second;
+ pendingVsyncs.emplace_back(displayId, timestamp);
+ }
+ mPendingVsyncs.clear();
+ } else if (descriptor == Callback::Hotplug) {
+ // Hotplug the primary display
+ pendingHotplugs.emplace_back(mHwc1DisplayMap[HWC_DISPLAY_PRIMARY],
+ static_cast<int32_t>(Connection::Connected));
+
+ for (auto pending : mPendingHotplugs) {
+ auto hwc1DisplayId = pending.first;
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ ALOGE("hwc1Hotplug: Couldn't find display for HWC1 id %d",
+ hwc1DisplayId);
+ continue;
+ }
+ auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+ auto connected = pending.second;
+ pendingHotplugs.emplace_back(displayId, connected);
+ }
+ }
+
+ // Call pending callbacks without the state lock held
+ lock.unlock();
+
+ if (hasPendingInvalidate) {
+ auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(pointer);
+ for (auto displayId : displayIds) {
+ refresh(callbackData, displayId);
+ }
+ }
+ if (!pendingVsyncs.empty()) {
+ auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
+ for (auto& pendingVsync : pendingVsyncs) {
+ vsync(callbackData, pendingVsync.first, pendingVsync.second);
+ }
+ }
+ if (!pendingHotplugs.empty()) {
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
+ for (auto& pendingHotplug : pendingHotplugs) {
+ hotplug(callbackData, pendingHotplug.first, pendingHotplug.second);
+ }
+ }
+ return Error::None;
+}
+
+// Display functions
+
+std::atomic<hwc2_display_t> HWC2On1Adapter::Display::sNextId(1);
+
+HWC2On1Adapter::Display::Display(HWC2On1Adapter& device, HWC2::DisplayType type)
+ : mId(sNextId++),
+ mDevice(device),
+ mDirtyCount(0),
+ mStateMutex(),
+ mZIsDirty(false),
+ mHwc1RequestedContents(nullptr),
+ mHwc1ReceivedContents(nullptr),
+ mRetireFence(),
+ mChanges(),
+ mHwc1Id(-1),
+ mConfigs(),
+ mActiveConfig(nullptr),
+ mName(),
+ mType(type),
+ mPowerMode(PowerMode::Off),
+ mVsyncEnabled(Vsync::Invalid),
+ mClientTarget(),
+ mOutputBuffer(),
+ mLayers() {}
+
+Error HWC2On1Adapter::Display::acceptChanges()
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ ALOGV("[%" PRIu64 "] acceptChanges failed, not validated", mId);
+ return Error::NotValidated;
+ }
+
+ ALOGV("[%" PRIu64 "] acceptChanges", mId);
+
+ for (auto& change : mChanges->getTypeChanges()) {
+ auto layerId = change.first;
+ auto type = change.second;
+ auto layer = mDevice.mLayers[layerId];
+ layer->setCompositionType(type);
+ }
+
+ mChanges->clearTypeChanges();
+
+ mHwc1RequestedContents = std::move(mHwc1ReceivedContents);
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::createLayer(hwc2_layer_t* outLayerId)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ auto layer = *mLayers.emplace(std::make_shared<Layer>(*this));
+ mDevice.mLayers.emplace(std::make_pair(layer->getId(), layer));
+ *outLayerId = layer->getId();
+ ALOGV("[%" PRIu64 "] created layer %" PRIu64, mId, *outLayerId);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::destroyLayer(hwc2_layer_t layerId)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ const auto mapLayer = mDevice.mLayers.find(layerId);
+ if (mapLayer == mDevice.mLayers.end()) {
+ ALOGV("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer",
+ mId, layerId);
+ return Error::BadLayer;
+ }
+ const auto layer = mapLayer->second;
+ mDevice.mLayers.erase(mapLayer);
+ const auto zRange = mLayers.equal_range(layer);
+ for (auto current = zRange.first; current != zRange.second; ++current) {
+ if (**current == *layer) {
+ current = mLayers.erase(current);
+ break;
+ }
+ }
+ ALOGV("[%" PRIu64 "] destroyed layer %" PRIu64, mId, layerId);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getActiveConfig(hwc2_config_t* outConfig)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mActiveConfig) {
+ ALOGV("[%" PRIu64 "] getActiveConfig --> %s", mId,
+ to_string(Error::BadConfig).c_str());
+ return Error::BadConfig;
+ }
+ auto configId = mActiveConfig->getId();
+ ALOGV("[%" PRIu64 "] getActiveConfig --> %u", mId, configId);
+ *outConfig = configId;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getAttribute(hwc2_config_t configId,
+ Attribute attribute, int32_t* outValue)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+ ALOGV("[%" PRIu64 "] getAttribute failed: bad config (%u)", mId,
+ configId);
+ return Error::BadConfig;
+ }
+ *outValue = mConfigs[configId]->getAttribute(attribute);
+ ALOGV("[%" PRIu64 "] getAttribute(%u, %s) --> %d", mId, configId,
+ to_string(attribute).c_str(), *outValue);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getChangedCompositionTypes(
+ uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ ALOGE("[%" PRIu64 "] getChangedCompositionTypes failed: not validated",
+ mId);
+ return Error::NotValidated;
+ }
+
+ if ((outLayers == nullptr) || (outTypes == nullptr)) {
+ *outNumElements = mChanges->getTypeChanges().size();
+ return Error::None;
+ }
+
+ uint32_t numWritten = 0;
+ for (const auto& element : mChanges->getTypeChanges()) {
+ if (numWritten == *outNumElements) {
+ break;
+ }
+ auto layerId = element.first;
+ auto intType = static_cast<int32_t>(element.second);
+ ALOGV("Adding %" PRIu64 " %s", layerId,
+ to_string(element.second).c_str());
+ outLayers[numWritten] = layerId;
+ outTypes[numWritten] = intType;
+ ++numWritten;
+ }
+ *outNumElements = numWritten;
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getConfigs(uint32_t* outNumConfigs,
+ hwc2_config_t* outConfigs)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!outConfigs) {
+ *outNumConfigs = mConfigs.size();
+ return Error::None;
+ }
+ uint32_t numWritten = 0;
+ for (const auto& config : mConfigs) {
+ if (numWritten == *outNumConfigs) {
+ break;
+ }
+ outConfigs[numWritten] = config->getId();
+ ++numWritten;
+ }
+ *outNumConfigs = numWritten;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getDozeSupport(int32_t* outSupport)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (mDevice.mHwc1MinorVersion < 4 || mHwc1Id != 0) {
+ *outSupport = 0;
+ } else {
+ *outSupport = 1;
+ }
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!outName) {
+ *outSize = mName.size();
+ return Error::None;
+ }
+ auto numCopied = mName.copy(outName, *outSize);
+ *outSize = numCopied;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getReleaseFences(uint32_t* outNumElements,
+ hwc2_layer_t* outLayers, int32_t* outFences)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ uint32_t numWritten = 0;
+ bool outputsNonNull = (outLayers != nullptr) && (outFences != nullptr);
+ for (const auto& layer : mLayers) {
+ if (outputsNonNull && (numWritten == *outNumElements)) {
+ break;
+ }
+
+ auto releaseFence = layer->getReleaseFence();
+ if (releaseFence != Fence::NO_FENCE) {
+ if (outputsNonNull) {
+ outLayers[numWritten] = layer->getId();
+ outFences[numWritten] = releaseFence->dup();
+ }
+ ++numWritten;
+ }
+ }
+ *outNumElements = numWritten;
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getRequests(int32_t* outDisplayRequests,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outLayerRequests)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ return Error::NotValidated;
+ }
+
+ if (outLayers == nullptr || outLayerRequests == nullptr) {
+ *outNumElements = mChanges->getNumLayerRequests();
+ return Error::None;
+ }
+
+ *outDisplayRequests = mChanges->getDisplayRequests();
+ uint32_t numWritten = 0;
+ for (const auto& request : mChanges->getLayerRequests()) {
+ if (numWritten == *outNumElements) {
+ break;
+ }
+ outLayers[numWritten] = request.first;
+ outLayerRequests[numWritten] = static_cast<int32_t>(request.second);
+ ++numWritten;
+ }
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getType(int32_t* outType)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ *outType = static_cast<int32_t>(mType);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::present(int32_t* outRetireFence)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (mChanges) {
+ Error error = mDevice.setAllDisplays();
+ if (error != Error::None) {
+ ALOGE("[%" PRIu64 "] present: setAllDisplaysFailed (%s)", mId,
+ to_string(error).c_str());
+ return error;
+ }
+ }
+
+ *outRetireFence = mRetireFence.get()->dup();
+ ALOGV("[%" PRIu64 "] present returning retire fence %d", mId,
+ *outRetireFence);
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setActiveConfig(hwc2_config_t configId)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ auto config = getConfig(configId);
+ if (!config) {
+ return Error::BadConfig;
+ }
+ mActiveConfig = config;
+ if (mDevice.mHwc1MinorVersion >= 4) {
+ int error = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
+ mHwc1Id, static_cast<int>(configId));
+ ALOGE_IF(error != 0,
+ "setActiveConfig: Failed to set active config on HWC1 (%d)",
+ error);
+ }
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setClientTarget(buffer_handle_t target,
+ int32_t acquireFence, int32_t /*dataspace*/)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] setClientTarget(%p, %d)", mId, target, acquireFence);
+ mClientTarget.setBuffer(target);
+ mClientTarget.setFence(acquireFence);
+ // dataspace can't be used by HWC1, so ignore it
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setOutputBuffer(buffer_handle_t buffer,
+ int32_t releaseFence)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] setOutputBuffer(%p, %d)", mId, buffer, releaseFence);
+ mOutputBuffer.setBuffer(buffer);
+ mOutputBuffer.setFence(releaseFence);
+ return Error::None;
+}
+
+static bool isValid(PowerMode mode)
+{
+ switch (mode) {
+ case PowerMode::Off: // Fall-through
+ case PowerMode::DozeSuspend: // Fall-through
+ case PowerMode::Doze: // Fall-through
+ case PowerMode::On: return true;
+ default: return false;
+ }
+}
+
+static int getHwc1PowerMode(PowerMode mode)
+{
+ switch (mode) {
+ case PowerMode::Off: return HWC_POWER_MODE_OFF;
+ case PowerMode::DozeSuspend: return HWC_POWER_MODE_DOZE_SUSPEND;
+ case PowerMode::Doze: return HWC_POWER_MODE_DOZE;
+ case PowerMode::On: return HWC_POWER_MODE_NORMAL;
+ default: return HWC_POWER_MODE_OFF;
+ }
+}
+
+Error HWC2On1Adapter::Display::setPowerMode(PowerMode mode)
+{
+ if (!isValid(mode)) {
+ return Error::BadParameter;
+ }
+ if (mode == mPowerMode) {
+ return Error::None;
+ }
+
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ int error = 0;
+ if (mDevice.mHwc1MinorVersion < 4) {
+ error = mDevice.mHwc1Device->blank(mDevice.mHwc1Device, mHwc1Id,
+ mode == PowerMode::Off);
+ } else {
+ error = mDevice.mHwc1Device->setPowerMode(mDevice.mHwc1Device,
+ mHwc1Id, getHwc1PowerMode(mode));
+ }
+ ALOGE_IF(error != 0, "setPowerMode: Failed to set power mode on HWC1 (%d)",
+ error);
+
+ ALOGV("[%" PRIu64 "] setPowerMode(%s)", mId, to_string(mode).c_str());
+ mPowerMode = mode;
+ return Error::None;
+}
+
+static bool isValid(Vsync enable) {
+ switch (enable) {
+ case Vsync::Enable: // Fall-through
+ case Vsync::Disable: return true;
+ default: return false;
+ }
+}
+
+Error HWC2On1Adapter::Display::setVsyncEnabled(Vsync enable)
+{
+ if (!isValid(enable)) {
+ return Error::BadParameter;
+ }
+ if (enable == mVsyncEnabled) {
+ return Error::None;
+ }
+
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ int error = mDevice.mHwc1Device->eventControl(mDevice.mHwc1Device,
+ mHwc1Id, HWC_EVENT_VSYNC, enable == Vsync::Enable);
+ ALOGE_IF(error != 0, "setVsyncEnabled: Failed to set vsync on HWC1 (%d)",
+ error);
+
+ mVsyncEnabled = enable;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::validate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] Entering validate", mId);
+
+ if (!mChanges) {
+ if (!mDevice.prepareAllDisplays()) {
+ return Error::BadDisplay;
+ }
+ }
+
+ *outNumTypes = mChanges->getNumTypes();
+ *outNumRequests = mChanges->getNumLayerRequests();
+ ALOGV("[%" PRIu64 "] validate --> %u types, %u requests", mId, *outNumTypes,
+ *outNumRequests);
+ for (auto request : mChanges->getTypeChanges()) {
+ ALOGV("Layer %" PRIu64 " --> %s", request.first,
+ to_string(request.second).c_str());
+ }
+ return *outNumTypes > 0 ? Error::HasChanges : Error::None;
+}
+
+// Display helpers
+
+Error HWC2On1Adapter::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ const auto mapLayer = mDevice.mLayers.find(layerId);
+ if (mapLayer == mDevice.mLayers.end()) {
+ ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer", mId);
+ return Error::BadLayer;
+ }
+
+ const auto layer = mapLayer->second;
+ const auto zRange = mLayers.equal_range(layer);
+ bool layerOnDisplay = false;
+ for (auto current = zRange.first; current != zRange.second; ++current) {
+ if (**current == *layer) {
+ if ((*current)->getZ() == z) {
+ // Don't change anything if the Z hasn't changed
+ return Error::None;
+ }
+ current = mLayers.erase(current);
+ layerOnDisplay = true;
+ break;
+ }
+ }
+
+ if (!layerOnDisplay) {
+ ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display",
+ mId);
+ return Error::BadLayer;
+ }
+
+ layer->setZ(z);
+ mLayers.emplace(std::move(layer));
+ mZIsDirty = true;
+
+ return Error::None;
+}
+
+static constexpr uint32_t ATTRIBUTES[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+static constexpr size_t NUM_ATTRIBUTES = sizeof(ATTRIBUTES) / sizeof(uint32_t);
+
+static constexpr uint32_t ATTRIBUTE_MAP[] = {
+ 5, // HWC_DISPLAY_NO_ATTRIBUTE = 0
+ 0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
+ 1, // HWC_DISPLAY_WIDTH = 2,
+ 2, // HWC_DISPLAY_HEIGHT = 3,
+ 3, // HWC_DISPLAY_DPI_X = 4,
+ 4, // HWC_DISPLAY_DPI_Y = 5,
+};
+
+template <uint32_t attribute>
+static constexpr bool attributesMatch()
+{
+ return ATTRIBUTES[ATTRIBUTE_MAP[attribute]] == attribute;
+}
+static_assert(attributesMatch<HWC_DISPLAY_VSYNC_PERIOD>(),
+ "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_WIDTH>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_HEIGHT>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_DPI_X>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_DPI_Y>(), "Tables out of sync");
+
+void HWC2On1Adapter::Display::populateConfigs()
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] populateConfigs", mId);
+
+ if (mHwc1Id == -1) {
+ ALOGE("populateConfigs: HWC1 ID not set");
+ return;
+ }
+
+ const size_t MAX_NUM_CONFIGS = 128;
+ uint32_t configs[MAX_NUM_CONFIGS] = {};
+ size_t numConfigs = MAX_NUM_CONFIGS;
+ mDevice.mHwc1Device->getDisplayConfigs(mDevice.mHwc1Device, mHwc1Id,
+ configs, &numConfigs);
+
+ for (size_t c = 0; c < numConfigs; ++c) {
+ uint32_t hwc1ConfigId = configs[c];
+ hwc2_config_t id = static_cast<hwc2_config_t>(mConfigs.size());
+ mConfigs.emplace_back(
+ std::make_shared<Config>(*this, id, hwc1ConfigId));
+ auto& config = mConfigs[id];
+
+ int32_t values[NUM_ATTRIBUTES] = {};
+ mDevice.mHwc1Device->getDisplayAttributes(mDevice.mHwc1Device, mHwc1Id,
+ hwc1ConfigId, ATTRIBUTES, values);
+
+ config->setAttribute(Attribute::VsyncPeriod,
+ values[ATTRIBUTE_MAP[HWC_DISPLAY_VSYNC_PERIOD]]);
+ config->setAttribute(Attribute::Width,
+ values[ATTRIBUTE_MAP[HWC_DISPLAY_WIDTH]]);
+ config->setAttribute(Attribute::Height,
+ values[ATTRIBUTE_MAP[HWC_DISPLAY_HEIGHT]]);
+ config->setAttribute(Attribute::DpiX,
+ values[ATTRIBUTE_MAP[HWC_DISPLAY_DPI_X]]);
+ config->setAttribute(Attribute::DpiY,
+ values[ATTRIBUTE_MAP[HWC_DISPLAY_DPI_Y]]);
+
+ ALOGV("Found config: %s", config->toString().c_str());
+ }
+
+ ALOGV("Getting active config");
+ if (mDevice.mHwc1Device->getActiveConfig != nullptr) {
+ auto activeConfig = mDevice.mHwc1Device->getActiveConfig(
+ mDevice.mHwc1Device, mHwc1Id);
+ if (activeConfig >= 0) {
+ ALOGV("Setting active config to %d", activeConfig);
+ mActiveConfig = mConfigs[activeConfig];
+ }
+ } else {
+ ALOGV("getActiveConfig is null, choosing config 0");
+ mActiveConfig = mConfigs[0];
+ }
+}
+
+void HWC2On1Adapter::Display::populateConfigs(uint32_t width, uint32_t height)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ mConfigs.emplace_back(std::make_shared<Config>(*this, 0, 0));
+ auto& config = mConfigs[0];
+
+ config->setAttribute(Attribute::Width, static_cast<int32_t>(width));
+ config->setAttribute(Attribute::Height, static_cast<int32_t>(height));
+ mActiveConfig = config;
+}
+
+bool HWC2On1Adapter::Display::prepare()
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ // Only prepare display contents for displays HWC1 knows about
+ if (mHwc1Id == -1) {
+ return true;
+ }
+
+ // It doesn't make sense to prepare a display for which there is no active
+ // config, so return early
+ if (!mActiveConfig) {
+ ALOGE("[%" PRIu64 "] Attempted to prepare, but no config active", mId);
+ return false;
+ }
+
+ ALOGV("[%" PRIu64 "] Entering prepare", mId);
+
+ auto currentCount = mHwc1RequestedContents ?
+ mHwc1RequestedContents->numHwLayers : 0;
+ auto requiredCount = mLayers.size() + 1;
+ ALOGV("[%" PRIu64 "] Requires %zd layers, %zd allocated in %p", mId,
+ requiredCount, currentCount, mHwc1RequestedContents.get());
+
+ bool layerCountChanged = (currentCount != requiredCount);
+ if (layerCountChanged) {
+ reallocateHwc1Contents();
+ }
+
+ bool applyAllState = false;
+ if (layerCountChanged || mZIsDirty) {
+ assignHwc1LayerIds();
+ mZIsDirty = false;
+ applyAllState = true;
+ }
+
+ mHwc1RequestedContents->retireFenceFd = -1;
+ mHwc1RequestedContents->flags = 0;
+ if (isDirty() || applyAllState) {
+ mHwc1RequestedContents->flags |= HWC_GEOMETRY_CHANGED;
+ }
+
+ for (auto& layer : mLayers) {
+ auto& hwc1Layer = mHwc1RequestedContents->hwLayers[layer->getHwc1Id()];
+ hwc1Layer.releaseFenceFd = -1;
+ layer->applyState(hwc1Layer, applyAllState);
+ }
+
+ mHwc1RequestedContents->outbuf = mOutputBuffer.getBuffer();
+ mHwc1RequestedContents->outbufAcquireFenceFd = mOutputBuffer.getFence();
+
+ prepareFramebufferTarget();
+
+ return true;
+}
+
+static void cloneHWCRegion(hwc_region_t& region)
+{
+ auto size = sizeof(hwc_rect_t) * region.numRects;
+ auto newRects = static_cast<hwc_rect_t*>(std::malloc(size));
+ std::copy_n(region.rects, region.numRects, newRects);
+ region.rects = newRects;
+}
+
+HWC2On1Adapter::Display::HWC1Contents
+ HWC2On1Adapter::Display::cloneRequestedContents() const
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ size_t size = sizeof(hwc_display_contents_1_t) +
+ sizeof(hwc_layer_1_t) * (mHwc1RequestedContents->numHwLayers);
+ auto contents = static_cast<hwc_display_contents_1_t*>(std::malloc(size));
+ std::memcpy(contents, mHwc1RequestedContents.get(), size);
+ for (size_t layerId = 0; layerId < contents->numHwLayers; ++layerId) {
+ auto& layer = contents->hwLayers[layerId];
+ // Deep copy the regions to avoid double-frees
+ cloneHWCRegion(layer.visibleRegionScreen);
+ cloneHWCRegion(layer.surfaceDamage);
+ }
+ return HWC1Contents(contents);
+}
+
+void HWC2On1Adapter::Display::setReceivedContents(HWC1Contents contents)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ mHwc1ReceivedContents = std::move(contents);
+
+ mChanges.reset(new Changes);
+
+ size_t numLayers = mHwc1ReceivedContents->numHwLayers;
+ for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
+ const auto& receivedLayer = mHwc1ReceivedContents->hwLayers[hwc1Id];
+ if (mHwc1LayerMap.count(hwc1Id) == 0) {
+ ALOGE_IF(receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET,
+ "setReceivedContents: HWC1 layer %zd doesn't have a"
+ " matching HWC2 layer, and isn't the framebuffer target",
+ hwc1Id);
+ continue;
+ }
+
+ Layer& layer = *mHwc1LayerMap[hwc1Id];
+ updateTypeChanges(receivedLayer, layer);
+ updateLayerRequests(receivedLayer, layer);
+ }
+}
+
+bool HWC2On1Adapter::Display::hasChanges() const
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+ return mChanges != nullptr;
+}
+
+Error HWC2On1Adapter::Display::set(hwc_display_contents_1& hwcContents)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges || (mChanges->getNumTypes() > 0)) {
+ ALOGE("[%" PRIu64 "] set failed: not validated", mId);
+ return Error::NotValidated;
+ }
+
+ // Set up the client/framebuffer target
+ auto numLayers = hwcContents.numHwLayers;
+
+ // Close acquire fences on FRAMEBUFFER layers, since they will not be used
+ // by HWC
+ for (size_t l = 0; l < numLayers - 1; ++l) {
+ auto& layer = hwcContents.hwLayers[l];
+ if (layer.compositionType == HWC_FRAMEBUFFER) {
+ ALOGV("Closing fence %d for layer %zd", layer.acquireFenceFd, l);
+ close(layer.acquireFenceFd);
+ layer.acquireFenceFd = -1;
+ }
+ }
+
+ auto& clientTargetLayer = hwcContents.hwLayers[numLayers - 1];
+ if (clientTargetLayer.compositionType == HWC_FRAMEBUFFER_TARGET) {
+ clientTargetLayer.handle = mClientTarget.getBuffer();
+ clientTargetLayer.acquireFenceFd = mClientTarget.getFence();
+ } else {
+ ALOGE("[%" PRIu64 "] set: last HWC layer wasn't FRAMEBUFFER_TARGET",
+ mId);
+ }
+
+ mChanges.reset();
+
+ return Error::None;
+}
+
+void HWC2On1Adapter::Display::addRetireFence(int fenceFd)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+ mRetireFence.add(fenceFd);
+}
+
+void HWC2On1Adapter::Display::addReleaseFences(
+ const hwc_display_contents_1_t& hwcContents)
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ size_t numLayers = hwcContents.numHwLayers;
+ for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
+ const auto& receivedLayer = hwcContents.hwLayers[hwc1Id];
+ if (mHwc1LayerMap.count(hwc1Id) == 0) {
+ if (receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET) {
+ ALOGE("addReleaseFences: HWC1 layer %zd doesn't have a"
+ " matching HWC2 layer, and isn't the framebuffer"
+ " target", hwc1Id);
+ }
+ // Close the framebuffer target release fence since we will use the
+ // display retire fence instead
+ if (receivedLayer.releaseFenceFd != -1) {
+ close(receivedLayer.releaseFenceFd);
+ }
+ continue;
+ }
+
+ Layer& layer = *mHwc1LayerMap[hwc1Id];
+ ALOGV("Adding release fence %d to layer %" PRIu64,
+ receivedLayer.releaseFenceFd, layer.getId());
+ layer.addReleaseFence(receivedLayer.releaseFenceFd);
+ }
+}
+
+static std::string hwc1CompositionString(int32_t type)
+{
+ switch (type) {
+ case HWC_FRAMEBUFFER: return "Framebuffer";
+ case HWC_OVERLAY: return "Overlay";
+ case HWC_BACKGROUND: return "Background";
+ case HWC_FRAMEBUFFER_TARGET: return "FramebufferTarget";
+ case HWC_SIDEBAND: return "Sideband";
+ case HWC_CURSOR_OVERLAY: return "CursorOverlay";
+ default:
+ return std::string("Unknown (") + std::to_string(type) + ")";
+ }
+}
+
+static std::string hwc1TransformString(int32_t transform)
+{
+ switch (transform) {
+ case 0: return "None";
+ case HWC_TRANSFORM_FLIP_H: return "FlipH";
+ case HWC_TRANSFORM_FLIP_V: return "FlipV";
+ case HWC_TRANSFORM_ROT_90: return "Rotate90";
+ case HWC_TRANSFORM_ROT_180: return "Rotate180";
+ case HWC_TRANSFORM_ROT_270: return "Rotate270";
+ case HWC_TRANSFORM_FLIP_H_ROT_90: return "FlipHRotate90";
+ case HWC_TRANSFORM_FLIP_V_ROT_90: return "FlipVRotate90";
+ default:
+ return std::string("Unknown (") + std::to_string(transform) + ")";
+ }
+}
+
+static std::string hwc1BlendModeString(int32_t mode)
+{
+ switch (mode) {
+ case HWC_BLENDING_NONE: return "None";
+ case HWC_BLENDING_PREMULT: return "Premultiplied";
+ case HWC_BLENDING_COVERAGE: return "Coverage";
+ default:
+ return std::string("Unknown (") + std::to_string(mode) + ")";
+ }
+}
+
+static std::string rectString(hwc_rect_t rect)
+{
+ std::stringstream output;
+ output << "[" << rect.left << ", " << rect.top << ", ";
+ output << rect.right << ", " << rect.bottom << "]";
+ return output.str();
+}
+
+static std::string approximateFloatString(float f)
+{
+ if (static_cast<int32_t>(f) == f) {
+ return std::to_string(static_cast<int32_t>(f));
+ }
+ int32_t truncated = static_cast<int32_t>(f * 10);
+ bool approximate = (static_cast<float>(truncated) != f * 10);
+ const size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ auto bytesWritten = snprintf(buffer, BUFFER_SIZE,
+ "%s%.1f", approximate ? "~" : "", f);
+ return std::string(buffer, bytesWritten);
+}
+
+static std::string frectString(hwc_frect_t frect)
+{
+ std::stringstream output;
+ output << "[" << approximateFloatString(frect.left) << ", ";
+ output << approximateFloatString(frect.top) << ", ";
+ output << approximateFloatString(frect.right) << ", ";
+ output << approximateFloatString(frect.bottom) << "]";
+ return output.str();
+}
+
+static std::string colorString(hwc_color_t color)
+{
+ std::stringstream output;
+ output << "RGBA [";
+ output << static_cast<int32_t>(color.r) << ", ";
+ output << static_cast<int32_t>(color.g) << ", ";
+ output << static_cast<int32_t>(color.b) << ", ";
+ output << static_cast<int32_t>(color.a) << "]";
+ return output.str();
+}
+
+static std::string alphaString(float f)
+{
+ const size_t BUFFER_SIZE = 8;
+ char buffer[BUFFER_SIZE] = {};
+ auto bytesWritten = snprintf(buffer, BUFFER_SIZE, "%.3f", f);
+ return std::string(buffer, bytesWritten);
+}
+
+static std::string to_string(const hwc_layer_1_t& hwcLayer,
+ int32_t hwc1MinorVersion)
+{
+ const char* fill = " ";
+
+ std::stringstream output;
+
+ output << " Composition: " <<
+ hwc1CompositionString(hwcLayer.compositionType);
+
+ if (hwcLayer.compositionType == HWC_BACKGROUND) {
+ output << " Color: " << colorString(hwcLayer.backgroundColor) << '\n';
+ } else if (hwcLayer.compositionType == HWC_SIDEBAND) {
+ output << " Stream: " << hwcLayer.sidebandStream << '\n';
+ } else {
+ output << " Buffer: " << hwcLayer.handle << "/" <<
+ hwcLayer.acquireFenceFd << '\n';
+ }
+
+ output << fill << "Display frame: " << rectString(hwcLayer.displayFrame) <<
+ '\n';
+
+ output << fill << "Source crop: ";
+ if (hwc1MinorVersion >= 3) {
+ output << frectString(hwcLayer.sourceCropf) << '\n';
+ } else {
+ output << rectString(hwcLayer.sourceCropi) << '\n';
+ }
+
+ output << fill << "Transform: " << hwc1TransformString(hwcLayer.transform);
+ output << " Blend mode: " << hwc1BlendModeString(hwcLayer.blending);
+ if (hwcLayer.planeAlpha != 0xFF) {
+ output << " Alpha: " << alphaString(hwcLayer.planeAlpha / 255.0f);
+ }
+ output << '\n';
+
+ if (hwcLayer.hints != 0) {
+ output << fill << "Hints:";
+ if ((hwcLayer.hints & HWC_HINT_TRIPLE_BUFFER) != 0) {
+ output << " TripleBuffer";
+ }
+ if ((hwcLayer.hints & HWC_HINT_CLEAR_FB) != 0) {
+ output << " ClearFB";
+ }
+ output << '\n';
+ }
+
+ if (hwcLayer.flags != 0) {
+ output << fill << "Flags:";
+ if ((hwcLayer.flags & HWC_SKIP_LAYER) != 0) {
+ output << " SkipLayer";
+ }
+ if ((hwcLayer.flags & HWC_IS_CURSOR_LAYER) != 0) {
+ output << " IsCursorLayer";
+ }
+ output << '\n';
+ }
+
+ return output.str();
+}
+
+static std::string to_string(const hwc_display_contents_1_t& hwcContents,
+ int32_t hwc1MinorVersion)
+{
+ const char* fill = " ";
+
+ std::stringstream output;
+ output << fill << "Geometry changed: " <<
+ ((hwcContents.flags & HWC_GEOMETRY_CHANGED) != 0 ? "Y\n" : "N\n");
+
+ output << fill << hwcContents.numHwLayers << " Layer" <<
+ ((hwcContents.numHwLayers == 1) ? "\n" : "s\n");
+ for (size_t layer = 0; layer < hwcContents.numHwLayers; ++layer) {
+ output << fill << " Layer " << layer;
+ output << to_string(hwcContents.hwLayers[layer], hwc1MinorVersion);
+ }
+
+ if (hwcContents.outbuf != nullptr) {
+ output << fill << "Output buffer: " << hwcContents.outbuf << "/" <<
+ hwcContents.outbufAcquireFenceFd << '\n';
+ }
+
+ return output.str();
+}
+
+std::string HWC2On1Adapter::Display::dump() const
+{
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ std::stringstream output;
+
+ output << " Display " << mId << ": ";
+ output << to_string(mType) << " ";
+ output << "HWC1 ID: " << mHwc1Id << " ";
+ output << "Power mode: " << to_string(mPowerMode) << " ";
+ output << "Vsync: " << to_string(mVsyncEnabled) << '\n';
+
+ output << " " << mConfigs.size() << " Config" <<
+ (mConfigs.size() == 1 ? "" : "s") << " (* Active)\n";
+ for (const auto& config : mConfigs) {
+ if (config == mActiveConfig) {
+ output << " * " << config->toString();
+ } else {
+ output << " " << config->toString();
+ }
+ }
+ output << '\n';
+
+ output << " " << mLayers.size() << " Layer" <<
+ (mLayers.size() == 1 ? "" : "s") << '\n';
+ for (const auto& layer : mLayers) {
+ output << layer->dump();
+ }
+
+ output << " Client target: " << mClientTarget.getBuffer() << '\n';
+
+ if (mOutputBuffer.getBuffer() != nullptr) {
+ output << " Output buffer: " << mOutputBuffer.getBuffer() << '\n';
+ }
+
+ if (mHwc1ReceivedContents) {
+ output << " Last received HWC1 state\n";
+ output << to_string(*mHwc1ReceivedContents, mDevice.mHwc1MinorVersion);
+ } else if (mHwc1RequestedContents) {
+ output << " Last requested HWC1 state\n";
+ output << to_string(*mHwc1RequestedContents, mDevice.mHwc1MinorVersion);
+ }
+
+ return output.str();
+}
+
+void HWC2On1Adapter::Display::Config::setAttribute(HWC2::Attribute attribute,
+ int32_t value)
+{
+ mAttributes[attribute] = value;
+}
+
+int32_t HWC2On1Adapter::Display::Config::getAttribute(Attribute attribute) const
+{
+ if (mAttributes.count(attribute) == 0) {
+ return -1;
+ }
+ return mAttributes.at(attribute);
+}
+
+std::string HWC2On1Adapter::Display::Config::toString() const
+{
+ std::string output;
+
+ const size_t BUFFER_SIZE = 100;
+ char buffer[BUFFER_SIZE] = {};
+ auto writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ "[%u] %u x %u", mHwcId,
+ mAttributes.at(HWC2::Attribute::Width),
+ mAttributes.at(HWC2::Attribute::Height));
+ output.append(buffer, writtenBytes);
+
+ if (mAttributes.count(HWC2::Attribute::VsyncPeriod) != 0) {
+ std::memset(buffer, 0, BUFFER_SIZE);
+ writtenBytes = snprintf(buffer, BUFFER_SIZE, " @ %.1f Hz",
+ 1e9 / mAttributes.at(HWC2::Attribute::VsyncPeriod));
+ output.append(buffer, writtenBytes);
+ }
+
+ if (mAttributes.count(HWC2::Attribute::DpiX) != 0 &&
+ mAttributes.at(HWC2::Attribute::DpiX) != -1) {
+ std::memset(buffer, 0, BUFFER_SIZE);
+ writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ ", DPI: %.1f x %.1f",
+ mAttributes.at(HWC2::Attribute::DpiX) / 1000.0f,
+ mAttributes.at(HWC2::Attribute::DpiY) / 1000.0f);
+ output.append(buffer, writtenBytes);
+ }
+
+ return output;
+}
+
+std::shared_ptr<const HWC2On1Adapter::Display::Config>
+ HWC2On1Adapter::Display::getConfig(hwc2_config_t configId) const
+{
+ if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+ return nullptr;
+ }
+ return mConfigs[configId];
+}
+
+void HWC2On1Adapter::Display::reallocateHwc1Contents()
+{
+ // Allocate an additional layer for the framebuffer target
+ auto numLayers = mLayers.size() + 1;
+ size_t size = sizeof(hwc_display_contents_1_t) +
+ sizeof(hwc_layer_1_t) * numLayers;
+ ALOGV("[%" PRIu64 "] reallocateHwc1Contents creating %zd layer%s", mId,
+ numLayers, numLayers != 1 ? "s" : "");
+ auto contents =
+ static_cast<hwc_display_contents_1_t*>(std::calloc(size, 1));
+ contents->numHwLayers = numLayers;
+ mHwc1RequestedContents.reset(contents);
+}
+
+void HWC2On1Adapter::Display::assignHwc1LayerIds()
+{
+ mHwc1LayerMap.clear();
+ size_t nextHwc1Id = 0;
+ for (auto& layer : mLayers) {
+ mHwc1LayerMap[nextHwc1Id] = layer;
+ layer->setHwc1Id(nextHwc1Id++);
+ }
+}
+
+void HWC2On1Adapter::Display::updateTypeChanges(const hwc_layer_1_t& hwc1Layer,
+ const Layer& layer)
+{
+ auto layerId = layer.getId();
+ switch (hwc1Layer.compositionType) {
+ case HWC_FRAMEBUFFER:
+ if (layer.getCompositionType() != Composition::Client) {
+ mChanges->addTypeChange(layerId, Composition::Client);
+ }
+ break;
+ case HWC_OVERLAY:
+ if (layer.getCompositionType() != Composition::Device) {
+ mChanges->addTypeChange(layerId, Composition::Device);
+ }
+ break;
+ case HWC_BACKGROUND:
+ ALOGE_IF(layer.getCompositionType() != Composition::SolidColor,
+ "updateTypeChanges: HWC1 requested BACKGROUND, but HWC2"
+ " wasn't expecting SolidColor");
+ break;
+ case HWC_FRAMEBUFFER_TARGET:
+ // Do nothing, since it shouldn't be modified by HWC1
+ break;
+ case HWC_SIDEBAND:
+ ALOGE_IF(layer.getCompositionType() != Composition::Sideband,
+ "updateTypeChanges: HWC1 requested SIDEBAND, but HWC2"
+ " wasn't expecting Sideband");
+ break;
+ case HWC_CURSOR_OVERLAY:
+ ALOGE_IF(layer.getCompositionType() != Composition::Cursor,
+ "updateTypeChanges: HWC1 requested CURSOR_OVERLAY, but"
+ " HWC2 wasn't expecting Cursor");
+ break;
+ }
+}
+
+void HWC2On1Adapter::Display::updateLayerRequests(
+ const hwc_layer_1_t& hwc1Layer, const Layer& layer)
+{
+ if ((hwc1Layer.hints & HWC_HINT_CLEAR_FB) != 0) {
+ mChanges->addLayerRequest(layer.getId(),
+ LayerRequest::ClearClientTarget);
+ }
+}
+
+void HWC2On1Adapter::Display::prepareFramebufferTarget()
+{
+ // We check that mActiveConfig is valid in Display::prepare
+ int32_t width = mActiveConfig->getAttribute(Attribute::Width);
+ int32_t height = mActiveConfig->getAttribute(Attribute::Height);
+
+ auto& hwc1Target = mHwc1RequestedContents->hwLayers[mLayers.size()];
+ hwc1Target.compositionType = HWC_FRAMEBUFFER_TARGET;
+ hwc1Target.releaseFenceFd = -1;
+ hwc1Target.hints = 0;
+ hwc1Target.flags = 0;
+ hwc1Target.transform = 0;
+ hwc1Target.blending = HWC_BLENDING_PREMULT;
+ if (mDevice.getHwc1MinorVersion() < 3) {
+ hwc1Target.sourceCropi = {0, 0, width, height};
+ } else {
+ hwc1Target.sourceCropf = {0.0f, 0.0f, static_cast<float>(width),
+ static_cast<float>(height)};
+ }
+ hwc1Target.displayFrame = {0, 0, width, height};
+ hwc1Target.planeAlpha = 255;
+ hwc1Target.visibleRegionScreen.numRects = 1;
+ auto rects = static_cast<hwc_rect_t*>(std::malloc(sizeof(hwc_rect_t)));
+ rects[0].left = 0;
+ rects[0].top = 0;
+ rects[0].right = width;
+ rects[0].bottom = height;
+ hwc1Target.visibleRegionScreen.rects = rects;
+
+ // We will set this to the correct value in set
+ hwc1Target.acquireFenceFd = -1;
+}
+
+// Layer functions
+
+std::atomic<hwc2_layer_t> HWC2On1Adapter::Layer::sNextId(1);
+
+HWC2On1Adapter::Layer::Layer(Display& display)
+ : mId(sNextId++),
+ mDisplay(display),
+ mBlendMode(*this, BlendMode::None),
+ mColor(*this, {0, 0, 0, 0}),
+ mCompositionType(*this, Composition::Invalid),
+ mDisplayFrame(*this, {0, 0, -1, -1}),
+ mPlaneAlpha(*this, 0.0f),
+ mSidebandStream(*this, nullptr),
+ mSourceCrop(*this, {0.0f, 0.0f, -1.0f, -1.0f}),
+ mTransform(*this, Transform::None),
+ mVisibleRegion(*this, std::vector<hwc_rect_t>()),
+ mZ(0),
+ mHwc1Id(0),
+ mHasUnsupportedPlaneAlpha(false) {}
+
+bool HWC2On1Adapter::SortLayersByZ::operator()(
+ const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs)
+{
+ return lhs->getZ() < rhs->getZ();
+}
+
+Error HWC2On1Adapter::Layer::setBuffer(buffer_handle_t buffer,
+ int32_t acquireFence)
+{
+ ALOGV("Setting acquireFence to %d for layer %" PRIu64, acquireFence, mId);
+ mBuffer.setBuffer(buffer);
+ mBuffer.setFence(acquireFence);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setCursorPosition(int32_t x, int32_t y)
+{
+ if (mCompositionType.getValue() != Composition::Cursor) {
+ return Error::BadLayer;
+ }
+
+ if (mDisplay.hasChanges()) {
+ return Error::NotValidated;
+ }
+
+ auto displayId = mDisplay.getHwc1Id();
+ auto hwc1Device = mDisplay.getDevice().getHwc1Device();
+ hwc1Device->setCursorPositionAsync(hwc1Device, displayId, x, y);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSurfaceDamage(hwc_region_t damage)
+{
+ mSurfaceDamage.resize(damage.numRects);
+ std::copy_n(damage.rects, damage.numRects, mSurfaceDamage.begin());
+ return Error::None;
+}
+
+// Layer state functions
+
+Error HWC2On1Adapter::Layer::setBlendMode(BlendMode mode)
+{
+ mBlendMode.setPending(mode);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setColor(hwc_color_t color)
+{
+ mColor.setPending(color);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setCompositionType(Composition type)
+{
+ mCompositionType.setPending(type);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setDisplayFrame(hwc_rect_t frame)
+{
+ mDisplayFrame.setPending(frame);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setPlaneAlpha(float alpha)
+{
+ mPlaneAlpha.setPending(alpha);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSidebandStream(const native_handle_t* stream)
+{
+ mSidebandStream.setPending(stream);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSourceCrop(hwc_frect_t crop)
+{
+ mSourceCrop.setPending(crop);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setTransform(Transform transform)
+{
+ mTransform.setPending(transform);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t rawVisible)
+{
+ std::vector<hwc_rect_t> visible(rawVisible.rects,
+ rawVisible.rects + rawVisible.numRects);
+ mVisibleRegion.setPending(std::move(visible));
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setZ(uint32_t z)
+{
+ mZ = z;
+ return Error::None;
+}
+
+void HWC2On1Adapter::Layer::addReleaseFence(int fenceFd)
+{
+ ALOGV("addReleaseFence %d to layer %" PRIu64, fenceFd, mId);
+ mReleaseFence.add(fenceFd);
+}
+
+const sp<Fence>& HWC2On1Adapter::Layer::getReleaseFence() const
+{
+ return mReleaseFence.get();
+}
+
+void HWC2On1Adapter::Layer::applyState(hwc_layer_1_t& hwc1Layer,
+ bool applyAllState)
+{
+ applyCommonState(hwc1Layer, applyAllState);
+ auto compositionType = mCompositionType.getPendingValue();
+ if (compositionType == Composition::SolidColor) {
+ applySolidColorState(hwc1Layer, applyAllState);
+ } else if (compositionType == Composition::Sideband) {
+ applySidebandState(hwc1Layer, applyAllState);
+ } else {
+ applyBufferState(hwc1Layer);
+ }
+ applyCompositionType(hwc1Layer, applyAllState);
+}
+
+// Layer dump helpers
+
+static std::string regionStrings(const std::vector<hwc_rect_t>& visibleRegion,
+ const std::vector<hwc_rect_t>& surfaceDamage)
+{
+ std::string regions;
+ regions += " Visible Region";
+ regions.resize(40, ' ');
+ regions += "Surface Damage\n";
+
+ size_t numPrinted = 0;
+ size_t maxSize = std::max(visibleRegion.size(), surfaceDamage.size());
+ while (numPrinted < maxSize) {
+ std::string line(" ");
+ if (visibleRegion.empty() && numPrinted == 0) {
+ line += "None";
+ } else if (numPrinted < visibleRegion.size()) {
+ line += rectString(visibleRegion[numPrinted]);
+ }
+ line.resize(40, ' ');
+ if (surfaceDamage.empty() && numPrinted == 0) {
+ line += "None";
+ } else if (numPrinted < surfaceDamage.size()) {
+ line += rectString(surfaceDamage[numPrinted]);
+ }
+ line += '\n';
+ regions += line;
+ ++numPrinted;
+ }
+ return regions;
+}
+
+std::string HWC2On1Adapter::Layer::dump() const
+{
+ std::stringstream output;
+ const char* fill = " ";
+
+ output << fill << to_string(mCompositionType.getPendingValue());
+ output << " Layer HWC2/1: " << mId << "/" << mHwc1Id << " ";
+ output << "Z: " << mZ;
+ if (mCompositionType.getValue() == HWC2::Composition::SolidColor) {
+ output << " " << colorString(mColor.getValue());
+ } else if (mCompositionType.getValue() == HWC2::Composition::Sideband) {
+ output << " Handle: " << mSidebandStream.getValue() << '\n';
+ } else {
+ output << " Buffer: " << mBuffer.getBuffer() << "/" <<
+ mBuffer.getFence() << '\n';
+ output << fill << " Display frame [LTRB]: " <<
+ rectString(mDisplayFrame.getValue()) << '\n';
+ output << fill << " Source crop: " <<
+ frectString(mSourceCrop.getValue()) << '\n';
+ output << fill << " Transform: " << to_string(mTransform.getValue());
+ output << " Blend mode: " << to_string(mBlendMode.getValue());
+ if (mPlaneAlpha.getValue() != 1.0f) {
+ output << " Alpha: " <<
+ alphaString(mPlaneAlpha.getValue()) << '\n';
+ } else {
+ output << '\n';
+ }
+ output << regionStrings(mVisibleRegion.getValue(), mSurfaceDamage);
+ }
+ return output.str();
+}
+
+static int getHwc1Blending(HWC2::BlendMode blendMode)
+{
+ switch (blendMode) {
+ case BlendMode::Coverage: return HWC_BLENDING_COVERAGE;
+ case BlendMode::Premultiplied: return HWC_BLENDING_PREMULT;
+ default: return HWC_BLENDING_NONE;
+ }
+}
+
+void HWC2On1Adapter::Layer::applyCommonState(hwc_layer_1_t& hwc1Layer,
+ bool applyAllState)
+{
+ auto minorVersion = mDisplay.getDevice().getHwc1MinorVersion();
+ if (applyAllState || mBlendMode.isDirty()) {
+ hwc1Layer.blending = getHwc1Blending(mBlendMode.getPendingValue());
+ mBlendMode.latch();
+ }
+ if (applyAllState || mDisplayFrame.isDirty()) {
+ hwc1Layer.displayFrame = mDisplayFrame.getPendingValue();
+ mDisplayFrame.latch();
+ }
+ if (applyAllState || mPlaneAlpha.isDirty()) {
+ auto pendingAlpha = mPlaneAlpha.getPendingValue();
+ if (minorVersion < 2) {
+ mHasUnsupportedPlaneAlpha = pendingAlpha < 1.0f;
+ } else {
+ hwc1Layer.planeAlpha =
+ static_cast<uint8_t>(255.0f * pendingAlpha + 0.5f);
+ }
+ mPlaneAlpha.latch();
+ }
+ if (applyAllState || mSourceCrop.isDirty()) {
+ if (minorVersion < 3) {
+ auto pending = mSourceCrop.getPendingValue();
+ hwc1Layer.sourceCropi.left =
+ static_cast<int32_t>(std::ceil(pending.left));
+ hwc1Layer.sourceCropi.top =
+ static_cast<int32_t>(std::ceil(pending.top));
+ hwc1Layer.sourceCropi.right =
+ static_cast<int32_t>(std::floor(pending.right));
+ hwc1Layer.sourceCropi.bottom =
+ static_cast<int32_t>(std::floor(pending.bottom));
+ } else {
+ hwc1Layer.sourceCropf = mSourceCrop.getPendingValue();
+ }
+ mSourceCrop.latch();
+ }
+ if (applyAllState || mTransform.isDirty()) {
+ hwc1Layer.transform =
+ static_cast<uint32_t>(mTransform.getPendingValue());
+ mTransform.latch();
+ }
+ if (applyAllState || mVisibleRegion.isDirty()) {
+ auto& hwc1VisibleRegion = hwc1Layer.visibleRegionScreen;
+
+ std::free(const_cast<hwc_rect_t*>(hwc1VisibleRegion.rects));
+
+ auto pending = mVisibleRegion.getPendingValue();
+ hwc_rect_t* newRects = static_cast<hwc_rect_t*>(
+ std::malloc(sizeof(hwc_rect_t) * pending.size()));
+ std::copy(pending.begin(), pending.end(), newRects);
+ hwc1VisibleRegion.rects = const_cast<const hwc_rect_t*>(newRects);
+ hwc1VisibleRegion.numRects = pending.size();
+ mVisibleRegion.latch();
+ }
+}
+
+void HWC2On1Adapter::Layer::applySolidColorState(hwc_layer_1_t& hwc1Layer,
+ bool applyAllState)
+{
+ if (applyAllState || mColor.isDirty()) {
+ hwc1Layer.backgroundColor = mColor.getPendingValue();
+ mColor.latch();
+ }
+}
+
+void HWC2On1Adapter::Layer::applySidebandState(hwc_layer_1_t& hwc1Layer,
+ bool applyAllState)
+{
+ if (applyAllState || mSidebandStream.isDirty()) {
+ hwc1Layer.sidebandStream = mSidebandStream.getPendingValue();
+ mSidebandStream.latch();
+ }
+}
+
+void HWC2On1Adapter::Layer::applyBufferState(hwc_layer_1_t& hwc1Layer)
+{
+ hwc1Layer.handle = mBuffer.getBuffer();
+ hwc1Layer.acquireFenceFd = mBuffer.getFence();
+}
+
+void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer,
+ bool applyAllState)
+{
+ if (mHasUnsupportedPlaneAlpha) {
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags = HWC_SKIP_LAYER;
+ return;
+ }
+
+ if (applyAllState || mCompositionType.isDirty()) {
+ hwc1Layer.flags = 0;
+ switch (mCompositionType.getPendingValue()) {
+ case Composition::Client:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ case Composition::Device:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ break;
+ case Composition::SolidColor:
+ hwc1Layer.compositionType = HWC_BACKGROUND;
+ break;
+ case Composition::Cursor:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ if (mDisplay.getDevice().getHwc1MinorVersion() >= 4) {
+ hwc1Layer.hints |= HWC_IS_CURSOR_LAYER;
+ }
+ break;
+ case Composition::Sideband:
+ if (mDisplay.getDevice().getHwc1MinorVersion() < 4) {
+ hwc1Layer.compositionType = HWC_SIDEBAND;
+ } else {
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ }
+ break;
+ default:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ }
+ ALOGV("Layer %" PRIu64 " %s set to %d", mId,
+ to_string(mCompositionType.getPendingValue()).c_str(),
+ hwc1Layer.compositionType);
+ ALOGV_IF(hwc1Layer.flags & HWC_SKIP_LAYER, " and skipping");
+ mCompositionType.latch();
+ }
+}
+
+// Adapter helpers
+
+void HWC2On1Adapter::populateCapabilities()
+{
+ ALOGV("populateCapabilities");
+ if (mHwc1MinorVersion >= 3U) {
+ int supportedTypes = 0;
+ auto result = mHwc1Device->query(mHwc1Device,
+ HWC_DISPLAY_TYPES_SUPPORTED, &supportedTypes);
+ if ((result == 0) && ((supportedTypes & HWC_DISPLAY_VIRTUAL) != 0)) {
+ ALOGI("Found support for HWC virtual displays");
+ mHwc1SupportsVirtualDisplays = true;
+ }
+ }
+ if (mHwc1MinorVersion >= 4U) {
+ mCapabilities.insert(Capability::SidebandStream);
+ }
+}
+
+HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id)
+{
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ auto display = mDisplays.find(id);
+ if (display == mDisplays.end()) {
+ return nullptr;
+ }
+
+ return display->second.get();
+}
+
+std::tuple<HWC2On1Adapter::Layer*, Error> HWC2On1Adapter::getLayer(
+ hwc2_display_t displayId, hwc2_layer_t layerId)
+{
+ auto display = getDisplay(displayId);
+ if (!display) {
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadDisplay);
+ }
+
+ auto layerEntry = mLayers.find(layerId);
+ if (layerEntry == mLayers.end()) {
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+ }
+
+ auto layer = layerEntry->second;
+ if (layer->getDisplay().getId() != displayId) {
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+ }
+ return std::make_tuple(layer.get(), Error::None);
+}
+
+void HWC2On1Adapter::populatePrimary()
+{
+ ALOGV("populatePrimary");
+
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ auto display =
+ std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
+ mHwc1DisplayMap[HWC_DISPLAY_PRIMARY] = display->getId();
+ display->setHwc1Id(HWC_DISPLAY_PRIMARY);
+ display->populateConfigs();
+ mDisplays.emplace(display->getId(), std::move(display));
+}
+
+bool HWC2On1Adapter::prepareAllDisplays()
+{
+ ATRACE_CALL();
+
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ for (const auto& displayPair : mDisplays) {
+ auto& display = displayPair.second;
+ if (!display->prepare()) {
+ return false;
+ }
+ }
+
+ if (mHwc1DisplayMap.count(0) == 0) {
+ ALOGE("prepareAllDisplays: Unable to find primary HWC1 display");
+ return false;
+ }
+
+ // Always push the primary display
+ std::vector<HWC2On1Adapter::Display::HWC1Contents> requestedContents;
+ auto primaryDisplayId = mHwc1DisplayMap[HWC_DISPLAY_PRIMARY];
+ auto& primaryDisplay = mDisplays[primaryDisplayId];
+ auto primaryDisplayContents = primaryDisplay->cloneRequestedContents();
+ requestedContents.push_back(std::move(primaryDisplayContents));
+
+ // Push the external display, if present
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_EXTERNAL) != 0) {
+ auto externalDisplayId = mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL];
+ auto& externalDisplay = mDisplays[externalDisplayId];
+ auto externalDisplayContents =
+ externalDisplay->cloneRequestedContents();
+ requestedContents.push_back(std::move(externalDisplayContents));
+ } else {
+ // Even if an external display isn't present, we still need to send
+ // at least two displays down to HWC1
+ requestedContents.push_back(nullptr);
+ }
+
+ // Push the hardware virtual display, if supported and present
+ if (mHwc1MinorVersion >= 3) {
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_VIRTUAL) != 0) {
+ auto virtualDisplayId = mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL];
+ auto& virtualDisplay = mDisplays[virtualDisplayId];
+ auto virtualDisplayContents =
+ virtualDisplay->cloneRequestedContents();
+ requestedContents.push_back(std::move(virtualDisplayContents));
+ } else {
+ requestedContents.push_back(nullptr);
+ }
+ }
+
+ mHwc1Contents.clear();
+ for (auto& displayContents : requestedContents) {
+ mHwc1Contents.push_back(displayContents.get());
+ if (!displayContents) {
+ continue;
+ }
+
+ ALOGV("Display %zd layers:", mHwc1Contents.size() - 1);
+ for (size_t l = 0; l < displayContents->numHwLayers; ++l) {
+ auto& layer = displayContents->hwLayers[l];
+ ALOGV(" %zd: %d", l, layer.compositionType);
+ }
+ }
+
+ ALOGV("Calling HWC1 prepare");
+ {
+ ATRACE_NAME("HWC1 prepare");
+ mHwc1Device->prepare(mHwc1Device, mHwc1Contents.size(),
+ mHwc1Contents.data());
+ }
+
+ for (size_t c = 0; c < mHwc1Contents.size(); ++c) {
+ auto& contents = mHwc1Contents[c];
+ if (!contents) {
+ continue;
+ }
+ ALOGV("Display %zd layers:", c);
+ for (size_t l = 0; l < contents->numHwLayers; ++l) {
+ ALOGV(" %zd: %d", l, contents->hwLayers[l].compositionType);
+ }
+ }
+
+ // Return the received contents to their respective displays
+ for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+ if (mHwc1Contents[hwc1Id] == nullptr) {
+ continue;
+ }
+
+ auto displayId = mHwc1DisplayMap[hwc1Id];
+ auto& display = mDisplays[displayId];
+ display->setReceivedContents(std::move(requestedContents[hwc1Id]));
+ }
+
+ return true;
+}
+
+Error HWC2On1Adapter::setAllDisplays()
+{
+ ATRACE_CALL();
+
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ // Make sure we're ready to validate
+ for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+ if (mHwc1Contents[hwc1Id] == nullptr) {
+ continue;
+ }
+
+ auto displayId = mHwc1DisplayMap[hwc1Id];
+ auto& display = mDisplays[displayId];
+ Error error = display->set(*mHwc1Contents[hwc1Id]);
+ if (error != Error::None) {
+ ALOGE("setAllDisplays: Failed to set display %zd: %s", hwc1Id,
+ to_string(error).c_str());
+ return error;
+ }
+ }
+
+ ALOGV("Calling HWC1 set");
+ {
+ ATRACE_NAME("HWC1 set");
+ mHwc1Device->set(mHwc1Device, mHwc1Contents.size(),
+ mHwc1Contents.data());
+ }
+
+ // Add retire and release fences
+ for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+ if (mHwc1Contents[hwc1Id] == nullptr) {
+ continue;
+ }
+
+ auto displayId = mHwc1DisplayMap[hwc1Id];
+ auto& display = mDisplays[displayId];
+ auto retireFenceFd = mHwc1Contents[hwc1Id]->retireFenceFd;
+ ALOGV("setAllDisplays: Adding retire fence %d to display %zd",
+ retireFenceFd, hwc1Id);
+ display->addRetireFence(mHwc1Contents[hwc1Id]->retireFenceFd);
+ display->addReleaseFences(*mHwc1Contents[hwc1Id]);
+ }
+
+ return Error::None;
+}
+
+void HWC2On1Adapter::hwc1Invalidate()
+{
+ ALOGV("Received hwc1Invalidate");
+
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered
+ if (mCallbacks.count(Callback::Refresh) == 0) {
+ mHasPendingInvalidate = true;
+ return;
+ }
+
+ const auto& callbackInfo = mCallbacks[Callback::Refresh];
+ std::vector<hwc2_display_t> displays;
+ for (const auto& displayPair : mDisplays) {
+ displays.emplace_back(displayPair.first);
+ }
+
+ // Call back without the state lock held
+ lock.unlock();
+
+ auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(callbackInfo.pointer);
+ for (auto display : displays) {
+ refresh(callbackInfo.data, display);
+ }
+}
+
+void HWC2On1Adapter::hwc1Vsync(int hwc1DisplayId, int64_t timestamp)
+{
+ ALOGV("Received hwc1Vsync(%d, %" PRId64 ")", hwc1DisplayId, timestamp);
+
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered
+ if (mCallbacks.count(Callback::Vsync) == 0) {
+ mPendingVsyncs.emplace_back(hwc1DisplayId, timestamp);
+ return;
+ }
+
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d", hwc1DisplayId);
+ return;
+ }
+
+ const auto& callbackInfo = mCallbacks[Callback::Vsync];
+ auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+
+ // Call back without the state lock held
+ lock.unlock();
+
+ auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
+ vsync(callbackInfo.data, displayId, timestamp);
+}
+
+void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected)
+{
+ ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected);
+
+ if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) {
+ ALOGE("hwc1Hotplug: Received hotplug for non-external display");
+ return;
+ }
+
+ std::unique_lock<std::timed_mutex> lock(mStateMutex);
+
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered
+ if (mCallbacks.count(Callback::Hotplug) == 0) {
+ mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
+ return;
+ }
+
+ hwc2_display_t displayId = UINT64_MAX;
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ if (connected == 0) {
+ ALOGW("hwc1Hotplug: Received disconnect for unconnected display");
+ return;
+ }
+
+ // Create a new display on connect
+ auto display = std::make_shared<HWC2On1Adapter::Display>(*this,
+ HWC2::DisplayType::Physical);
+ display->setHwc1Id(HWC_DISPLAY_EXTERNAL);
+ display->populateConfigs();
+ displayId = display->getId();
+ mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL] = displayId;
+ mDisplays.emplace(displayId, std::move(display));
+ } else {
+ if (connected != 0) {
+ ALOGW("hwc1Hotplug: Received connect for previously connected "
+ "display");
+ return;
+ }
+
+ // Disconnect an existing display
+ displayId = mHwc1DisplayMap[hwc1DisplayId];
+ mHwc1DisplayMap.erase(HWC_DISPLAY_EXTERNAL);
+ mDisplays.erase(displayId);
+ }
+
+ const auto& callbackInfo = mCallbacks[Callback::Hotplug];
+
+ // Call back without the state lock held
+ lock.unlock();
+
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(callbackInfo.pointer);
+ auto hwc2Connected = (connected == 0) ?
+ HWC2::Connection::Disconnected : HWC2::Connection::Connected;
+ hotplug(callbackInfo.data, displayId, static_cast<int32_t>(hwc2Connected));
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
new file mode 100644
index 0000000..500c48f
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
@@ -0,0 +1,627 @@
+/*
+ * Copyright 2015 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_HWC2_ON_1_ADAPTER_H
+#define ANDROID_SF_HWC2_ON_1_ADAPTER_H
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include <ui/Fence.h>
+
+#include <atomic>
+#include <map>
+#include <mutex>
+#include <queue>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+struct hwc_composer_device_1;
+struct hwc_display_contents_1;
+struct hwc_layer_1;
+
+namespace android {
+
+class HWC2On1Adapter : public hwc2_device_t
+{
+public:
+ HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
+ ~HWC2On1Adapter();
+
+ struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; }
+ uint8_t getHwc1MinorVersion() const { return mHwc1MinorVersion; }
+
+private:
+ static inline HWC2On1Adapter* getAdapter(hwc2_device_t* device) {
+ return static_cast<HWC2On1Adapter*>(device);
+ }
+
+ // getCapabilities
+
+ void doGetCapabilities(uint32_t* outCount,
+ int32_t* /*hwc2_capability_t*/ outCapabilities);
+ static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
+ int32_t* /*hwc2_capability_t*/ outCapabilities) {
+ getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
+ }
+
+ // getFunction
+
+ hwc2_function_pointer_t doGetFunction(HWC2::FunctionDescriptor descriptor);
+ static hwc2_function_pointer_t getFunctionHook(hwc2_device_t* device,
+ int32_t intDesc) {
+ auto descriptor = static_cast<HWC2::FunctionDescriptor>(intDesc);
+ return getAdapter(device)->doGetFunction(descriptor);
+ }
+
+ // Device functions
+
+ HWC2::Error createVirtualDisplay(uint32_t width, uint32_t height,
+ hwc2_display_t* outDisplay);
+ static int32_t createVirtualDisplayHook(hwc2_device_t* device,
+ uint32_t width, uint32_t height, hwc2_display_t* outDisplay) {
+ auto error = getAdapter(device)->createVirtualDisplay(width, height,
+ outDisplay);
+ return static_cast<int32_t>(error);
+ }
+
+ HWC2::Error destroyVirtualDisplay(hwc2_display_t display);
+ static int32_t destroyVirtualDisplayHook(hwc2_device_t* device,
+ hwc2_display_t display) {
+ auto error = getAdapter(device)->destroyVirtualDisplay(display);
+ return static_cast<int32_t>(error);
+ }
+
+ std::string mDumpString;
+ void dump(uint32_t* outSize, char* outBuffer);
+ static void dumpHook(hwc2_device_t* device, uint32_t* outSize,
+ char* outBuffer) {
+ getAdapter(device)->dump(outSize, outBuffer);
+ }
+
+ uint32_t getMaxVirtualDisplayCount();
+ static uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* device) {
+ return getAdapter(device)->getMaxVirtualDisplayCount();
+ }
+
+ HWC2::Error registerCallback(HWC2::Callback descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer);
+ static int32_t registerCallbackHook(hwc2_device_t* device,
+ int32_t intDesc, hwc2_callback_data_t callbackData,
+ hwc2_function_pointer_t pointer) {
+ auto descriptor = static_cast<HWC2::Callback>(intDesc);
+ auto error = getAdapter(device)->registerCallback(descriptor,
+ callbackData, pointer);
+ return static_cast<int32_t>(error);
+ }
+
+ // Display functions
+
+ class Layer;
+
+ class SortLayersByZ {
+ public:
+ bool operator()(const std::shared_ptr<Layer>& lhs,
+ const std::shared_ptr<Layer>& rhs);
+ };
+
+ class DisplayContentsDeleter {
+ public:
+ void operator()(struct hwc_display_contents_1* contents);
+ };
+
+ class DeferredFence {
+ public:
+ DeferredFence()
+ : mMutex(),
+ mFences({Fence::NO_FENCE, Fence::NO_FENCE}) {}
+
+ void add(int32_t fenceFd) {
+ mFences.emplace(new Fence(fenceFd));
+ mFences.pop();
+ }
+
+ const sp<Fence>& get() const {
+ return mFences.front();
+ }
+
+ private:
+ mutable std::mutex mMutex;
+ std::queue<sp<Fence>> mFences;
+ };
+
+ class FencedBuffer {
+ public:
+ FencedBuffer() : mBuffer(nullptr), mFence(Fence::NO_FENCE) {}
+
+ void setBuffer(buffer_handle_t buffer) { mBuffer = buffer; }
+ void setFence(int fenceFd) { mFence = new Fence(fenceFd); }
+
+ buffer_handle_t getBuffer() const { return mBuffer; }
+ int getFence() const { return mFence->dup(); }
+
+ private:
+ buffer_handle_t mBuffer;
+ sp<Fence> mFence;
+ };
+
+ class Display {
+ public:
+ typedef std::unique_ptr<hwc_display_contents_1,
+ DisplayContentsDeleter> HWC1Contents;
+
+ Display(HWC2On1Adapter& device, HWC2::DisplayType type);
+
+ hwc2_display_t getId() const { return mId; }
+ HWC2On1Adapter& getDevice() const { return mDevice; }
+
+ // Does not require locking because it is set before adding the
+ // Displays to the Adapter's list of displays
+ void setHwc1Id(int32_t id) { mHwc1Id = id; }
+ int32_t getHwc1Id() const { return mHwc1Id; }
+
+ void incDirty() { ++mDirtyCount; }
+ void decDirty() { --mDirtyCount; }
+ bool isDirty() const { return mDirtyCount > 0 || mZIsDirty; }
+
+ // HWC2 Display functions
+ HWC2::Error acceptChanges();
+ HWC2::Error createLayer(hwc2_layer_t* outLayerId);
+ HWC2::Error destroyLayer(hwc2_layer_t layerId);
+ HWC2::Error getActiveConfig(hwc2_config_t* outConfigId);
+ HWC2::Error getAttribute(hwc2_config_t configId,
+ HWC2::Attribute attribute, int32_t* outValue);
+ HWC2::Error getChangedCompositionTypes(uint32_t* outNumElements,
+ hwc2_layer_t* outLayers, int32_t* outTypes);
+ HWC2::Error getConfigs(uint32_t* outNumConfigs,
+ hwc2_config_t* outConfigIds);
+ HWC2::Error getDozeSupport(int32_t* outSupport);
+ HWC2::Error getName(uint32_t* outSize, char* outName);
+ HWC2::Error getReleaseFences(uint32_t* outNumElements,
+ hwc2_layer_t* outLayers, int32_t* outFences);
+ HWC2::Error getRequests(int32_t* outDisplayRequests,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outLayerRequests);
+ HWC2::Error getType(int32_t* outType);
+ HWC2::Error present(int32_t* outRetireFence);
+ HWC2::Error setActiveConfig(hwc2_config_t configId);
+ HWC2::Error setClientTarget(buffer_handle_t target,
+ int32_t acquireFence, int32_t dataspace);
+ HWC2::Error setOutputBuffer(buffer_handle_t buffer,
+ int32_t releaseFence);
+ HWC2::Error setPowerMode(HWC2::PowerMode mode);
+ HWC2::Error setVsyncEnabled(HWC2::Vsync enabled);
+ HWC2::Error validate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests);
+
+ HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
+
+ // Read configs from HWC1 device
+ void populateConfigs();
+
+ // Set configs for a virtual display
+ void populateConfigs(uint32_t width, uint32_t height);
+
+ bool prepare();
+ HWC1Contents cloneRequestedContents() const;
+ void setReceivedContents(HWC1Contents contents);
+ bool hasChanges() const;
+ HWC2::Error set(hwc_display_contents_1& hwcContents);
+ void addRetireFence(int fenceFd);
+ void addReleaseFences(const hwc_display_contents_1& hwcContents);
+
+ std::string dump() const;
+
+ private:
+ class Config {
+ public:
+ Config(Display& display, hwc2_config_t id, uint32_t hwcId)
+ : mDisplay(display),
+ mId(id),
+ mHwcId(hwcId) {}
+
+ bool isOnDisplay(const Display& display) const {
+ return display.getId() == mDisplay.getId();
+ }
+
+ hwc2_config_t getId() const { return mId; }
+ uint32_t getHwcId() const { return mHwcId; }
+
+ void setAttribute(HWC2::Attribute attribute, int32_t value);
+ int32_t getAttribute(HWC2::Attribute attribute) const;
+
+ std::string toString() const;
+
+ private:
+ Display& mDisplay;
+ const hwc2_config_t mId;
+ const uint32_t mHwcId;
+ std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
+ };
+
+ class Changes {
+ public:
+ uint32_t getNumTypes() const {
+ return static_cast<uint32_t>(mTypeChanges.size());
+ }
+
+ uint32_t getNumLayerRequests() const {
+ return static_cast<uint32_t>(mLayerRequests.size());
+ }
+
+ const std::unordered_map<hwc2_layer_t, HWC2::Composition>&
+ getTypeChanges() const {
+ return mTypeChanges;
+ }
+
+ const std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>&
+ getLayerRequests() const {
+ return mLayerRequests;
+ }
+
+ int32_t getDisplayRequests() const {
+ int32_t requests = 0;
+ for (auto request : mDisplayRequests) {
+ requests |= static_cast<int32_t>(request);
+ }
+ return requests;
+ }
+
+ void addTypeChange(hwc2_layer_t layerId,
+ HWC2::Composition type) {
+ mTypeChanges.insert({layerId, type});
+ }
+
+ void clearTypeChanges() { mTypeChanges.clear(); }
+
+ void addLayerRequest(hwc2_layer_t layerId,
+ HWC2::LayerRequest request) {
+ mLayerRequests.insert({layerId, request});
+ }
+
+ private:
+ std::unordered_map<hwc2_layer_t, HWC2::Composition>
+ mTypeChanges;
+ std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>
+ mLayerRequests;
+ std::unordered_set<HWC2::DisplayRequest> mDisplayRequests;
+ };
+
+ std::shared_ptr<const Config>
+ getConfig(hwc2_config_t configId) const;
+
+ void reallocateHwc1Contents();
+ void assignHwc1LayerIds();
+
+ void updateTypeChanges(const struct hwc_layer_1& hwc1Layer,
+ const Layer& layer);
+ void updateLayerRequests(const struct hwc_layer_1& hwc1Layer,
+ const Layer& layer);
+
+ void prepareFramebufferTarget();
+
+ static std::atomic<hwc2_display_t> sNextId;
+ const hwc2_display_t mId;
+ HWC2On1Adapter& mDevice;
+
+ std::atomic<size_t> mDirtyCount;
+
+ // The state of this display should only be modified from
+ // SurfaceFlinger's main loop, with the exception of when dump is
+ // called. To prevent a bad state from crashing us during a dump
+ // call, all public calls into Display must acquire this mutex.
+ //
+ // It is recursive because we don't want to deadlock in validate
+ // (or present) when we call HWC2On1Adapter::prepareAllDisplays
+ // (or setAllDisplays), which calls back into Display functions
+ // which require locking.
+ mutable std::recursive_mutex mStateMutex;
+
+ bool mZIsDirty;
+ HWC1Contents mHwc1RequestedContents;
+ HWC1Contents mHwc1ReceivedContents;
+ DeferredFence mRetireFence;
+
+ // Will only be non-null after the layer has been validated but
+ // before it has been presented
+ std::unique_ptr<Changes> mChanges;
+
+ int32_t mHwc1Id;
+ std::vector<std::shared_ptr<Config>> mConfigs;
+ std::shared_ptr<const Config> mActiveConfig;
+ std::string mName;
+ HWC2::DisplayType mType;
+ HWC2::PowerMode mPowerMode;
+ HWC2::Vsync mVsyncEnabled;
+
+ FencedBuffer mClientTarget;
+ FencedBuffer mOutputBuffer;
+
+ std::multiset<std::shared_ptr<Layer>, SortLayersByZ> mLayers;
+ std::unordered_map<size_t, std::shared_ptr<Layer>> mHwc1LayerMap;
+ };
+
+ template <typename ...Args>
+ static int32_t callDisplayFunction(hwc2_device_t* device,
+ hwc2_display_t displayId, HWC2::Error (Display::*member)(Args...),
+ Args... args) {
+ auto display = getAdapter(device)->getDisplay(displayId);
+ if (!display) {
+ return static_cast<int32_t>(HWC2::Error::BadDisplay);
+ }
+ auto error = ((*display).*member)(std::forward<Args>(args)...);
+ return static_cast<int32_t>(error);
+ }
+
+ template <typename MF, MF memFunc, typename ...Args>
+ static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId,
+ Args... args) {
+ return HWC2On1Adapter::callDisplayFunction(device, displayId, memFunc,
+ std::forward<Args>(args)...);
+ }
+
+ static int32_t getDisplayAttributeHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_config_t config,
+ int32_t intAttribute, int32_t* outValue) {
+ auto attribute = static_cast<HWC2::Attribute>(intAttribute);
+ return callDisplayFunction(device, display, &Display::getAttribute,
+ config, attribute, outValue);
+ }
+
+ static int32_t setPowerModeHook(hwc2_device_t* device,
+ hwc2_display_t display, int32_t intMode) {
+ auto mode = static_cast<HWC2::PowerMode>(intMode);
+ return callDisplayFunction(device, display, &Display::setPowerMode,
+ mode);
+ }
+
+ static int32_t setVsyncEnabledHook(hwc2_device_t* device,
+ hwc2_display_t display, int32_t intEnabled) {
+ auto enabled = static_cast<HWC2::Vsync>(intEnabled);
+ return callDisplayFunction(device, display, &Display::setVsyncEnabled,
+ enabled);
+ }
+
+ // Layer functions
+
+ template <typename T>
+ class LatchedState {
+ public:
+ LatchedState(Layer& parent, T initialValue)
+ : mParent(parent),
+ mPendingValue(initialValue),
+ mValue(initialValue) {}
+
+ void setPending(T value) {
+ if (value == mPendingValue) {
+ return;
+ }
+ if (mPendingValue == mValue) {
+ mParent.incDirty();
+ } else if (value == mValue) {
+ mParent.decDirty();
+ }
+ mPendingValue = value;
+ }
+
+ T getValue() const { return mValue; }
+ T getPendingValue() const { return mPendingValue; }
+
+ bool isDirty() const { return mPendingValue != mValue; }
+
+ void latch() {
+ if (isDirty()) {
+ mValue = mPendingValue;
+ mParent.decDirty();
+ }
+ }
+
+ private:
+ Layer& mParent;
+ T mPendingValue;
+ T mValue;
+ };
+
+ class Layer {
+ public:
+ Layer(Display& display);
+
+ bool operator==(const Layer& other) { return mId == other.mId; }
+ bool operator!=(const Layer& other) { return !(*this == other); }
+
+ hwc2_layer_t getId() const { return mId; }
+ Display& getDisplay() const { return mDisplay; }
+
+ void incDirty() { if (mDirtyCount++ == 0) mDisplay.incDirty(); }
+ void decDirty() { if (--mDirtyCount == 0) mDisplay.decDirty(); }
+ bool isDirty() const { return mDirtyCount > 0; }
+
+ // HWC2 Layer functions
+ HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence);
+ HWC2::Error setCursorPosition(int32_t x, int32_t y);
+ HWC2::Error setSurfaceDamage(hwc_region_t damage);
+
+ // HWC2 Layer state functions
+ HWC2::Error setBlendMode(HWC2::BlendMode mode);
+ HWC2::Error setColor(hwc_color_t color);
+ HWC2::Error setCompositionType(HWC2::Composition type);
+ HWC2::Error setDisplayFrame(hwc_rect_t frame);
+ HWC2::Error setPlaneAlpha(float alpha);
+ HWC2::Error setSidebandStream(const native_handle_t* stream);
+ HWC2::Error setSourceCrop(hwc_frect_t crop);
+ HWC2::Error setTransform(HWC2::Transform transform);
+ HWC2::Error setVisibleRegion(hwc_region_t visible);
+ HWC2::Error setZ(uint32_t z);
+
+ HWC2::Composition getCompositionType() const {
+ return mCompositionType.getValue();
+ }
+ uint32_t getZ() const { return mZ; }
+
+ void addReleaseFence(int fenceFd);
+ const sp<Fence>& getReleaseFence() const;
+
+ void setHwc1Id(size_t id) { mHwc1Id = id; }
+ size_t getHwc1Id() const { return mHwc1Id; }
+
+ void applyState(struct hwc_layer_1& hwc1Layer, bool applyAllState);
+
+ std::string dump() const;
+
+ private:
+ void applyCommonState(struct hwc_layer_1& hwc1Layer,
+ bool applyAllState);
+ void applySolidColorState(struct hwc_layer_1& hwc1Layer,
+ bool applyAllState);
+ void applySidebandState(struct hwc_layer_1& hwc1Layer,
+ bool applyAllState);
+ void applyBufferState(struct hwc_layer_1& hwc1Layer);
+ void applyCompositionType(struct hwc_layer_1& hwc1Layer,
+ bool applyAllState);
+
+ static std::atomic<hwc2_layer_t> sNextId;
+ const hwc2_layer_t mId;
+ Display& mDisplay;
+ size_t mDirtyCount;
+
+ FencedBuffer mBuffer;
+ std::vector<hwc_rect_t> mSurfaceDamage;
+
+ LatchedState<HWC2::BlendMode> mBlendMode;
+ LatchedState<hwc_color_t> mColor;
+ LatchedState<HWC2::Composition> mCompositionType;
+ LatchedState<hwc_rect_t> mDisplayFrame;
+ LatchedState<float> mPlaneAlpha;
+ LatchedState<const native_handle_t*> mSidebandStream;
+ LatchedState<hwc_frect_t> mSourceCrop;
+ LatchedState<HWC2::Transform> mTransform;
+ LatchedState<std::vector<hwc_rect_t>> mVisibleRegion;
+ uint32_t mZ;
+
+ DeferredFence mReleaseFence;
+
+ size_t mHwc1Id;
+ bool mHasUnsupportedPlaneAlpha;
+ };
+
+ template <typename ...Args>
+ static int32_t callLayerFunction(hwc2_device_t* device,
+ hwc2_display_t displayId, hwc2_layer_t layerId,
+ HWC2::Error (Layer::*member)(Args...), Args... args) {
+ auto result = getAdapter(device)->getLayer(displayId, layerId);
+ auto error = std::get<HWC2::Error>(result);
+ if (error == HWC2::Error::None) {
+ auto layer = std::get<Layer*>(result);
+ error = ((*layer).*member)(std::forward<Args>(args)...);
+ }
+ return static_cast<int32_t>(error);
+ }
+
+ template <typename MF, MF memFunc, typename ...Args>
+ static int32_t layerHook(hwc2_device_t* device, hwc2_display_t displayId,
+ hwc2_layer_t layerId, Args... args) {
+ return HWC2On1Adapter::callLayerFunction(device, displayId, layerId,
+ memFunc, std::forward<Args>(args)...);
+ }
+
+ // Layer state functions
+
+ static int32_t setLayerBlendModeHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intMode) {
+ auto mode = static_cast<HWC2::BlendMode>(intMode);
+ return callLayerFunction(device, display, layer,
+ &Layer::setBlendMode, mode);
+ }
+
+ static int32_t setLayerCompositionTypeHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intType) {
+ auto type = static_cast<HWC2::Composition>(intType);
+ return callLayerFunction(device, display, layer,
+ &Layer::setCompositionType, type);
+ }
+
+ static int32_t setLayerTransformHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intTransform) {
+ auto transform = static_cast<HWC2::Transform>(intTransform);
+ return callLayerFunction(device, display, layer, &Layer::setTransform,
+ transform);
+ }
+
+ static int32_t setLayerZOrderHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, uint32_t z) {
+ return callDisplayFunction(device, display, &Display::updateLayerZ,
+ layer, z);
+ }
+
+ // Adapter internals
+
+ void populateCapabilities();
+ Display* getDisplay(hwc2_display_t id);
+ std::tuple<Layer*, HWC2::Error> getLayer(hwc2_display_t displayId,
+ hwc2_layer_t layerId);
+ void populatePrimary();
+
+ bool prepareAllDisplays();
+ std::vector<struct hwc_display_contents_1*> mHwc1Contents;
+ HWC2::Error setAllDisplays();
+
+ void hwc1Invalidate();
+ void hwc1Vsync(int hwc1DisplayId, int64_t timestamp);
+ void hwc1Hotplug(int hwc1DisplayId, int connected);
+
+ // These are set in the constructor and before any asynchronous events are
+ // possible
+
+ struct hwc_composer_device_1* const mHwc1Device;
+ const uint8_t mHwc1MinorVersion;
+ bool mHwc1SupportsVirtualDisplays;
+
+ class Callbacks;
+ const std::unique_ptr<Callbacks> mHwc1Callbacks;
+
+ std::unordered_set<HWC2::Capability> mCapabilities;
+
+ // These are only accessed from the main SurfaceFlinger thread (not from
+ // callbacks or dump
+
+ std::map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
+ std::shared_ptr<Display> mHwc1VirtualDisplay;
+
+ // These are potentially accessed from multiple threads, and are protected
+ // by this mutex
+ std::timed_mutex mStateMutex;
+
+ struct CallbackInfo {
+ hwc2_callback_data_t data;
+ hwc2_function_pointer_t pointer;
+ };
+ std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
+ bool mHasPendingInvalidate;
+ std::vector<std::pair<int, int64_t>> mPendingVsyncs;
+ std::vector<std::pair<int, int>> mPendingHotplugs;
+
+ std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+ std::unordered_map<int, hwc2_display_t> mHwc1DisplayMap;
+};
+
+} // namespace android
+
+#endif
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 64c1dd9..1a0d689 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -547,8 +547,14 @@
return 0;
}
-status_t VirtualDisplaySurface::setSingleBufferMode(bool singleBufferMode) {
- return mSource[SOURCE_SINK]->setSingleBufferMode(singleBufferMode);
+status_t VirtualDisplaySurface::setSingleBufferMode(bool /*singleBufferMode*/) {
+ ALOGE("setSingleBufferMode not supported on VirtualDisplaySurface");
+ return INVALID_OPERATION;
+}
+
+status_t VirtualDisplaySurface::setAutoRefresh(bool /*autoRefresh*/) {
+ ALOGE("setAutoRefresh not supported on VirtualDisplaySurface");
+ return INVALID_OPERATION;
}
status_t VirtualDisplaySurface::setDequeueTimeout(nsecs_t /* timeout */) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 7f451a9..ede204c 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -121,6 +121,7 @@
virtual String8 getConsumerName() const override;
virtual uint64_t getNextFrameNumber() const override;
virtual status_t setSingleBufferMode(bool singleBufferMode) override;
+ virtual status_t setAutoRefresh(bool autoRefresh) override;
virtual status_t setDequeueTimeout(nsecs_t timeout) override;
//
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 28e5e43..9dca798 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -88,7 +88,7 @@
mQueueItems(),
mLastFrameNumberReceived(0),
mUpdateTexImageFailed(false),
- mSingleBufferMode(false)
+ mAutoRefresh(false)
{
mCurrentCrop.makeInvalid();
mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -1263,7 +1263,7 @@
// ----------------------------------------------------------------------------
bool Layer::shouldPresentNow(const DispSync& dispSync) const {
- if (mSidebandStreamChanged || mSingleBufferMode) {
+ if (mSidebandStreamChanged || mAutoRefresh) {
return true;
}
@@ -1287,7 +1287,7 @@
bool Layer::onPreComposition() {
mRefreshPending = false;
- return mQueuedFrames > 0 || mSidebandStreamChanged || mSingleBufferMode;
+ return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
}
void Layer::onPostComposition() {
@@ -1344,7 +1344,7 @@
}
Region outDirtyRegion;
- if (mQueuedFrames > 0 || mSingleBufferMode) {
+ if (mQueuedFrames > 0 || mAutoRefresh) {
// if we've already called updateTexImage() without going through
// a composition step, we have to skip this layer at this point
@@ -1510,7 +1510,7 @@
// buffer mode.
bool queuedBuffer = false;
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
- mFlinger->mPrimaryDispSync, &mSingleBufferMode, &queuedBuffer,
+ mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
mLastFrameNumberReceived);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
@@ -1566,7 +1566,7 @@
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
- || mSingleBufferMode) {
+ || mAutoRefresh) {
mFlinger->signalLayerUpdate();
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d91e94e..1773daf 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -307,7 +307,7 @@
* Returns if a frame is queued.
*/
bool hasQueuedFrame() const { return mQueuedFrames > 0 ||
- mSidebandStreamChanged || mSingleBufferMode; }
+ mSidebandStreamChanged || mAutoRefresh; }
// -----------------------------------------------------------------------
@@ -493,7 +493,7 @@
std::atomic<uint64_t> mLastFrameNumberReceived;
bool mUpdateTexImageFailed; // This is only modified from the main thread
- bool mSingleBufferMode;
+ bool mAutoRefresh;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index efc44ab..e161d9f 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -135,6 +135,10 @@
return mProducer->setSingleBufferMode(singleBufferMode);
}
+status_t MonitoredProducer::setAutoRefresh(bool autoRefresh) {
+ return mProducer->setAutoRefresh(autoRefresh);
+}
+
status_t MonitoredProducer::setDequeueTimeout(nsecs_t timeout) {
return mProducer->setDequeueTimeout(timeout);
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index aea2e39..35ce558 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -60,7 +60,8 @@
virtual uint64_t getNextFrameNumber() const override;
virtual status_t setDequeueTimeout(nsecs_t timeout) override;
virtual IBinder* onAsBinder();
- virtual status_t setSingleBufferMode(bool singleBufferMode);
+ virtual status_t setSingleBufferMode(bool singleBufferMode) override;
+ virtual status_t setAutoRefresh(bool autoRefresh) override;
private:
sp<IGraphicBufferProducer> mProducer;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1e33847..737cc82 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3183,14 +3183,7 @@
// if we have secure windows on this display, never allow the screen capture
// unless the producer interface is local (i.e.: we can take a screenshot for
// ourselves).
- if (!IInterface::asBinder(producer)->localBinder()) {
- Mutex::Autolock _l(mStateLock);
- sp<const DisplayDevice> hw(getDisplayDevice(display));
- if (hw->getSecureLayerVisible()) {
- ALOGW("FB is protected: PERMISSION_DENIED");
- return PERMISSION_DENIED;
- }
- }
+ bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
// Convert to surfaceflinger's internal rotation type.
Transform::orientation_flags rotationFlags;
@@ -3223,19 +3216,22 @@
bool useIdentityTransform;
Transform::orientation_flags rotation;
status_t result;
+ bool isLocalScreenshot;
public:
MessageCaptureScreen(SurfaceFlinger* flinger,
const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation)
+ bool useIdentityTransform,
+ Transform::orientation_flags rotation,
+ bool isLocalScreenshot)
: flinger(flinger), display(display), producer(producer),
sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
useIdentityTransform(useIdentityTransform),
- rotation(rotation),
- result(PERMISSION_DENIED)
+ rotation(rotation), result(PERMISSION_DENIED),
+ isLocalScreenshot(isLocalScreenshot)
{
}
status_t getResult() const {
@@ -3246,7 +3242,7 @@
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
result = flinger->captureScreenImplLocked(hw, producer,
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotation);
+ useIdentityTransform, rotation, isLocalScreenshot);
static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
return true;
}
@@ -3269,7 +3265,7 @@
sp<MessageBase> msg = new MessageCaptureScreen(this,
display, IGraphicBufferProducer::asInterface( wrapper ),
sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotationFlags);
+ useIdentityTransform, rotationFlags, isLocalScreenshot);
status_t res = postMessageAsync(msg);
if (res == NO_ERROR) {
@@ -3353,7 +3349,8 @@
const sp<IGraphicBufferProducer>& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation)
+ bool useIdentityTransform, Transform::orientation_flags rotation,
+ bool isLocalScreenshot)
{
ATRACE_CALL();
@@ -3374,6 +3371,24 @@
reqWidth = (!reqWidth) ? hw_w : reqWidth;
reqHeight = (!reqHeight) ? hw_h : reqHeight;
+ bool secureLayerIsVisible = false;
+ const LayerVector& layers(mDrawingState.layersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i = 0 ; i < count ; ++i) {
+ const sp<Layer>& layer(layers[i]);
+ const Layer::State& state(layer->getDrawingState());
+ if (state.layerStack == hw->getLayerStack() && state.z >= minLayerZ &&
+ state.z <= maxLayerZ && layer->isVisible() &&
+ layer->isSecure()) {
+ secureLayerIsVisible = true;
+ }
+ }
+
+ if (!isLocalScreenshot && secureLayerIsVisible) {
+ ALOGW("FB is protected: PERMISSION_DENIED");
+ return PERMISSION_DENIED;
+ }
+
// create a surface (because we're a producer, and we need to
// dequeue/queue a buffer)
sp<Surface> sur = new Surface(producer, false);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4e0160a..4101a70 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -329,7 +329,8 @@
const sp<IGraphicBufferProducer>& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation);
+ bool useIdentityTransform, Transform::orientation_flags rotation,
+ bool isLocalScreenshot);
/* ------------------------------------------------------------------------
* EGL
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 5722fb4..d3b66e6 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -32,7 +32,7 @@
// ---------------------------------------------------------------------------
status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
- const DispSync& dispSync, bool* singleBufferMode, bool* queuedBuffer,
+ const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer,
uint64_t maxFrameNumber)
{
ATRACE_CALL();
@@ -78,8 +78,8 @@
return BUFFER_REJECTED;
}
- if (singleBufferMode) {
- *singleBufferMode = item.mSingleBufferMode;
+ if (autoRefresh) {
+ *autoRefresh = item.mAutoRefresh;
}
if (queuedBuffer) {
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 207c243..f3942ab 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -57,7 +57,7 @@
// this does not guarantee that the buffer has been bound to the GL
// texture.
status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
- bool* singleBufferMode, bool* queuedBuffer,
+ bool* autoRefresh, bool* queuedBuffer,
uint64_t maxFrameNumber = 0);
// See GLConsumer::bindTextureImageLocked().
diff --git a/vulkan/api/templates/vulkan_h.tmpl b/vulkan/api/templates/vulkan_h.tmpl
index b2a77ec..83a5e40 100644
--- a/vulkan/api/templates/vulkan_h.tmpl
+++ b/vulkan/api/templates/vulkan_h.tmpl
@@ -17,7 +17,7 @@
#endif
¶
/*
-** Copyright (c) 2015 The Khronos Group Inc.
+** Copyright (c) 2015-2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -47,12 +47,16 @@
#define VK_VERSION_1_0 1
#include "vk_platform.h"
¶
-#define VK_MAKE_VERSION(major, minor, patch) ((major << 22) | (minor << 12) | patch)
+#define VK_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))
¶
// Vulkan API version supported by this file
#define VK_API_VERSION \
VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}})
¶
+#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
+#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
+#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
+¶
#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L)
#define VK_NULL_HANDLE nullptr
#else
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 9b1e684..10565ab 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
// API version (major.minor.patch)
define VERSION_MAJOR 1
define VERSION_MINOR 0
-define VERSION_PATCH 2
+define VERSION_PATCH 3
// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -75,7 +75,7 @@
@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5
@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME "VK_KHR_win32_surface"
-@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2
+@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 1
@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report"
@@ -1299,9 +1299,9 @@
type VkFlags VkDebugReportFlagsEXT
@extension("VK_EXT_debug_report")
bitfield VkDebugReportFlagBitsEXT {
- VK_DEBUG_REPORT_INFO_BIT_EXT = 0x00000001,
- VK_DEBUG_REPORT_WARN_BIT_EXT = 0x00000002,
- VK_DEBUG_REPORT_PERF_WARN_BIT_EXT = 0x00000004,
+ VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,
+ VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002,
+ VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004,
VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,
VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
}
@@ -5130,7 +5130,7 @@
cmd VkResult vkGetPhysicalDeviceWin32PresentationSupportKHR(
VkPhysicalDevice physicalDevice,
u32 queueFamilyIndex) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
+ physicalDeviceObject := GetPhysicalDevice(physicalDevice)
return ?
}
diff --git a/vulkan/include/vulkan/vk_ext_debug_report.h b/vulkan/include/vulkan/vk_ext_debug_report.h
deleted file mode 100644
index c391033..0000000
--- a/vulkan/include/vulkan/vk_ext_debug_report.h
+++ /dev/null
@@ -1,149 +0,0 @@
-//
-// File: vk_ext_debug_report.h
-//
-/*
- *
- * Copyright (C) 2015 Valve Corporation
- * Copyright (C) 2015 Google Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author: Cody Northrop <cody@lunarg.com>
- * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
- * Author: Tony Barbour <tony@LunarG.com>
- *
- */
-
-#pragma once
-
-#include "vulkan/vulkan.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif // __cplusplus
-
-/*
-***************************************************************************************************
-* DebugReport Vulkan Extension API
-***************************************************************************************************
-*/
-#define VK_EXT_debug_report 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
-
-#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2
-#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
-
-
-typedef enum VkDebugReportObjectTypeEXT {
- VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,
- VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,
- VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2,
- VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3,
- VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4,
- VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5,
- VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6,
- VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7,
- VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8,
- VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9,
- VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10,
- VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11,
- VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12,
- VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13,
- VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14,
- VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15,
- VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16,
- VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17,
- VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18,
- VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20,
- VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23,
- VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24,
- VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
- VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
- VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
- VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28,
-} VkDebugReportObjectTypeEXT;
-
-typedef enum VkDebugReportErrorEXT {
- VK_DEBUG_REPORT_ERROR_NONE_EXT = 0,
- VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1,
-} VkDebugReportErrorEXT;
-
-typedef enum VkDebugReportFlagBitsEXT {
- VK_DEBUG_REPORT_INFO_BIT_EXT = 0x00000001,
- VK_DEBUG_REPORT_WARN_BIT_EXT = 0x00000002,
- VK_DEBUG_REPORT_PERF_WARN_BIT_EXT = 0x00000004,
- VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,
- VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
-} VkDebugReportFlagBitsEXT;
-typedef VkFlags VkDebugReportFlagsEXT;
-
-typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)(
- VkDebugReportFlagsEXT flags,
- VkDebugReportObjectTypeEXT objectType,
- uint64_t object,
- size_t location,
- int32_t messageCode,
- const char* pLayerPrefix,
- const char* pMessage,
- void* pUserData);
-
-
-typedef struct VkDebugReportCallbackCreateInfoEXT {
- VkStructureType sType;
- const void* pNext;
- VkDebugReportFlagsEXT flags;
- PFN_vkDebugReportCallbackEXT pfnCallback;
- void* pUserData;
-} VkDebugReportCallbackCreateInfoEXT;
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
-typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(
- VkInstance instance,
- const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDebugReportCallbackEXT* pCallback);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(
- VkInstance instance,
- VkDebugReportCallbackEXT callback,
- const VkAllocationCallbacks* pAllocator);
-
-VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(
- VkInstance instance,
- VkDebugReportFlagsEXT flags,
- VkDebugReportObjectTypeEXT objectType,
- uint64_t object,
- size_t location,
- int32_t messageCode,
- const char* pLayerPrefix,
- const char* pMessage);
-#endif
-
-#ifdef __cplusplus
-} // extern "C"
-#endif // __cplusplus
-
diff --git a/vulkan/include/vulkan/vk_layer_interface.h b/vulkan/include/vulkan/vk_layer_interface.h
index 8aef495..5aae51e 100644
--- a/vulkan/include/vulkan/vk_layer_interface.h
+++ b/vulkan/include/vulkan/vk_layer_interface.h
@@ -31,7 +31,6 @@
#pragma once
#include <vulkan/vulkan.h>
-#include <vulkan/vk_ext_debug_report.h>
// ------------------------------------------------------------------------------------------------
// CreateInstance and CreateDevice support structures
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 9940f85..cd6a71a 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -6,7 +6,7 @@
#endif
/*
-** Copyright (c) 2015 The Khronos Group Inc.
+** Copyright (c) 2015-2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -38,11 +38,14 @@
#include "vk_platform.h"
#define VK_MAKE_VERSION(major, minor, patch) \
- ((major << 22) | (minor << 12) | patch)
+ (((major) << 22) | ((minor) << 12) | (patch))
// Vulkan API version supported by this file
-#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 2)
+#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 3)
+#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
+#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
+#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
#define VK_NULL_HANDLE 0
@@ -3664,6 +3667,107 @@
#endif
#endif /* VK_USE_PLATFORM_WIN32_KHR */
+#define VK_EXT_debug_report 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
+
+#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 1
+#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
+
+
+typedef enum VkDebugReportObjectTypeEXT {
+ VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,
+ VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,
+ VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3,
+ VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4,
+ VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5,
+ VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6,
+ VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8,
+ VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9,
+ VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10,
+ VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11,
+ VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12,
+ VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13,
+ VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14,
+ VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15,
+ VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16,
+ VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17,
+ VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18,
+ VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20,
+ VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23,
+ VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24,
+ VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
+ VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
+ VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28,
+} VkDebugReportObjectTypeEXT;
+
+typedef enum VkDebugReportErrorEXT {
+ VK_DEBUG_REPORT_ERROR_NONE_EXT = 0,
+ VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1,
+} VkDebugReportErrorEXT;
+
+
+typedef enum VkDebugReportFlagBitsEXT {
+ VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,
+ VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002,
+ VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004,
+ VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,
+ VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
+} VkDebugReportFlagBitsEXT;
+typedef VkFlags VkDebugReportFlagsEXT;
+
+typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)(
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objectType,
+ uint64_t object,
+ size_t location,
+ int32_t messageCode,
+ const char* pLayerPrefix,
+ const char* pMessage,
+ void* pUserData);
+
+
+typedef struct VkDebugReportCallbackCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkDebugReportFlagsEXT flags;
+ PFN_vkDebugReportCallbackEXT pfnCallback;
+ void* pUserData;
+} VkDebugReportCallbackCreateInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
+typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(
+ VkInstance instance,
+ const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkDebugReportCallbackEXT* pCallback);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(
+ VkInstance instance,
+ VkDebugReportCallbackEXT callback,
+ const VkAllocationCallbacks* pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(
+ VkInstance instance,
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objectType,
+ uint64_t object,
+ size_t location,
+ int32_t messageCode,
+ const char* pLayerPrefix,
+ const char* pMessage);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index 779fedf..85b8ab2 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -16,6 +16,8 @@
include $(CLEAR_VARS)
LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
+
LOCAL_CFLAGS := -DLOG_TAG=\"vulkan\" \
-std=c99 -fvisibility=hidden -fstrict-aliasing \
-Weverything -Werror \
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index 5bce240..c6f7570 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -18,7 +18,6 @@
#define LIBVULKAN_DEBUG_REPORT_H 1
#include <shared_mutex>
-#include <vulkan/vk_ext_debug_report.h>
namespace vulkan {
diff --git a/vulkan/libvulkan/dispatch.tmpl b/vulkan/libvulkan/dispatch.tmpl
index 306aae4..0a0338e 100644
--- a/vulkan/libvulkan/dispatch.tmpl
+++ b/vulkan/libvulkan/dispatch.tmpl
@@ -46,7 +46,6 @@
¶
#define VK_USE_PLATFORM_ANDROID_KHR
#include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vk_ext_debug_report.h>
#include <vulkan/vulkan.h>
¶
namespace vulkan {
diff --git a/vulkan/libvulkan/dispatch_gen.h b/vulkan/libvulkan/dispatch_gen.h
index 7bab6ca..cef4ccf 100644
--- a/vulkan/libvulkan/dispatch_gen.h
+++ b/vulkan/libvulkan/dispatch_gen.h
@@ -18,7 +18,6 @@
#define VK_USE_PLATFORM_ANDROID_KHR
#include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vk_ext_debug_report.h>
#include <vulkan/vulkan.h>
namespace vulkan {
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 1a57c22..fc60f35 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -496,7 +496,7 @@
void* /*user_data*/) {
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
ALOGE("[%s] Code %d : %s", layer_prefix, message_code, message);
- } else if (flags & VK_DEBUG_REPORT_WARN_BIT_EXT) {
+ } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
ALOGW("[%s] Code %d : %s", layer_prefix, message_code, message);
}
return false;
@@ -1205,7 +1205,7 @@
const VkDebugReportCallbackCreateInfoEXT callback_create_info = {
.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
.flags =
- VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARN_BIT_EXT,
+ VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
.pfnCallback = LogDebugMessageCallback,
};
PFN_vkCreateDebugReportCallbackEXT create_debug_report_callback =
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index f8de675..7f944cf 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -107,6 +107,79 @@
}
}
+const VkSurfaceTransformFlagsKHR kSupportedTransforms =
+ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR |
+ VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
+ VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR |
+ VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
+ // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
+ // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR |
+ // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
+ // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR |
+ // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR |
+ VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
+
+VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) {
+ // Native and Vulkan transforms are isomorphic, but are represented
+ // differently. Vulkan transforms are built up of an optional horizontal
+ // mirror, followed by a clockwise 0/90/180/270-degree rotation. Native
+ // transforms are built up from a horizontal flip, vertical flip, and
+ // 90-degree rotation, all optional but always in that order.
+
+ // TODO(jessehall): For now, only support pure rotations, not
+ // flip or flip-and-rotate, until I have more time to test them and build
+ // sample code. As far as I know we never actually use anything besides
+ // pure rotations anyway.
+
+ switch (native) {
+ case 0: // 0x0
+ return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+ // case NATIVE_WINDOW_TRANSFORM_FLIP_H: // 0x1
+ // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR;
+ // case NATIVE_WINDOW_TRANSFORM_FLIP_V: // 0x2
+ // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR;
+ case NATIVE_WINDOW_TRANSFORM_ROT_180: // FLIP_H | FLIP_V
+ return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
+ case NATIVE_WINDOW_TRANSFORM_ROT_90: // 0x4
+ return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
+ // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90:
+ // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR;
+ // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90:
+ // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
+ case NATIVE_WINDOW_TRANSFORM_ROT_270: // FLIP_H | FLIP_V | ROT_90
+ return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
+ case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
+ default:
+ return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+ }
+}
+
+int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) {
+ switch (transform) {
+ case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_270;
+ case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_180;
+ case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_90;
+ // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
+ // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
+ // return NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
+ // return NATIVE_WINDOW_TRANSFORM_FLIP_H |
+ // NATIVE_WINDOW_TRANSFORM_ROT_90;
+ // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
+ // return NATIVE_WINDOW_TRANSFORM_FLIP_V;
+ // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
+ // return NATIVE_WINDOW_TRANSFORM_FLIP_V |
+ // NATIVE_WINDOW_TRANSFORM_ROT_90;
+ case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
+ case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
+ default:
+ return 0;
+ }
+}
+
// ----------------------------------------------------------------------------
struct Surface {
@@ -238,6 +311,14 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
+ int transform_hint;
+ err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
+ if (err != 0) {
+ ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
// TODO(jessehall): Figure out what the min/max values should be.
capabilities->minImageCount = 2;
capabilities->maxImageCount = 3;
@@ -252,12 +333,9 @@
capabilities->maxImageArrayLayers = 1;
- // TODO(jessehall): We can support all transforms, fix this once
- // implemented.
- capabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
-
- // TODO(jessehall): Implement based on NATIVE_WINDOW_TRANSFORM_HINT.
- capabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+ capabilities->supportedTransforms = kSupportedTransforms;
+ capabilities->currentTransform =
+ TranslateNativeToVulkanTransform(transform_hint);
// On Android, window composition is a WindowManager property, not something
// associated with the bufferqueue. It can't be changed from here.
@@ -347,8 +425,9 @@
"color spaces other than SRGB_NONLINEAR not yet implemented");
ALOGE_IF(create_info->oldSwapchain,
"swapchain re-creation not yet implemented");
- ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
- "swapchain preTransform not yet implemented");
+ ALOGE_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
+ "swapchain preTransform %d not supported",
+ create_info->preTransform);
ALOGW_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
"swapchain present mode %d not supported",
@@ -402,6 +481,26 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
+ // VkSwapchainCreateInfo::preTransform indicates the transformation the app
+ // applied during rendering. native_window_set_transform() expects the
+ // inverse: the transform the app is requesting that the compositor perform
+ // during composition. With native windows, pre-transform works by rendering
+ // with the same transform the compositor is applying (as in Vulkan), but
+ // then requesting the inverse transform, so that when the compositor does
+ // it's job the two transforms cancel each other out and the compositor ends
+ // up applying an identity transform to the app's buffer.
+ err = native_window_set_buffers_transform(
+ surface.window.get(),
+ InvertTransformToNative(create_info->preTransform));
+ if (err != 0) {
+ // TODO(jessehall): Improve error reporting. Can we enumerate possible
+ // errors and translate them to valid Vulkan result codes?
+ ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
+ InvertTransformToNative(create_info->preTransform),
+ strerror(-err), err);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
err = native_window_set_scaling_mode(
surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
if (err != 0) {
@@ -412,16 +511,18 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
- uint32_t min_undequeued_buffers;
- err = surface.window->query(
- surface.window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
- reinterpret_cast<int*>(&min_undequeued_buffers));
- if (err != 0) {
+ int query_value;
+ err = surface.window->query(surface.window.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &query_value);
+ if (err != 0 || query_value < 0) {
// TODO(jessehall): Improve error reporting. Can we enumerate possible
// errors and translate them to valid Vulkan result codes?
- ALOGE("window->query failed: %s (%d)", strerror(-err), err);
+ ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
+ query_value);
return VK_ERROR_INITIALIZATION_FAILED;
}
+ uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
// The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
// async mode or not, and assumes not. But in async mode, the BufferQueue
// requires an extra undequeued buffer.
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index cd61e86..6f57238 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -15,7 +15,6 @@
*/
#include <hardware/hwvulkan.h>
-#include <vulkan/vk_ext_debug_report.h>
#include <algorithm>
#include <array>
diff --git a/vulkan/nulldrv/null_driver.tmpl b/vulkan/nulldrv/null_driver.tmpl
index 7488692..3a84971 100644
--- a/vulkan/nulldrv/null_driver.tmpl
+++ b/vulkan/nulldrv/null_driver.tmpl
@@ -49,7 +49,6 @@
#define NULLDRV_NULL_DRIVER_H 1
¶
#include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vk_ext_debug_report.h>
#include <vulkan/vulkan.h>
¶
namespace null_driver {«
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 87ff681..98952b8 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -20,7 +20,6 @@
#define NULLDRV_NULL_DRIVER_H 1
#include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vk_ext_debug_report.h>
#include <vulkan/vulkan.h>
namespace null_driver {
diff --git a/vulkan/tools/Android.mk b/vulkan/tools/Android.mk
index 31d6089..337e683 100644
--- a/vulkan/tools/Android.mk
+++ b/vulkan/tools/Android.mk
@@ -21,7 +21,8 @@
LOCAL_CFLAGS += -Weverything -Werror -Wno-padded -Wno-undef -Wno-switch-enum
LOCAL_CPPFLAGS := -std=c++1y \
-Wno-c++98-compat-pedantic \
- -Wno-c99-extensions
+ -Wno-c99-extensions \
+ -Wno-old-style-cast
LOCAL_C_INCLUDES := \
frameworks/native/vulkan/include
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
index b88c35d..e97e5f5 100644
--- a/vulkan/tools/vkinfo.cpp
+++ b/vulkan/tools/vkinfo.cpp
@@ -22,13 +22,19 @@
#include <vector>
#include <vulkan/vulkan.h>
-#include <vulkan/vk_ext_debug_report.h>
#define LOG_TAG "vkinfo"
#include <log/log.h>
namespace {
+struct Options {
+ bool layer_description;
+ bool layer_extensions;
+ bool unsupported_features;
+ bool validate;
+};
+
struct GpuInfo {
VkPhysicalDeviceProperties properties;
VkPhysicalDeviceMemoryProperties memory;
@@ -116,7 +122,9 @@
die("vkEnumerateDeviceExtensionProperties (data)", result);
}
-void GatherGpuInfo(VkPhysicalDevice gpu, GpuInfo& info) {
+void GatherGpuInfo(VkPhysicalDevice gpu,
+ const Options &options,
+ GpuInfo& info) {
VkResult result;
uint32_t count;
@@ -188,7 +196,7 @@
.pQueueCreateInfos = &queue_create_info,
.enabledExtensionCount = num_extensions,
.ppEnabledExtensionNames = extensions,
- .enabledLayerCount = num_layers,
+ .enabledLayerCount = (options.validate) ? num_layers : 0,
.ppEnabledLayerNames = kValidationLayers,
.pEnabledFeatures = &info.features,
};
@@ -198,7 +206,7 @@
vkDestroyDevice(device, nullptr);
}
-void GatherInfo(VulkanInfo* info) {
+void GatherInfo(VulkanInfo* info, const Options& options) {
VkResult result;
uint32_t count;
@@ -249,11 +257,20 @@
// clang-format on
uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*);
+ const VkApplicationInfo application_info = {
+ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+ .pApplicationName = "vkinfo",
+ .applicationVersion = 0,
+ .pEngineName = "vkinfo",
+ .engineVersion = 0,
+ .apiVersion = VK_API_VERSION,
+ };
const VkInstanceCreateInfo create_info = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ .pApplicationInfo = &application_info,
.enabledExtensionCount = num_extensions,
.ppEnabledExtensionNames = extensions,
- .enabledLayerCount = num_layers,
+ .enabledLayerCount = (options.validate) ? num_layers : 0,
.ppEnabledLayerNames = kValidationLayers,
};
VkInstance instance;
@@ -275,18 +292,13 @@
info->gpus.resize(num_gpus);
for (size_t i = 0; i < gpus.size(); i++)
- GatherGpuInfo(gpus[i], info->gpus.at(i));
+ GatherGpuInfo(gpus[i], options, info->gpus.at(i));
vkDestroyInstance(instance, nullptr);
}
// ----------------------------------------------------------------------------
-struct Options {
- bool layer_description;
- bool layer_extensions;
-};
-
const size_t kMaxIndent = 8;
const size_t kIndentSize = 3;
std::array<char, kMaxIndent * kIndentSize + 1> kIndent;
@@ -301,16 +313,6 @@
(kIndent.size() - (kIndentSize * std::min(n, kMaxIndent) + 1));
}
-uint32_t ExtractMajorVersion(uint32_t version) {
- return (version >> 22) & 0x3FF;
-}
-uint32_t ExtractMinorVersion(uint32_t version) {
- return (version >> 12) & 0x3FF;
-}
-uint32_t ExtractPatchVersion(uint32_t version) {
- return (version >> 0) & 0xFFF;
-}
-
const char* VkPhysicalDeviceTypeStr(VkPhysicalDeviceType type) {
switch (type) {
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
@@ -342,9 +344,9 @@
size_t indent) {
for (size_t i = 0; i < layers.size(); i++) {
printf("%s%s %u.%u.%u/%u\n", Indent(indent), layers[i].layerName,
- ExtractMajorVersion(layers[i].specVersion),
- ExtractMinorVersion(layers[i].specVersion),
- ExtractPatchVersion(layers[i].specVersion),
+ VK_VERSION_MAJOR(layers[i].specVersion),
+ VK_VERSION_MINOR(layers[i].specVersion),
+ VK_VERSION_PATCH(layers[i].specVersion),
layers[i].implementationVersion);
if (options.layer_description)
printf("%s%s\n", Indent(indent + 1), layers[i].description);
@@ -358,6 +360,128 @@
}
}
+void PrintAllFeatures(const char* indent,
+ const VkPhysicalDeviceFeatures& features) {
+ // clang-format off
+ printf("%srobustBufferAccess: %s\n", indent, features.robustBufferAccess ? "YES" : "NO");
+ printf("%sfullDrawIndexUint32: %s\n", indent, features.fullDrawIndexUint32 ? "YES" : "NO");
+ printf("%simageCubeArray: %s\n", indent, features.imageCubeArray ? "YES" : "NO");
+ printf("%sindependentBlend: %s\n", indent, features.independentBlend ? "YES" : "NO");
+ printf("%sgeometryShader: %s\n", indent, features.geometryShader ? "YES" : "NO");
+ printf("%stessellationShader: %s\n", indent, features.tessellationShader ? "YES" : "NO");
+ printf("%ssampleRateShading: %s\n", indent, features.sampleRateShading ? "YES" : "NO");
+ printf("%sdualSrcBlend: %s\n", indent, features.dualSrcBlend ? "YES" : "NO");
+ printf("%slogicOp: %s\n", indent, features.logicOp ? "YES" : "NO");
+ printf("%smultiDrawIndirect: %s\n", indent, features.multiDrawIndirect ? "YES" : "NO");
+ printf("%sdrawIndirectFirstInstance: %s\n", indent, features.drawIndirectFirstInstance ? "YES" : "NO");
+ printf("%sdepthClamp: %s\n", indent, features.depthClamp ? "YES" : "NO");
+ printf("%sdepthBiasClamp: %s\n", indent, features.depthBiasClamp ? "YES" : "NO");
+ printf("%sfillModeNonSolid: %s\n", indent, features.fillModeNonSolid ? "YES" : "NO");
+ printf("%sdepthBounds: %s\n", indent, features.depthBounds ? "YES" : "NO");
+ printf("%swideLines: %s\n", indent, features.wideLines ? "YES" : "NO");
+ printf("%slargePoints: %s\n", indent, features.largePoints ? "YES" : "NO");
+ printf("%salphaToOne: %s\n", indent, features.alphaToOne ? "YES" : "NO");
+ printf("%smultiViewport: %s\n", indent, features.multiViewport ? "YES" : "NO");
+ printf("%ssamplerAnisotropy: %s\n", indent, features.samplerAnisotropy ? "YES" : "NO");
+ printf("%stextureCompressionETC2: %s\n", indent, features.textureCompressionETC2 ? "YES" : "NO");
+ printf("%stextureCompressionASTC_LDR: %s\n", indent, features.textureCompressionASTC_LDR ? "YES" : "NO");
+ printf("%stextureCompressionBC: %s\n", indent, features.textureCompressionBC ? "YES" : "NO");
+ printf("%socclusionQueryPrecise: %s\n", indent, features.occlusionQueryPrecise ? "YES" : "NO");
+ printf("%spipelineStatisticsQuery: %s\n", indent, features.pipelineStatisticsQuery ? "YES" : "NO");
+ printf("%svertexPipelineStoresAndAtomics: %s\n", indent, features.vertexPipelineStoresAndAtomics ? "YES" : "NO");
+ printf("%sfragmentStoresAndAtomics: %s\n", indent, features.fragmentStoresAndAtomics ? "YES" : "NO");
+ printf("%sshaderTessellationAndGeometryPointSize: %s\n", indent, features.shaderTessellationAndGeometryPointSize ? "YES" : "NO");
+ printf("%sshaderImageGatherExtended: %s\n", indent, features.shaderImageGatherExtended ? "YES" : "NO");
+ printf("%sshaderStorageImageExtendedFormats: %s\n", indent, features.shaderStorageImageExtendedFormats ? "YES" : "NO");
+ printf("%sshaderStorageImageMultisample: %s\n", indent, features.shaderStorageImageMultisample ? "YES" : "NO");
+ printf("%sshaderStorageImageReadWithoutFormat: %s\n", indent, features.shaderStorageImageReadWithoutFormat ? "YES" : "NO");
+ printf("%sshaderStorageImageWriteWithoutFormat: %s\n", indent, features.shaderStorageImageWriteWithoutFormat ? "YES" : "NO");
+ printf("%sshaderUniformBufferArrayDynamicIndexing: %s\n", indent, features.shaderUniformBufferArrayDynamicIndexing ? "YES" : "NO");
+ printf("%sshaderSampledImageArrayDynamicIndexing: %s\n", indent, features.shaderSampledImageArrayDynamicIndexing ? "YES" : "NO");
+ printf("%sshaderStorageBufferArrayDynamicIndexing: %s\n", indent, features.shaderStorageBufferArrayDynamicIndexing ? "YES" : "NO");
+ printf("%sshaderStorageImageArrayDynamicIndexing: %s\n", indent, features.shaderStorageImageArrayDynamicIndexing ? "YES" : "NO");
+ printf("%sshaderClipDistance: %s\n", indent, features.shaderClipDistance ? "YES" : "NO");
+ printf("%sshaderCullDistance: %s\n", indent, features.shaderCullDistance ? "YES" : "NO");
+ printf("%sshaderFloat64: %s\n", indent, features.shaderFloat64 ? "YES" : "NO");
+ printf("%sshaderInt64: %s\n", indent, features.shaderInt64 ? "YES" : "NO");
+ printf("%sshaderInt16: %s\n", indent, features.shaderInt16 ? "YES" : "NO");
+ printf("%sshaderResourceResidency: %s\n", indent, features.shaderResourceResidency ? "YES" : "NO");
+ printf("%sshaderResourceMinLod: %s\n", indent, features.shaderResourceMinLod ? "YES" : "NO");
+ printf("%ssparseBinding: %s\n", indent, features.sparseBinding ? "YES" : "NO");
+ printf("%ssparseResidencyBuffer: %s\n", indent, features.sparseResidencyBuffer ? "YES" : "NO");
+ printf("%ssparseResidencyImage2D: %s\n", indent, features.sparseResidencyImage2D ? "YES" : "NO");
+ printf("%ssparseResidencyImage3D: %s\n", indent, features.sparseResidencyImage3D ? "YES" : "NO");
+ printf("%ssparseResidency2Samples: %s\n", indent, features.sparseResidency2Samples ? "YES" : "NO");
+ printf("%ssparseResidency4Samples: %s\n", indent, features.sparseResidency4Samples ? "YES" : "NO");
+ printf("%ssparseResidency8Samples: %s\n", indent, features.sparseResidency8Samples ? "YES" : "NO");
+ printf("%ssparseResidency16Samples: %s\n", indent, features.sparseResidency16Samples ? "YES" : "NO");
+ printf("%ssparseResidencyAliased: %s\n", indent, features.sparseResidencyAliased ? "YES" : "NO");
+ printf("%svariableMultisampleRate: %s\n", indent, features.variableMultisampleRate ? "YES" : "NO");
+ printf("%sinheritedQueries: %s\n", indent, features.inheritedQueries ? "YES" : "NO");
+ // clang-format on
+}
+
+void PrintSupportedFeatures(const char* indent,
+ const VkPhysicalDeviceFeatures& features) {
+ // clang-format off
+ if (features.robustBufferAccess) printf("%srobustBufferAccess\n", indent);
+ if (features.fullDrawIndexUint32) printf("%sfullDrawIndexUint32\n", indent);
+ if (features.imageCubeArray) printf("%simageCubeArray\n", indent);
+ if (features.independentBlend) printf("%sindependentBlend\n", indent);
+ if (features.geometryShader) printf("%sgeometryShader\n", indent);
+ if (features.tessellationShader) printf("%stessellationShader\n", indent);
+ if (features.sampleRateShading) printf("%ssampleRateShading\n", indent);
+ if (features.dualSrcBlend) printf("%sdualSrcBlend\n", indent);
+ if (features.logicOp) printf("%slogicOp\n", indent);
+ if (features.multiDrawIndirect) printf("%smultiDrawIndirect\n", indent);
+ if (features.drawIndirectFirstInstance) printf("%sdrawIndirectFirstInstance\n", indent);
+ if (features.depthClamp) printf("%sdepthClamp\n", indent);
+ if (features.depthBiasClamp) printf("%sdepthBiasClamp\n", indent);
+ if (features.fillModeNonSolid) printf("%sfillModeNonSolid\n", indent);
+ if (features.depthBounds) printf("%sdepthBounds\n", indent);
+ if (features.wideLines) printf("%swideLines\n", indent);
+ if (features.largePoints) printf("%slargePoints\n", indent);
+ if (features.alphaToOne) printf("%salphaToOne\n", indent);
+ if (features.multiViewport) printf("%smultiViewport\n", indent);
+ if (features.samplerAnisotropy) printf("%ssamplerAnisotropy\n", indent);
+ if (features.textureCompressionETC2) printf("%stextureCompressionETC2\n", indent);
+ if (features.textureCompressionASTC_LDR) printf("%stextureCompressionASTC_LDR\n", indent);
+ if (features.textureCompressionBC) printf("%stextureCompressionBC\n", indent);
+ if (features.occlusionQueryPrecise) printf("%socclusionQueryPrecise\n", indent);
+ if (features.pipelineStatisticsQuery) printf("%spipelineStatisticsQuery\n", indent);
+ if (features.vertexPipelineStoresAndAtomics) printf("%svertexPipelineStoresAndAtomics\n", indent);
+ if (features.fragmentStoresAndAtomics) printf("%sfragmentStoresAndAtomics\n", indent);
+ if (features.shaderTessellationAndGeometryPointSize) printf("%sshaderTessellationAndGeometryPointSize\n", indent);
+ if (features.shaderImageGatherExtended) printf("%sshaderImageGatherExtended\n", indent);
+ if (features.shaderStorageImageExtendedFormats) printf("%sshaderStorageImageExtendedFormats\n", indent);
+ if (features.shaderStorageImageMultisample) printf("%sshaderStorageImageMultisample\n", indent);
+ if (features.shaderStorageImageReadWithoutFormat) printf("%sshaderStorageImageReadWithoutFormat\n", indent);
+ if (features.shaderStorageImageWriteWithoutFormat) printf("%sshaderStorageImageWriteWithoutFormat\n", indent);
+ if (features.shaderUniformBufferArrayDynamicIndexing) printf("%sshaderUniformBufferArrayDynamicIndexing\n", indent);
+ if (features.shaderSampledImageArrayDynamicIndexing) printf("%sshaderSampledImageArrayDynamicIndexing\n", indent);
+ if (features.shaderStorageBufferArrayDynamicIndexing) printf("%sshaderStorageBufferArrayDynamicIndexing\n", indent);
+ if (features.shaderStorageImageArrayDynamicIndexing) printf("%sshaderStorageImageArrayDynamicIndexing\n", indent);
+ if (features.shaderClipDistance) printf("%sshaderClipDistance\n", indent);
+ if (features.shaderCullDistance) printf("%sshaderCullDistance\n", indent);
+ if (features.shaderFloat64) printf("%sshaderFloat64\n", indent);
+ if (features.shaderInt64) printf("%sshaderInt64\n", indent);
+ if (features.shaderInt16) printf("%sshaderInt16\n", indent);
+ if (features.shaderResourceResidency) printf("%sshaderResourceResidency\n", indent);
+ if (features.shaderResourceMinLod) printf("%sshaderResourceMinLod\n", indent);
+ if (features.sparseBinding) printf("%ssparseBinding\n", indent);
+ if (features.sparseResidencyBuffer) printf("%ssparseResidencyBuffer\n", indent);
+ if (features.sparseResidencyImage2D) printf("%ssparseResidencyImage2D\n", indent);
+ if (features.sparseResidencyImage3D) printf("%ssparseResidencyImage3D\n", indent);
+ if (features.sparseResidency2Samples) printf("%ssparseResidency2Samples\n", indent);
+ if (features.sparseResidency4Samples) printf("%ssparseResidency4Samples\n", indent);
+ if (features.sparseResidency8Samples) printf("%ssparseResidency8Samples\n", indent);
+ if (features.sparseResidency16Samples) printf("%ssparseResidency16Samples\n", indent);
+ if (features.sparseResidencyAliased) printf("%ssparseResidencyAliased\n", indent);
+ if (features.variableMultisampleRate) printf("%svariableMultisampleRate\n", indent);
+ if (features.inheritedQueries) printf("%sinheritedQueries\n", indent);
+ // clang-format on
+}
+
void PrintGpuInfo(const GpuInfo& info, const Options& options, size_t indent) {
VkResult result;
std::ostringstream strbuf;
@@ -365,9 +489,9 @@
printf("%s\"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n", Indent(indent),
info.properties.deviceName,
VkPhysicalDeviceTypeStr(info.properties.deviceType),
- ExtractMajorVersion(info.properties.apiVersion),
- ExtractMinorVersion(info.properties.apiVersion),
- ExtractPatchVersion(info.properties.apiVersion),
+ VK_VERSION_MAJOR(info.properties.apiVersion),
+ VK_VERSION_MINOR(info.properties.apiVersion),
+ VK_VERSION_PATCH(info.properties.apiVersion),
info.properties.driverVersion, info.properties.vendorID,
info.properties.deviceID);
@@ -422,64 +546,12 @@
qprops.minImageTransferGranularity.depth);
}
- // clang-format off
printf("%sFeatures:\n", Indent(indent + 1));
- printf("%srobustBufferAccess: %s\n", Indent(indent + 2), info.features.robustBufferAccess ? "YES" : "NO");
- printf("%sfullDrawIndexUint32: %s\n", Indent(indent + 2), info.features.fullDrawIndexUint32 ? "YES" : "NO");
- printf("%simageCubeArray: %s\n", Indent(indent + 2), info.features.imageCubeArray ? "YES" : "NO");
- printf("%sindependentBlend: %s\n", Indent(indent + 2), info.features.independentBlend ? "YES" : "NO");
- printf("%sgeometryShader: %s\n", Indent(indent + 2), info.features.geometryShader ? "YES" : "NO");
- printf("%stessellationShader: %s\n", Indent(indent + 2), info.features.tessellationShader ? "YES" : "NO");
- printf("%ssampleRateShading: %s\n", Indent(indent + 2), info.features.sampleRateShading ? "YES" : "NO");
- printf("%sdualSrcBlend: %s\n", Indent(indent + 2), info.features.dualSrcBlend ? "YES" : "NO");
- printf("%slogicOp: %s\n", Indent(indent + 2), info.features.logicOp ? "YES" : "NO");
- printf("%smultiDrawIndirect: %s\n", Indent(indent + 2), info.features.multiDrawIndirect ? "YES" : "NO");
- printf("%sdrawIndirectFirstInstance: %s\n", Indent(indent + 2), info.features.drawIndirectFirstInstance ? "YES" : "NO");
- printf("%sdepthClamp: %s\n", Indent(indent + 2), info.features.depthClamp ? "YES" : "NO");
- printf("%sdepthBiasClamp: %s\n", Indent(indent + 2), info.features.depthBiasClamp ? "YES" : "NO");
- printf("%sfillModeNonSolid: %s\n", Indent(indent + 2), info.features.fillModeNonSolid ? "YES" : "NO");
- printf("%sdepthBounds: %s\n", Indent(indent + 2), info.features.depthBounds ? "YES" : "NO");
- printf("%swideLines: %s\n", Indent(indent + 2), info.features.wideLines ? "YES" : "NO");
- printf("%slargePoints: %s\n", Indent(indent + 2), info.features.largePoints ? "YES" : "NO");
- printf("%salphaToOne: %s\n", Indent(indent + 2), info.features.alphaToOne ? "YES" : "NO");
- printf("%smultiViewport: %s\n", Indent(indent + 2), info.features.multiViewport ? "YES" : "NO");
- printf("%ssamplerAnisotropy: %s\n", Indent(indent + 2), info.features.samplerAnisotropy ? "YES" : "NO");
- printf("%stextureCompressionETC2: %s\n", Indent(indent + 2), info.features.textureCompressionETC2 ? "YES" : "NO");
- printf("%stextureCompressionASTC_LDR: %s\n", Indent(indent + 2), info.features.textureCompressionASTC_LDR ? "YES" : "NO");
- printf("%stextureCompressionBC: %s\n", Indent(indent + 2), info.features.textureCompressionBC ? "YES" : "NO");
- printf("%socclusionQueryPrecise: %s\n", Indent(indent + 2), info.features.occlusionQueryPrecise ? "YES" : "NO");
- printf("%spipelineStatisticsQuery: %s\n", Indent(indent + 2), info.features.pipelineStatisticsQuery ? "YES" : "NO");
- printf("%svertexPipelineStoresAndAtomics: %s\n", Indent(indent + 2), info.features.vertexPipelineStoresAndAtomics ? "YES" : "NO");
- printf("%sfragmentStoresAndAtomics: %s\n", Indent(indent + 2), info.features.fragmentStoresAndAtomics ? "YES" : "NO");
- printf("%sshaderTessellationAndGeometryPointSize: %s\n", Indent(indent + 2), info.features.shaderTessellationAndGeometryPointSize ? "YES" : "NO");
- printf("%sshaderImageGatherExtended: %s\n", Indent(indent + 2), info.features.shaderImageGatherExtended ? "YES" : "NO");
- printf("%sshaderStorageImageExtendedFormats: %s\n", Indent(indent + 2), info.features.shaderStorageImageExtendedFormats ? "YES" : "NO");
- printf("%sshaderStorageImageMultisample: %s\n", Indent(indent + 2), info.features.shaderStorageImageMultisample ? "YES" : "NO");
- printf("%sshaderStorageImageReadWithoutFormat: %s\n", Indent(indent + 2), info.features.shaderStorageImageReadWithoutFormat ? "YES" : "NO");
- printf("%sshaderStorageImageWriteWithoutFormat: %s\n", Indent(indent + 2), info.features.shaderStorageImageWriteWithoutFormat ? "YES" : "NO");
- printf("%sshaderUniformBufferArrayDynamicIndexing: %s\n", Indent(indent + 2), info.features.shaderUniformBufferArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderSampledImageArrayDynamicIndexing: %s\n", Indent(indent + 2), info.features.shaderSampledImageArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderStorageBufferArrayDynamicIndexing: %s\n", Indent(indent + 2), info.features.shaderStorageBufferArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderStorageImageArrayDynamicIndexing: %s\n", Indent(indent + 2), info.features.shaderStorageImageArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderClipDistance: %s\n", Indent(indent + 2), info.features.shaderClipDistance ? "YES" : "NO");
- printf("%sshaderCullDistance: %s\n", Indent(indent + 2), info.features.shaderCullDistance ? "YES" : "NO");
- printf("%sshaderFloat64: %s\n", Indent(indent + 2), info.features.shaderFloat64 ? "YES" : "NO");
- printf("%sshaderInt64: %s\n", Indent(indent + 2), info.features.shaderInt64 ? "YES" : "NO");
- printf("%sshaderInt16: %s\n", Indent(indent + 2), info.features.shaderInt16 ? "YES" : "NO");
- printf("%sshaderResourceResidency: %s\n", Indent(indent + 2), info.features.shaderResourceResidency ? "YES" : "NO");
- printf("%sshaderResourceMinLod: %s\n", Indent(indent + 2), info.features.shaderResourceMinLod ? "YES" : "NO");
- printf("%ssparseBinding: %s\n", Indent(indent + 2), info.features.sparseBinding ? "YES" : "NO");
- printf("%ssparseResidencyBuffer: %s\n", Indent(indent + 2), info.features.sparseResidencyBuffer ? "YES" : "NO");
- printf("%ssparseResidencyImage2D: %s\n", Indent(indent + 2), info.features.sparseResidencyImage2D ? "YES" : "NO");
- printf("%ssparseResidencyImage3D: %s\n", Indent(indent + 2), info.features.sparseResidencyImage3D ? "YES" : "NO");
- printf("%ssparseResidency2Samples: %s\n", Indent(indent + 2), info.features.sparseResidency2Samples ? "YES" : "NO");
- printf("%ssparseResidency4Samples: %s\n", Indent(indent + 2), info.features.sparseResidency4Samples ? "YES" : "NO");
- printf("%ssparseResidency8Samples: %s\n", Indent(indent + 2), info.features.sparseResidency8Samples ? "YES" : "NO");
- printf("%ssparseResidency16Samples: %s\n", Indent(indent + 2), info.features.sparseResidency16Samples ? "YES" : "NO");
- printf("%ssparseResidencyAliased: %s\n", Indent(indent + 2), info.features.sparseResidencyAliased ? "YES" : "NO");
- printf("%svariableMultisampleRate: %s\n", Indent(indent + 2), info.features.variableMultisampleRate ? "YES" : "NO");
- printf("%sinheritedQueries: %s\n", Indent(indent + 2), info.features.inheritedQueries ? "YES" : "NO");
- // clang-format on
+ if (options.unsupported_features) {
+ PrintAllFeatures(Indent(indent + 2), info.features);
+ } else {
+ PrintSupportedFeatures(Indent(indent + 2), info.features);
+ }
printf("%sExtensions [%zu]:\n", Indent(indent + 1), info.extensions.size());
if (!info.extensions.empty())
@@ -505,6 +577,15 @@
PrintGpuInfo(gpu, options, indent + 1);
}
+const char kUsageString[] =
+ "usage: vkinfo [options]\n"
+ " -v enable all the following verbose options\n"
+ " -layer_description print layer description strings\n"
+ " -layer_extensions print extensions supported by each layer\n"
+ " -unsupported_features print all physical device features\n"
+ " -validate enable validation layers if present\n"
+ " -debug_pause pause at start until resumed via debugger\n";
+
} // namespace
// ----------------------------------------------------------------------------
@@ -513,15 +594,26 @@
static volatile bool startup_pause = false;
Options options = {
.layer_description = false, .layer_extensions = false,
+ .unsupported_features = false,
+ .validate = false,
};
for (int argi = 1; argi < argc; argi++) {
+ if (strcmp(argv[argi], "-h") == 0) {
+ fputs(kUsageString, stdout);
+ return 0;
+ }
if (strcmp(argv[argi], "-v") == 0) {
options.layer_description = true;
options.layer_extensions = true;
+ options.unsupported_features = true;
} else if (strcmp(argv[argi], "-layer_description") == 0) {
options.layer_description = true;
} else if (strcmp(argv[argi], "-layer_extensions") == 0) {
options.layer_extensions = true;
+ } else if (strcmp(argv[argi], "-unsupported_features") == 0) {
+ options.unsupported_features = true;
+ } else if (strcmp(argv[argi], "-validate") == 0) {
+ options.validate = true;
} else if (strcmp(argv[argi], "-debug_pause") == 0) {
startup_pause = true;
}
@@ -532,7 +624,7 @@
}
VulkanInfo info;
- GatherInfo(&info);
+ GatherInfo(&info, options);
PrintInfo(info, options);
return 0;
}