diff options
296 files changed, 18841 insertions, 14995 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 9dbbb7757c..1b9057977c 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -130,6 +130,14 @@ static const TracingCategory k_categories[] = { { REQ, "events/irq/enable" }, { OPT, "events/ipi/enable" }, } }, + { "irqoff", "IRQ-disabled code section tracing", 0, { + { REQ, "events/preemptirq/irq_enable/enable" }, + { REQ, "events/preemptirq/irq_disable/enable" }, + } }, + { "preemptoff", "Preempt-disabled code section tracing", 0, { + { REQ, "events/preemptirq/preempt_enable/enable" }, + { REQ, "events/preemptirq/preempt_disable/enable" }, + } }, { "i2c", "I2C Events", 0, { { REQ, "events/i2c/enable" }, { REQ, "events/i2c/i2c_read/enable" }, @@ -144,6 +152,8 @@ static const TracingCategory k_categories[] = { { "freq", "CPU Frequency", 0, { { REQ, "events/power/cpu_frequency/enable" }, { OPT, "events/power/clock_set_rate/enable" }, + { OPT, "events/power/clock_disable/enable" }, + { OPT, "events/power/clock_enable/enable" }, { OPT, "events/power/cpu_frequency_limits/enable" }, } }, { "membus", "Memory Bus Utilization", 0, { diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp index 022d3dd6ba..48d5d4aed7 100644 --- a/cmds/cmd/cmd.cpp +++ b/cmds/cmd/cmd.cpp @@ -61,7 +61,8 @@ class MyShellCallback : public BnShellCallback public: bool mActive = true; - virtual int openOutputFile(const String16& path, const String16& seLinuxContext) { + virtual int openFile(const String16& path, const String16& seLinuxContext, + const String16& mode) { String8 path8(path); char cwd[256]; getcwd(cwd, 256); @@ -71,7 +72,32 @@ public: aerr << "Open attempt after active for: " << fullPath << endl; return -EPERM; } - int fd = open(fullPath.string(), O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG); +#if DEBUG + ALOGD("openFile: %s, full=%s", path8.string(), fullPath.string()); +#endif + int flags = 0; + bool checkRead = false; + bool checkWrite = false; + if (mode == String16("w")) { + flags = O_WRONLY|O_CREAT|O_TRUNC; + checkWrite = true; + } else if (mode == String16("w+")) { + flags = O_RDWR|O_CREAT|O_TRUNC; + checkRead = checkWrite = true; + } else if (mode == String16("r")) { + flags = O_RDONLY; + checkRead = true; + } else if (mode == String16("r+")) { + flags = O_RDWR; + checkRead = checkWrite = true; + } else { + aerr << "Invalid mode requested: " << mode.string() << endl; + return -EINVAL; + } + int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG); +#if DEBUG + ALOGD("openFile: fd=%d", fd); +#endif if (fd < 0) { return fd; } @@ -80,14 +106,33 @@ public: security_context_t tmp = NULL; getfilecon(fullPath.string(), &tmp); Unique_SecurityContext context(tmp); - int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(), - "file", "write", NULL); - if (accessGranted != 0) { - close(fd); - aerr << "System server has no access to file context " << context.get() - << " (from path " << fullPath.string() << ", context " - << seLinuxContext8.string() << ")" << endl; - return -EPERM; + if (checkWrite) { + int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(), + "file", "write", NULL); + if (accessGranted != 0) { +#if DEBUG + ALOGD("openFile: failed selinux write check!"); +#endif + close(fd); + aerr << "System server has no access to write file context " << context.get() + << " (from path " << fullPath.string() << ", context " + << seLinuxContext8.string() << ")" << endl; + return -EPERM; + } + } + if (checkRead) { + int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(), + "file", "read", NULL); + if (accessGranted != 0) { +#if DEBUG + ALOGD("openFile: failed selinux read check!"); +#endif + close(fd); + aerr << "System server has no access to read file context " << context.get() + << " (from path " << fullPath.string() << ", context " + << seLinuxContext8.string() << ")" << endl; + return -EPERM; + } } } return fd; @@ -131,6 +176,9 @@ int main(int argc, char* const argv[]) proc->setThreadPoolMaxThreadCount(0); proc->startThreadPool(); +#if DEBUG + ALOGD("cmd: starting"); +#endif sp<IServiceManager> sm = defaultServiceManager(); fflush(stdout); if (sm == NULL) { diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index ede4254a9b..85eb464104 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -43,7 +43,7 @@ namespace { static constexpr const char* kSuPath = "/system/xbin/su"; -static bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) { +static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) { sigset_t child_mask, old_mask; sigemptyset(&child_mask); sigaddset(&child_mask, SIGCHLD); @@ -54,10 +54,11 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) { } timespec ts; - ts.tv_sec = timeout_seconds; - ts.tv_nsec = 0; + ts.tv_sec = MSEC_TO_SEC(timeout_ms); + ts.tv_nsec = (timeout_ms % 1000) * 1000000; int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts)); int saved_errno = errno; + // Set the signals back the way they were. if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) { printf("*** sigprocmask failed: %s\n", strerror(errno)); @@ -91,7 +92,7 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) { CommandOptions CommandOptions::DEFAULT = CommandOptions::WithTimeout(10).Build(); CommandOptions CommandOptions::AS_ROOT = CommandOptions::WithTimeout(10).AsRoot().Build(); -CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(int64_t timeout) : values(timeout) { +CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(int64_t timeout_ms) : values(timeout_ms) { } CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Always() { @@ -130,8 +131,8 @@ CommandOptions CommandOptions::CommandOptionsBuilder::Build() { return CommandOptions(values); } -CommandOptions::CommandOptionsValues::CommandOptionsValues(int64_t timeout) - : timeout_(timeout), +CommandOptions::CommandOptionsValues::CommandOptionsValues(int64_t timeout_ms) + : timeout_ms_(timeout_ms), always_(false), account_mode_(DONT_DROP_ROOT), output_mode_(NORMAL_OUTPUT), @@ -142,7 +143,11 @@ CommandOptions::CommandOptions(const CommandOptionsValues& values) : values(valu } int64_t CommandOptions::Timeout() const { - return values.timeout_; + return MSEC_TO_SEC(values.timeout_ms_); +} + +int64_t CommandOptions::TimeoutInMs() const { + return values.timeout_ms_; } bool CommandOptions::Always() const { @@ -161,8 +166,12 @@ std::string CommandOptions::LoggingMessage() const { return values.logging_message_; } -CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(int64_t timeout) { - return CommandOptions::CommandOptionsBuilder(timeout); +CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(int64_t timeout_sec) { + return CommandOptions::CommandOptionsBuilder(SEC_TO_MSEC(timeout_sec)); +} + +CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeoutInMs(int64_t timeout_ms) { + return CommandOptions::CommandOptionsBuilder(timeout_ms); } std::string PropertiesHelper::build_type_ = ""; @@ -314,7 +323,7 @@ int RunCommandToFd(int fd, const std::string& title, const std::vector<std::stri /* handle parent case */ int status; - bool ret = waitpid_with_timeout(pid, options.Timeout(), &status); + bool ret = waitpid_with_timeout(pid, options.TimeoutInMs(), &status); fsync(fd); uint64_t elapsed = Nanotime() - start; @@ -333,9 +342,9 @@ int RunCommandToFd(int fd, const std::string& title, const std::vector<std::stri static_cast<float>(elapsed) / NANOS_PER_SEC, pid); } kill(pid, SIGTERM); - if (!waitpid_with_timeout(pid, 5, nullptr)) { + if (!waitpid_with_timeout(pid, 5000, nullptr)) { kill(pid, SIGKILL); - if (!waitpid_with_timeout(pid, 5, nullptr)) { + if (!waitpid_with_timeout(pid, 5000, nullptr)) { if (!silent) dprintf(fd, "could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid); diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h index 698ceffcc4..8342099821 100644 --- a/cmds/dumpstate/DumpstateUtil.h +++ b/cmds/dumpstate/DumpstateUtil.h @@ -19,6 +19,16 @@ #include <cstdint> #include <string> +/* + * Converts seconds to milliseconds. + */ +#define SEC_TO_MSEC(second) (second * 1000) + +/* + * Converts milliseconds to seconds. + */ +#define MSEC_TO_SEC(millisecond) (millisecond / 1000) + namespace android { namespace os { namespace dumpstate { @@ -66,9 +76,9 @@ class CommandOptions { private: class CommandOptionsValues { private: - CommandOptionsValues(int64_t timeout); + CommandOptionsValues(int64_t timeout_ms); - int64_t timeout_; + int64_t timeout_ms_; bool always_; PrivilegeMode account_mode_; OutputMode output_mode_; @@ -102,13 +112,15 @@ class CommandOptions { CommandOptions Build(); private: - CommandOptionsBuilder(int64_t timeout); + CommandOptionsBuilder(int64_t timeout_ms); CommandOptionsValues values; friend class CommandOptions; }; - /** Gets the command timeout, in seconds. */ + /** Gets the command timeout in seconds. */ int64_t Timeout() const; + /** Gets the command timeout in milliseconds. */ + int64_t TimeoutInMs() const; /* Checks whether the command should always be run, even on dry-run mode. */ bool Always() const; /** Gets the PrivilegeMode of the command. */ @@ -118,8 +130,11 @@ class CommandOptions { /** Gets the logging message header, it any. */ std::string LoggingMessage() const; - /** Creates a builder with the requied timeout. */ - static CommandOptionsBuilder WithTimeout(int64_t timeout); + /** Creates a builder with the requied timeout in seconds. */ + static CommandOptionsBuilder WithTimeout(int64_t timeout_sec); + + /** Creates a builder with the requied timeout in milliseconds. */ + static CommandOptionsBuilder WithTimeoutInMs(int64_t timeout_ms); // Common options. static CommandOptions DEFAULT; diff --git a/cmds/dumpstate/bugreport-format.md b/cmds/dumpstate/bugreport-format.md index b995b808c1..dee89cf174 100644 --- a/cmds/dumpstate/bugreport-format.md +++ b/cmds/dumpstate/bugreport-format.md @@ -56,8 +56,20 @@ files upon the end user’s request: - `description.txt`: whose value is a multi-line, detailed description of the problem. ## Android O versions -On _Android O (OhMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made: -- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-1`). +On _Android O (Oreo)_, the following changes were made: +- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-split-anr`). + +## Android P versions +On _Android P (PleaseMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made: +- Dumpsys sections are dumped by priority (version `2.0-dev-priority-dumps`). + Supported priorities can be specified when registering framework services. Section headers are + changed to contain priority info. + `DUMPSYS` -> `DUMPSYS CRITICAL/HIGH/NORMAL` + `DUMP OF SERVICE <servicename>` -> `DUMP OF SERVICE CRITICAL/HIGH/NORMAL <servicename>` + Supported Priorities: + - CRITICAL - services that must dump first, and fast (under 100ms). Ex: cpuinfo. + - HIGH - services that also must dump first, but can take longer (under 250ms) to dump. Ex: meminfo. + - NORMAL - services that have no rush to dump and can take a long time (under 10s). ## Intermediate versions During development, the versions will be suffixed with _-devX_ or diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 51942dd483..b97df35051 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -81,6 +81,7 @@ void add_mountinfo(); #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur" #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref" #define WLUTIL "/vendor/xbin/wlutil" +#define WMTRACE_DATA_DIR "/data/misc/wmtrace" // TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. @@ -112,8 +113,8 @@ static int RunCommand(const std::string& title, const std::vector<std::string>& } static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs, const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS, - long dumpsysTimeout = 0) { - return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeout); + long dumpsysTimeoutMs = 0) { + return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs); } static int DumpFile(const std::string& title, const std::string& path) { return ds.DumpFile(title, path); @@ -690,7 +691,9 @@ void Dumpstate::PrintHeader() const { printf("Kernel: "); DumpFileToFd(STDOUT_FILENO, "", "/proc/version"); printf("Command line: %s\n", strtok(cmdline_buf, "\n")); - ds.RunCommand("UPTIME", {"uptime"}, CommandOptions::DEFAULT); + printf("Uptime: "); + RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"}, + CommandOptions::WithTimeout(1).Always().Build()); printf("Bugreport format version: %s\n", version_.c_str()); printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_, PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str()); @@ -829,33 +832,32 @@ static void DoKmsg() { } static void DoLogcat() { - unsigned long timeout; + unsigned long timeout_ms; // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags"); // calculate timeout - timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash"); - if (timeout < 20000) { - timeout = 20000; + timeout_ms = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash"); + if (timeout_ms < 20000) { + timeout_ms = 20000; } RunCommand("SYSTEM LOG", - {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", - "-d", "*:v"}, - CommandOptions::WithTimeout(timeout / 1000).Build()); - timeout = logcat_timeout("events"); - if (timeout < 20000) { - timeout = 20000; + {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); + timeout_ms = logcat_timeout("events"); + if (timeout_ms < 20000) { + timeout_ms = 20000; } RunCommand("EVENT LOG", {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, - CommandOptions::WithTimeout(timeout / 1000).Build()); - timeout = logcat_timeout("radio"); - if (timeout < 20000) { - timeout = 20000; + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); + timeout_ms = logcat_timeout("radio"); + if (timeout_ms < 20000) { + timeout_ms = 20000; } RunCommand("RADIO LOG", {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, - CommandOptions::WithTimeout(timeout / 1000).Build()); + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"}); @@ -1055,11 +1057,44 @@ static void DumpIpAddrAndRules() { RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"}); } +// Runs dumpsys on services that must dump first and and will take less than 100ms to dump. +static void RunDumpsysCritical() { + if (ds.CurrentVersionSupportsPriorityDumps()) { + RunDumpsys("DUMPSYS CRITICAL", {"--priority", "CRITICAL"}, + CommandOptions::WithTimeout(5).DropRoot().Build()); + } else { + RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"}, + CommandOptions::WithTimeout(90).DropRoot().Build()); + RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"}, + CommandOptions::WithTimeout(10).DropRoot().Build()); + } +} + +// Runs dumpsys on services that must dump first but can take up to 250ms to dump. +static void RunDumpsysHigh() { + if (ds.CurrentVersionSupportsPriorityDumps()) { + RunDumpsys("DUMPSYS HIGH", {"--priority", "HIGH"}, + CommandOptions::WithTimeout(20).DropRoot().Build()); + } else { + RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"}); + } +} + +// Runs dumpsys on services that must dump but can take up to 10s to dump. +static void RunDumpsysNormal() { + if (ds.CurrentVersionSupportsPriorityDumps()) { + RunDumpsys("DUMPSYS NORMAL", {"--priority", "NORMAL"}, + CommandOptions::WithTimeout(90).DropRoot().Build()); + } else { + RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, + CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); + } +} + static void dumpstate() { DurationReporter duration_reporter("DUMPSTATE"); dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); - /* TODO: Remove duplicate uptime call when tools use it from header */ RunCommand("UPTIME", {"uptime"}); DumpBlockStatFiles(); dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd"); @@ -1080,7 +1115,7 @@ static void dumpstate() { DumpFile("KERNEL SYNC", "/d/sync"); RunCommand("PROCESSES AND THREADS", - {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"}); + {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"}); RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT); if (ds.IsZipping()) { @@ -1146,15 +1181,11 @@ static void dumpstate() { RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"}); RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"}); - RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"}, - CommandOptions::WithTimeout(10).Build()); + RunDumpsysHigh(); RunCommand("SYSTEM PROPERTIES", {"getprop"}); - RunCommand("VOLD DUMP", {"vdc", "dump"}); - RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"}); - - RunCommand("STORAGED TASKIOINFO", {"storaged", "-u"}, CommandOptions::WithTimeout(10).Build()); + RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"}); RunCommand("FILESYSTEMS & FREE SPACE", {"df"}); @@ -1167,6 +1198,11 @@ static void dumpstate() { DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats"); DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state"); + /* Add window and surface trace files. */ + if (!PropertiesHelper::IsUserBuild()) { + ds.AddDir(WMTRACE_DATA_DIR, false); + } + ds.DumpstateBoard(); /* Migrate the ril_dumpstate to a device specific dumpstate? */ @@ -1187,8 +1223,7 @@ static void dumpstate() { printf("== Android Framework Services\n"); printf("========================================================\n"); - RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(), - 10); + RunDumpsysNormal(); printf("========================================================\n"); printf("== Checkins\n"); @@ -1260,8 +1295,10 @@ static void DumpstateTelephonyOnly() { printf("== Android Framework Services\n"); printf("========================================================\n"); - RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10); - RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10); + RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); + RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); printf("========================================================\n"); printf("== Running Application Services\n"); @@ -1586,6 +1623,7 @@ int main(int argc, char *argv[]) { do_fb = 0; } else if (ds.extra_options_ == "bugreportwear") { ds.update_progress_ = true; + do_zip_file = 1; } else if (ds.extra_options_ == "bugreporttelephony") { telephony_only = true; } else { @@ -1629,10 +1667,12 @@ int main(int argc, char *argv[]) { ds.version_ = VERSION_CURRENT; } - if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) { - MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n", - ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(), - VERSION_SPLIT_ANR.c_str()); + if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR && + ds.version_ != VERSION_PRIORITY_DUMPS) { + MYLOGE( + "invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s', '%s')\n", + ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(), + VERSION_SPLIT_ANR.c_str(), VERSION_PRIORITY_DUMPS.c_str()); exit(1); } @@ -1823,10 +1863,7 @@ int main(int argc, char *argv[]) { // Invoking the following dumpsys calls before dump_traces() to try and // keep the system stats as close to its initial state as possible. - RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"}, - CommandOptions::WithTimeout(90).DropRoot().Build()); - RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"}, - CommandOptions::WithTimeout(10).DropRoot().Build()); + RunDumpsysCritical(); // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed. dump_raft(); @@ -1856,6 +1893,9 @@ int main(int argc, char *argv[]) { RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build()); + // Run iotop as root to show top 100 IO threads + RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"}); + if (!DropRootUser()) { return -1; } diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 7757c1e445..8db23a94f4 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -149,9 +149,15 @@ static std::string VERSION_CURRENT = "1.0"; /* * Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version - * will be bumped to 2.0-dev-1. + * will be bumped to 2.0. */ -static std::string VERSION_SPLIT_ANR = "2.0-dev-1"; +static std::string VERSION_SPLIT_ANR = "2.0-dev-split-anr"; + +/* + * Temporary version that adds priority based dumps. Once tools support it, the current version + * will be bumped to 2.0. + */ +static std::string VERSION_PRIORITY_DUMPS = "2.0-dev-priority-dumps"; /* * "Alias" for the current version. @@ -190,19 +196,19 @@ class Dumpstate { /* * Runs `dumpsys` with the given arguments, automatically setting its timeout - * (`-t` argument) + * (`-T` argument) * according to the command options. * * |title| description of the command printed on `stdout` (or empty to skip * description). * |dumpsys_args| `dumpsys` arguments (except `-t`). * |options| optional argument defining the command's behavior. - * |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -t` (otherwise it uses the + * |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -T` (otherwise it uses the * timeout from `options`) */ void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args, const android::os::dumpstate::CommandOptions& options = DEFAULT_DUMPSYS, - long dumpsys_timeout = 0); + long dumpsys_timeout_ms = 0); /* * Prints the contents of a file. @@ -266,6 +272,9 @@ class Dumpstate { /* Gets the path of a bugreport file with the given suffix. */ std::string GetPath(const std::string& suffix) const; + /* Returns true if the current version supports priority dump feature. */ + bool CurrentVersionSupportsPriorityDumps() const; + // TODO: initialize fields on constructor // dumpstate id - unique after each device reboot. diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 92b0c0d8bc..a2e94538c2 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -1001,7 +1001,7 @@ TEST_F(DumpstateUtilTest, RunCommandCrashes) { err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code")); } -TEST_F(DumpstateUtilTest, RunCommandTimesout) { +TEST_F(DumpstateUtilTest, RunCommandTimesoutWithSec) { CreateFd("RunCommandTimesout.txt"); EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"}, CommandOptions::WithTimeout(1).Build())); @@ -1011,6 +1011,17 @@ TEST_F(DumpstateUtilTest, RunCommandTimesout) { " --sleep 2' timed out after 1")); } +TEST_F(DumpstateUtilTest, RunCommandTimesoutWithMsec) { + CreateFd("RunCommandTimesout.txt"); + EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"}, + CommandOptions::WithTimeoutInMs(1000).Build())); + EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand + + " --sleep 2' timed out after 1")); + EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand + + " --sleep 2' timed out after 1")); +} + + TEST_F(DumpstateUtilTest, RunCommandIsKilled) { CreateFd("RunCommandIsKilled.txt"); CaptureStderr(); diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp index a96a69d034..ac48041f6d 100644 --- a/cmds/dumpstate/utils.cpp +++ b/cmds/dumpstate/utils.cpp @@ -215,10 +215,10 @@ int32_t Progress::Get() const { return progress_; } -bool Progress::Inc(int32_t delta) { +bool Progress::Inc(int32_t delta_sec) { bool changed = false; - if (delta >= 0) { - progress_ += delta; + if (delta_sec >= 0) { + progress_ += delta_sec; if (progress_ > max_) { int32_t old_max = max_; max_ = floor((float)progress_ * growth_factor_); @@ -257,6 +257,10 @@ std::string Dumpstate::GetPath(const std::string& suffix) const { name_.c_str(), suffix.c_str()); } +bool Dumpstate::CurrentVersionSupportsPriorityDumps() const { + return (version_ == VERSION_PRIORITY_DUMPS); +} + void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) { progress_ = std::move(progress); } @@ -719,9 +723,9 @@ int Dumpstate::RunCommand(const std::string& title, const std::vector<std::strin } void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args, - const CommandOptions& options, long dumpsysTimeout) { - long timeout = dumpsysTimeout > 0 ? dumpsysTimeout : options.Timeout(); - std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-t", std::to_string(timeout)}; + const CommandOptions& options, long dumpsysTimeoutMs) { + long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs(); + std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)}; dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end()); RunCommand(title, dumpsys, options); } @@ -1161,14 +1165,14 @@ void dump_route_tables() { } // TODO: make this function thread safe if sections are generated in parallel. -void Dumpstate::UpdateProgress(int32_t delta) { +void Dumpstate::UpdateProgress(int32_t delta_sec) { if (progress_ == nullptr) { MYLOGE("UpdateProgress: progress_ not set\n"); return; } // Always update progess so stats can be tuned... - bool max_changed = progress_->Inc(delta); + bool max_changed = progress_->Inc(delta_sec); // ...but only notifiy listeners when necessary. if (!update_progress_) return; diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp index 34769644d5..f68b862f24 100644 --- a/cmds/dumpsys/Android.bp +++ b/cmds/dumpsys/Android.bp @@ -17,6 +17,10 @@ cc_defaults { "libbinder", ], + static_libs: [ + "libserviceutils", + ], + clang: true, } diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index 32277499a6..0862a40734 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -25,6 +25,7 @@ #include <binder/Parcel.h> #include <binder/ProcessState.h> #include <binder/TextOutput.h> +#include <serviceutils/PriorityDumper.h> #include <utils/Log.h> #include <utils/Vector.h> @@ -53,13 +54,19 @@ static int sort_func(const String16* lhs, const String16* rhs) static void usage() { fprintf(stderr, - "usage: dumpsys\n" + "usage: dumpsys\n" " To dump all services.\n" "or:\n" - " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n" + " dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | " + "SERVICE [ARGS]]\n" " --help: shows this help\n" " -l: only list services, do not dump them\n" - " -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n" + " -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n" + " -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n" + " --proto: filter services that support dumping data in proto format. Dumps" + " will be in proto format.\n" + " --priority LEVEL: filter services based on specified priority\n" + " LEVEL must be one of CRITICAL | HIGH | NORMAL\n" " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n" " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n"); } @@ -73,18 +80,38 @@ static bool IsSkipped(const Vector<String16>& skipped, const String16& service) return false; } +static bool ConvertPriorityTypeToBitmask(const String16& type, int& bitmask) { + if (type == PriorityDumper::PRIORITY_ARG_CRITICAL) { + bitmask = IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL; + return true; + } + if (type == PriorityDumper::PRIORITY_ARG_HIGH) { + bitmask = IServiceManager::DUMP_FLAG_PRIORITY_HIGH; + return true; + } + if (type == PriorityDumper::PRIORITY_ARG_NORMAL) { + bitmask = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL; + return true; + } + return false; +} + int Dumpsys::main(int argc, char* const argv[]) { Vector<String16> services; Vector<String16> args; + String16 priorityType; Vector<String16> skippedServices; + Vector<String16> protoServices; bool showListOnly = false; bool skipServices = false; - int timeoutArg = 10; - static struct option longOptions[] = { - {"skip", no_argument, 0, 0 }, - {"help", no_argument, 0, 0 }, - { 0, 0, 0, 0 } - }; + bool filterByProto = false; + int timeoutArgMs = 10000; + int dumpPriorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL; + static struct option longOptions[] = {{"priority", required_argument, 0, 0}, + {"proto", no_argument, 0, 0}, + {"skip", no_argument, 0, 0}, + {"help", no_argument, 0, 0}, + {0, 0, 0, 0}}; // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but // happens on test cases). @@ -93,7 +120,7 @@ int Dumpsys::main(int argc, char* const argv[]) { int c; int optionIndex = 0; - c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex); + c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex); if (c == -1) { break; @@ -103,18 +130,39 @@ int Dumpsys::main(int argc, char* const argv[]) { case 0: if (!strcmp(longOptions[optionIndex].name, "skip")) { skipServices = true; + } else if (!strcmp(longOptions[optionIndex].name, "proto")) { + filterByProto = true; } else if (!strcmp(longOptions[optionIndex].name, "help")) { usage(); return 0; + } else if (!strcmp(longOptions[optionIndex].name, "priority")) { + priorityType = String16(String8(optarg)); + if (!ConvertPriorityTypeToBitmask(priorityType, dumpPriorityFlags)) { + fprintf(stderr, "\n"); + usage(); + return -1; + } } break; case 't': { - char *endptr; - timeoutArg = strtol(optarg, &endptr, 10); - if (*endptr != '\0' || timeoutArg <= 0) { - fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg); + char* endptr; + timeoutArgMs = strtol(optarg, &endptr, 10); + timeoutArgMs = timeoutArgMs * 1000; + if (*endptr != '\0' || timeoutArgMs <= 0) { + fprintf(stderr, "Error: invalid timeout(seconds) number: '%s'\n", optarg); + return -1; + } + } + break; + + case 'T': + { + char* endptr; + timeoutArgMs = strtol(optarg, &endptr, 10); + if (*endptr != '\0' || timeoutArgMs <= 0) { + fprintf(stderr, "Error: invalid timeout(milliseconds) number: '%s'\n", optarg); return -1; } } @@ -151,9 +199,23 @@ int Dumpsys::main(int argc, char* const argv[]) { if (services.empty() || showListOnly) { // gets all services - services = sm_->listServices(); + services = sm_->listServices(dumpPriorityFlags); services.sort(sort_func); - args.add(String16("-a")); + if (filterByProto) { + protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO); + protoServices.sort(sort_func); + Vector<String16> intersection; + std::set_intersection(services.begin(), services.end(), protoServices.begin(), + protoServices.end(), std::back_inserter(intersection)); + services = std::move(intersection); + args.insertAt(String16(PriorityDumper::PROTO_ARG), 0); + } + if (dumpPriorityFlags != IServiceManager::DUMP_FLAG_PRIORITY_ALL) { + args.insertAt(String16(PriorityDumper::PRIORITY_ARG), 0); + args.insertAt(priorityType, 1); + } else { + args.add(String16("-a")); + } } const size_t N = services.size(); @@ -197,7 +259,11 @@ int Dumpsys::main(int argc, char* const argv[]) { if (N > 1) { aout << "------------------------------------------------------------" "-------------------" << endl; - aout << "DUMP OF SERVICE " << service_name << ":" << endl; + if (dumpPriorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) { + aout << "DUMP OF SERVICE " << service_name << ":" << endl; + } else { + aout << "DUMP OF SERVICE " << priorityType << " " << service_name << ":" << endl; + } } // dump blocks until completion, so spawn a thread.. @@ -216,7 +282,7 @@ int Dumpsys::main(int argc, char* const argv[]) { } }); - auto timeout = std::chrono::seconds(timeoutArg); + auto timeout = std::chrono::milliseconds(timeoutArgMs); auto start = std::chrono::steady_clock::now(); auto end = start + timeout; @@ -268,8 +334,8 @@ int Dumpsys::main(int argc, char* const argv[]) { if (timed_out) { aout << endl - << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArg - << "s) EXPIRED ***" << endl + << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArgMs + << "ms) EXPIRED ***" << endl << endl; } diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp index 39fcb80631..e182b9d287 100644 --- a/cmds/dumpsys/tests/Android.bp +++ b/cmds/dumpsys/tests/Android.bp @@ -15,6 +15,7 @@ cc_test { static_libs: [ "libdumpsys", "libgmock", + "libserviceutils", ], clang: true, diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index 16fefe64ba..bdb0a9ad8f 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -22,6 +22,7 @@ #include <gtest/gtest.h> #include <android-base/file.h> +#include <serviceutils/PriorityDumper.h> #include <utils/String16.h> #include <utils/String8.h> #include <utils/Vector.h> @@ -50,8 +51,8 @@ class ServiceManagerMock : public IServiceManager { public: MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&)); MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&)); - MOCK_METHOD3(addService, status_t(const String16&, const sp<IBinder>&, bool)); - MOCK_METHOD0(listServices, Vector<String16>()); + MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int)); + MOCK_METHOD1(listServices, Vector<String16>(int)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); @@ -131,7 +132,16 @@ class DumpsysTest : public Test { for (auto& service : services) { services16.add(String16(service.c_str())); } - EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16)); + EXPECT_CALL(sm_, listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL)) + .WillRepeatedly(Return(services16)); + } + + void ExpectListServicesWithPriority(std::vector<std::string> services, int dumpFlags) { + Vector<String16> services16; + for (auto& service : services) { + services16.add(String16(service.c_str())); + } + EXPECT_CALL(sm_, listServices(dumpFlags)).WillRepeatedly(Return(services16)); } sp<BinderMock> ExpectCheckService(const char* name, bool running = true) { @@ -179,7 +189,10 @@ class DumpsysTest : public Test { } void AssertRunningServices(const std::vector<std::string>& services) { - std::string expected("Currently running services:\n"); + std::string expected; + if (services.size() > 1) { + expected.append("Currently running services:\n"); + } for (const std::string& service : services) { expected.append(" ").append(service).append("\n"); } @@ -198,6 +211,13 @@ class DumpsysTest : public Test { EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump)); } + void AssertDumpedWithPriority(const std::string& service, const std::string& dump, + const char16_t* priorityType) { + std::string priority = String8(priorityType).c_str(); + EXPECT_THAT(stdout_, + HasSubstr("DUMP OF SERVICE " + priority + " " + service + ":\n" + dump)); + } + void AssertNotDumped(const std::string& dump) { EXPECT_THAT(stdout_, Not(HasSubstr(dump))); } @@ -236,6 +256,39 @@ TEST_F(DumpsysTest, ListRunningServices) { AssertNotDumped({"Valet"}); } +// Tests 'dumpsys -l --priority HIGH' +TEST_F(DumpsysTest, ListAllServicesWithPriority) { + ExpectListServicesWithPriority({"Locksmith", "Valet"}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH); + ExpectCheckService("Locksmith"); + ExpectCheckService("Valet"); + + CallMain({"-l", "--priority", "HIGH"}); + + AssertRunningServices({"Locksmith", "Valet"}); +} + +// Tests 'dumpsys -l --priority HIGH' with and empty list +TEST_F(DumpsysTest, ListEmptyServicesWithPriority) { + ExpectListServicesWithPriority({}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH); + + CallMain({"-l", "--priority", "HIGH"}); + + AssertRunningServices({}); +} + +// Tests 'dumpsys -l --proto' +TEST_F(DumpsysTest, ListAllServicesWithProto) { + ExpectListServicesWithPriority({"Locksmith", "Valet", "Car"}, + IServiceManager::DUMP_FLAG_PRIORITY_ALL); + ExpectListServicesWithPriority({"Valet", "Car"}, IServiceManager::DUMP_FLAG_PROTO); + ExpectCheckService("Car"); + ExpectCheckService("Valet"); + + CallMain({"-l", "--proto"}); + + AssertRunningServices({"Car", "Valet"}); +} + // Tests 'dumpsys service_name' on a service is running TEST_F(DumpsysTest, DumpRunningService) { ExpectDump("Valet", "Here's your car"); @@ -246,12 +299,25 @@ TEST_F(DumpsysTest, DumpRunningService) { } // Tests 'dumpsys -t 1 service_name' on a service that times out after 2s -TEST_F(DumpsysTest, DumpRunningServiceTimeout) { +TEST_F(DumpsysTest, DumpRunningServiceTimeoutInSec) { sp<BinderMock> binder_mock = ExpectDumpAndHang("Valet", 2, "Here's your car"); CallMain({"-t", "1", "Valet"}); - AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1s) EXPIRED"); + AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1000ms) EXPIRED"); + AssertNotDumped("Here's your car"); + + // TODO(b/65056227): BinderMock is not destructed because thread is detached on dumpsys.cpp + Mock::AllowLeak(binder_mock.get()); +} + +// Tests 'dumpsys -T 500 service_name' on a service that times out after 2s +TEST_F(DumpsysTest, DumpRunningServiceTimeoutInMs) { + sp<BinderMock> binder_mock = ExpectDumpAndHang("Valet", 2, "Here's your car"); + + CallMain({"-T", "500", "Valet"}); + + AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (500ms) EXPIRED"); AssertNotDumped("Here's your car"); // TODO(b/65056227): BinderMock is not destructed because thread is detached on dumpsys.cpp @@ -300,3 +366,98 @@ TEST_F(DumpsysTest, DumpWithSkip) { AssertNotDumped("dump3"); AssertNotDumped("dump5"); } + +// Tests 'dumpsys --skip skipped3 skipped5 --priority CRITICAL', which should skip these services +TEST_F(DumpsysTest, DumpWithSkipAndPriority) { + ExpectListServicesWithPriority({"running1", "stopped2", "skipped3", "running4", "skipped5"}, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL); + ExpectDump("running1", "dump1"); + ExpectCheckService("stopped2", false); + ExpectDump("skipped3", "dump3"); + ExpectDump("running4", "dump4"); + ExpectDump("skipped5", "dump5"); + + CallMain({"--priority", "CRITICAL", "--skip", "skipped3", "skipped5"}); + + AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"}); + AssertDumpedWithPriority("running1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL); + AssertDumpedWithPriority("running4", "dump4", PriorityDumper::PRIORITY_ARG_CRITICAL); + AssertStopped("stopped2"); + AssertNotDumped("dump3"); + AssertNotDumped("dump5"); +} + +// Tests 'dumpsys --priority CRITICAL' +TEST_F(DumpsysTest, DumpWithPriorityCritical) { + ExpectListServicesWithPriority({"runningcritical1", "runningcritical2"}, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL); + ExpectDump("runningcritical1", "dump1"); + ExpectDump("runningcritical2", "dump2"); + + CallMain({"--priority", "CRITICAL"}); + + AssertRunningServices({"runningcritical1", "runningcritical2"}); + AssertDumpedWithPriority("runningcritical1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL); + AssertDumpedWithPriority("runningcritical2", "dump2", PriorityDumper::PRIORITY_ARG_CRITICAL); +} + +// Tests 'dumpsys --priority HIGH' +TEST_F(DumpsysTest, DumpWithPriorityHigh) { + ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"}, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH); + ExpectDump("runninghigh1", "dump1"); + ExpectDump("runninghigh2", "dump2"); + + CallMain({"--priority", "HIGH"}); + + AssertRunningServices({"runninghigh1", "runninghigh2"}); + AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH); + AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH); +} + +// Tests 'dumpsys --priority NORMAL' +TEST_F(DumpsysTest, DumpWithPriorityNormal) { + ExpectListServicesWithPriority({"runningnormal1", "runningnormal2"}, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL); + ExpectDump("runningnormal1", "dump1"); + ExpectDump("runningnormal2", "dump2"); + + CallMain({"--priority", "NORMAL"}); + + AssertRunningServices({"runningnormal1", "runningnormal2"}); + AssertDumpedWithPriority("runningnormal1", "dump1", PriorityDumper::PRIORITY_ARG_NORMAL); + AssertDumpedWithPriority("runningnormal2", "dump2", PriorityDumper::PRIORITY_ARG_NORMAL); +} + +// Tests 'dumpsys --proto' +TEST_F(DumpsysTest, DumpWithProto) { + ExpectListServicesWithPriority({"run8", "run1", "run2", "run5"}, + IServiceManager::DUMP_FLAG_PRIORITY_ALL); + ExpectListServicesWithPriority({"run3", "run2", "run4", "run8"}, + IServiceManager::DUMP_FLAG_PROTO); + ExpectDump("run2", "dump1"); + ExpectDump("run8", "dump2"); + + CallMain({"--proto"}); + + AssertRunningServices({"run2", "run8"}); + AssertDumped("run2", "dump1"); + AssertDumped("run8", "dump2"); +} + +// Tests 'dumpsys --priority HIGH --proto' +TEST_F(DumpsysTest, DumpWithPriorityHighAndProto) { + ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"}, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH); + ExpectListServicesWithPriority({"runninghigh1", "runninghigh2", "runninghigh3"}, + IServiceManager::DUMP_FLAG_PROTO); + + ExpectDump("runninghigh1", "dump1"); + ExpectDump("runninghigh2", "dump2"); + + CallMain({"--priority", "HIGH", "--proto"}); + + AssertRunningServices({"runninghigh1", "runninghigh2"}); + AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH); + AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH); +} diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp index dfc3e581fd..d5b3372f96 100644 --- a/cmds/flatland/GLHelper.cpp +++ b/cmds/flatland/GLHelper.cpp @@ -269,24 +269,10 @@ bool GLHelper::createWindowSurface(uint32_t w, uint32_t h, return false; } - SurfaceComposerClient::openGlobalTransaction(); - err = sc->setLayer(0x7FFFFFFF); - if (err != NO_ERROR) { - fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err); - return false; - } - err = sc->setMatrix(scale, 0.0f, 0.0f, scale); - if (err != NO_ERROR) { - fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err); - return false; - } - - err = sc->show(); - if (err != NO_ERROR) { - fprintf(stderr, "SurfaceComposer::show error: %#x\n", err); - return false; - } - SurfaceComposerClient::closeGlobalTransaction(); + SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF) + .setMatrix(sc, scale, 0.0f, 0.0f, scale) + .show(sc) + .apply(); sp<ANativeWindow> anw = sc->getSurface(); EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp index 7d1537a63f..90c7da47b1 100644 --- a/cmds/installd/Android.bp +++ b/cmds/installd/Android.bp @@ -18,6 +18,7 @@ cc_defaults { shared_libs: [ "libbase", "libbinder", + "libcrypto", "libcutils", "liblog", "liblogwrap", diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk index 1d21b3ce1b..b3dc5ec997 100644 --- a/cmds/installd/Android.mk +++ b/cmds/installd/Android.mk @@ -27,6 +27,7 @@ LOCAL_SRC_FILES := otapreopt.cpp globals.cpp utils.cpp dexopt.cpp LOCAL_HEADER_LIBRARIES := dex2oat_headers LOCAL_SHARED_LIBRARIES := \ libbase \ + libcrypto \ libcutils \ liblog \ liblogwrap \ diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 6877fb73fd..715bf8cdd2 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -2365,6 +2365,22 @@ binder::Status InstalldNativeService::reconcileSecondaryDexFile( return result ? ok() : error(); } +binder::Status InstalldNativeService::hashSecondaryDexFile( + const std::string& dexPath, const std::string& packageName, int32_t uid, + const std::unique_ptr<std::string>& volumeUuid, int32_t storageFlag, + std::vector<uint8_t>* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_UUID(volumeUuid); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); + + // mLock is not taken here since we will never modify the file system. + // If a file is modified just as we are reading it this may result in an + // anomalous hash, but that's ok. + bool result = android::installd::hash_secondary_dex_file( + dexPath, packageName, uid, volumeUuid, storageFlag, _aidl_return); + return result ? ok() : error(); +} + binder::Status InstalldNativeService::invalidateMounts() { ENFORCE_UID(AID_SYSTEM); std::lock_guard<std::recursive_mutex> lock(mMountsLock); diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 2d22934afe..57dd834a01 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -120,6 +120,9 @@ public: binder::Status reconcileSecondaryDexFile(const std::string& dexPath, const std::string& packageName, int32_t uid, const std::vector<std::string>& isa, const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return); + binder::Status hashSecondaryDexFile(const std::string& dexPath, + const std::string& packageName, int32_t uid, const std::unique_ptr<std::string>& volumeUuid, + int32_t storageFlag, std::vector<uint8_t>* _aidl_return); binder::Status invalidateMounts(); binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid, diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index dbd89f5e21..394c028a19 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -86,6 +86,9 @@ interface IInstalld { int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid, int storage_flag); + byte[] hashSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName, + int uid, @nullable @utf8InCpp String volumeUuid, int storageFlag); + void invalidateMounts(); boolean isQuotaSupported(@nullable @utf8InCpp String uuid); } diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 29d5c32f16..ee3e1dc2a6 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "installed" +#include <array> #include <fcntl.h> #include <stdlib.h> #include <string.h> @@ -27,6 +28,7 @@ #include <sys/wait.h> #include <unistd.h> +#include <android-base/file.h> #include <android-base/logging.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> @@ -36,6 +38,7 @@ #include <cutils/properties.h> #include <cutils/sched_policy.h> #include <log/log.h> // TODO: Move everything to base/logging. +#include <openssl/sha.h> #include <private/android_filesystem_config.h> #include <selinux/android.h> #include <system/thread_defs.h> @@ -46,8 +49,10 @@ #include "otapreopt_utils.h" #include "utils.h" -using android::base::StringPrintf; using android::base::EndsWith; +using android::base::ReadFully; +using android::base::StringPrintf; +using android::base::WriteFully; using android::base::unique_fd; namespace android { @@ -2055,6 +2060,90 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, } } +// Compute and return the hash (SHA-256) of the secondary dex file at dex_path. +// Returns true if all parameters are valid and the hash successfully computed and stored in +// out_secondary_dex_hash. +// Also returns true with an empty hash if the file does not currently exist or is not accessible to +// the app. +// For any other errors (e.g. if any of the parameters are invalid) returns false. +bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid, + const std::unique_ptr<std::string>& volume_uuid, int storage_flag, + std::vector<uint8_t>* out_secondary_dex_hash) { + out_secondary_dex_hash->clear(); + + const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str(); + + if (storage_flag != FLAG_STORAGE_CE && storage_flag != FLAG_STORAGE_DE) { + LOG(ERROR) << "hash_secondary_dex_file called with invalid storage_flag: " + << storage_flag; + return false; + } + + // Pipe to get the hash result back from our child process. + unique_fd pipe_read, pipe_write; + if (!Pipe(&pipe_read, &pipe_write)) { + PLOG(ERROR) << "Failed to create pipe"; + return false; + } + + // Fork so that actual access to the files is done in the app's own UID, to ensure we only + // access data the app itself can access. + pid_t pid = fork(); + if (pid == 0) { + // child -- drop privileges before continuing + drop_capabilities(uid); + pipe_read.reset(); + + if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) { + LOG(ERROR) << "Could not validate secondary dex path " << dex_path; + _exit(1); + } + + unique_fd fd(TEMP_FAILURE_RETRY(open(dex_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW))); + if (fd == -1) { + if (errno == EACCES || errno == ENOENT) { + // Not treated as an error. + _exit(0); + } + PLOG(ERROR) << "Failed to open secondary dex " << dex_path; + _exit(1); + } + + SHA256_CTX ctx; + SHA256_Init(&ctx); + + std::vector<uint8_t> buffer(65536); + while (true) { + ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size())); + if (bytes_read == 0) { + break; + } else if (bytes_read == -1) { + PLOG(ERROR) << "Failed to read secondary dex " << dex_path; + _exit(1); + } + + SHA256_Update(&ctx, buffer.data(), bytes_read); + } + + std::array<uint8_t, SHA256_DIGEST_LENGTH> hash; + SHA256_Final(hash.data(), &ctx); + if (!WriteFully(pipe_write, hash.data(), hash.size())) { + _exit(1); + } + + _exit(0); + } + + // parent + pipe_write.reset(); + + out_secondary_dex_hash->resize(SHA256_DIGEST_LENGTH); + if (!ReadFully(pipe_read, out_secondary_dex_hash->data(), out_secondary_dex_hash->size())) { + out_secondary_dex_hash->clear(); + } + return wait_child(pid) == 0; +} + // Helper for move_ab, so that we can have common failure-case cleanup. static bool unlink_and_rename(const char* from, const char* to) { // Check whether "from" exists, and if so whether it's regular. If it is, unlink. Otherwise, diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h index 8d81611067..496f594806 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -75,6 +75,10 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, const std::unique_ptr<std::string>& volumeUuid, int storage_flag, /*out*/bool* out_secondary_dex_exists); +bool hash_secondary_dex_file(const std::string& dex_path, + const std::string& pkgname, int uid, const std::unique_ptr<std::string>& volume_uuid, + int storage_flag, std::vector<uint8_t>* out_secondary_dex_hash); + 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* compiler_filter, const char* volume_uuid, const char* class_loader_context, const char* se_info, diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 8a56894423..d938d8afad 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -889,6 +889,7 @@ private: CHECK(EndsWith(path, "/")); path = path + "oat"; if (access(path.c_str(), F_OK) == 0) { + LOG(INFO) << "Skipping A/B OTA preopt of already preopted package " << apk_path; return true; } } @@ -900,7 +901,7 @@ private: // this tool will wipe the OTA artifact cache and try again (for robustness after // a failed OTA with remaining cache artifacts). if (access(apk_path, F_OK) != 0) { - LOG(WARNING) << "Skipping preopt of non-existing package " << apk_path; + LOG(WARNING) << "Skipping A/B OTA preopt of non-existing package " << apk_path; return true; } diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp index 1a22992cb8..47346fb7e7 100644 --- a/cmds/installd/tests/Android.bp +++ b/cmds/installd/tests/Android.bp @@ -24,6 +24,7 @@ cc_test { shared_libs: [ "libbase", "libbinder", + "libcrypto", "libcutils", "libselinux", "libutils", @@ -44,6 +45,7 @@ cc_test { shared_libs: [ "libbase", "libbinder", + "libcrypto", "libcutils", "libselinux", "libutils", @@ -64,6 +66,7 @@ cc_test { shared_libs: [ "libbase", "libbinder", + "libcrypto", "libcutils", "libselinux", "libutils", diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp index ca812bdeeb..a5af5d740e 100644 --- a/cmds/installd/tests/installd_service_test.cpp +++ b/cmds/installd/tests/installd_service_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <sstream> #include <stdlib.h> #include <string.h> #include <sys/statvfs.h> @@ -56,16 +57,19 @@ bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *ins return create_cache_path_default(path, src, instruction_set); } +static std::string get_full_path(const char* path) { + return StringPrintf("/data/local/tmp/user/0/%s", path); +} + static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) { - const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str(); - ::mkdir(fullPath, mode); - ::chown(fullPath, owner, group); - ::chmod(fullPath, mode); + const std::string fullPath = get_full_path(path); + ::mkdir(fullPath.c_str(), mode); + ::chown(fullPath.c_str(), owner, group); + ::chmod(fullPath.c_str(), mode); } static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) { - int fd = ::open(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), - O_RDWR | O_CREAT, mode); + int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode); ::fchown(fd, owner, group); ::fchmod(fd, mode); ::close(fd); @@ -73,13 +77,13 @@ static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) { static int stat_gid(const char* path) { struct stat buf; - ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf); + ::stat(get_full_path(path).c_str(), &buf); return buf.st_gid; } static int stat_mode(const char* path) { struct stat buf; - ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf); + ::stat(get_full_path(path).c_str(), &buf); return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID); } @@ -149,6 +153,69 @@ TEST_F(ServiceTest, FixupAppData_Moved) { EXPECT_EQ(10000, stat_gid("com.example/bar/file")); } +TEST_F(ServiceTest, HashSecondaryDex) { + LOG(INFO) << "HashSecondaryDex"; + + mkdir("com.example", 10000, 10000, 0700); + mkdir("com.example/foo", 10000, 10000, 0700); + touch("com.example/foo/file", 10000, 20000, 0700); + + std::vector<uint8_t> result; + std::string dexPath = get_full_path("com.example/foo/file"); + EXPECT_TRUE(service->hashSecondaryDexFile( + dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk()); + + EXPECT_EQ(result.size(), 32U); + + std::ostringstream output; + output << std::hex << std::setfill('0'); + for (auto b : result) { + output << std::setw(2) << +b; + } + + // This is the SHA256 of an empty string (sha256sum /dev/null) + EXPECT_EQ(output.str(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); +} + +TEST_F(ServiceTest, HashSecondaryDex_NoSuch) { + LOG(INFO) << "HashSecondaryDex_NoSuch"; + + std::vector<uint8_t> result; + std::string dexPath = get_full_path("com.example/foo/file"); + EXPECT_TRUE(service->hashSecondaryDexFile( + dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk()); + + EXPECT_EQ(result.size(), 0U); +} + +TEST_F(ServiceTest, HashSecondaryDex_Unreadable) { + LOG(INFO) << "HashSecondaryDex_Unreadable"; + + mkdir("com.example", 10000, 10000, 0700); + mkdir("com.example/foo", 10000, 10000, 0700); + touch("com.example/foo/file", 10000, 20000, 0300); + + std::vector<uint8_t> result; + std::string dexPath = get_full_path("com.example/foo/file"); + EXPECT_TRUE(service->hashSecondaryDexFile( + dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk()); + + EXPECT_EQ(result.size(), 0U); +} + +TEST_F(ServiceTest, HashSecondaryDex_WrongApp) { + LOG(INFO) << "HashSecondaryDex_WrongApp"; + + mkdir("com.example", 10000, 10000, 0700); + mkdir("com.example/foo", 10000, 10000, 0700); + touch("com.example/foo/file", 10000, 20000, 0700); + + std::vector<uint8_t> result; + std::string dexPath = get_full_path("com.example/foo/file"); + EXPECT_FALSE(service->hashSecondaryDexFile( + dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk()); +} + TEST_F(ServiceTest, CalculateOat) { char buf[PKG_PATH_MAX]; diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index 31cd0cb5ac..6b340a8d3a 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -138,6 +138,7 @@ struct svcinfo uint32_t handle; struct binder_death death; int allow_isolated; + uint32_t dumpsys_priority; size_t len; uint16_t name[0]; }; @@ -198,11 +199,8 @@ uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid) return si->handle; } -int do_add_service(struct binder_state *bs, - const uint16_t *s, size_t len, - uint32_t handle, uid_t uid, int allow_isolated, - pid_t spid) -{ +int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, + uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) { struct svcinfo *si; //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, @@ -239,6 +237,7 @@ int do_add_service(struct binder_state *bs, si->death.func = (void*) svcinfo_death; si->death.ptr = si; si->allow_isolated = allow_isolated; + si->dumpsys_priority = dumpsys_priority; si->next = svclist; svclist = si; } @@ -259,6 +258,7 @@ int svcmgr_handler(struct binder_state *bs, uint32_t handle; uint32_t strict_policy; int allow_isolated; + uint32_t dumpsys_priority; //ALOGI("target=%p code=%d pid=%d uid=%d\n", // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); @@ -317,13 +317,15 @@ int svcmgr_handler(struct binder_state *bs, } handle = bio_get_ref(msg); allow_isolated = bio_get_uint32(msg) ? 1 : 0; - if (do_add_service(bs, s, len, handle, txn->sender_euid, - allow_isolated, txn->sender_pid)) + dumpsys_priority = bio_get_uint32(msg); + if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, + txn->sender_pid)) return -1; break; case SVC_MGR_LIST_SERVICES: { uint32_t n = bio_get_uint32(msg); + uint32_t req_dumpsys_priority = bio_get_uint32(msg); if (!svc_can_list(txn->sender_pid, txn->sender_euid)) { ALOGE("list_service() uid=%d - PERMISSION DENIED\n", @@ -331,8 +333,15 @@ int svcmgr_handler(struct binder_state *bs, return -1; } si = svclist; - while ((n-- > 0) && si) + // walk through the list of services n times skipping services that + // do not support the requested priority + while (si) { + if (si->dumpsys_priority & req_dumpsys_priority) { + if (n == 0) break; + n--; + } si = si->next; + } if (si) { bio_put_string16(reply, si->name); return 0; diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 2b5389b8dc..4140f40888 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -24,9 +24,9 @@ #include <gui/BufferQueue.h> #include <gui/ISurfaceComposer.h> +#include <gui/LayerState.h> #include <gui/Surface.h> #include <private/gui/ComposerService.h> -#include <private/gui/LayerState.h> #include <ui/DisplayInfo.h> #include <utils/Log.h> @@ -338,27 +338,29 @@ status_t Replayer::dispatchEvent(int index) { status_t Replayer::doTransaction(const Transaction& t, const std::shared_ptr<Event>& event) { ALOGV("Started Transaction"); - SurfaceComposerClient::openGlobalTransaction(); + SurfaceComposerClient::Transaction liveTransaction; status_t status = NO_ERROR; - status = doSurfaceTransaction(t.surface_change()); - doDisplayTransaction(t.display_change()); + status = doSurfaceTransaction(liveTransaction, t.surface_change()); + doDisplayTransaction(liveTransaction, t.display_change()); if (t.animation()) { - SurfaceComposerClient::setAnimationTransaction(); + liveTransaction.setAnimationTransaction(); } event->readyToExecute(); - SurfaceComposerClient::closeGlobalTransaction(t.synchronous()); + liveTransaction.apply(t.synchronous()); ALOGV("Ended Transaction"); return status; } -status_t Replayer::doSurfaceTransaction(const SurfaceChanges& surfaceChanges) { +status_t Replayer::doSurfaceTransaction( + SurfaceComposerClient::Transaction& transaction, + const SurfaceChanges& surfaceChanges) { status_t status = NO_ERROR; for (const SurfaceChange& change : surfaceChanges) { @@ -369,62 +371,66 @@ status_t Replayer::doSurfaceTransaction(const SurfaceChanges& surfaceChanges) { switch (change.SurfaceChange_case()) { case SurfaceChange::SurfaceChangeCase::kPosition: - status = setPosition(change.id(), change.position()); + setPosition(transaction, change.id(), change.position()); break; case SurfaceChange::SurfaceChangeCase::kSize: - status = setSize(change.id(), change.size()); + setSize(transaction, change.id(), change.size()); break; case SurfaceChange::SurfaceChangeCase::kAlpha: - status = setAlpha(change.id(), change.alpha()); + setAlpha(transaction, change.id(), change.alpha()); break; case SurfaceChange::SurfaceChangeCase::kLayer: - status = setLayer(change.id(), change.layer()); + setLayer(transaction, change.id(), change.layer()); break; case SurfaceChange::SurfaceChangeCase::kCrop: - status = setCrop(change.id(), change.crop()); + setCrop(transaction, change.id(), change.crop()); break; case SurfaceChange::SurfaceChangeCase::kMatrix: - status = setMatrix(change.id(), change.matrix()); + setMatrix(transaction, change.id(), change.matrix()); break; case SurfaceChange::SurfaceChangeCase::kFinalCrop: - status = setFinalCrop(change.id(), change.final_crop()); + setFinalCrop(transaction, change.id(), change.final_crop()); break; case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode: - status = setOverrideScalingMode(change.id(), change.override_scaling_mode()); + setOverrideScalingMode(transaction, change.id(), + change.override_scaling_mode()); break; case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint: - status = setTransparentRegionHint(change.id(), change.transparent_region_hint()); + setTransparentRegionHint(transaction, change.id(), + change.transparent_region_hint()); break; case SurfaceChange::SurfaceChangeCase::kLayerStack: - status = setLayerStack(change.id(), change.layer_stack()); + setLayerStack(transaction, change.id(), change.layer_stack()); break; case SurfaceChange::SurfaceChangeCase::kHiddenFlag: - status = setHiddenFlag(change.id(), change.hidden_flag()); + setHiddenFlag(transaction, change.id(), change.hidden_flag()); break; case SurfaceChange::SurfaceChangeCase::kOpaqueFlag: - status = setOpaqueFlag(change.id(), change.opaque_flag()); + setOpaqueFlag(transaction, change.id(), change.opaque_flag()); break; case SurfaceChange::SurfaceChangeCase::kSecureFlag: - status = setSecureFlag(change.id(), change.secure_flag()); + setSecureFlag(transaction, change.id(), change.secure_flag()); break; case SurfaceChange::SurfaceChangeCase::kDeferredTransaction: waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock); - status = setDeferredTransaction(change.id(), change.deferred_transaction()); + setDeferredTransaction(transaction, change.id(), + change.deferred_transaction()); break; default: - status = NO_ERROR; + status = 1; break; } if (status != NO_ERROR) { - ALOGE("SET TRANSACTION FAILED"); + ALOGE("Unknown Transaction Code"); return status; } } return status; } -void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) { +void Replayer::doDisplayTransaction(SurfaceComposerClient::Transaction& t, + const DisplayChanges& displayChanges) { for (const DisplayChange& change : displayChanges) { ALOGV("Doing display transaction"); std::unique_lock<std::mutex> lock(mDisplayLock); @@ -434,16 +440,16 @@ void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) { switch (change.DisplayChange_case()) { case DisplayChange::DisplayChangeCase::kSurface: - setDisplaySurface(change.id(), change.surface()); + setDisplaySurface(t, change.id(), change.surface()); break; case DisplayChange::DisplayChangeCase::kLayerStack: - setDisplayLayerStack(change.id(), change.layer_stack()); + setDisplayLayerStack(t, change.id(), change.layer_stack()); break; case DisplayChange::DisplayChangeCase::kSize: - setDisplaySize(change.id(), change.size()); + setDisplaySize(t, change.id(), change.size()); break; case DisplayChange::DisplayChangeCase::kProjection: - setDisplayProjection(change.id(), change.projection()); + setDisplayProjection(t, change.id(), change.projection()); break; default: break; @@ -451,57 +457,66 @@ void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) { } } -status_t Replayer::setPosition(layer_id id, const PositionChange& pc) { +void Replayer::setPosition(SurfaceComposerClient::Transaction& t, + layer_id id, const PositionChange& pc) { ALOGV("Layer %d: Setting Position -- x=%f, y=%f", id, pc.x(), pc.y()); - return mLayers[id]->setPosition(pc.x(), pc.y()); + t.setPosition(mLayers[id], pc.x(), pc.y()); } -status_t Replayer::setSize(layer_id id, const SizeChange& sc) { +void Replayer::setSize(SurfaceComposerClient::Transaction& t, + layer_id id, const SizeChange& sc) { ALOGV("Layer %d: Setting Size -- w=%u, h=%u", id, sc.w(), sc.h()); - return mLayers[id]->setSize(sc.w(), sc.h()); + t.setSize(mLayers[id], sc.w(), sc.h()); } -status_t Replayer::setLayer(layer_id id, const LayerChange& lc) { +void Replayer::setLayer(SurfaceComposerClient::Transaction& t, + layer_id id, const LayerChange& lc) { ALOGV("Layer %d: Setting Layer -- layer=%d", id, lc.layer()); - return mLayers[id]->setLayer(lc.layer()); + t.setLayer(mLayers[id], lc.layer()); } -status_t Replayer::setAlpha(layer_id id, const AlphaChange& ac) { +void Replayer::setAlpha(SurfaceComposerClient::Transaction& t, + layer_id id, const AlphaChange& ac) { ALOGV("Layer %d: Setting Alpha -- alpha=%f", id, ac.alpha()); - return mLayers[id]->setAlpha(ac.alpha()); + t.setAlpha(mLayers[id], ac.alpha()); } -status_t Replayer::setCrop(layer_id id, const CropChange& cc) { +void Replayer::setCrop(SurfaceComposerClient::Transaction& t, + layer_id id, const CropChange& cc) { ALOGV("Layer %d: Setting Crop -- left=%d, top=%d, right=%d, bottom=%d", id, cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(), cc.rectangle().bottom()); Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(), cc.rectangle().bottom()); - return mLayers[id]->setCrop(r); + t.setCrop(mLayers[id], r); } -status_t Replayer::setFinalCrop(layer_id id, const FinalCropChange& fcc) { +void Replayer::setFinalCrop(SurfaceComposerClient::Transaction& t, + layer_id id, const FinalCropChange& fcc) { ALOGV("Layer %d: Setting Final Crop -- left=%d, top=%d, right=%d, bottom=%d", id, fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(), fcc.rectangle().bottom()); Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(), fcc.rectangle().bottom()); - return mLayers[id]->setFinalCrop(r); + t.setFinalCrop(mLayers[id], r); } -status_t Replayer::setMatrix(layer_id id, const MatrixChange& mc) { +void Replayer::setMatrix(SurfaceComposerClient::Transaction& t, + layer_id id, const MatrixChange& mc) { ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy()); - return mLayers[id]->setMatrix(mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy()); + t.setMatrix(mLayers[id], mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy()); } -status_t Replayer::setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc) { +void Replayer::setOverrideScalingMode(SurfaceComposerClient::Transaction& t, + layer_id id, const OverrideScalingModeChange& osmc) { ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode()); - return mLayers[id]->setOverrideScalingMode(osmc.override_scaling_mode()); + t.setOverrideScalingMode(mLayers[id], osmc.override_scaling_mode()); } -status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trhc) { +void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t, + layer_id id, const TransparentRegionHintChange& trhc) { ALOGV("Setting Transparent Region Hint"); Region re = Region(); @@ -510,71 +525,80 @@ status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegion re.merge(rect); } - return mLayers[id]->setTransparentRegionHint(re); + t.setTransparentRegionHint(mLayers[id], re); } -status_t Replayer::setLayerStack(layer_id id, const LayerStackChange& lsc) { +void Replayer::setLayerStack(SurfaceComposerClient::Transaction& t, + layer_id id, const LayerStackChange& lsc) { ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack()); - return mLayers[id]->setLayerStack(lsc.layer_stack()); + t.setLayerStack(mLayers[id], lsc.layer_stack()); } -status_t Replayer::setHiddenFlag(layer_id id, const HiddenFlagChange& hfc) { +void Replayer::setHiddenFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const HiddenFlagChange& hfc) { ALOGV("Layer %d: Setting Hidden Flag -- hidden_flag=%d", id, hfc.hidden_flag()); layer_id flag = hfc.hidden_flag() ? layer_state_t::eLayerHidden : 0; - return mLayers[id]->setFlags(flag, layer_state_t::eLayerHidden); + t.setFlags(mLayers[id], flag, layer_state_t::eLayerHidden); } -status_t Replayer::setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc) { +void Replayer::setOpaqueFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const OpaqueFlagChange& ofc) { ALOGV("Layer %d: Setting Opaque Flag -- opaque_flag=%d", id, ofc.opaque_flag()); layer_id flag = ofc.opaque_flag() ? layer_state_t::eLayerOpaque : 0; - return mLayers[id]->setFlags(flag, layer_state_t::eLayerOpaque); + t.setFlags(mLayers[id], flag, layer_state_t::eLayerOpaque); } -status_t Replayer::setSecureFlag(layer_id id, const SecureFlagChange& sfc) { +void Replayer::setSecureFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const SecureFlagChange& sfc) { ALOGV("Layer %d: Setting Secure Flag -- secure_flag=%d", id, sfc.secure_flag()); layer_id flag = sfc.secure_flag() ? layer_state_t::eLayerSecure : 0; - return mLayers[id]->setFlags(flag, layer_state_t::eLayerSecure); + t.setFlags(mLayers[id], flag, layer_state_t::eLayerSecure); } -status_t Replayer::setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc) { +void Replayer::setDeferredTransaction(SurfaceComposerClient::Transaction& t, + layer_id id, const DeferredTransactionChange& dtc) { ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, " "frame_number=%llu", id, dtc.layer_id(), dtc.frame_number()); if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) { ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id()); - return BAD_VALUE; + return; } auto handle = mLayers[dtc.layer_id()]->getHandle(); - return mLayers[id]->deferTransactionUntil(handle, dtc.frame_number()); + t.deferTransactionUntil(mLayers[id], handle, dtc.frame_number()); } -void Replayer::setDisplaySurface(display_id id, const DispSurfaceChange& /*dsc*/) { +void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t, + display_id id, const DispSurfaceChange& /*dsc*/) { sp<IGraphicBufferProducer> outProducer; sp<IGraphicBufferConsumer> outConsumer; BufferQueue::createBufferQueue(&outProducer, &outConsumer); - SurfaceComposerClient::setDisplaySurface(mDisplays[id], outProducer); + t.setDisplaySurface(mDisplays[id], outProducer); } -void Replayer::setDisplayLayerStack(display_id id, const LayerStackChange& lsc) { - SurfaceComposerClient::setDisplayLayerStack(mDisplays[id], lsc.layer_stack()); +void Replayer::setDisplayLayerStack(SurfaceComposerClient::Transaction& t, + display_id id, const LayerStackChange& lsc) { + t.setDisplayLayerStack(mDisplays[id], lsc.layer_stack()); } -void Replayer::setDisplaySize(display_id id, const SizeChange& sc) { - SurfaceComposerClient::setDisplaySize(mDisplays[id], sc.w(), sc.h()); +void Replayer::setDisplaySize(SurfaceComposerClient::Transaction& t, + display_id id, const SizeChange& sc) { + t.setDisplaySize(mDisplays[id], sc.w(), sc.h()); } -void Replayer::setDisplayProjection(display_id id, const ProjectionChange& pc) { +void Replayer::setDisplayProjection(SurfaceComposerClient::Transaction& t, + display_id id, const ProjectionChange& pc) { Rect viewport = Rect(pc.viewport().left(), pc.viewport().top(), pc.viewport().right(), pc.viewport().bottom()); Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom()); - SurfaceComposerClient::setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame); + t.setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame); } status_t Replayer::createSurfaceControl( diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h index f36c9fd4a4..295403eace 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -77,28 +77,48 @@ class Replayer { void deleteDisplay(const DisplayDeletion& delete_, const std::shared_ptr<Event>& event); void updatePowerMode(const PowerModeUpdate& update, const std::shared_ptr<Event>& event); - status_t doSurfaceTransaction(const SurfaceChanges& surfaceChange); - void doDisplayTransaction(const DisplayChanges& displayChange); - - status_t setPosition(layer_id id, const PositionChange& pc); - status_t setSize(layer_id id, const SizeChange& sc); - status_t setAlpha(layer_id id, const AlphaChange& ac); - status_t setLayer(layer_id id, const LayerChange& lc); - status_t setCrop(layer_id id, const CropChange& cc); - status_t setFinalCrop(layer_id id, const FinalCropChange& fcc); - status_t setMatrix(layer_id id, const MatrixChange& mc); - status_t setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc); - status_t setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trgc); - status_t setLayerStack(layer_id id, const LayerStackChange& lsc); - status_t setHiddenFlag(layer_id id, const HiddenFlagChange& hfc); - status_t setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc); - status_t setSecureFlag(layer_id id, const SecureFlagChange& sfc); - status_t setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc); - - void setDisplaySurface(display_id id, const DispSurfaceChange& dsc); - void setDisplayLayerStack(display_id id, const LayerStackChange& lsc); - void setDisplaySize(display_id id, const SizeChange& sc); - void setDisplayProjection(display_id id, const ProjectionChange& pc); + status_t doSurfaceTransaction(SurfaceComposerClient::Transaction& transaction, + const SurfaceChanges& surfaceChange); + void doDisplayTransaction(SurfaceComposerClient::Transaction& transaction, + const DisplayChanges& displayChange); + + void setPosition(SurfaceComposerClient::Transaction& t, + layer_id id, const PositionChange& pc); + void setSize(SurfaceComposerClient::Transaction& t, + layer_id id, const SizeChange& sc); + void setAlpha(SurfaceComposerClient::Transaction& t, + layer_id id, const AlphaChange& ac); + void setLayer(SurfaceComposerClient::Transaction& t, + layer_id id, const LayerChange& lc); + void setCrop(SurfaceComposerClient::Transaction& t, + layer_id id, const CropChange& cc); + void setFinalCrop(SurfaceComposerClient::Transaction& t, + layer_id id, const FinalCropChange& fcc); + void setMatrix(SurfaceComposerClient::Transaction& t, + layer_id id, const MatrixChange& mc); + void setOverrideScalingMode(SurfaceComposerClient::Transaction& t, + layer_id id, const OverrideScalingModeChange& osmc); + void setTransparentRegionHint(SurfaceComposerClient::Transaction& t, + layer_id id, const TransparentRegionHintChange& trgc); + void setLayerStack(SurfaceComposerClient::Transaction& t, + layer_id id, const LayerStackChange& lsc); + void setHiddenFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const HiddenFlagChange& hfc); + void setOpaqueFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const OpaqueFlagChange& ofc); + void setSecureFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const SecureFlagChange& sfc); + void setDeferredTransaction(SurfaceComposerClient::Transaction& t, + layer_id id, const DeferredTransactionChange& dtc); + + void setDisplaySurface(SurfaceComposerClient::Transaction& t, + display_id id, const DispSurfaceChange& dsc); + void setDisplayLayerStack(SurfaceComposerClient::Transaction& t, + display_id id, const LayerStackChange& lsc); + void setDisplaySize(SurfaceComposerClient::Transaction& t, + display_id id, const SizeChange& sc); + void setDisplayProjection(SurfaceComposerClient::Transaction& t, + display_id id, const ProjectionChange& pc); void doDeleteSurfaceControls(); void waitUntilTimestamp(int64_t timestamp); diff --git a/data/etc/android.hardware.wifi.rtt.xml b/data/etc/android.hardware.wifi.rtt.xml new file mode 100644 index 0000000000..60529ea1ae --- /dev/null +++ b/data/etc/android.hardware.wifi.rtt.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature indicating that the device supports WiFi RTT (IEEE 802.11mc). --> +<permissions> + <feature name="android.hardware.wifi.rtt" /> +</permissions> diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml index ec7be53bfc..b6abc1bd83 100644 --- a/data/etc/handheld_core_hardware.xml +++ b/data/etc/handheld_core_hardware.xml @@ -55,7 +55,7 @@ <feature name="android.software.device_admin" /> <!-- Feature to specify if the device support managed users. --> - <feature name="android.software.managed_users" /> + <feature name="android.software.managed_users" notLowRam="true"/> <!-- Feature to specify if the device supports a VR mode. feature name="android.software.vr.mode" --> diff --git a/docs/Doxyfile b/docs/Doxyfile index bb0ca3251f..0ec45514f7 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -677,7 +677,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../include/android ../../av/include/ndk ../../av/include/camera/ndk +INPUT = ../include/android ../../av/media/ndk/include ../../av/camera/ndk/include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is diff --git a/include/android/sensor.h b/include/android/sensor.h index a88733cac7..2db0ee7fd9 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -197,7 +197,7 @@ enum { * A sensor event. */ -/* NOTE: Must match hardware/sensors.h */ +/* NOTE: changes to these structs have to be backward compatible */ typedef struct ASensorVector { union { float v[3]; @@ -259,7 +259,7 @@ typedef struct { }; } AAdditionalInfoEvent; -/* NOTE: Must match hardware/sensors.h */ +/* NOTE: changes to this struct has to be backward compatible */ typedef struct ASensorEvent { int32_t version; /* sizeof(struct ASensorEvent) */ int32_t sensor; diff --git a/include/audiomanager/IPlayer.h b/include/audiomanager/IPlayer.h deleted file mode 100644 index de5c1c7b64..0000000000 --- a/include/audiomanager/IPlayer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_IPLAYER_H -#define ANDROID_IPLAYER_H - -#include <stdint.h> -#include <sys/types.h> - -#include <media/VolumeShaper.h> -#include <utils/RefBase.h> -#include <utils/Errors.h> -#include <binder/IInterface.h> - -namespace android { - -// ---------------------------------------------------------------------------- - -class IPlayer : public IInterface -{ -public: - DECLARE_META_INTERFACE(Player); - - virtual void start() = 0; - - virtual void pause() = 0; - - virtual void stop() = 0; - - virtual void setVolume(float vol) = 0; - - virtual void setPan(float pan) = 0; - - virtual void setStartDelayMs(int delayMs) = 0; - - virtual void applyVolumeShaper( - const sp<VolumeShaper::Configuration>& configuration, - const sp<VolumeShaper::Operation>& operation) = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnPlayer : public BnInterface<IPlayer> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IPLAYER_H diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 944947420e..6187528cff 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -31,7 +31,6 @@ #include <utils/Errors.h> #include <utils/Timers.h> #include <utils/RefBase.h> -#include <utils/String8.h> #include <utils/Vector.h> #include <utils/BitSet.h> @@ -142,16 +141,16 @@ protected: virtual ~InputChannel(); public: - InputChannel(const String8& name, int fd); + InputChannel(const std::string& name, int fd); /* Creates a pair of input channels. * * Returns OK on success. */ - static status_t openInputChannelPair(const String8& name, + static status_t openInputChannelPair(const std::string& name, sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel); - inline String8 getName() const { return mName; } + inline std::string getName() const { return mName; } inline int getFd() const { return mFd; } /* Sends a message to the other endpoint. @@ -183,7 +182,7 @@ public: sp<InputChannel> dup() const; private: - String8 mName; + std::string mName; int mFd; }; @@ -455,7 +454,6 @@ private: int32_t* displayId); void updateTouchState(InputMessage& msg); - bool rewriteMessage(const TouchState& state, InputMessage& msg); void resampleTouchState(nsecs_t frameTime, MotionEvent* event, const InputMessage *next); @@ -464,6 +462,7 @@ private: status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled); + static bool rewriteMessage(const TouchState& state, InputMessage& msg); static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg); static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg); static void addSample(MotionEvent* event, const InputMessage* msg); diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 795f575a2e..ffa1614b55 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -264,6 +264,40 @@ private: Movement mMovements[HISTORY_SIZE]; }; +class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { +public: + ImpulseVelocityTrackerStrategy(); + virtual ~ImpulseVelocityTrackerStrategy(); + + virtual void clear(); + virtual void clearPointers(BitSet32 idBits); + virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, + const VelocityTracker::Position* positions); + virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; + +private: + // Sample horizon. + // We don't use too much history by default since we want to react to quick + // changes in direction. + static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms + + // Number of samples to keep. + static constexpr size_t HISTORY_SIZE = 20; + + struct Movement { + nsecs_t eventTime; + BitSet32 idBits; + VelocityTracker::Position positions[MAX_POINTERS]; + + inline const VelocityTracker::Position& getPosition(uint32_t id) const { + return positions[idBits.getIndexOfBit(id)]; + } + }; + + size_t mIndex; + Movement mMovements[HISTORY_SIZE]; +}; + } // namespace android #endif // _LIBINPUT_VELOCITY_TRACKER_H diff --git a/include/layerproto b/include/layerproto new file mode 120000 index 0000000000..ef21a4eb8e --- /dev/null +++ b/include/layerproto @@ -0,0 +1 @@ +../services/surfaceflinger/layerproto/include/layerproto/
\ No newline at end of file diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp new file mode 100644 index 0000000000..290471889a --- /dev/null +++ b/libs/binder/ActivityManager.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <mutex> +#include <binder/ActivityManager.h> +#include <binder/Binder.h> +#include <binder/IServiceManager.h> + +#include <utils/SystemClock.h> + +namespace android { + +ActivityManager::ActivityManager() +{ +} + +sp<IActivityManager> ActivityManager::getService() +{ + std::lock_guard<Mutex> scoped_lock(mLock); + int64_t startTime = 0; + sp<IActivityManager> service = mService; + while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) { + sp<IBinder> binder = defaultServiceManager()->checkService(String16("activity")); + if (binder == NULL) { + // Wait for the activity service to come back... + if (startTime == 0) { + startTime = uptimeMillis(); + ALOGI("Waiting for activity service"); + } else if ((uptimeMillis() - startTime) > 10000) { + ALOGW("Waiting too long for activity service, giving up"); + service = NULL; + break; + } + sleep(1); + } else { + service = interface_cast<IActivityManager>(binder); + mService = service; + } + } + return service; +} + +int ActivityManager::openContentUri(const String16& stringUri) +{ + sp<IActivityManager> service = getService(); + return service != NULL ? service->openContentUri(stringUri) : -1; +} + +void ActivityManager::registerUidObserver(const sp<IUidObserver>& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage) +{ + sp<IActivityManager> service = getService(); + if (service != NULL) { + service->registerUidObserver(observer, event, cutpoint, callingPackage); + } +} + +void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer) +{ + sp<IActivityManager> service = getService(); + if (service != NULL) { + service->unregisterUidObserver(observer); + } +} + +}; // namespace android diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index c130087fb5..2a07cd1fdb 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -38,6 +38,7 @@ cc_library { }, srcs: [ + "ActivityManager.cpp", "AppOpsManager.cpp", "Binder.cpp", "BpBinder.cpp", @@ -56,6 +57,7 @@ cc_library { "IResultReceiver.cpp", "IServiceManager.cpp", "IShellCallback.cpp", + "IUidObserver.cpp", "MemoryBase.cpp", "MemoryDealer.cpp", "MemoryHeapBase.cpp", diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index c0e029622a..289433b0bd 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -21,6 +21,7 @@ #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> +#include <cutils/compiler.h> #include <utils/Log.h> #include <stdio.h> @@ -32,6 +33,23 @@ namespace android { // --------------------------------------------------------------------------- +Mutex BpBinder::sTrackingLock; +std::unordered_map<int32_t,uint32_t> BpBinder::sTrackingMap; +int BpBinder::sNumTrackedUids = 0; +std::atomic_bool BpBinder::sCountByUidEnabled(false); +binder_proxy_limit_callback BpBinder::sLimitCallback; +bool BpBinder::sBinderProxyThrottleCreate = false; + +// Arbitrarily high value that probably distinguishes a bad behaving app +uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500; +// Another arbitrary value a binder count needs to drop below before another callback will be called +uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000; + +enum { + CALLBACK_TRIGGERED_MASK = 0x80000000, // A flag denoting that the callback has been called + COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value +}; + BpBinder::ObjectManager::ObjectManager() { } @@ -87,11 +105,47 @@ void BpBinder::ObjectManager::kill() // --------------------------------------------------------------------------- -BpBinder::BpBinder(int32_t handle) + +BpBinder* BpBinder::create(int32_t handle) { + int32_t trackedUid = -1; + if (sCountByUidEnabled) { + BpBinder* out; + trackedUid = IPCThreadState::self()->getCallingUid(); + AutoMutex _l(sTrackingLock); + if ((sTrackingMap[trackedUid] & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) { + ALOGE("Too many binder proxy objects sent to uid %d from uid %d (over %d proxies held)", + getuid(), trackedUid, sBinderProxyCountHighWatermark); + + if (sBinderProxyThrottleCreate) { + ALOGE("Returning Null Binder Proxy Object to uid %d", trackedUid); + out = nullptr; + } else { + // increment and construct here in case callback has an async kill causing a race + sTrackingMap[trackedUid]++; + out = new BpBinder(handle, trackedUid); + } + + if (sLimitCallback && !(sTrackingMap[trackedUid] & CALLBACK_TRIGGERED_MASK)) { + sTrackingMap[trackedUid] |= CALLBACK_TRIGGERED_MASK; + sLimitCallback(trackedUid); + } + } else { + sTrackingMap[trackedUid]++; + out = new BpBinder(handle, trackedUid); + } + + return out; + } else { + return new BpBinder(handle, trackedUid); + } +} + +BpBinder::BpBinder(int32_t handle, int32_t trackedUid) : mHandle(handle) , mAlive(1) , mObitsSent(0) , mObituaries(NULL) + , mTrackedUid(trackedUid) { ALOGV("Creating BpBinder %p handle %d\n", this, mHandle); @@ -315,6 +369,24 @@ BpBinder::~BpBinder() IPCThreadState* ipc = IPCThreadState::self(); + if (mTrackedUid >= 0) { + AutoMutex _l(sTrackingLock); + if (CC_UNLIKELY(sTrackingMap[mTrackedUid] == 0)) { + ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle); + } else { + if (CC_UNLIKELY( + (sTrackingMap[mTrackedUid] & CALLBACK_TRIGGERED_MASK) && + ((sTrackingMap[mTrackedUid] & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark) + )) { + // Clear the Callback Triggered bit when crossing below the low watermark + sTrackingMap[mTrackedUid] &= ~CALLBACK_TRIGGERED_MASK; + } + if (--sTrackingMap[mTrackedUid] == 0) { + sTrackingMap.erase(mTrackedUid); + } + } + } + mLock.lock(); Vector<Obituary>* obits = mObituaries; if(obits != NULL) { @@ -360,6 +432,42 @@ bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false; } +uint32_t BpBinder::getBinderProxyCount(uint32_t uid) +{ + AutoMutex _l(sTrackingLock); + auto it = sTrackingMap.find(uid); + if (it != sTrackingMap.end()) { + return it->second & COUNTING_VALUE_MASK; + } + return 0; +} + +void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts) +{ + AutoMutex _l(sTrackingLock); + uids.setCapacity(sTrackingMap.size()); + counts.setCapacity(sTrackingMap.size()); + for (const auto& it : sTrackingMap) { + uids.push_back(it.first); + counts.push_back(it.second & COUNTING_VALUE_MASK); + } +} + +void BpBinder::enableCountByUid() { sCountByUidEnabled.store(true); } +void BpBinder::disableCountByUid() { sCountByUidEnabled.store(false); } +void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); } + +void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) { + AutoMutex _l(sTrackingLock); + sLimitCallback = cb; +} + +void BpBinder::setBinderProxyCountWatermarks(int high, int low) { + AutoMutex _l(sTrackingLock); + sBinderProxyCountHighWatermark = high; + sBinderProxyCountLowWatermark = low; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index 50a8b28aae..b7a5fd99f6 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -56,6 +56,28 @@ public: } return fd; } + + virtual void registerUidObserver(const sp<IUidObserver>& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeStrongBinder(IInterface::asBinder(observer)); + data.writeInt32(event); + data.writeInt32(cutpoint); + data.writeString16(callingPackage); + remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply); + } + + virtual void unregisterUidObserver(const sp<IUidObserver>& observer) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeStrongBinder(IInterface::asBinder(observer)); + remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply); + } }; // ------------------------------------------------------------------------------------ diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index c7a0f43a9d..70f5108722 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -161,19 +161,18 @@ public: } virtual status_t addService(const String16& name, const sp<IBinder>& service, - bool allowIsolated) - { + bool allowIsolated, int dumpsysPriority) { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1 : 0); + data.writeInt32(dumpsysPriority); status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err; } - virtual Vector<String16> listServices() - { + virtual Vector<String16> listServices(int dumpsysPriority) { Vector<String16> res; int n = 0; @@ -181,6 +180,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeInt32(n++); + data.writeInt32(dumpsysPriority); status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); if (err != NO_ERROR) break; diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp index c793df3266..23b83a6a0b 100644 --- a/libs/binder/IShellCallback.cpp +++ b/libs/binder/IShellCallback.cpp @@ -39,11 +39,13 @@ public: { } - virtual int openOutputFile(const String16& path, const String16& seLinuxContext) { + virtual int openFile(const String16& path, const String16& seLinuxContext, + const String16& mode) { Parcel data, reply; data.writeInterfaceToken(IShellCallback::getInterfaceDescriptor()); data.writeString16(path); data.writeString16(seLinuxContext); + data.writeString16(mode); remote()->transact(OP_OPEN_OUTPUT_FILE, data, &reply, 0); reply.readExceptionCode(); int fd = reply.readParcelFileDescriptor(); @@ -64,7 +66,8 @@ status_t BnShellCallback::onTransact( CHECK_INTERFACE(IShellCallback, data, reply); String16 path(data.readString16()); String16 seLinuxContext(data.readString16()); - int fd = openOutputFile(path, seLinuxContext); + String16 mode(data.readString16()); + int fd = openFile(path, seLinuxContext, mode); if (reply != NULL) { reply->writeNoException(); if (fd >= 0) { diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp new file mode 100644 index 0000000000..697e948a6d --- /dev/null +++ b/libs/binder/IUidObserver.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/IUidObserver.h> + +#include <binder/Parcel.h> + +namespace android { + +// ------------------------------------------------------------------------------------ + +class BpUidObserver : public BpInterface<IUidObserver> +{ +public: + explicit BpUidObserver(const sp<IBinder>& impl) + : BpInterface<IUidObserver>(impl) + { + } + + virtual void onUidGone(uid_t uid, bool disabled) + { + Parcel data, reply; + data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); + data.writeInt32((int32_t) uid); + data.writeInt32(disabled ? 1 : 0); + remote()->transact(ON_UID_GONE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void onUidActive(uid_t uid) + { + Parcel data, reply; + data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); + data.writeInt32((int32_t) uid); + remote()->transact(ON_UID_ACTIVE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void onUidIdle(uid_t uid, bool disabled) + { + Parcel data, reply; + data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); + data.writeInt32((int32_t) uid); + data.writeInt32(disabled ? 1 : 0); + remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +// ---------------------------------------------------------------------- + +IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver"); + +// ---------------------------------------------------------------------- + +status_t BnUidObserver::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case ON_UID_GONE_TRANSACTION: { + CHECK_INTERFACE(IUidObserver, data, reply); + uid_t uid = data.readInt32(); + bool disabled = data.readInt32() == 1; + onUidGone(uid, disabled); + return NO_ERROR; + } break; + + case ON_UID_ACTIVE_TRANSACTION: { + CHECK_INTERFACE(IUidObserver, data, reply); + uid_t uid = data.readInt32(); + onUidActive(uid); + return NO_ERROR; + } break; + + case ON_UID_IDLE_TRANSACTION: { + CHECK_INTERFACE(IUidObserver, data, reply); + uid_t uid = data.readInt32(); + bool disabled = data.readInt32() == 1; + onUidIdle(uid, disabled); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index da806aa25d..597fca9b19 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -282,7 +282,7 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) return NULL; } - b = new BpBinder(handle); + b = BpBinder::create(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; @@ -316,7 +316,7 @@ wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle) // arriving from the driver. IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { - b = new BpBinder(handle); + b = BpBinder::create(handle); result = b; e->binder = b; if (b) e->refs = b->getWeakRefs(); diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp index 006f7f94e9..a9d5055549 100644 --- a/libs/binder/Status.cpp +++ b/libs/binder/Status.cpp @@ -102,6 +102,15 @@ status_t Status::readFromParcel(const Parcel& parcel) { } mMessage = String8(message); + // Skip over the remote stack trace data + int32_t remote_stack_trace_header_size; + status = parcel.readInt32(&remote_stack_trace_header_size); + if (status != OK) { + setFromStatusT(status); + return status; + } + parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size); + if (mException == EX_SERVICE_SPECIFIC) { status = parcel.readInt32(&mErrorCode); } else if (mException == EX_PARCELABLE) { @@ -137,6 +146,7 @@ status_t Status::writeToParcel(Parcel* parcel) const { return status; } status = parcel->writeString16(String16(mMessage)); + status = parcel->writeInt32(0); // Empty remote stack trace header if (mException == EX_SERVICE_SPECIFIC) { status = parcel->writeInt32(mErrorCode); } else if (mException == EX_PARCELABLE) { diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 3264666a21..5b66b923e7 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -52,6 +52,6 @@ interface IPackageManagerNative { * Unknown or unknowable versions are returned as 0. */ - int getVersionCodeForPackage(in String packageName); + long getVersionCodeForPackage(in String packageName); } diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h new file mode 100644 index 0000000000..408c428a67 --- /dev/null +++ b/libs/binder/include/binder/ActivityManager.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ACTIVITY_MANAGER_H +#define ANDROID_ACTIVITY_MANAGER_H + +#include <binder/IActivityManager.h> + +#include <utils/threads.h> + +// --------------------------------------------------------------------------- +namespace android { + +class ActivityManager +{ +public: + + enum { + // Flag for registerUidObserver: report uid gone + UID_OBSERVER_GONE = 1<<1, + // Flag for registerUidObserver: report uid has become idle + UID_OBSERVER_IDLE = 1<<2, + // Flag for registerUidObserver: report uid has become active + UID_OBSERVER_ACTIVE = 1<<3 + }; + + enum { + // Not a real process state + PROCESS_STATE_UNKNOWN = -1 + }; + + ActivityManager(); + + int openContentUri(const String16& stringUri); + void registerUidObserver(const sp<IUidObserver>& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage); + void unregisterUidObserver(const sp<IUidObserver>& observer); + +private: + Mutex mLock; + sp<IActivityManager> mService; + sp<IActivityManager> getService(); +}; + + +}; // namespace android +// --------------------------------------------------------------------------- +#endif // ANDROID_ACTIVITY_MANAGER_H diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h index ef703bda90..4ce82a122c 100644 --- a/libs/binder/include/binder/BinderService.h +++ b/libs/binder/include/binder/BinderService.h @@ -34,15 +34,17 @@ template<typename SERVICE> class BinderService { public: - static status_t publish(bool allowIsolated = false) { + static status_t publish(bool allowIsolated = false, + int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) { sp<IServiceManager> sm(defaultServiceManager()); - return sm->addService( - String16(SERVICE::getServiceName()), - new SERVICE(), allowIsolated); + return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated, + dumpFlags); } - static void publishAndJoinThreadPool(bool allowIsolated = false) { - publish(allowIsolated); + static void publishAndJoinThreadPool( + bool allowIsolated = false, + int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) { + publish(allowIsolated, dumpFlags); joinThreadPool(); } diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 7ef93aa390..8bd297bcfb 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -19,15 +19,20 @@ #include <binder/IBinder.h> #include <utils/KeyedVector.h> +#include <utils/Mutex.h> #include <utils/threads.h> +#include <unordered_map> + // --------------------------------------------------------------------------- namespace android { +using binder_proxy_limit_callback = void(*)(int); + class BpBinder : public IBinder { public: - BpBinder(int32_t handle); + static BpBinder* create(int32_t handle); inline int32_t handle() const { return mHandle; } @@ -61,6 +66,14 @@ public: status_t setConstantData(const void* data, size_t size); void sendObituary(); + static uint32_t getBinderProxyCount(uint32_t uid); + static void getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts); + static void enableCountByUid(); + static void disableCountByUid(); + static void setCountByUidEnabled(bool enable); + static void setLimitCallback(binder_proxy_limit_callback cb); + static void setBinderProxyCountWatermarks(int high, int low); + class ObjectManager { public: @@ -91,6 +104,7 @@ public: }; protected: + BpBinder(int32_t handle,int32_t trackedUid); virtual ~BpBinder(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); @@ -115,6 +129,16 @@ private: ObjectManager mObjects; Parcel* mConstantData; mutable String16 mDescriptorCache; + int32_t mTrackedUid; + + static Mutex sTrackingLock; + static std::unordered_map<int32_t,uint32_t> sTrackingMap; + static int sNumTrackedUids; + static std::atomic_bool sCountByUidEnabled; + static binder_proxy_limit_callback sLimitCallback; + static uint32_t sBinderProxyCountHighWatermark; + static uint32_t sBinderProxyCountLowWatermark; + static bool sBinderProxyThrottleCreate; }; }; // namespace android diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h index 5ad218035a..bac2a99a8f 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include/binder/IActivityManager.h @@ -18,6 +18,7 @@ #define ANDROID_IACTIVITY_MANAGER_H #include <binder/IInterface.h> +#include <binder/IUidObserver.h> namespace android { @@ -28,10 +29,17 @@ class IActivityManager : public IInterface public: DECLARE_META_INTERFACE(ActivityManager) - virtual int openContentUri(const String16& /* stringUri */) = 0; + virtual int openContentUri(const String16& stringUri) = 0; + virtual void registerUidObserver(const sp<IUidObserver>& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage) = 0; + virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0; enum { - OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + REGISTER_UID_OBSERVER_TRANSACTION, + UNREGISTER_UID_OBSERVER_TRANSACTION }; }; @@ -39,4 +47,4 @@ public: }; // namespace android -#endif // ANDROID_IACTIVITY_MANAGER_H
\ No newline at end of file +#endif // ANDROID_IACTIVITY_MANAGER_H diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 3b23f81e43..19e841a347 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -31,6 +31,15 @@ class IServiceManager : public IInterface { public: DECLARE_META_INTERFACE(ServiceManager) + /* + * Must match values in IServiceManager.java + */ + static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0; + static const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1; + static const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2; + static const int DUMP_FLAG_PRIORITY_ALL = + DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL; + static const int DUMP_FLAG_PROTO = 1 << 3; /** * Retrieve an existing service, blocking for a few seconds @@ -46,14 +55,14 @@ public: /** * Register a service. */ - virtual status_t addService( const String16& name, - const sp<IBinder>& service, - bool allowIsolated = false) = 0; + virtual status_t addService(const String16& name, const sp<IBinder>& service, + bool allowIsolated = false, + int dumpsysFlags = DUMP_FLAG_PRIORITY_NORMAL) = 0; /** * Return list of all existing services. */ - virtual Vector<String16> listServices() = 0; + virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0; enum { GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h index fda9ee6ba7..b47e995183 100644 --- a/libs/binder/include/binder/IShellCallback.h +++ b/libs/binder/include/binder/IShellCallback.h @@ -29,7 +29,8 @@ class IShellCallback : public IInterface public: DECLARE_META_INTERFACE(ShellCallback); - virtual int openOutputFile(const String16& path, const String16& seLinuxContext) = 0; + virtual int openFile(const String16& path, const String16& seLinuxContext, + const String16& mode) = 0; enum { OP_OPEN_OUTPUT_FILE = IBinder::FIRST_CALL_TRANSACTION diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h new file mode 100644 index 0000000000..fd4d8a6de1 --- /dev/null +++ b/libs/binder/include/binder/IUidObserver.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +#ifndef ANDROID_IUID_OBSERVER_H +#define ANDROID_IUID_OBSERVER_H + +#include <binder/IInterface.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class IUidObserver : public IInterface +{ +public: + DECLARE_META_INTERFACE(UidObserver) + + virtual void onUidGone(uid_t uid, bool disabled) = 0; + virtual void onUidActive(uid_t uid) = 0; + virtual void onUidIdle(uid_t uid, bool disabled) = 0; + + enum { + ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + ON_UID_ACTIVE_TRANSACTION, + ON_UID_IDLE_TRANSACTION + }; +}; + +// ---------------------------------------------------------------------- + +class BnUidObserver : public BnInterface<IUidObserver> +{ +public: + virtual status_t onTransact(uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_IUID_OBSERVER_H diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp index 455f2c418d..bf41e0b45e 100644 --- a/libs/binder/tests/binderThroughputTest.cpp +++ b/libs/binder/tests/binderThroughputTest.cpp @@ -215,7 +215,7 @@ void worker_fx(int num, int target = cs_pair ? num % server_count : rand() % workers.size(); int sz = payload_size; - while (sz > sizeof(uint32_t)) { + while (sz >= sizeof(uint32_t)) { data.writeInt32(0); sz -= sizeof(uint32_t); } @@ -381,6 +381,7 @@ int main(int argc, char *argv[]) // No need to run training round in this case. if (atoi(argv[i+1]) > 0) { max_time_bucket = strtoull(argv[i+1], (char **)NULL, 10) * 1000; + time_per_bucket = max_time_bucket / num_buckets; i++; } else { cout << "Max latency -m must be positive." << endl; diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index 9f995380bd..4da30e9980 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -22,7 +22,6 @@ cc_library_shared { cflags: ["-Wall", "-Werror"], shared_libs: [ - "libnativeloader", "liblog", ], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 39b5829faf..961f1011e0 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -20,12 +20,23 @@ #include <mutex> +#include <android/dlext.h> #include <log/log.h> -#include <nativeloader/dlext_namespaces.h> // TODO(b/37049319) Get this from a header once one exists extern "C" { android_namespace_t* android_get_exported_namespace(const char*); + android_namespace_t* android_create_namespace(const char* name, + const char* ld_library_path, + const char* default_library_path, + uint64_t type, + const char* permitted_when_isolated_path, + android_namespace_t* parent); + + enum { + ANDROID_NAMESPACE_TYPE_ISOLATED = 1, + ANDROID_NAMESPACE_TYPE_SHARED = 2, + }; } namespace android { @@ -45,6 +56,32 @@ void GraphicsEnv::setDriverPath(const std::string path) { mDriverPath = path; } +void GraphicsEnv::setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths) { + if (mLayerPaths.empty()) { + mLayerPaths = layerPaths; + mAppNamespace = appNamespace; + } else { + ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'", + layerPaths.c_str(), appNamespace); + } +} + +android_namespace_t* GraphicsEnv::getAppNamespace() { + return mAppNamespace; +} + +const std::string GraphicsEnv::getLayerPaths(){ + return mLayerPaths; +} + +const std::string GraphicsEnv::getDebugLayers() { + return mDebugLayers; +} + +void GraphicsEnv::setDebugLayers(const std::string layers) { + mDebugLayers = layers; +} + android_namespace_t* GraphicsEnv::getDriverNamespace() { static std::once_flag once; std::call_once(once, [this]() { diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 781707694a..213580c20b 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -35,10 +35,20 @@ public: void setDriverPath(const std::string path); android_namespace_t* getDriverNamespace(); + void setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths); + android_namespace_t* getAppNamespace(); + const std::string getLayerPaths(); + + void setDebugLayers(const std::string layers); + const std::string getDebugLayers(); + private: GraphicsEnv() = default; std::string mDriverPath; + std::string mDebugLayers; + std::string mLayerPaths; android_namespace_t* mDriverNamespace = nullptr; + android_namespace_t* mAppNamespace = nullptr; }; } // namespace android diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index cf72d55894..c713e9e554 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -19,7 +19,7 @@ cc_library_headers { cc_library_shared { name: "libgui", - vendor_available: true, + vendor_available: false, vndk: { enabled: true, }, diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index da4295609b..34e6d80061 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -49,16 +49,6 @@ BufferItemConsumer::BufferItemConsumer( BufferItemConsumer::~BufferItemConsumer() {} -void BufferItemConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - BI_LOGE("setName: BufferItemConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); -} - void BufferItemConsumer::setBufferFreedListener( const wp<BufferFreedListener>& listener) { Mutex::Autolock _l(mMutex); diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 7aa7872513..f9e292e199 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -182,6 +182,16 @@ bool ConsumerBase::isAbandoned() { return mAbandoned; } +void ConsumerBase::setName(const String8& name) { + Mutex::Autolock _l(mMutex); + if (mAbandoned) { + CB_LOGE("setName: ConsumerBase is abandoned!"); + return; + } + mName = name; + mConsumer->setConsumerName(name); +} + void ConsumerBase::setFrameAvailableListener( const wp<FrameAvailableListener>& listener) { CB_LOGV("setFrameAvailableListener"); @@ -237,6 +247,50 @@ status_t ConsumerBase::setDefaultBufferDataSpace( return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); } +status_t ConsumerBase::setConsumerUsageBits(uint64_t usage) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setConsumerUsageBits: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setConsumerUsageBits(usage); +} + +status_t ConsumerBase::setTransformHint(uint32_t hint) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setTransformHint: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setTransformHint(hint); +} + +status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); +} + +sp<NativeHandle> ConsumerBase::getSidebandStream() const { + Mutex::Autolock _l(mMutex); + if (mAbandoned) { + CB_LOGE("getSidebandStream: ConsumerBase is abandoned!"); + return nullptr; + } + + sp<NativeHandle> stream; + status_t err = mConsumer->getSidebandStream(&stream); + if (err != NO_ERROR) { + CB_LOGE("failed to get sideband stream: %d", err); + return nullptr; + } + + return stream; +} + status_t ConsumerBase::getOccupancyHistory(bool forceFlush, std::vector<OccupancyTracker::Segment>* outHistory) { Mutex::Autolock _l(mMutex); diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index ae7c65c441..8edf60400c 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -18,11 +18,11 @@ #define LOG_TAG "CpuConsumer" //#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <cutils/compiler.h> -#include <utils/Log.h> -#include <gui/BufferItem.h> #include <gui/CpuConsumer.h> +#include <gui/BufferItem.h> +#include <utils/Log.h> + #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) @@ -44,20 +44,19 @@ CpuConsumer::CpuConsumer(const sp<IGraphicBufferConsumer>& bq, mConsumer->setMaxAcquiredBufferCount(static_cast<int32_t>(maxLockedBuffers)); } -CpuConsumer::~CpuConsumer() { - // ConsumerBase destructor does all the work. +size_t CpuConsumer::findAcquiredBufferLocked(uintptr_t id) const { + for (size_t i = 0; i < mMaxLockedBuffers; i++) { + const auto& ab = mAcquiredBuffers[i]; + // note that this finds AcquiredBuffer::kUnusedId as well + if (ab.mLockedBufferId == id) { + return i; + } + } + return mMaxLockedBuffers; // an invalid index } - - -void CpuConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - CC_LOGE("setName: CpuConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); +static uintptr_t getLockedBufferId(const CpuConsumer::LockedBuffer& buffer) { + return reinterpret_cast<uintptr_t>(buffer.data); } static bool isPossiblyYUV(PixelFormat format) { @@ -88,10 +87,74 @@ static bool isPossiblyYUV(PixelFormat format) { } } +status_t CpuConsumer::lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const { + android_ycbcr ycbcr = android_ycbcr(); + + PixelFormat format = item.mGraphicBuffer->getPixelFormat(); + PixelFormat flexFormat = format; + if (isPossiblyYUV(format)) { + int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; + status_t err = item.mGraphicBuffer->lockAsyncYCbCr(GraphicBuffer::USAGE_SW_READ_OFTEN, + item.mCrop, &ycbcr, fenceFd); + if (err == OK) { + flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; + if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { + CC_LOGV("locking buffer of format %#x as flex YUV", format); + } + } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", strerror(-err), err); + return err; + } + } + + if (ycbcr.y != nullptr) { + outBuffer->data = reinterpret_cast<uint8_t*>(ycbcr.y); + outBuffer->stride = static_cast<uint32_t>(ycbcr.ystride); + outBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb); + outBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr); + outBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride); + outBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step); + } else { + // not flexible YUV; try lockAsync + void* bufferPointer = nullptr; + int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; + status_t err = item.mGraphicBuffer->lockAsync(GraphicBuffer::USAGE_SW_READ_OFTEN, + item.mCrop, &bufferPointer, fenceFd); + if (err != OK) { + CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), err); + return err; + } + + outBuffer->data = reinterpret_cast<uint8_t*>(bufferPointer); + outBuffer->stride = item.mGraphicBuffer->getStride(); + outBuffer->dataCb = nullptr; + outBuffer->dataCr = nullptr; + outBuffer->chromaStride = 0; + outBuffer->chromaStep = 0; + } + + outBuffer->width = item.mGraphicBuffer->getWidth(); + outBuffer->height = item.mGraphicBuffer->getHeight(); + outBuffer->format = format; + outBuffer->flexFormat = flexFormat; + + outBuffer->crop = item.mCrop; + outBuffer->transform = item.mTransform; + outBuffer->scalingMode = item.mScalingMode; + outBuffer->timestamp = item.mTimestamp; + outBuffer->dataSpace = item.mDataSpace; + outBuffer->frameNumber = item.mFrameNumber; + + return OK; +} + status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t err; if (!nativeBuffer) return BAD_VALUE; + + Mutex::Autolock _l(mMutex); + if (mCurrentLockedBuffers == mMaxLockedBuffers) { CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.", mMaxLockedBuffers); @@ -99,9 +162,6 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } BufferItem b; - - Mutex::Autolock _l(mMutex); - err = acquireBufferLocked(&b, 0); if (err != OK) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { @@ -112,94 +172,23 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } } - int slot = b.mSlot; - - void *bufferPointer = NULL; - android_ycbcr ycbcr = android_ycbcr(); - - PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat(); - PixelFormat flexFormat = format; - if (isPossiblyYUV(format)) { - if (b.mFence.get()) { - err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &ycbcr, - b.mFence->dup()); - } else { - err = mSlots[slot].mGraphicBuffer->lockYCbCr( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &ycbcr); - } - if (err == OK) { - bufferPointer = ycbcr.y; - flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; - if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { - CC_LOGV("locking buffer of format %#x as flex YUV", format); - } - } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { - CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", - strerror(-err), err); - return err; - } + if (b.mGraphicBuffer == nullptr) { + b.mGraphicBuffer = mSlots[b.mSlot].mGraphicBuffer; } - if (bufferPointer == NULL) { // not flexible YUV - if (b.mFence.get()) { - err = mSlots[slot].mGraphicBuffer->lockAsync( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &bufferPointer, - b.mFence->dup()); - } else { - err = mSlots[slot].mGraphicBuffer->lock( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &bufferPointer); - } - if (err != OK) { - CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", - strerror(-err), err); - return err; - } + err = lockBufferItem(b, nativeBuffer); + if (err != OK) { + return err; } - size_t lockedIdx = 0; - for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { - if (mAcquiredBuffers[lockedIdx].mSlot == - BufferQueue::INVALID_BUFFER_SLOT) { - break; - } - } - assert(lockedIdx < mMaxLockedBuffers); - - AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); - ab.mSlot = slot; - ab.mBufferPointer = bufferPointer; - ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer; - - nativeBuffer->data = - reinterpret_cast<uint8_t*>(bufferPointer); - nativeBuffer->width = mSlots[slot].mGraphicBuffer->getWidth(); - nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight(); - nativeBuffer->format = format; - nativeBuffer->flexFormat = flexFormat; - nativeBuffer->stride = (ycbcr.y != NULL) ? - static_cast<uint32_t>(ycbcr.ystride) : - mSlots[slot].mGraphicBuffer->getStride(); - - nativeBuffer->crop = b.mCrop; - nativeBuffer->transform = b.mTransform; - nativeBuffer->scalingMode = b.mScalingMode; - nativeBuffer->timestamp = b.mTimestamp; - nativeBuffer->dataSpace = b.mDataSpace; - nativeBuffer->frameNumber = b.mFrameNumber; - - nativeBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb); - nativeBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr); - nativeBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride); - nativeBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step); + // find an unused AcquiredBuffer + size_t lockedIdx = findAcquiredBufferLocked(AcquiredBuffer::kUnusedId); + ALOG_ASSERT(lockedIdx < mMaxLockedBuffers); + AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); + + ab.mSlot = b.mSlot; + ab.mGraphicBuffer = b.mGraphicBuffer; + ab.mLockedBufferId = getLockedBufferId(*nativeBuffer); mCurrentLockedBuffers++; @@ -208,60 +197,34 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); - size_t lockedIdx = 0; - void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); - for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { - if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break; - } + uintptr_t id = getLockedBufferId(nativeBuffer); + size_t lockedIdx = + (id != AcquiredBuffer::kUnusedId) ? findAcquiredBufferLocked(id) : mMaxLockedBuffers; if (lockedIdx == mMaxLockedBuffers) { CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); return BAD_VALUE; } - return releaseAcquiredBufferLocked(lockedIdx); -} + AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); -status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) { - status_t err; - int fd = -1; - - err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd); + int fenceFd = -1; + status_t err = ab.mGraphicBuffer->unlockAsync(&fenceFd); if (err != OK) { CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__, lockedIdx); return err; } - int buf = mAcquiredBuffers[lockedIdx].mSlot; - if (CC_LIKELY(fd != -1)) { - sp<Fence> fence(new Fence(fd)); - addReleaseFenceLocked( - mAcquiredBuffers[lockedIdx].mSlot, - mSlots[buf].mGraphicBuffer, - fence); - } - // release the buffer if it hasn't already been freed by the BufferQueue. - // This can happen, for example, when the producer of this buffer - // disconnected after this buffer was acquired. - if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer == - mSlots[buf].mGraphicBuffer)) { - releaseBufferLocked( - buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - } + sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); + addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence); + releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer); - AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); - ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT; - ab.mBufferPointer = NULL; - ab.mGraphicBuffer.clear(); + ab.reset(); mCurrentLockedBuffers--; - return OK; -} -void CpuConsumer::freeBufferLocked(int slotIndex) { - ConsumerBase::freeBufferLocked(slotIndex); + return OK; } } // namespace android diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp index fccca97f54..a379ad6306 100644 --- a/libs/gui/FrameTimestamps.cpp +++ b/libs/gui/FrameTimestamps.cpp @@ -628,7 +628,6 @@ FrameEventHistoryDelta& FrameEventHistoryDelta::operator=( ALOGE("FrameEventHistoryDelta assign clobbering history."); } mDeltas = std::move(src.mDeltas); - ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty."); return *this; } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 14d9937142..788a6eb8f0 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -31,6 +31,8 @@ #include <hardware/hardware.h> +#include <math/mat4.h> + #include <gui/BufferItem.h> #include <gui/GLConsumer.h> #include <gui/ISurfaceComposer.h> @@ -75,33 +77,7 @@ static const struct { "_______________" }; -// Transform matrices -static float mtxIdentity[16] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, -}; -static float mtxFlipH[16] = { - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; -static float mtxFlipV[16] = { - 1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 1, -}; -static float mtxRot90[16] = { - 0, 1, 0, 0, - -1, 0, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; - -static void mtxMul(float out[16], const float a[16], const float b[16]); +static const mat4 mtxIdentity; Mutex GLConsumer::sStaticInitLock; sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer; @@ -173,7 +149,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, { GLC_LOGV("GLConsumer"); - memcpy(mCurrentTransformMatrix, mtxIdentity, + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); @@ -202,7 +178,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, { GLC_LOGV("GLConsumer"); - memcpy(mCurrentTransformMatrix, mtxIdentity, + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); @@ -758,25 +734,6 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { return OK; } -bool GLConsumer::isExternalFormat(PixelFormat format) -{ - switch (format) { - // supported YUV formats - case HAL_PIXEL_FORMAT_YV12: - // Legacy/deprecated YUV formats - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_422_I: - return true; - } - - // Any OEM format needs to be considered - if (format>=0x100 && format<=0x1FF) - return true; - - return false; -} - uint32_t GLConsumer::getCurrentTextureTarget() const { return mTexTarget; } @@ -820,34 +777,37 @@ void GLConsumer::computeCurrentTransformMatrixLocked() { void GLConsumer::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering) { - - float xform[16]; - for (int i = 0; i < 16; i++) { - xform[i] = mtxIdentity[i]; - } + // Transform matrices + static const mat4 mtxFlipH( + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1 + ); + static const mat4 mtxFlipV( + 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 1 + ); + static const mat4 mtxRot90( + 0, 1, 0, 0, + -1, 0, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1 + ); + + mat4 xform; if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - float result[16]; - mtxMul(result, xform, mtxFlipH); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxFlipH; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - float result[16]; - mtxMul(result, xform, mtxFlipV); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxFlipV; } if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - float result[16]; - mtxMul(result, xform, mtxRot90); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxRot90; } - float mtxBeforeFlipV[16]; if (!cropRect.isEmpty()) { float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; float bufferWidth = buf->getWidth(); @@ -893,25 +853,63 @@ void GLConsumer::computeTransformMatrix(float outTransform[16], sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; } - float crop[16] = { + + mat4 crop( sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, - tx, ty, 0, 1, - }; - - mtxMul(mtxBeforeFlipV, crop, xform); - } else { - for (int i = 0; i < 16; i++) { - mtxBeforeFlipV[i] = xform[i]; - } + tx, ty, 0, 1 + ); + xform = crop * xform; } // SurfaceFlinger expects the top of its window textures to be at a Y // coordinate of 0, so GLConsumer must behave the same way. We don't // want to expose this to applications, however, so we must add an // additional vertical flip to the transform after all the other transforms. - mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV); + xform = mtxFlipV * xform; + + memcpy(outTransform, xform.asArray(), sizeof(xform)); +} + +Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) { + Rect outCrop = crop; + + uint32_t newWidth = static_cast<uint32_t>(crop.width()); + uint32_t newHeight = static_cast<uint32_t>(crop.height()); + + if (newWidth * bufferHeight > newHeight * bufferWidth) { + newWidth = newHeight * bufferWidth / bufferHeight; + ALOGV("too wide: newWidth = %d", newWidth); + } else if (newWidth * bufferHeight < newHeight * bufferWidth) { + newHeight = newWidth * bufferHeight / bufferWidth; + ALOGV("too tall: newHeight = %d", newHeight); + } + + uint32_t currentWidth = static_cast<uint32_t>(crop.width()); + uint32_t currentHeight = static_cast<uint32_t>(crop.height()); + + // The crop is too wide + if (newWidth < currentWidth) { + uint32_t dw = currentWidth - newWidth; + auto halfdw = dw / 2; + outCrop.left += halfdw; + // Not halfdw because it would subtract 1 too few when dw is odd + outCrop.right -= (dw - halfdw); + // The crop is too tall + } else if (newHeight < currentHeight) { + uint32_t dh = currentHeight - newHeight; + auto halfdh = dh / 2; + outCrop.top += halfdh; + // Not halfdh because it would subtract 1 too few when dh is odd + outCrop.bottom -= (dh - halfdh); + } + + ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", + outCrop.left, outCrop.top, + outCrop.right,outCrop.bottom); + + return outCrop; } nsecs_t GLConsumer::getTimestamp() { @@ -945,45 +943,9 @@ sp<GraphicBuffer> GLConsumer::getCurrentBuffer(int* outSlot) const { Rect GLConsumer::getCurrentCrop() const { Mutex::Autolock lock(mMutex); - - Rect outCrop = mCurrentCrop; - if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { - uint32_t newWidth = static_cast<uint32_t>(mCurrentCrop.width()); - uint32_t newHeight = static_cast<uint32_t>(mCurrentCrop.height()); - - if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) { - newWidth = newHeight * mDefaultWidth / mDefaultHeight; - GLC_LOGV("too wide: newWidth = %d", newWidth); - } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) { - newHeight = newWidth * mDefaultHeight / mDefaultWidth; - GLC_LOGV("too tall: newHeight = %d", newHeight); - } - - uint32_t currentWidth = static_cast<uint32_t>(mCurrentCrop.width()); - uint32_t currentHeight = static_cast<uint32_t>(mCurrentCrop.height()); - - // The crop is too wide - if (newWidth < currentWidth) { - uint32_t dw = currentWidth - newWidth; - auto halfdw = dw / 2; - outCrop.left += halfdw; - // Not halfdw because it would subtract 1 too few when dw is odd - outCrop.right -= (dw - halfdw); - // The crop is too tall - } else if (newHeight < currentHeight) { - uint32_t dh = currentHeight - newHeight; - auto halfdh = dh / 2; - outCrop.top += halfdh; - // Not halfdh because it would subtract 1 too few when dh is odd - outCrop.bottom -= (dh - halfdh); - } - - GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", - outCrop.left, outCrop.top, - outCrop.right,outCrop.bottom); - } - - return outCrop; + return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) + ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight) + : mCurrentCrop; } uint32_t GLConsumer::getCurrentTransform() const { @@ -1006,11 +968,6 @@ std::shared_ptr<FenceTime> GLConsumer::getCurrentFenceTime() const { return mCurrentFenceTime; } -status_t GLConsumer::doGLFenceWait() const { - Mutex::Autolock lock(mMutex); - return doGLFenceWaitLocked(); -} - status_t GLConsumer::doGLFenceWaitLocked() const { EGLDisplay dpy = eglGetCurrentDisplay(); @@ -1086,61 +1043,8 @@ void GLConsumer::abandonLocked() { ConsumerBase::abandonLocked(); } -void GLConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - GLC_LOGE("setName: GLConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); -} - -status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setDefaultBufferFormat: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -status_t GLConsumer::setDefaultBufferDataSpace( - android_dataspace defaultDataSpace) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setDefaultBufferDataSpace: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); -} - status_t GLConsumer::setConsumerUsageBits(uint64_t usage) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!"); - return NO_INIT; - } - usage |= DEFAULT_USAGE_FLAGS; - return mConsumer->setConsumerUsageBits(usage); -} - -status_t GLConsumer::setTransformHint(uint32_t hint) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setTransformHint: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setTransformHint(hint); -} - -status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setMaxAcquiredBufferCount: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); + return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); } void GLConsumer::dumpLocked(String8& result, const char* prefix) const @@ -1155,28 +1059,6 @@ void GLConsumer::dumpLocked(String8& result, const char* prefix) const ConsumerBase::dumpLocked(result, prefix); } -static void mtxMul(float out[16], const float a[16], const float b[16]) { - out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; - out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; - out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; - out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; - - out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; - out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; - out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; - out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; - - out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; - out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; - out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; - out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; - - out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; - out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; - out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; - out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; -} - GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8e7f814313..5de84ecbab 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -29,8 +29,7 @@ #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> #include <gui/LayerDebugInfo.h> - -#include <private/gui/LayerState.h> +#include <gui/LayerState.h> #include <system/graphics.h> @@ -101,17 +100,13 @@ public: remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - ISurfaceComposer::Rotation rotation) - { + virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, + ISurfaceComposer::Rotation rotation) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); - data.writeStrongBinder(IInterface::asBinder(producer)); data.write(sourceCrop); data.writeUint32(reqWidth); data.writeUint32(reqHeight); @@ -119,8 +114,45 @@ public: data.writeInt32(maxLayerZ); data.writeInt32(static_cast<int32_t>(useIdentityTransform)); data.writeInt32(static_cast<int32_t>(rotation)); - remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); - return reply.readInt32(); + status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); + + if (err != NO_ERROR) { + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + return err; + } + + *outBuffer = new GraphicBuffer(); + reply.read(**outBuffer); + return err; + } + + virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder, + sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop, + float frameScale) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(layerHandleBinder); + data.write(sourceCrop); + data.writeFloat(frameScale); + status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); + + if (err != NO_ERROR) { + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + return err; + } + + *outBuffer = new GraphicBuffer(); + reply.read(**outBuffer); + + return err; } virtual bool authenticateSurfaceTexture( @@ -571,8 +603,7 @@ status_t BnSurfaceComposer::onTransact( case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IBinder> display = data.readStrongBinder(); - sp<IGraphicBufferProducer> producer = - interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); + sp<GraphicBuffer> outBuffer; Rect sourceCrop(Rect::EMPTY_RECT); data.read(sourceCrop); uint32_t reqWidth = data.readUint32(); @@ -582,11 +613,28 @@ status_t BnSurfaceComposer::onTransact( bool useIdentityTransform = static_cast<bool>(data.readInt32()); int32_t rotation = data.readInt32(); - status_t res = captureScreen(display, producer, - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation)); + status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight, + minLayerZ, maxLayerZ, useIdentityTransform, + static_cast<ISurfaceComposer::Rotation>(rotation)); reply->writeInt32(res); + if (res == NO_ERROR) { + reply->write(*outBuffer); + } + return NO_ERROR; + } + case CAPTURE_LAYERS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> layerHandleBinder = data.readStrongBinder(); + sp<GraphicBuffer> outBuffer; + Rect sourceCrop(Rect::EMPTY_RECT); + data.read(sourceCrop); + float frameScale = data.readFloat(); + + status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale); + reply->writeInt32(res); + if (res == NO_ERROR) { + reply->write(*outBuffer); + } return NO_ERROR; } case AUTHENTICATE_SURFACE: { diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp index 57ddde075a..d3dc16d30e 100644 --- a/libs/gui/LayerDebugInfo.cpp +++ b/libs/gui/LayerDebugInfo.cpp @@ -43,7 +43,10 @@ status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { RETURN_ON_ERROR(parcel->writeInt32(mHeight)); RETURN_ON_ERROR(parcel->write(mCrop)); RETURN_ON_ERROR(parcel->write(mFinalCrop)); - RETURN_ON_ERROR(parcel->writeFloat(mAlpha)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.r)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.g)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.b)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.a)); RETURN_ON_ERROR(parcel->writeUint32(mFlags)); RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat)); RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace))); @@ -79,7 +82,14 @@ status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) { RETURN_ON_ERROR(parcel->readInt32(&mHeight)); RETURN_ON_ERROR(parcel->read(mCrop)); RETURN_ON_ERROR(parcel->read(mFinalCrop)); - RETURN_ON_ERROR(parcel->readFloat(&mAlpha)); + mColor.r = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.g = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.b = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.a = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); RETURN_ON_ERROR(parcel->readUint32(&mFlags)); RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat)); // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways? @@ -116,8 +126,10 @@ std::string to_string(const LayerDebugInfo& info) { result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty); result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str()); result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str()); - result.appendFormat("alpha=%.3f, flags=0x%08x, ", - static_cast<double>(info.mAlpha), info.mFlags); + result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ", + static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g), + static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a), + info.mFlags); result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]", static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]), static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1])); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 9b06e63610..b5295f2801 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -18,7 +18,7 @@ #include <binder/Parcel.h> #include <gui/ISurfaceComposerClient.h> #include <gui/IGraphicBufferProducer.h> -#include <private/gui/LayerState.h> +#include <gui/LayerState.h> namespace android { @@ -45,6 +45,10 @@ status_t layer_state_t::write(Parcel& output) const output.writeInt32(overrideScalingMode); output.writeStrongBinder(IInterface::asBinder(barrierGbp)); output.writeStrongBinder(relativeLayerHandle); + output.writeStrongBinder(parentHandleForChild); + output.writeFloat(color.r); + output.writeFloat(color.g); + output.writeFloat(color.b); output.write(transparentRegion); return NO_ERROR; } @@ -77,6 +81,10 @@ status_t layer_state_t::read(const Parcel& input) barrierGbp = interface_cast<IGraphicBufferProducer>(input.readStrongBinder()); relativeLayerHandle = input.readStrongBinder(); + parentHandleForChild = input.readStrongBinder(); + color.r = input.readFloat(); + color.g = input.readFloat(); + color.b = input.readFloat(); input.read(transparentRegion); return NO_ERROR; } @@ -128,5 +136,101 @@ status_t DisplayState::read(const Parcel& input) { return NO_ERROR; } +void DisplayState::merge(const DisplayState& other) { + if (other.what & eSurfaceChanged) { + what |= eSurfaceChanged; + surface = other.surface; + } + if (other.what & eLayerStackChanged) { + what |= eLayerStackChanged; + layerStack = other.layerStack; + } + if (other.what & eDisplayProjectionChanged) { + what |= eDisplayProjectionChanged; + orientation = other.orientation; + viewport = other.viewport; + frame = other.frame; + } + if (other.what & eDisplaySizeChanged) { + what |= eDisplaySizeChanged; + width = other.width; + height = other.height; + } +} + +void layer_state_t::merge(const layer_state_t& other) { + if (other.what & ePositionChanged) { + what |= ePositionChanged; + x = other.x; + y = other.y; + } + if (other.what & eLayerChanged) { + what |= eLayerChanged; + z = other.z; + } + if (other.what & eSizeChanged) { + what |= eSizeChanged; + w = other.w; + h = other.h; + } + if (other.what & eAlphaChanged) { + what |= eAlphaChanged; + alpha = other.alpha; + } + if (other.what & eMatrixChanged) { + what |= eMatrixChanged; + matrix = other.matrix; + } + if (other.what & eTransparentRegionChanged) { + what |= eTransparentRegionChanged; + transparentRegion = other.transparentRegion; + } + if (other.what & eFlagsChanged) { + what |= eFlagsChanged; + flags = other.flags; + mask = other.mask; + } + if (other.what & eLayerStackChanged) { + what |= eLayerStackChanged; + layerStack = other.layerStack; + } + if (other.what & eCropChanged) { + what |= eCropChanged; + crop = other.crop; + } + if (other.what & eDeferTransaction) { + what |= eDeferTransaction; + barrierHandle = other.barrierHandle; + barrierGbp = other.barrierGbp; + frameNumber = other.frameNumber; + } + if (other.what & eFinalCropChanged) { + what |= eFinalCropChanged; + finalCrop = other.finalCrop; + } + if (other.what & eOverrideScalingModeChanged) { + what |= eOverrideScalingModeChanged; + overrideScalingMode = other.overrideScalingMode; + } + if (other.what & eGeometryAppliesWithResize) { + what |= eGeometryAppliesWithResize; + } + if (other.what & eReparentChildren) { + what |= eReparentChildren; + reparentHandle = other.reparentHandle; + } + if (other.what & eDetachChildren) { + what |= eDetachChildren; + } + if (other.what & eRelativeLayerChanged) { + what |= eRelativeLayerChanged; + z = other.z; + relativeLayerHandle = other.relativeLayerHandle; + } + if (other.what & eReparent) { + what |= eReparent; + parentHandleForChild = other.parentHandleForChild; + } +} }; // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index d9d945dff1..80216bc63e 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1512,6 +1512,12 @@ int Surface::setBuffersDataSpace(android_dataspace dataSpace) return NO_ERROR; } +android_dataspace_t Surface::getBuffersDataSpace() { + ALOGV("Surface::getBuffersDataSpace"); + Mutex::Autolock lock(mMutex); + return mDataSpace; +} + void Surface::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].buffer = 0; @@ -1754,4 +1760,25 @@ status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) return OK; } +status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer) { + if (buffer == nullptr) { + return BAD_VALUE; + } + int err = static_cast<ANativeWindow*>(surface)->perform(surface, NATIVE_WINDOW_API_CONNECT, + NATIVE_WINDOW_API_CPU); + if (err != OK) { + return err; + } + err = surface->attachBuffer(buffer->getNativeBuffer()); + if (err != OK) { + return err; + } + err = static_cast<ANativeWindow*>(surface)->queueBuffer(surface, buffer->getNativeBuffer(), -1); + if (err != OK) { + return err; + } + err = surface->disconnect(NATIVE_WINDOW_API_CPU); + return err; +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7ae2672249..939a209c3f 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -21,7 +21,6 @@ #include <utils/Errors.h> #include <utils/Log.h> -#include <utils/Singleton.h> #include <utils/SortedVector.h> #include <utils/String8.h> #include <utils/threads.h> @@ -37,11 +36,11 @@ #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> +#include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> -#include <private/gui/LayerState.h> namespace android { // --------------------------------------------------------------------------- @@ -97,204 +96,95 @@ void ComposerService::composerServiceDied() // --------------------------------------------------------------------------- -static inline -int compare_type(const ComposerState& lhs, const ComposerState& rhs) { - if (lhs.client < rhs.client) return -1; - if (lhs.client > rhs.client) return 1; - if (lhs.state.surface < rhs.state.surface) return -1; - if (lhs.state.surface > rhs.state.surface) return 1; - return 0; -} - -static inline -int compare_type(const DisplayState& lhs, const DisplayState& rhs) { - return compare_type(lhs.token, rhs.token); -} - -class Composer : public Singleton<Composer> -{ - friend class Singleton<Composer>; - - mutable Mutex mLock; - SortedVector<ComposerState> mComposerStates; - SortedVector<DisplayState > mDisplayStates; - uint32_t mForceSynchronous; - uint32_t mTransactionNestCount; - bool mAnimation; - - Composer() : Singleton<Composer>(), - mForceSynchronous(0), mTransactionNestCount(0), - mAnimation(false) - { } - - void openGlobalTransactionImpl(); - void closeGlobalTransactionImpl(bool synchronous); - void setAnimationTransactionImpl(); - status_t enableVSyncInjectionsImpl(bool enable); - status_t injectVSyncImpl(nsecs_t when); - - layer_state_t* getLayerStateLocked( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id); - - DisplayState& getDisplayStateLocked(const sp<IBinder>& token); - -public: - sp<IBinder> createDisplay(const String8& displayName, bool secure); - void destroyDisplay(const sp<IBinder>& display); - sp<IBinder> getBuiltInDisplay(int32_t id); - - status_t setPosition(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - float x, float y); - status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - uint32_t w, uint32_t h); - status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - int32_t z); - status_t setRelativeLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - const sp<IBinder>& relativeTo, int32_t z); - status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - const Region& transparentRegion); - status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - float alpha); - status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - float dsdx, float dtdx, float dtdy, float dsdy); - status_t setOrientation(int orientation); - status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - const Rect& crop); - status_t setFinalCrop(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const Rect& crop); - status_t setLayerStack(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t layerStack); - status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const sp<IBinder>& handle, - uint64_t frameNumber); - status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const sp<Surface>& barrierSurface, - uint64_t frameNumber); - status_t reparentChildren(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, - const sp<IBinder>& newParentHandle); - status_t detachChildren(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id); - status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t overrideScalingMode); - status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id); - - status_t setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer); - void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); - void setDisplayProjection(const sp<IBinder>& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect); - void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); - - static void setAnimationTransaction() { - Composer::getInstance().setAnimationTransactionImpl(); - } - - static void openGlobalTransaction() { - Composer::getInstance().openGlobalTransactionImpl(); +SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : + mForceSynchronous(other.mForceSynchronous), + mTransactionNestCount(other.mTransactionNestCount), + mAnimation(other.mAnimation) { + mDisplayStates = other.mDisplayStates; + mComposerStates = other.mComposerStates; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { + for (auto const& state : other.mComposerStates) { + ssize_t index = mComposerStates.indexOf(state); + if (index < 0) { + mComposerStates.add(state); + } else { + mComposerStates.editItemAt(static_cast<size_t>(index)).state.merge(state.state); + } } + other.mComposerStates.clear(); - static void closeGlobalTransaction(bool synchronous) { - Composer::getInstance().closeGlobalTransactionImpl(synchronous); + for (auto const& state : other.mDisplayStates) { + ssize_t index = mDisplayStates.indexOf(state); + if (index < 0) { + mDisplayStates.add(state); + } else { + mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state); + } } + other.mDisplayStates.clear(); - static status_t enableVSyncInjections(bool enable) { - return Composer::getInstance().enableVSyncInjectionsImpl(enable); - } + return *this; +} - static status_t injectVSync(nsecs_t when) { - return Composer::getInstance().injectVSyncImpl(when); +status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { + if (mStatus != NO_ERROR) { + return mStatus; } -}; -ANDROID_SINGLETON_STATIC_INSTANCE(Composer); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); -// --------------------------------------------------------------------------- + Vector<ComposerState> composerStates; + Vector<DisplayState> displayStates; + uint32_t flags = 0; -sp<IBinder> Composer::createDisplay(const String8& displayName, bool secure) { - return ComposerService::getComposerService()->createDisplay(displayName, - secure); -} + mForceSynchronous |= synchronous; -void Composer::destroyDisplay(const sp<IBinder>& display) { - return ComposerService::getComposerService()->destroyDisplay(display); -} + composerStates = mComposerStates; + mComposerStates.clear(); -sp<IBinder> Composer::getBuiltInDisplay(int32_t id) { - return ComposerService::getComposerService()->getBuiltInDisplay(id); -} + displayStates = mDisplayStates; + mDisplayStates.clear(); -void Composer::openGlobalTransactionImpl() { - { // scope for the lock - Mutex::Autolock _l(mLock); - mTransactionNestCount += 1; + if (mForceSynchronous) { + flags |= ISurfaceComposer::eSynchronous; + } + if (mAnimation) { + flags |= ISurfaceComposer::eAnimation; } -} - -void Composer::closeGlobalTransactionImpl(bool synchronous) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - - Vector<ComposerState> transaction; - Vector<DisplayState> displayTransaction; - uint32_t flags = 0; - - { // scope for the lock - Mutex::Autolock _l(mLock); - mForceSynchronous |= synchronous; - if (!mTransactionNestCount) { - ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior " - "call to openGlobalTransaction()."); - } else if (--mTransactionNestCount) { - return; - } - - transaction = mComposerStates; - mComposerStates.clear(); - displayTransaction = mDisplayStates; - mDisplayStates.clear(); + mForceSynchronous = false; + mAnimation = false; - if (mForceSynchronous) { - flags |= ISurfaceComposer::eSynchronous; - } - if (mAnimation) { - flags |= ISurfaceComposer::eAnimation; - } + sf->setTransactionState(composerStates, displayStates, flags); + mStatus = NO_ERROR; + return NO_ERROR; +} - mForceSynchronous = false; - mAnimation = false; - } +// --------------------------------------------------------------------------- - sm->setTransactionState(transaction, displayTransaction, flags); +sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) { + return ComposerService::getComposerService()->createDisplay(displayName, + secure); } -status_t Composer::enableVSyncInjectionsImpl(bool enable) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return sm->enableVSyncInjections(enable); +void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) { + return ComposerService::getComposerService()->destroyDisplay(display); } -status_t Composer::injectVSyncImpl(nsecs_t when) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return sm->injectVSync(when); +sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) { + return ComposerService::getComposerService()->getBuiltInDisplay(id); } -void Composer::setAnimationTransactionImpl() { - Mutex::Autolock _l(mLock); +void SurfaceComposerClient::Transaction::setAnimationTransaction() { mAnimation = true; } -layer_state_t* Composer::getLayerStateLocked( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) { - +layer_state_t* SurfaceComposerClient::Transaction::getLayerStateLocked(const sp<SurfaceControl>& sc) { ComposerState s; - s.client = client->mClient; - s.state.surface = id; + s.client = sc->getClient()->mClient; + s.state.surface = sc->getHandle(); ssize_t index = mComposerStates.indexOf(s); if (index < 0) { @@ -306,24 +196,36 @@ layer_state_t* Composer::getLayerStateLocked( return &(out[index].state); } -status_t Composer::setPosition(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, float x, float y) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition( + const sp<SurfaceControl>& sc, float x, float y) { + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::ePositionChanged; s->x = x; s->y = y; - return NO_ERROR; + return *this; } -status_t Composer::setSize(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t w, uint32_t h) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::show( + const sp<SurfaceControl>& sc) { + return setFlags(sc, 0, layer_state_t::eLayerHidden); +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide( + const sp<SurfaceControl>& sc) { + return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize( + const sp<SurfaceControl>& sc, uint32_t w, uint32_t h) { + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eSizeChanged; s->w = w; s->h = h; @@ -331,41 +233,41 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client, // Resizing a surface makes the transaction synchronous. mForceSynchronous = true; - return NO_ERROR; + return *this; } -status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t z) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer( + const sp<SurfaceControl>& sc, int32_t z) { + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eLayerChanged; s->z = z; - return NO_ERROR; + return *this; } -status_t Composer::setRelativeLayer(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const sp<IBinder>& relativeTo, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(const sp<SurfaceControl>& sc, const sp<IBinder>& relativeTo, int32_t z) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerStateLocked(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; } s->what |= layer_state_t::eRelativeLayerChanged; s->relativeLayerHandle = relativeTo; s->z = z; - return NO_ERROR; + return *this; } -status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t flags, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags( + const sp<SurfaceControl>& sc, uint32_t flags, uint32_t mask) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } if ((mask & layer_state_t::eLayerOpaque) || (mask & layer_state_t::eLayerHidden) || (mask & layer_state_t::eLayerSecure)) { @@ -374,50 +276,54 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; - return NO_ERROR; + return *this; } -status_t Composer::setTransparentRegionHint( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransparentRegionHint( + const sp<SurfaceControl>& sc, const Region& transparentRegion) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eTransparentRegionChanged; s->transparentRegion = transparentRegion; - return NO_ERROR; + return *this; } -status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, float alpha) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha( + const sp<SurfaceControl>& sc, float alpha) { + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eAlphaChanged; s->alpha = alpha; - return NO_ERROR; + return *this; } -status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t layerStack) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack( + const sp<SurfaceControl>& sc, uint32_t layerStack) { + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eLayerStackChanged; s->layerStack = layerStack; - return NO_ERROR; + return *this; } -status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, float dsdx, float dtdx, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix( + const sp<SurfaceControl>& sc, float dsdx, float dtdx, float dtdy, float dsdy) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eMatrixChanged; layer_state_t::matrix22_t matrix; matrix.dsdx = dsdx; @@ -425,93 +331,115 @@ status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; - return NO_ERROR; + return *this; } -status_t Composer::setCrop(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const Rect& crop) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop( + const sp<SurfaceControl>& sc, const Rect& crop) { + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eCropChanged; s->crop = crop; - return NO_ERROR; + return *this; } -status_t Composer::setFinalCrop(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const Rect& crop) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) { + layer_state_t* s = getLayerStateLocked(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eFinalCropChanged; s->finalCrop = crop; - return NO_ERROR; + return *this; } -status_t Composer::deferTransactionUntil( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil( + const sp<SurfaceControl>& sc, const sp<IBinder>& handle, uint64_t frameNumber) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerStateLocked(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDeferTransaction; s->barrierHandle = handle; s->frameNumber = frameNumber; - return NO_ERROR; + return *this; } -status_t Composer::deferTransactionUntil( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil( + const sp<SurfaceControl>& sc, const sp<Surface>& barrierSurface, uint64_t frameNumber) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerStateLocked(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDeferTransaction; s->barrierGbp = barrierSurface->getIGraphicBufferProducer(); s->frameNumber = frameNumber; - return NO_ERROR; + return *this; } -status_t Composer::reparentChildren( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren( + const sp<SurfaceControl>& sc, const sp<IBinder>& newParentHandle) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerStateLocked(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eReparentChildren; s->reparentHandle = newParentHandle; - return NO_ERROR; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent( + const sp<SurfaceControl>& sc, + const sp<IBinder>& newParentHandle) { + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eReparent; + s->parentHandleForChild = newParentHandle; + return *this; } -status_t Composer::detachChildren( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor( + const sp<SurfaceControl>& sc, + const half3& color) { + layer_state_t* s = getLayerStateLocked(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eColorChanged; + s->color = color; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren( + const sp<SurfaceControl>& sc) { + layer_state_t* s = getLayerStateLocked(sc); + if (!s) { + mStatus = BAD_INDEX; } s->what |= layer_state_t::eDetachChildren; - return NO_ERROR; + return *this; } -status_t Composer::setOverrideScalingMode( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t overrideScalingMode) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode( + const sp<SurfaceControl>& sc, int32_t overrideScalingMode) { + layer_state_t* s = getLayerStateLocked(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } switch (overrideScalingMode) { @@ -524,29 +452,29 @@ status_t Composer::setOverrideScalingMode( default: ALOGE("unknown scaling mode: %d", overrideScalingMode); - return BAD_VALUE; + mStatus = BAD_VALUE; + return *this; } s->what |= layer_state_t::eOverrideScalingModeChanged; s->overrideScalingMode = overrideScalingMode; - return NO_ERROR; + return *this; } -status_t Composer::setGeometryAppliesWithResize( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize( + const sp<SurfaceControl>& sc) { + layer_state_t* s = getLayerStateLocked(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eGeometryAppliesWithResize; - return NO_ERROR; + return *this; } // --------------------------------------------------------------------------- -DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { +DisplayState& SurfaceComposerClient::Transaction::getDisplayStateLocked(const sp<IBinder>& token) { DisplayState s; s.token = token; ssize_t index = mDisplayStates.indexOf(s); @@ -558,8 +486,8 @@ DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { return mDisplayStates.editItemAt(static_cast<size_t>(index)); } -status_t Composer::setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer) { +status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token, + const sp<IGraphicBufferProducer>& bufferProducer) { if (bufferProducer.get() != nullptr) { // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. @@ -571,26 +499,23 @@ status_t Composer::setDisplaySurface(const sp<IBinder>& token, return err; } } - Mutex::Autolock _l(mLock); DisplayState& s(getDisplayStateLocked(token)); s.surface = bufferProducer; s.what |= DisplayState::eSurfaceChanged; return NO_ERROR; } -void Composer::setDisplayLayerStack(const sp<IBinder>& token, +void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack) { - Mutex::Autolock _l(mLock); DisplayState& s(getDisplayStateLocked(token)); s.layerStack = layerStack; s.what |= DisplayState::eLayerStackChanged; } -void Composer::setDisplayProjection(const sp<IBinder>& token, +void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect) { - Mutex::Autolock _l(mLock); DisplayState& s(getDisplayStateLocked(token)); s.orientation = orientation; s.viewport = layerStackRect; @@ -599,8 +524,7 @@ void Composer::setDisplayProjection(const sp<IBinder>& token, mForceSynchronous = true; // TODO: do we actually still need this? } -void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) { - Mutex::Autolock _l(mLock); +void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) { DisplayState& s(getDisplayStateLocked(token)); s.width = width; s.height = height; @@ -610,22 +534,27 @@ void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() - : mStatus(NO_INIT), mComposer(Composer::getInstance()) + : mStatus(NO_INIT) { } SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root) - : mStatus(NO_INIT), mComposer(Composer::getInstance()), mParent(root) + : mStatus(NO_INIT), mParent(root) +{ +} + +SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client) + : mStatus(NO_ERROR), mClient(client) { } void SurfaceComposerClient::onFirstRef() { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - if (sm != 0) { + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + if (sf != 0 && mStatus == NO_INIT) { auto rootProducer = mParent.promote(); sp<ISurfaceComposerClient> conn; - conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) : - sm->createConnection(); + conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) : + sf->createConnection(); if (conn != 0) { mClient = conn; mStatus = NO_ERROR; @@ -648,8 +577,8 @@ sp<IBinder> SurfaceComposerClient::connection() const { status_t SurfaceComposerClient::linkToComposerDeath( const sp<IBinder::DeathRecipient>& recipient, void* cookie, uint32_t flags) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + return IInterface::asBinder(sf)->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { @@ -692,19 +621,6 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( return sur; } -sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, - bool secure) { - return Composer::getInstance().createDisplay(displayName, secure); -} - -void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) { - Composer::getInstance().destroyDisplay(display); -} - -sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) { - return Composer::getInstance().getBuiltInDisplay(id); -} - status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) { if (mStatus != NO_ERROR) return mStatus; @@ -727,152 +643,18 @@ status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token, return mClient->getLayerFrameStats(token, outStats); } -inline Composer& SurfaceComposerClient::getComposer() { - return mComposer; -} - // ---------------------------------------------------------------------------- -void SurfaceComposerClient::openGlobalTransaction() { - Composer::openGlobalTransaction(); -} - -void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) { - Composer::closeGlobalTransaction(synchronous); -} - -void SurfaceComposerClient::setAnimationTransaction() { - Composer::setAnimationTransaction(); -} - status_t SurfaceComposerClient::enableVSyncInjections(bool enable) { - return Composer::enableVSyncInjections(enable); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + return sf->enableVSyncInjections(enable); } status_t SurfaceComposerClient::injectVSync(nsecs_t when) { - return Composer::injectVSync(when); -} - -// ---------------------------------------------------------------------------- - -status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) { - return getComposer().setCrop(this, id, crop); -} - -status_t SurfaceComposerClient::setFinalCrop(const sp<IBinder>& id, - const Rect& crop) { - return getComposer().setFinalCrop(this, id, crop); -} - -status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) { - return getComposer().setPosition(this, id, x, y); -} - -status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint32_t h) { - return getComposer().setSize(this, id, w, h); -} - -status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) { - return getComposer().setLayer(this, id, z); -} - -status_t SurfaceComposerClient::setRelativeLayer(const sp<IBinder>& id, - const sp<IBinder>& relativeTo, int32_t z) { - return getComposer().setRelativeLayer(this, id, relativeTo, z); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + return sf->injectVSync(when); } -status_t SurfaceComposerClient::hide(const sp<IBinder>& id) { - return getComposer().setFlags(this, id, - layer_state_t::eLayerHidden, - layer_state_t::eLayerHidden); -} - -status_t SurfaceComposerClient::show(const sp<IBinder>& id) { - return getComposer().setFlags(this, id, - 0, - layer_state_t::eLayerHidden); -} - -status_t SurfaceComposerClient::setFlags(const sp<IBinder>& id, uint32_t flags, - uint32_t mask) { - return getComposer().setFlags(this, id, flags, mask); -} - -status_t SurfaceComposerClient::setTransparentRegionHint(const sp<IBinder>& id, - const Region& transparentRegion) { - return getComposer().setTransparentRegionHint(this, id, transparentRegion); -} - -status_t SurfaceComposerClient::setAlpha(const sp<IBinder>& id, float alpha) { - return getComposer().setAlpha(this, id, alpha); -} - -status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) { - return getComposer().setLayerStack(this, id, layerStack); -} - -status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, - float dtdy, float dsdy) { - return getComposer().setMatrix(this, id, dsdx, dtdx, dtdy, dsdy); -} - -status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id, - const sp<IBinder>& handle, uint64_t frameNumber) { - return getComposer().deferTransactionUntil(this, id, handle, frameNumber); -} - -status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id, - const sp<Surface>& barrierSurface, uint64_t frameNumber) { - return getComposer().deferTransactionUntil(this, id, barrierSurface, frameNumber); -} - -status_t SurfaceComposerClient::reparentChildren(const sp<IBinder>& id, - const sp<IBinder>& newParentHandle) { - return getComposer().reparentChildren(this, id, newParentHandle); -} - -status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) { - return getComposer().detachChildren(this, id); -} - -status_t SurfaceComposerClient::setOverrideScalingMode( - const sp<IBinder>& id, int32_t overrideScalingMode) { - return getComposer().setOverrideScalingMode( - this, id, overrideScalingMode); -} - -status_t SurfaceComposerClient::setGeometryAppliesWithResize( - const sp<IBinder>& id) { - return getComposer().setGeometryAppliesWithResize(this, id); -} - -// ---------------------------------------------------------------------------- - -status_t SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer) { - return Composer::getInstance().setDisplaySurface(token, bufferProducer); -} - -void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token, - uint32_t layerStack) { - Composer::getInstance().setDisplayLayerStack(token, layerStack); -} - -void SurfaceComposerClient::setDisplayProjection(const sp<IBinder>& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect) { - Composer::getInstance().setDisplayProjection(token, orientation, - layerStackRect, displayRect); -} - -void SurfaceComposerClient::setDisplaySize(const sp<IBinder>& token, - uint32_t width, uint32_t height) { - Composer::getInstance().setDisplaySize(token, width, height); -} - -// ---------------------------------------------------------------------------- - status_t SurfaceComposerClient::getDisplayConfigs( const sp<IBinder>& display, Vector<DisplayInfo>* configs) { @@ -940,149 +722,27 @@ status_t SurfaceComposerClient::getHdrCapabilities(const sp<IBinder>& display, // ---------------------------------------------------------------------------- -status_t ScreenshotClient::capture( - const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform) { - sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (s == NULL) return NO_INIT; - return s->captureScreen(display, producer, sourceCrop, - reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform); -} - -status_t ScreenshotClient::captureToBuffer(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, - uint32_t rotation, - sp<GraphicBuffer>* outBuffer) { +status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth, + uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, uint32_t rotation, + sp<GraphicBuffer>* outBuffer) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); if (s == NULL) return NO_INIT; - - sp<IGraphicBufferConsumer> gbpConsumer; - sp<IGraphicBufferProducer> producer; - BufferQueue::createBufferQueue(&producer, &gbpConsumer); - sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer, - GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER, - 1, true)); - - status_t ret = s->captureScreen(display, producer, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation)); + status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, minLayerZ, + maxLayerZ, useIdentityTransform, + static_cast<ISurfaceComposer::Rotation>(rotation)); if (ret != NO_ERROR) { return ret; } - BufferItem b; - consumer->acquireBuffer(&b, 0, true); - *outBuffer = b.mGraphicBuffer; return ret; } -ScreenshotClient::ScreenshotClient() - : mHaveBuffer(false) { - memset(&mBuffer, 0, sizeof(mBuffer)); -} - -ScreenshotClient::~ScreenshotClient() { - ScreenshotClient::release(); -} - -sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const { - if (mCpuConsumer == NULL) { - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&mProducer, &consumer); - mCpuConsumer = new CpuConsumer(consumer, 1); - mCpuConsumer->setName(String8("ScreenshotClient")); - } - return mCpuConsumer; -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation) { +status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, + float frameScale, sp<GraphicBuffer>* outBuffer) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); if (s == NULL) return NO_INIT; - sp<CpuConsumer> cpuConsumer = getCpuConsumer(); - - if (mHaveBuffer) { - mCpuConsumer->unlockBuffer(mBuffer); - memset(&mBuffer, 0, sizeof(mBuffer)); - mHaveBuffer = false; - } - - status_t err = s->captureScreen(display, mProducer, sourceCrop, - reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation)); - - if (err == NO_ERROR) { - err = mCpuConsumer->lockNextBuffer(&mBuffer); - if (err == NO_ERROR) { - mHaveBuffer = true; - } - } - return err; -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform) { - - return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, - bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, 0, 0, - INT32_MIN, INT32_MAX, - useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, - uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, - INT32_MIN, INT32_MAX, - useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -void ScreenshotClient::release() { - if (mHaveBuffer) { - mCpuConsumer->unlockBuffer(mBuffer); - memset(&mBuffer, 0, sizeof(mBuffer)); - mHaveBuffer = false; - } - mCpuConsumer.clear(); -} - -void const* ScreenshotClient::getPixels() const { - return mBuffer.data; -} - -uint32_t ScreenshotClient::getWidth() const { - return mBuffer.width; -} - -uint32_t ScreenshotClient::getHeight() const { - return mBuffer.height; -} - -PixelFormat ScreenshotClient::getFormat() const { - return mBuffer.format; -} - -uint32_t ScreenshotClient::getStride() const { - return mBuffer.stride; -} - -size_t ScreenshotClient::getSize() const { - return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format); -} - -android_dataspace ScreenshotClient::getDataSpace() const { - return mBuffer.dataSpace; + status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale); + return ret; } - // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 58bd273de6..f5fb8acf44 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -97,112 +97,6 @@ bool SurfaceControl::isSameSurface( return lhs->mHandle == rhs->mHandle; } -status_t SurfaceControl::setLayerStack(uint32_t layerStack) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setLayerStack(mHandle, layerStack); -} - -status_t SurfaceControl::setLayer(int32_t layer) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setLayer(mHandle, layer); -} - -status_t SurfaceControl::setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setRelativeLayer(mHandle, relativeTo, layer); -} - -status_t SurfaceControl::setPosition(float x, float y) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setPosition(mHandle, x, y); -} -status_t SurfaceControl::setGeometryAppliesWithResize() { - status_t err = validate(); - if (err < 0) return err; - return mClient->setGeometryAppliesWithResize(mHandle); -} -status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setSize(mHandle, w, h); -} -status_t SurfaceControl::hide() { - status_t err = validate(); - if (err < 0) return err; - return mClient->hide(mHandle); -} -status_t SurfaceControl::show() { - status_t err = validate(); - if (err < 0) return err; - return mClient->show(mHandle); -} -status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setFlags(mHandle, flags, mask); -} -status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setTransparentRegionHint(mHandle, transparent); -} -status_t SurfaceControl::setAlpha(float alpha) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setAlpha(mHandle, alpha); -} -status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setMatrix(mHandle, dsdx, dtdx, dtdy, dsdy); -} -status_t SurfaceControl::setCrop(const Rect& crop) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setCrop(mHandle, crop); -} -status_t SurfaceControl::setFinalCrop(const Rect& crop) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setFinalCrop(mHandle, crop); -} - -status_t SurfaceControl::deferTransactionUntil(const sp<IBinder>& handle, - uint64_t frameNumber) { - status_t err = validate(); - if (err < 0) return err; - return mClient->deferTransactionUntil(mHandle, handle, frameNumber); -} - -status_t SurfaceControl::deferTransactionUntil(const sp<Surface>& handle, - uint64_t frameNumber) { - status_t err = validate(); - if (err < 0) return err; - return mClient->deferTransactionUntil(mHandle, handle, frameNumber); -} - -status_t SurfaceControl::reparentChildren(const sp<IBinder>& newParentHandle) { - status_t err = validate(); - if (err < 0) return err; - return mClient->reparentChildren(mHandle, newParentHandle); -} - -status_t SurfaceControl::detachChildren() { - status_t err = validate(); - if (err < 0) return err; - return mClient->detachChildren(mHandle); -} - -status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setOverrideScalingMode(mHandle, overrideScalingMode); -} - status_t SurfaceControl::clearLayerFrameStats() const { status_t err = validate(); if (err < 0) return err; @@ -267,5 +161,33 @@ sp<IBinder> SurfaceControl::getHandle() const return mHandle; } +sp<SurfaceComposerClient> SurfaceControl::getClient() const +{ + return mClient; +} + +void SurfaceControl::writeToParcel(Parcel* parcel) +{ + parcel->writeStrongBinder(ISurfaceComposerClient::asBinder(mClient->getClient())); + parcel->writeStrongBinder(mHandle); + parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); +} + +sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel) +{ + sp<IBinder> client = parcel->readStrongBinder(); + sp<IBinder> handle = parcel->readStrongBinder(); + if (client == nullptr || handle == nullptr) + { + ALOGE("Invalid parcel"); + return nullptr; + } + sp<IBinder> gbp; + parcel->readNullableStrongBinder(&gbp); + return new SurfaceControl(new SurfaceComposerClient( + interface_cast<ISurfaceComposerClient>(client)), + handle.get(), interface_cast<IGraphicBufferProducer>(gbp)); +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index d9c57757f5..a905610ee2 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -57,10 +57,6 @@ class BufferItemConsumer: public ConsumerBase ~BufferItemConsumer() override; - // set the name of the BufferItemConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - // setBufferFreedListener sets the listener object that will be notified // when an old buffer is being freed. void setBufferFreedListener(const wp<BufferFreedListener>& listener); diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index e9fc8fd1ea..366ced380b 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -89,6 +89,18 @@ public: // See IGraphicBufferConsumer::setDefaultBufferDataSpace status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); + // See IGraphicBufferConsumer::setConsumerUsageBits + status_t setConsumerUsageBits(uint64_t usage); + + // See IGraphicBufferConsumer::setTransformHint + status_t setTransformHint(uint32_t hint); + + // See IGraphicBufferConsumer::setMaxAcquiredBufferCount + status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); + + // See IGraphicBufferConsumer::getSidebandStream + sp<NativeHandle> getSidebandStream() const; + // See IGraphicBufferConsumer::getOccupancyHistory status_t getOccupancyHistory(bool forceFlush, std::vector<OccupancyTracker::Segment>* outHistory); @@ -187,7 +199,7 @@ protected: // ConsumerBase::releaseBufferLocked. virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer, - EGLDisplay display, EGLSyncKHR eglFence); + EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR); // returns true iff the slot still has the graphicBuffer in it. bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer); diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h index 58602bf321..d375611e5b 100644 --- a/libs/gui/include/gui/CpuConsumer.h +++ b/libs/gui/include/gui/CpuConsumer.h @@ -94,12 +94,6 @@ class CpuConsumer : public ConsumerBase CpuConsumer(const sp<IGraphicBufferConsumer>& bq, size_t maxLockedBuffers, bool controlledByApp = false); - virtual ~CpuConsumer(); - - // set the name of the CpuConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - // Gets the next graphics buffer from the producer and locks it for CPU use, // filling out the passed-in locked buffer structure with the native pointer // and metadata. Returns BAD_VALUE if no new buffer is available, and @@ -119,31 +113,39 @@ class CpuConsumer : public ConsumerBase private: // Maximum number of buffers that can be locked at a time - size_t mMaxLockedBuffers; - - status_t releaseAcquiredBufferLocked(size_t lockedIdx); - - virtual void freeBufferLocked(int slotIndex); + const size_t mMaxLockedBuffers; // Tracking for buffers acquired by the user struct AcquiredBuffer { + static constexpr uintptr_t kUnusedId = 0; + // Need to track the original mSlot index and the buffer itself because // the mSlot entry may be freed/reused before the acquired buffer is // released. int mSlot; sp<GraphicBuffer> mGraphicBuffer; - void *mBufferPointer; + uintptr_t mLockedBufferId; AcquiredBuffer() : mSlot(BufferQueue::INVALID_BUFFER_SLOT), - mBufferPointer(NULL) { + mLockedBufferId(kUnusedId) { + } + + void reset() { + mSlot = BufferQueue::INVALID_BUFFER_SLOT; + mGraphicBuffer.clear(); + mLockedBufferId = kUnusedId; } }; + + size_t findAcquiredBufferLocked(uintptr_t id) const; + + status_t lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const; + Vector<AcquiredBuffer> mAcquiredBuffers; // Count of currently locked buffers size_t mCurrentLockedBuffers; - }; } // namespace android diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 75f2ccaaea..71ed3bf239 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -138,6 +138,10 @@ public: const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering); + // Scale the crop down horizontally or vertically such that it has the + // same aspect ratio as the buffer does. + static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight); + // getTimestamp retrieves the timestamp associated with the texture image // set by the most recent call to updateTexImage. // @@ -197,22 +201,9 @@ public: // buffer is ready to be read from. std::shared_ptr<FenceTime> getCurrentFenceTime() const; - // doGLFenceWait inserts a wait command into the OpenGL ES command stream - // to ensure that it is safe for future OpenGL ES commands to access the - // current texture buffer. - status_t doGLFenceWait() const; - - // set the name of the GLConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - - // These functions call the corresponding BufferQueue implementation - // so the refactoring can proceed smoothly - status_t setDefaultBufferFormat(PixelFormat defaultFormat); - status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); + // setConsumerUsageBits overrides the ConsumerBase method to OR + // DEFAULT_USAGE_FLAGS to usage. status_t setConsumerUsageBits(uint64_t usage); - status_t setTransformHint(uint32_t hint); - status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); // detachFromContext detaches the GLConsumer from the calling thread's // current OpenGL ES context. This context must be the same as the context @@ -267,8 +258,6 @@ protected: return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence); } - static bool isExternalFormat(PixelFormat format); - struct PendingRelease { PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer(), display(nullptr), fence(nullptr) {} diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index b2267426a8..e26e332589 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -29,6 +29,7 @@ #include <ui/FrameStats.h> #include <ui/PixelFormat.h> +#include <ui/GraphicBuffer.h> #include <vector> @@ -167,12 +168,14 @@ public: /* Capture the specified screen. requires READ_FRAME_BUFFER permission * This function will fail if there is a secure window on screen. */ - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - Rotation rotation = eRotateNone) = 0; + virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, + Rotation rotation = eRotateNone) = 0; + + virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder, + sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop, + float frameScale = 1.0) = 0; /* Clears the frame statistics for animations. * @@ -226,6 +229,7 @@ public: SET_ACTIVE_CONFIG, CONNECT_DISPLAY, CAPTURE_SCREEN, + CAPTURE_LAYERS, CLEAR_ANIMATION_FRAME_STATS, GET_ANIMATION_FRAME_STATS, SET_POWER_MODE, diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 2c613ea8c5..d5bbef25f8 100644 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h @@ -41,7 +41,7 @@ public: eCursorWindow = 0x00002000, eFXSurfaceNormal = 0x00000000, - eFXSurfaceDim = 0x00020000, + eFXSurfaceColor = 0x00020000, eFXSurfaceMask = 0x000F0000, }; diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h index 8453e043ef..92bd8c5b28 100644 --- a/libs/gui/include/gui/LayerDebugInfo.h +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -22,6 +22,7 @@ #include <ui/Region.h> #include <string> +#include <math/vec4.h> namespace android { @@ -52,7 +53,7 @@ public: int32_t mHeight = -1; Rect mCrop = Rect::INVALID_RECT; Rect mFinalCrop = Rect::INVALID_RECT; - float mAlpha = 0.f; + half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf); uint32_t mFlags = 0; PixelFormat mPixelFormat = PIXEL_FORMAT_NONE; android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 307c764702..f3fb82feb3 100644 --- a/libs/gui/include/private/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -25,6 +25,7 @@ #include <ui/Region.h> #include <ui/Rect.h> #include <gui/IGraphicBufferProducer.h> +#include <math/vec3.h> namespace android { @@ -59,7 +60,9 @@ struct layer_state_t { eGeometryAppliesWithResize = 0x00001000, eReparentChildren = 0x00002000, eDetachChildren = 0x00004000, - eRelativeLayerChanged = 0x00008000 + eRelativeLayerChanged = 0x00008000, + eReparent = 0x00010000, + eColorChanged = 0x00020000 }; layer_state_t() @@ -74,6 +77,7 @@ struct layer_state_t { matrix.dsdy = matrix.dtdx = 0.0f; } + void merge(const layer_state_t& other); status_t write(Parcel& output) const; status_t read(const Parcel& input); @@ -107,6 +111,10 @@ struct layer_state_t { sp<IBinder> relativeLayerHandle; + sp<IBinder> parentHandleForChild; + + half3 color; + // non POD must be last. see write/read Region transparentRegion; }; @@ -137,6 +145,7 @@ struct DisplayState { }; DisplayState(); + void merge(const DisplayState& other); uint32_t what; sp<IBinder> token; @@ -150,6 +159,20 @@ struct DisplayState { status_t read(const Parcel& input); }; +static inline +int compare_type(const ComposerState& lhs, const ComposerState& rhs) { + if (lhs.client < rhs.client) return -1; + if (lhs.client > rhs.client) return 1; + if (lhs.state.surface < rhs.state.surface) return -1; + if (lhs.state.surface > rhs.state.surface) return 1; + return 0; +} + +static inline +int compare_type(const DisplayState& lhs, const DisplayState& rhs) { + return compare_type(lhs.token, rhs.token); +} + }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 55dd6bf067..354f23ab06 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -281,6 +281,10 @@ public: // detachNextBuffer, or attachBuffer call. status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out); + android_dataspace_t getBuffersDataSpace(); + + static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer); + protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 145c0597bd..55b96ac93d 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -32,13 +32,14 @@ #include <gui/CpuConsumer.h> #include <gui/SurfaceControl.h> +#include <math/vec3.h> +#include <gui/LayerState.h> namespace android { // --------------------------------------------------------------------------- struct DisplayInfo; -class Composer; class HdrCapabilities; class ISurfaceComposerClient; class IGraphicBufferProducer; @@ -51,6 +52,7 @@ class SurfaceComposerClient : public RefBase friend class Composer; public: SurfaceComposerClient(); + SurfaceComposerClient(const sp<ISurfaceComposerClient>& client); SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent); virtual ~SurfaceComposerClient(); @@ -121,157 +123,173 @@ public: //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi. static sp<IBinder> getBuiltInDisplay(int32_t id); - // ------------------------------------------------------------------------ - // Composer parameters - // All composer parameters must be changed within a transaction - // several surfaces can be updated in one transaction, all changes are - // committed at once when the transaction is closed. - // closeGlobalTransaction() requires an IPC with the server. - - //! Open a composer transaction on all active SurfaceComposerClients. - static void openGlobalTransaction(); - - //! Close a composer transaction on all active SurfaceComposerClients. - static void closeGlobalTransaction(bool synchronous = false); - static status_t enableVSyncInjections(bool enable); static status_t injectVSync(nsecs_t when); - //! Flag the currently open transaction as an animation transaction. - static void setAnimationTransaction(); - - status_t hide(const sp<IBinder>& id); - status_t show(const sp<IBinder>& id); - status_t setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent); - status_t setLayer(const sp<IBinder>& id, int32_t layer); - status_t setRelativeLayer(const sp<IBinder>& id, - const sp<IBinder>& relativeTo, int32_t layer); - status_t setAlpha(const sp<IBinder>& id, float alpha=1.0f); - status_t setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy); - status_t setPosition(const sp<IBinder>& id, float x, float y); - status_t setSize(const sp<IBinder>& id, uint32_t w, uint32_t h); - status_t setCrop(const sp<IBinder>& id, const Rect& crop); - status_t setFinalCrop(const sp<IBinder>& id, const Rect& crop); - status_t setLayerStack(const sp<IBinder>& id, uint32_t layerStack); - status_t deferTransactionUntil(const sp<IBinder>& id, - const sp<IBinder>& handle, uint64_t frameNumber); - status_t deferTransactionUntil(const sp<IBinder>& id, - const sp<Surface>& handle, uint64_t frameNumber); - status_t reparentChildren(const sp<IBinder>& id, - const sp<IBinder>& newParentHandle); - status_t detachChildren(const sp<IBinder>& id); - status_t setOverrideScalingMode(const sp<IBinder>& id, - int32_t overrideScalingMode); - status_t setGeometryAppliesWithResize(const sp<IBinder>& id); + class Transaction { + SortedVector<ComposerState> mComposerStates; + SortedVector<DisplayState > mDisplayStates; + uint32_t mForceSynchronous = 0; + uint32_t mTransactionNestCount = 0; + bool mAnimation = false; + + int mStatus = NO_ERROR; + + layer_state_t* getLayerStateLocked(const sp<SurfaceControl>& sc); + DisplayState& getDisplayStateLocked(const sp<IBinder>& token); + + public: + Transaction() = default; + virtual ~Transaction() = default; + Transaction(Transaction const& other); + + status_t apply(bool synchronous = false); + // Merge another transaction in to this one, clearing other + // as if it had been applied. + Transaction& merge(Transaction&& other); + Transaction& show(const sp<SurfaceControl>& sc); + Transaction& hide(const sp<SurfaceControl>& sc); + Transaction& setPosition(const sp<SurfaceControl>& sc, + float x, float y); + Transaction& setSize(const sp<SurfaceControl>& sc, + uint32_t w, uint32_t h); + Transaction& setLayer(const sp<SurfaceControl>& sc, + int32_t z); + + // Sets a Z order relative to the Surface specified by "relativeTo" but + // without becoming a full child of the relative. Z-ordering works exactly + // as if it were a child however. + // + // As a nod to sanity, only non-child surfaces may have a relative Z-order. + // + // This overrides any previous call and is overriden by any future calls + // to setLayer. + // + // If the relative is removed, the Surface will have no layer and be + // invisible, until the next time set(Relative)Layer is called. + Transaction& setRelativeLayer(const sp<SurfaceControl>& sc, + const sp<IBinder>& relativeTo, int32_t z); + Transaction& setFlags(const sp<SurfaceControl>& sc, + uint32_t flags, uint32_t mask); + Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc, + const Region& transparentRegion); + Transaction& setAlpha(const sp<SurfaceControl>& sc, + float alpha); + Transaction& setMatrix(const sp<SurfaceControl>& sc, + float dsdx, float dtdx, float dtdy, float dsdy); + Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop); + Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop); + Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack); + // Defers applying any changes made in this transaction until the Layer + // identified by handle reaches the given frameNumber. If the Layer identified + // by handle is removed, then we will apply this transaction regardless of + // what frame number has been reached. + Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc, + const sp<IBinder>& handle, + uint64_t frameNumber); + // A variant of deferTransactionUntil which identifies the Layer we wait for by + // Surface instead of Handle. Useful for clients which may not have the + // SurfaceControl for some of their Surfaces. Otherwise behaves identically. + Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc, + const sp<Surface>& barrierSurface, + uint64_t frameNumber); + // Reparents all children of this layer to the new parent handle. + Transaction& reparentChildren(const sp<SurfaceControl>& sc, + const sp<IBinder>& newParentHandle); + + /// Reparents the current layer to the new parent handle. The new parent must not be null. + // This can be used instead of reparentChildren if the caller wants to + // only re-parent a specific child. + Transaction& reparent(const sp<SurfaceControl>& sc, + const sp<IBinder>& newParentHandle); + + Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color); + + // Detaches all child surfaces (and their children recursively) + // from their SurfaceControl. + // The child SurfaceControls will not throw exceptions or return errors, + // but transactions will have no effect. + // The child surfaces will continue to follow their parent surfaces, + // and remain eligible for rendering, but their relative state will be + // frozen. We use this in the WindowManager, in app shutdown/relaunch + // scenarios, where the app would otherwise clean up its child Surfaces. + // Sometimes the WindowManager needs to extend their lifetime slightly + // in order to perform an exit animation or prevent flicker. + Transaction& detachChildren(const sp<SurfaceControl>& sc); + // Set an override scaling mode as documented in <system/window.h> + // the override scaling mode will take precedence over any client + // specified scaling mode. -1 will clear the override scaling mode. + Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc, + int32_t overrideScalingMode); + + // If the size changes in this transaction, all geometry updates specified + // in this transaction will not complete until a buffer of the new size + // arrives. As some elements normally apply immediately, this enables + // freezing the total geometry of a surface until a resize is completed. + Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc); + + status_t setDisplaySurface(const sp<IBinder>& token, + const sp<IGraphicBufferProducer>& bufferProducer); + + void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); + + /* setDisplayProjection() defines the projection of layer stacks + * to a given display. + * + * - orientation defines the display's orientation. + * - layerStackRect defines which area of the window manager coordinate + * space will be used. + * - displayRect defines where on the display will layerStackRect be + * mapped to. displayRect is specified post-orientation, that is + * it uses the orientation seen by the end-user. + */ + void setDisplayProjection(const sp<IBinder>& token, + uint32_t orientation, + const Rect& layerStackRect, + const Rect& displayRect); + void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); + void setAnimationTransaction(); + }; status_t destroySurface(const sp<IBinder>& id); status_t clearLayerFrameStats(const sp<IBinder>& token) const; status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const; - static status_t clearAnimationFrameStats(); static status_t getAnimationFrameStats(FrameStats* outStats); static status_t getHdrCapabilities(const sp<IBinder>& display, HdrCapabilities* outCapabilities); - static status_t setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer); - static void setDisplayLayerStack(const sp<IBinder>& token, - uint32_t layerStack); - static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); - - /* setDisplayProjection() defines the projection of layer stacks - * to a given display. - * - * - orientation defines the display's orientation. - * - layerStackRect defines which area of the window manager coordinate - * space will be used. - * - displayRect defines where on the display will layerStackRect be - * mapped to. displayRect is specified post-orientation, that is - * it uses the orientation seen by the end-user. - */ static void setDisplayProjection(const sp<IBinder>& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect); + inline sp<ISurfaceComposerClient> getClient() { return mClient; } + private: virtual void onFirstRef(); - Composer& getComposer(); mutable Mutex mLock; status_t mStatus; sp<ISurfaceComposerClient> mClient; - Composer& mComposer; wp<IGraphicBufferProducer> mParent; }; // --------------------------------------------------------------------------- -class ScreenshotClient -{ +class ScreenshotClient { public: // if cropping isn't required, callers may pass in a default Rect, e.g.: // capture(display, producer, Rect(), reqWidth, ...); - static status_t capture( - const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform); - static status_t captureToBuffer( - const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - uint32_t rotation, - sp<GraphicBuffer>* outbuffer); -private: - mutable sp<CpuConsumer> mCpuConsumer; - mutable sp<IGraphicBufferProducer> mProducer; - CpuConsumer::LockedBuffer mBuffer; - bool mHaveBuffer; - -public: - ScreenshotClient(); - ~ScreenshotClient(); - - // frees the previous screenshot and captures a new one - // if cropping isn't required, callers may pass in a default Rect, e.g.: - // update(display, Rect(), useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, bool useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - bool useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation); - - sp<CpuConsumer> getCpuConsumer() const; - - // release memory occupied by the screenshot - void release(); - - // pixels are valid until this object is freed or - // release() or update() is called - void const* getPixels() const; - - uint32_t getWidth() const; - uint32_t getHeight() const; - PixelFormat getFormat() const; - uint32_t getStride() const; - // size of allocated memory in bytes - size_t getSize() const; - android_dataspace getDataSpace() const; + static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth, + uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, uint32_t rotation, + sp<GraphicBuffer>* outBuffer); + static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float fameScale, + sp<GraphicBuffer>* outBuffer); }; // --------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index c15209d32c..1416d87110 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -29,6 +29,7 @@ #include <ui/Region.h> #include <gui/ISurfaceComposerClient.h> +#include <math/vec3.h> namespace android { @@ -43,6 +44,9 @@ class SurfaceComposerClient; class SurfaceControl : public RefBase { public: + static sp<SurfaceControl> readFromParcel(Parcel* parcel); + void writeToParcel(Parcel* parcel); + static bool isValid(const sp<SurfaceControl>& surface) { return (surface != 0) && surface->isValid(); } @@ -60,87 +64,6 @@ public: // disconnect any api that's connected void disconnect(); - status_t setLayerStack(uint32_t layerStack); - status_t setLayer(int32_t layer); - - // Sets a Z order relative to the Surface specified by "relativeTo" but - // without becoming a full child of the relative. Z-ordering works exactly - // as if it were a child however. - // - // As a nod to sanity, only non-child surfaces may have a relative Z-order. - // - // This overrides any previous and is overriden by any future calls - // to setLayer. - // - // If the relative dissapears, the Surface will have no layer and be - // invisible, until the next time set(Relative)Layer is called. - // - // TODO: This is probably a hack. Currently it exists only to work around - // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type - // which allows inserting a window between a SurfaceView and it's main application - // window. However, since we are using child windows for the SurfaceView, but not using - // child windows elsewhere in O, the WindowManager can't set the layer appropriately. - // This is only used by the "TvInputService" and following the port of ViewRootImpl - // to child surfaces, we can then port this and remove this method. - status_t setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer); - status_t setPosition(float x, float y); - status_t setSize(uint32_t w, uint32_t h); - status_t hide(); - status_t show(); - status_t setFlags(uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint(const Region& transparent); - status_t setAlpha(float alpha=1.0f); - - // Experimentarily it appears that the matrix transforms the - // on-screen rectangle and it's contents before the position is - // applied. - // - // TODO: Test with other combinations to find approximate transformation rules. - // - // For example: - // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives - // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y)) - status_t setMatrix(float dsdx, float dtdx, float dtdy, float dsdy); - status_t setCrop(const Rect& crop); - status_t setFinalCrop(const Rect& crop); - - // If the size changes in this transaction, all geometry updates specified - // in this transaction will not complete until a buffer of the new size - // arrives. As some elements normally apply immediately, this enables - // freezing the total geometry of a surface until a resize is completed. - status_t setGeometryAppliesWithResize(); - - // Defers applying any changes made in this transaction until the Layer - // identified by handle reaches the given frameNumber. If the Layer identified - // by handle is removed, then we will apply this transaction regardless of - // what frame number has been reached. - status_t deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber); - - // A variant of deferTransactionUntil which identifies the Layer we wait for by - // Surface instead of Handle. Useful for clients which may not have the - // SurfaceControl for some of their Surfaces. Otherwise behaves identically. - status_t deferTransactionUntil(const sp<Surface>& barrier, uint64_t frameNumber); - - // Reparents all children of this layer to the new parent handle. - status_t reparentChildren(const sp<IBinder>& newParentHandle); - - // Detaches all child surfaces (and their children recursively) - // from their SurfaceControl. - // The child SurfaceControl's will not throw exceptions or return errors, - // but transactions will have no effect. - // The child surfaces will continue to follow their parent surfaces, - // and remain eligible for rendering, but their relative state will be - // frozen. We use this in the WindowManager, in app shutdown/relaunch - // scenarios, where the app would otherwise clean up its child Surfaces. - // Sometimes the WindowManager needs to extend their lifetime slightly - // in order to perform an exit animation or prevent flicker. - status_t detachChildren(); - - // Set an override scaling mode as documented in <system/window.h> - // the override scaling mode will take precedence over any client - // specified scaling mode. -1 will clear the override scaling mode. - status_t setOverrideScalingMode(int32_t overrideScalingMode); - static status_t writeSurfaceToParcel( const sp<SurfaceControl>& control, Parcel* parcel); @@ -151,6 +74,8 @@ public: status_t clearLayerFrameStats() const; status_t getLayerFrameStats(FrameStats* outStats) const; + sp<SurfaceComposerClient> getClient() const; + private: // can't be copied SurfaceControl& operator = (SurfaceControl& rhs); diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index 588e54142f..36be7d9368 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -33,6 +33,7 @@ #include <utils/Mutex.h> #include <utils/Condition.h> +#include <thread> #include <vector> #define CPU_CONSUMER_TEST_FORMAT_RAW 0 #define CPU_CONSUMER_TEST_FORMAT_Y8 0 @@ -681,6 +682,70 @@ TEST_P(CpuConsumerTest, FromCpuLockMax) { } } +TEST_P(CpuConsumerTest, FromCpuInvalid) { + status_t err = mCC->lockNextBuffer(nullptr); + ASSERT_EQ(BAD_VALUE, err) << "lockNextBuffer did not fail"; + + CpuConsumer::LockedBuffer b; + err = mCC->unlockBuffer(b); + ASSERT_EQ(BAD_VALUE, err) << "unlockBuffer did not fail"; +} + +TEST_P(CpuConsumerTest, FromCpuMultiThread) { + CpuConsumerTestParams params = GetParam(); + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1)); + + for (int i = 0; i < 10; i++) { + std::atomic<int> threadReadyCount(0); + auto lockAndUnlock = [&]() { + threadReadyCount++; + // busy wait + while (threadReadyCount < params.maxLockedBuffers + 1); + + CpuConsumer::LockedBuffer b; + status_t err = mCC->lockNextBuffer(&b); + if (err == NO_ERROR) { + usleep(1000); + err = mCC->unlockBuffer(b); + ASSERT_NO_ERROR(err, "Could not unlock buffer: "); + } else if (err == NOT_ENOUGH_DATA) { + // there are params.maxLockedBuffers+1 threads so one of the + // threads might get this error + } else { + FAIL() << "Could not lock buffer"; + } + }; + + // produce buffers + for (int j = 0; j < params.maxLockedBuffers + 1; j++) { + const int64_t time = 1234L; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, &stride)); + } + + // spawn threads + std::vector<std::thread> threads; + for (int j = 0; j < params.maxLockedBuffers + 1; j++) { + threads.push_back(std::thread(lockAndUnlock)); + } + + // join threads + for (auto& thread : threads) { + thread.join(); + } + + // we produced N+1 buffers, but the threads might only consume N + CpuConsumer::LockedBuffer b; + if (mCC->lockNextBuffer(&b) == NO_ERROR) { + mCC->unlockBuffer(b); + } + + if (HasFatalFailure()) { + break; + } + } +} + CpuConsumerTestParams y8TestSets[] = { { 512, 512, 1, HAL_PIXEL_FORMAT_Y8}, { 512, 512, 3, HAL_PIXEL_FORMAT_Y8}, diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp index 1739d9c7ca..a91552f7fe 100644 --- a/libs/gui/tests/GLTest.cpp +++ b/libs/gui/tests/GLTest.cpp @@ -22,6 +22,8 @@ namespace android { +using Transaction = SurfaceComposerClient::Transaction; + static int abs(int value) { return value > 0 ? value : -value; } @@ -68,10 +70,10 @@ void GLTest::SetUp() { ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); - ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); + Transaction t; + ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7FFFFFFF) + .show(mSurfaceControl) + .apply()); sp<ANativeWindow> window = mSurfaceControl->getSurface(); mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index ca43c68f92..470a338639 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -42,6 +42,8 @@ using namespace std::chrono_literals; using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +using Transaction = SurfaceComposerClient::Transaction; + static bool hasWideColorDisplay = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); @@ -69,10 +71,10 @@ protected: ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff)); - ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); + Transaction t; + ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff) + .show(mSurfaceControl) + .apply()); mSurface = mSurfaceControl->getSurface(); ASSERT_TRUE(mSurface != NULL); @@ -114,14 +116,11 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp<ANativeWindow> anw(mSurface); // Verify the screenshot works with no protected buffers. - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); sp<IBinder> display(sf->getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain)); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), + sp<GraphicBuffer> outBuffer; + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), 64, 64, 0, 0x7fffffff, false)); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), @@ -152,7 +151,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { &buf)); ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), 64, 64, 0, 0x7fffffff, false)); } @@ -522,11 +521,16 @@ public: status_t setActiveColorMode(const sp<IBinder>& /*display*/, android_color_mode_t /*colorMode*/) override { return NO_ERROR; } status_t captureScreen(const sp<IBinder>& /*display*/, - const sp<IGraphicBufferProducer>& /*producer*/, + sp<GraphicBuffer>* /*outBuffer*/, Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/, int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/, bool /*useIdentityTransform*/, Rotation /*rotation*/) override { return NO_ERROR; } + virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/, + sp<GraphicBuffer>* /*outBuffer*/, + const Rect& /*sourceCrop*/, float /*frameScale*/) override { + return NO_ERROR; + } status_t clearAnimationFrameStats() override { return NO_ERROR; } status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { return NO_ERROR; diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 9abd04ca04..5fe8d8bc9c 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -99,34 +99,34 @@ size_t InputMessage::size() const { // --- InputChannel --- -InputChannel::InputChannel(const String8& name, int fd) : +InputChannel::InputChannel(const std::string& name, int fd) : mName(name), mFd(fd) { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel constructed: name='%s', fd=%d", - mName.string(), fd); + mName.c_str(), fd); #endif int result = fcntl(mFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket " - "non-blocking. errno=%d", mName.string(), errno); + "non-blocking. errno=%d", mName.c_str(), errno); } InputChannel::~InputChannel() { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel destroyed: name='%s', fd=%d", - mName.string(), mFd); + mName.c_str(), mFd); #endif ::close(mFd); } -status_t InputChannel::openInputChannelPair(const String8& name, +status_t InputChannel::openInputChannelPair(const std::string& name, sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { status_t result = -errno; ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", - name.string(), errno); + name.c_str(), errno); outServerChannel.clear(); outClientChannel.clear(); return result; @@ -138,12 +138,12 @@ status_t InputChannel::openInputChannelPair(const String8& name, setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); - String8 serverChannelName = name; - serverChannelName.append(" (server)"); + std::string serverChannelName = name; + serverChannelName += " (server)"; outServerChannel = new InputChannel(serverChannelName, sockets[0]); - String8 clientChannelName = name; - clientChannelName.append(" (client)"); + std::string clientChannelName = name; + clientChannelName += " (client)"; outClientChannel = new InputChannel(clientChannelName, sockets[1]); return OK; } @@ -158,7 +158,7 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { if (nWrite < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(), + ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(), msg->header.type, error); #endif if (error == EAGAIN || error == EWOULDBLOCK) { @@ -173,13 +173,13 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { if (size_t(nWrite) != msgLength) { #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ error sending message type %d, send was incomplete", - mName.string(), msg->header.type); + mName.c_str(), msg->header.type); #endif return DEAD_OBJECT; } #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type); + ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type); #endif return OK; } @@ -193,7 +193,7 @@ status_t InputChannel::receiveMessage(InputMessage* msg) { if (nRead < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno); + ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno); #endif if (error == EAGAIN || error == EWOULDBLOCK) { return WOULD_BLOCK; @@ -206,20 +206,20 @@ status_t InputChannel::receiveMessage(InputMessage* msg) { if (nRead == 0) { // check for EOF #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string()); + ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str()); #endif return DEAD_OBJECT; } if (!msg->isValid(nRead)) { #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received invalid message", mName.string()); + ALOGD("channel '%s' ~ received invalid message", mName.c_str()); #endif return BAD_VALUE; } #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type); + ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type); #endif return OK; } @@ -254,8 +254,8 @@ status_t InputPublisher::publishKeyEvent( #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d," - "downTime=%lld, eventTime=%lld", - mChannel->getName().string(), seq, + "downTime=%" PRId64 ", eventTime=%" PRId64, + mChannel->getName().c_str(), seq, deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, downTime, eventTime); #endif @@ -305,9 +305,9 @@ status_t InputPublisher::publishMotionEvent( ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, " "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, " - "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " + "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", " "pointerCount=%" PRIu32, - mChannel->getName().string(), seq, + mChannel->getName().c_str(), seq, deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); #endif @@ -319,7 +319,7 @@ status_t InputPublisher::publishMotionEvent( if (pointerCount > MAX_POINTERS || pointerCount < 1) { ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".", - mChannel->getName().string(), pointerCount); + mChannel->getName().c_str(), pointerCount); return BAD_VALUE; } @@ -352,7 +352,7 @@ status_t InputPublisher::publishMotionEvent( status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ receiveFinishedSignal", - mChannel->getName().string()); + mChannel->getName().c_str()); #endif InputMessage msg; @@ -364,7 +364,7 @@ status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandle } if (msg.header.type != InputMessage::TYPE_FINISHED) { ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer", - mChannel->getName().string(), msg.header.type); + mChannel->getName().c_str(), msg.header.type); return UNKNOWN_ERROR; } *outSeq = msg.body.finished.seq; @@ -401,8 +401,8 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) { #if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld", - mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime); + ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64, + mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime); #endif *outSeq = 0; @@ -426,7 +426,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, if (*outEvent) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } @@ -445,7 +445,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, *outEvent = keyEvent; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed key event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } @@ -458,7 +458,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ appended to batch event", - mChannel->getName().string()); + mChannel->getName().c_str()); #endif break; } else { @@ -474,7 +474,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event and " "deferred current event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } @@ -488,7 +488,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ started batch event", - mChannel->getName().string()); + mChannel->getName().c_str()); #endif break; } @@ -503,14 +503,14 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, *displayId = mMsg.body.motion.displayId; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } default: ALOGE("channel '%s' consumer ~ Received unexpected message of type %d", - mChannel->getName().string(), mMsg.header.type); + mChannel->getName().c_str(), mMsg.header.type); return UNKNOWN_ERROR; } } @@ -828,7 +828,7 @@ bool InputConsumer::shouldResampleTool(int32_t toolType) { status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s", - mChannel->getName().string(), seq, handled ? "true" : "false"); + mChannel->getName().c_str(), seq, handled ? "true" : "false"); #endif if (!seq) { diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 62acea360e..e54f147621 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -75,7 +75,9 @@ static std::string vectorToString(const float* a, uint32_t m) { str += " ]"; return str; } +#endif +#if DEBUG_STRATEGY static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { std::string str; str = "["; @@ -141,6 +143,11 @@ bool VelocityTracker::configureStrategy(const char* strategy) { } VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) { + if (!strcmp("impulse", strategy)) { + // Physical model of pushing an object. Quality: VERY GOOD. + // Works with duplicate coordinates, unclean finger liftoff. + return new ImpulseVelocityTrackerStrategy(); + } if (!strcmp("lsq1", strategy)) { // 1st order least squares. Quality: POOR. // Frequently underfits the touch data especially when the finger accelerates @@ -352,9 +359,6 @@ bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const { // --- LeastSquaresVelocityTrackerStrategy --- -const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON; -const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE; - LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy( uint32_t degree, Weighting weighting) : mDegree(degree), mWeighting(weighting) { @@ -863,10 +867,6 @@ void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, // --- LegacyVelocityTrackerStrategy --- -const nsecs_t LegacyVelocityTrackerStrategy::HORIZON; -const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE; -const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION; - LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() { clear(); } @@ -979,4 +979,194 @@ bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, return true; } +// --- ImpulseVelocityTrackerStrategy --- + +ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() { + clear(); +} + +ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() { +} + +void ImpulseVelocityTrackerStrategy::clear() { + mIndex = 0; + mMovements[0].idBits.clear(); +} + +void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { + BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); + mMovements[mIndex].idBits = remainingIdBits; +} + +void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, + const VelocityTracker::Position* positions) { + if (++mIndex == HISTORY_SIZE) { + mIndex = 0; + } + + Movement& movement = mMovements[mIndex]; + movement.eventTime = eventTime; + movement.idBits = idBits; + uint32_t count = idBits.count(); + for (uint32_t i = 0; i < count; i++) { + movement.positions[i] = positions[i]; + } +} + +/** + * Calculate the total impulse provided to the screen and the resulting velocity. + * + * The touchscreen is modeled as a physical object. + * Initial condition is discussed below, but for now suppose that v(t=0) = 0 + * + * The kinetic energy of the object at the release is E=0.5*m*v^2 + * Then vfinal = sqrt(2E/m). The goal is to calculate E. + * + * The kinetic energy at the release is equal to the total work done on the object by the finger. + * The total work W is the sum of all dW along the path. + * + * dW = F*dx, where dx is the piece of path traveled. + * Force is change of momentum over time, F = dp/dt = m dv/dt. + * Then substituting: + * dW = m (dv/dt) * dx = m * v * dv + * + * Summing along the path, we get: + * W = sum(dW) = sum(m * v * dv) = m * sum(v * dv) + * Since the mass stays constant, the equation for final velocity is: + * vfinal = sqrt(2*sum(v * dv)) + * + * Here, + * dv : change of velocity = (v[i+1]-v[i]) + * dx : change of distance = (x[i+1]-x[i]) + * dt : change of time = (t[i+1]-t[i]) + * v : instantaneous velocity = dx/dt + * + * The final formula is: + * vfinal = sqrt(2) * sqrt(sum((v[i]-v[i-1])*|v[i]|)) for all i + * The absolute value is needed to properly account for the sign. If the velocity over a + * particular segment descreases, then this indicates braking, which means that negative + * work was done. So for two positive, but decreasing, velocities, this contribution would be + * negative and will cause a smaller final velocity. + * + * Initial condition + * There are two ways to deal with initial condition: + * 1) Assume that v(0) = 0, which would mean that the screen is initially at rest. + * This is not entirely accurate. We are only taking the past X ms of touch data, where X is + * currently equal to 100. However, a touch event that created a fling probably lasted for longer + * than that, which would mean that the user has already been interacting with the touchscreen + * and it has probably already been moving. + * 2) Assume that the touchscreen has already been moving at a certain velocity, calculate this + * initial velocity and the equivalent energy, and start with this initial energy. + * Consider an example where we have the following data, consisting of 3 points: + * time: t0, t1, t2 + * x : x0, x1, x2 + * v : 0 , v1, v2 + * Here is what will happen in each of these scenarios: + * 1) By directly applying the formula above with the v(0) = 0 boundary condition, we will get + * vfinal = sqrt(2*(|v1|*(v1-v0) + |v2|*(v2-v1))). This can be simplified since v0=0 + * vfinal = sqrt(2*(|v1|*v1 + |v2|*(v2-v1))) = sqrt(2*(v1^2 + |v2|*(v2 - v1))) + * since velocity is a real number + * 2) If we treat the screen as already moving, then it must already have an energy (per mass) + * equal to 1/2*v1^2. Then the initial energy should be 1/2*v1*2, and only the second segment + * will contribute to the total kinetic energy (since we can effectively consider that v0=v1). + * This will give the following expression for the final velocity: + * vfinal = sqrt(2*(1/2*v1^2 + |v2|*(v2-v1))) + * This analysis can be generalized to an arbitrary number of samples. + * + * + * Comparing the two equations above, we see that the only mathematical difference + * is the factor of 1/2 in front of the first velocity term. + * This boundary condition would allow for the "proper" calculation of the case when all of the + * samples are equally spaced in time and distance, which should suggest a constant velocity. + * + * Note that approach 2) is sensitive to the proper ordering of the data in time, since + * the boundary condition must be applied to the oldest sample to be accurate. + */ +static float kineticEnergyToVelocity(float work) { + static constexpr float sqrt2 = 1.41421356237; + return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2; +} + +static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) { + // The input should be in reversed time order (most recent sample at index i=0) + // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function + static constexpr float NANOS_PER_SECOND = 1E-9; + + if (count < 2) { + return 0; // if 0 or 1 points, velocity is zero + } + if (t[1] > t[0]) { // Algorithm will still work, but not perfectly + ALOGE("Samples provided to calculateImpulseVelocity in the wrong order"); + } + if (count == 2) { // if 2 points, basic linear calculation + if (t[1] == t[0]) { + ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]); + return 0; + } + return (x[1] - x[0]) / (NANOS_PER_SECOND * (t[1] - t[0])); + } + // Guaranteed to have at least 3 points here + float work = 0; + for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time + if (t[i] == t[i-1]) { + ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]); + continue; + } + float vprev = kineticEnergyToVelocity(work); // v[i-1] + float vcurr = (x[i] - x[i-1]) / (NANOS_PER_SECOND * (t[i] - t[i-1])); // v[i] + work += (vcurr - vprev) * fabsf(vcurr); + if (i == count - 1) { + work *= 0.5; // initial condition, case 2) above + } + } + return kineticEnergyToVelocity(work); +} + +bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id, + VelocityTracker::Estimator* outEstimator) const { + outEstimator->clear(); + + // Iterate over movement samples in reverse time order and collect samples. + float x[HISTORY_SIZE]; + float y[HISTORY_SIZE]; + nsecs_t time[HISTORY_SIZE]; + size_t m = 0; // number of points that will be used for fitting + size_t index = mIndex; + const Movement& newestMovement = mMovements[mIndex]; + do { + const Movement& movement = mMovements[index]; + if (!movement.idBits.hasBit(id)) { + break; + } + + nsecs_t age = newestMovement.eventTime - movement.eventTime; + if (age > HORIZON) { + break; + } + + const VelocityTracker::Position& position = movement.getPosition(id); + x[m] = position.x; + y[m] = position.y; + time[m] = movement.eventTime; + index = (index == 0 ? HISTORY_SIZE : index) - 1; + } while (++m < HISTORY_SIZE); + + if (m == 0) { + return false; // no data + } + outEstimator->xCoeff[0] = 0; + outEstimator->yCoeff[0] = 0; + outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m); + outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m); + outEstimator->xCoeff[2] = 0; + outEstimator->yCoeff[2] = 0; + outEstimator->time = newestMovement.eventTime; + outEstimator->degree = 2; // similar results to 2nd degree fit + outEstimator->confidence = 1; +#if DEBUG_STRATEGY + ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]); +#endif + return true; +} + } // namespace android diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 0028655075..aca9521c76 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -6,11 +6,12 @@ cc_test { "InputChannel_test.cpp", "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", + "VelocityTracker_test.cpp", ], cflags: [ "-Wall", + "-Wextra", "-Werror", - "-Wno-error=sign-compare", // to fix later "-Wno-unused-variable", ], shared_libs: [ @@ -19,6 +20,7 @@ cc_test { "libutils", "libbinder", "libui", + "libbase", ] } diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp index e71ebe2a1d..96c165cac2 100644 --- a/libs/input/tests/InputChannel_test.cpp +++ b/libs/input/tests/InputChannel_test.cpp @@ -41,9 +41,9 @@ TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptor // of a pipe and to check for EPIPE on the other end after the channel is destroyed. Pipe pipe; - sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd); + sp<InputChannel> inputChannel = new InputChannel("channel name", pipe.sendFd); - EXPECT_STREQ("channel name", inputChannel->getName().string()) + EXPECT_STREQ("channel name", inputChannel->getName().c_str()) << "channel should have provided name"; EXPECT_EQ(pipe.sendFd, inputChannel->getFd()) << "channel should have provided fd"; @@ -60,16 +60,16 @@ TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptor TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { sp<InputChannel> serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; // Name - EXPECT_STREQ("channel name (server)", serverChannel->getName().string()) + EXPECT_STREQ("channel name (server)", serverChannel->getName().c_str()) << "server channel should have suffixed name"; - EXPECT_STREQ("channel name (client)", clientChannel->getName().string()) + EXPECT_STREQ("channel name (client)", clientChannel->getName().c_str()) << "client channel should have suffixed name"; // Server->Client communication @@ -111,7 +111,7 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) { sp<InputChannel> serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) @@ -125,7 +125,7 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) { TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { sp<InputChannel> serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) @@ -141,7 +141,7 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) { sp<InputChannel> serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 3fb1c6df9b..fd3b7c8ee4 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -184,7 +184,7 @@ TEST_F(KeyEventTest, Properties) { ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType()); ASSERT_EQ(2, event.getDeviceId()); - ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource()); + ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_GAMEPAD), event.getSource()); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction()); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags()); ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode()); @@ -196,7 +196,7 @@ TEST_F(KeyEventTest, Properties) { // Set source. event.setSource(AINPUT_SOURCE_JOYSTICK); - ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource()); + ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource()); } @@ -300,7 +300,7 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { // Check properties. ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType()); ASSERT_EQ(2, event->getDeviceId()); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource()); + ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_TOUCHSCREEN), event->getSource()); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction()); ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags()); ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags()); @@ -432,7 +432,7 @@ TEST_F(MotionEventTest, Properties) { // Set source. event.setSource(AINPUT_SOURCE_JOYSTICK); - ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource()); + ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource()); // Set action. event.setAction(AMOTION_EVENT_ACTION_CANCEL); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index a1367387bc..c5322414fd 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -36,7 +36,7 @@ protected: PreallocatedInputEventFactory mEventFactory; virtual void SetUp() { - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); mPublisher = new InputPublisher(serverChannel); @@ -89,8 +89,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { uint32_t consumeSeq; InputEvent* event; + int32_t displayId; status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event, - 0); + &displayId); ASSERT_EQ(OK, status) << "consumer consume should return OK"; @@ -133,7 +134,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { const uint32_t seq = 15; const int32_t deviceId = 1; const int32_t source = AINPUT_SOURCE_TOUCHSCREEN; - const int32_t displayId = 0; + int32_t displayId = 0; const int32_t action = AMOTION_EVENT_ACTION_MOVE; const int32_t actionButton = 0; const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; @@ -176,7 +177,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { uint32_t consumeSeq; InputEvent* event; status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event, - 0); + &displayId); ASSERT_EQ(OK, status) << "consumer consume should return OK"; @@ -253,19 +254,36 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) { ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); } +TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) { + status_t status; + const size_t pointerCount = 1; + PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } + + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); + ASSERT_EQ(BAD_VALUE, status) + << "publisher publishMotionEvent should return BAD_VALUE"; +} + TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) { status_t status; const size_t pointerCount = 0; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } -TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) { +TEST_F(InputPublisherAndConsumerTest, + PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) { status_t status; const size_t pointerCount = MAX_POINTERS + 1; PointerProperties pointerProperties[pointerCount]; @@ -275,7 +293,7 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp new file mode 100644 index 0000000000..43b6012e0d --- /dev/null +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VelocityTracker_test" + +#include <math.h> + +#include <android-base/stringprintf.h> +#include <gtest/gtest.h> +#include <input/VelocityTracker.h> + +using android::base::StringPrintf; + +namespace android { + +constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually defined tests + +// velocity must be in the range (1-tol)*EV <= velocity <= (1+tol)*EV +// here EV = expected value, tol = VELOCITY_TOLERANCE +constexpr float VELOCITY_TOLERANCE = 0.2; + +// --- VelocityTrackerTest --- +class VelocityTrackerTest : public testing::Test { }; + +static void checkVelocity(float Vactual, float Vtarget) { + // Compare directions + if ((Vactual > 0 && Vtarget <= 0) || (Vactual < 0 && Vtarget >= 0)) { + FAIL() << StringPrintf("Velocity %f does not have the same direction" + " as the target velocity %f", Vactual, Vtarget); + } + + // Compare magnitudes + const float Vlower = fabsf(Vtarget * (1 - VELOCITY_TOLERANCE)); + const float Vupper = fabsf(Vtarget * (1 + VELOCITY_TOLERANCE)); + if (fabsf(Vactual) < Vlower) { + FAIL() << StringPrintf("Velocity %f is more than %.0f%% below target velocity %f", + Vactual, VELOCITY_TOLERANCE * 100, Vtarget); + } + if (fabsf(Vactual) > Vupper) { + FAIL() << StringPrintf("Velocity %f is more than %.0f%% above target velocity %f", + Vactual, VELOCITY_TOLERANCE * 100, Vtarget); + } + SUCCEED() << StringPrintf("Velocity %f within %.0f%% of target %f)", + Vactual, VELOCITY_TOLERANCE * 100, Vtarget); +} + +void failWithMessage(std::string message) { + FAIL() << message; // cannot do this directly from a non-void function +} + +struct Position { + nsecs_t time; + float x; + float y; +}; + + +MotionEvent* createSimpleMotionEvent(const Position* positions, size_t numSamples) { + /** + * Only populate the basic fields of a MotionEvent, such as time and a single axis + * Designed for use with manually-defined tests. + * Create a new MotionEvent on the heap, caller responsible for destroying the object. + */ + if (numSamples < 1) { + failWithMessage(StringPrintf("Need at least 1 sample to create a MotionEvent." + " Received numSamples=%zu", numSamples)); + } + + MotionEvent* event = new MotionEvent(); + PointerCoords coords; + PointerProperties properties[1]; + + properties[0].id = DEFAULT_POINTER_ID; + properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + // First sample added separately with initialize + coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x); + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y); + event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords); + + for (size_t i = 1; i < numSamples; i++) { + coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x); + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[i].y); + event->addSample(positions[i].time, &coords); + } + return event; +} + +static void computeAndCheckVelocity(const Position* positions, size_t numSamples, + int32_t axis, float targetVelocity) { + VelocityTracker vt(nullptr); + float Vx, Vy; + + MotionEvent* event = createSimpleMotionEvent(positions, numSamples); + vt.addMovement(event); + + vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy); + + switch (axis) { + case AMOTION_EVENT_AXIS_X: + checkVelocity(Vx, targetVelocity); + break; + case AMOTION_EVENT_AXIS_Y: + checkVelocity(Vy, targetVelocity); + break; + default: + FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y"; + } + delete event; +} + +/* + * ================== VelocityTracker tests generated manually ===================================== + */ + // @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy +TEST_F(VelocityTrackerTest, DISABLED_ThreePointsPositiveVelocityTest) { + // Same coordinate is reported 2 times in a row + // It is difficult to determine the correct answer here, but at least the direction + // of the reported velocity should be positive. + Position values[] = { + { 0, 273, NAN }, + { 12585000, 293, NAN }, + { 14730000, 293, NAN }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1600); +} + +TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) { + // Same coordinate is reported 3 times in a row + Position values[] = { + { 0, 293, NAN }, + { 6132000, 293, NAN }, + { 11283000, 293, NAN }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 0); +} + +TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) { + // Fixed velocity at 5 points per 10 milliseconds + Position values[] = { + { 0, 0, NAN }, + { 10000000, 5, NAN }, + { 20000000, 10, NAN }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 500); +} + + +/** + * ================== VelocityTracker tests generated by recording real events ===================== + * + * To add a test, record the input coordinates and event times to all calls + * to void VelocityTracker::addMovement(const MotionEvent* event). + * Also record all calls to VelocityTracker::clear(). + * Finally, record the output of VelocityTracker::getVelocity(...) + * This will give you the necessary data to create a new test. + */ + +// --------------- Recorded by hand on swordfish --------------------------------------------------- +// @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy +TEST_F(VelocityTrackerTest, DISABLED_SwordfishFlingDown) { + // Recording of a fling on Swordfish that could cause a fling in the wrong direction + Position values[] = { + { 0, 271, 96 }, + { 16071042, 269.786346, 106.922775 }, + { 35648403, 267.983063, 156.660034 }, + { 52313925, 262.638397, 220.339081 }, + { 68976522, 266.138824, 331.581116 }, + { 85639375, 274.79245, 428.113159 }, + { 96948871, 274.79245, 428.113159 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 623.577637); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 8523.348633); +} + +// --------------- Recorded by hand on sailfish, generated by a script ----------------------------- +// For some of these tests, the X-direction velocity checking has been removed, because the lsq2 +// and the impulse VelocityTrackerStrategies did not agree within 20%. +// Since the flings were recorded in the Y-direction, the intentional user action should only +// be relevant for the Y axis. +// There have been also cases where lsq2 and impulse disagreed more than 20% in the Y-direction. +// Those recordings have been discarded because we didn't feel one strategy's interpretation was +// more correct than another's but didn't want to increase the tolerance for the entire test suite. +// +// There are 18 tests total below: 9 in the positive Y direction and 9 in the opposite. +// The recordings were loosely binned into 3 categories - slow, faster, and fast, which roughly +// characterizes the velocity of the finger motion. +// These can be treated approximately as: +// slow - less than 1 page gets scrolled +// faster - more than 1 page gets scrolled, but less than 3 +// fast - entire list is scrolled (fling is done as hard as possible) + +TEST_F(VelocityTrackerTest, SailfishFlingUpSlow1) { + // Sailfish - fling up - slow - 1 + Position values[] = { + { 235089067457000, 528.00, 983.00 }, + { 235089084684000, 527.00, 981.00 }, + { 235089093349000, 527.00, 977.00 }, + { 235089095677625, 527.00, 975.93 }, + { 235089101859000, 527.00, 970.00 }, + { 235089110378000, 528.00, 960.00 }, + { 235089112497111, 528.25, 957.51 }, + { 235089118760000, 531.00, 946.00 }, + { 235089126686000, 535.00, 931.00 }, + { 235089129316820, 536.33, 926.02 }, + { 235089135199000, 540.00, 914.00 }, + { 235089144297000, 546.00, 896.00 }, + { 235089146136443, 547.21, 892.36 }, + { 235089152923000, 553.00, 877.00 }, + { 235089160784000, 559.00, 851.00 }, + { 235089162955851, 560.66, 843.82 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 872.794617); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 951.698181); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3604.819336); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3044.966064); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpSlow2) { + // Sailfish - fling up - slow - 2 + Position values[] = { + { 235110560704000, 522.00, 1107.00 }, + { 235110575764000, 522.00, 1107.00 }, + { 235110584385000, 522.00, 1107.00 }, + { 235110588421179, 521.52, 1106.52 }, + { 235110592830000, 521.00, 1106.00 }, + { 235110601385000, 520.00, 1104.00 }, + { 235110605088160, 519.14, 1102.27 }, + { 235110609952000, 518.00, 1100.00 }, + { 235110618353000, 517.00, 1093.00 }, + { 235110621755146, 516.60, 1090.17 }, + { 235110627010000, 517.00, 1081.00 }, + { 235110634785000, 518.00, 1063.00 }, + { 235110638422450, 518.87, 1052.58 }, + { 235110643161000, 520.00, 1039.00 }, + { 235110651767000, 524.00, 1011.00 }, + { 235110655089581, 525.54, 1000.19 }, + { 235110660368000, 530.00, 980.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4096.583008); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3455.094238); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpSlow3) { + // Sailfish - fling up - slow - 3 + Position values[] = { + { 792536237000, 580.00, 1317.00 }, + { 792541538987, 580.63, 1311.94 }, + { 792544613000, 581.00, 1309.00 }, + { 792552301000, 583.00, 1295.00 }, + { 792558362309, 585.13, 1282.92 }, + { 792560828000, 586.00, 1278.00 }, + { 792569446000, 589.00, 1256.00 }, + { 792575185095, 591.54, 1241.41 }, + { 792578491000, 593.00, 1233.00 }, + { 792587044000, 597.00, 1211.00 }, + { 792592008172, 600.28, 1195.92 }, + { 792594616000, 602.00, 1188.00 }, + { 792603129000, 607.00, 1167.00 }, + { 792608831290, 609.48, 1155.83 }, + { 792612321000, 611.00, 1149.00 }, + { 792620768000, 615.00, 1131.00 }, + { 792625653873, 617.32, 1121.73 }, + { 792629200000, 619.00, 1115.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 574.33429); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 617.40564); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2361.982666); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2500.055664); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFaster1) { + // Sailfish - fling up - faster - 1 + Position values[] = { + { 235160420675000, 610.00, 1042.00 }, + { 235160428220000, 609.00, 1026.00 }, + { 235160436544000, 609.00, 1024.00 }, + { 235160441852394, 609.64, 1020.82 }, + { 235160444878000, 610.00, 1019.00 }, + { 235160452673000, 613.00, 1006.00 }, + { 235160458519743, 617.18, 992.06 }, + { 235160461061000, 619.00, 986.00 }, + { 235160469798000, 627.00, 960.00 }, + { 235160475186713, 632.22, 943.02 }, + { 235160478051000, 635.00, 934.00 }, + { 235160486489000, 644.00, 906.00 }, + { 235160491853697, 649.56, 890.56 }, + { 235160495177000, 653.00, 881.00 }, + { 235160504148000, 662.00, 858.00 }, + { 235160509231495, 666.81, 845.37 }, + { 235160512603000, 670.00, 837.00 }, + { 235160520366000, 679.00, 814.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1274.141724); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1438.53186); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3877.35498); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3695.859619); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFaster2) { + // Sailfish - fling up - faster - 2 + Position values[] = { + { 847153808000, 576.00, 1264.00 }, + { 847171174000, 576.00, 1262.00 }, + { 847179640000, 576.00, 1257.00 }, + { 847185187540, 577.41, 1249.22 }, + { 847187487000, 578.00, 1246.00 }, + { 847195710000, 581.00, 1227.00 }, + { 847202027059, 583.93, 1209.40 }, + { 847204324000, 585.00, 1203.00 }, + { 847212672000, 590.00, 1176.00 }, + { 847218861395, 594.36, 1157.11 }, + { 847221190000, 596.00, 1150.00 }, + { 847230484000, 602.00, 1124.00 }, + { 847235701400, 607.56, 1103.83 }, + { 847237986000, 610.00, 1095.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4280.07959); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4241.004395); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFaster3) { + // Sailfish - fling up - faster - 3 + Position values[] = { + { 235200532789000, 507.00, 1084.00 }, + { 235200549221000, 507.00, 1083.00 }, + { 235200557841000, 507.00, 1081.00 }, + { 235200558051189, 507.00, 1080.95 }, + { 235200566314000, 507.00, 1078.00 }, + { 235200574876586, 508.97, 1070.12 }, + { 235200575006000, 509.00, 1070.00 }, + { 235200582900000, 514.00, 1054.00 }, + { 235200591276000, 525.00, 1023.00 }, + { 235200591701829, 525.56, 1021.42 }, + { 235200600064000, 542.00, 976.00 }, + { 235200608519000, 563.00, 911.00 }, + { 235200608527086, 563.02, 910.94 }, + { 235200616933000, 590.00, 844.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -8715.686523); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -7639.026367); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFast1) { + // Sailfish - fling up - fast - 1 + Position values[] = { + { 920922149000, 561.00, 1412.00 }, + { 920930185000, 559.00, 1377.00 }, + { 920930262463, 558.98, 1376.66 }, + { 920938547000, 559.00, 1371.00 }, + { 920947096857, 562.91, 1342.68 }, + { 920947302000, 563.00, 1342.00 }, + { 920955502000, 577.00, 1272.00 }, + { 920963931021, 596.87, 1190.54 }, + { 920963987000, 597.00, 1190.00 }, + { 920972530000, 631.00, 1093.00 }, + { 920980765511, 671.31, 994.68 }, + { 920980906000, 672.00, 993.00 }, + { 920989261000, 715.00, 903.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5670.329102); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5991.866699); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -13021.101562); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -15093.995117); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFast2) { + // Sailfish - fling up - fast - 2 + Position values[] = { + { 235247153233000, 518.00, 1168.00 }, + { 235247170452000, 517.00, 1167.00 }, + { 235247178908000, 515.00, 1159.00 }, + { 235247179556213, 514.85, 1158.39 }, + { 235247186821000, 515.00, 1125.00 }, + { 235247195265000, 521.00, 1051.00 }, + { 235247196389476, 521.80, 1041.15 }, + { 235247203649000, 538.00, 932.00 }, + { 235247212253000, 571.00, 794.00 }, + { 235247213222491, 574.72, 778.45 }, + { 235247220736000, 620.00, 641.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20286.958984); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20494.587891); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingUpFast3) { + // Sailfish - fling up - fast - 3 + Position values[] = { + { 235302568736000, 529.00, 1167.00 }, + { 235302576644000, 523.00, 1140.00 }, + { 235302579395063, 520.91, 1130.61 }, + { 235302585140000, 522.00, 1130.00 }, + { 235302593615000, 527.00, 1065.00 }, + { 235302596207444, 528.53, 1045.12 }, + { 235302602102000, 559.00, 872.00 }, + { 235302610545000, 652.00, 605.00 }, + { 235302613019881, 679.26, 526.73 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -39295.941406); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -36461.421875); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownSlow1) { + // Sailfish - fling down - slow - 1 + Position values[] = { + { 235655749552755, 582.00, 432.49 }, + { 235655750638000, 582.00, 433.00 }, + { 235655758865000, 582.00, 440.00 }, + { 235655766221523, 581.16, 448.43 }, + { 235655767594000, 581.00, 450.00 }, + { 235655776044000, 580.00, 462.00 }, + { 235655782890696, 579.18, 474.35 }, + { 235655784360000, 579.00, 477.00 }, + { 235655792795000, 578.00, 496.00 }, + { 235655799559531, 576.27, 515.04 }, + { 235655800612000, 576.00, 518.00 }, + { 235655809535000, 574.00, 542.00 }, + { 235655816988015, 572.17, 564.86 }, + { 235655817685000, 572.00, 567.00 }, + { 235655825981000, 569.00, 595.00 }, + { 235655833808653, 566.26, 620.60 }, + { 235655834541000, 566.00, 623.00 }, + { 235655842893000, 563.00, 649.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -419.749695); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -398.303894); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3309.016357); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3969.099854); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownSlow2) { + // Sailfish - fling down - slow - 2 + Position values[] = { + { 235671152083370, 485.24, 558.28 }, + { 235671154126000, 485.00, 559.00 }, + { 235671162497000, 484.00, 566.00 }, + { 235671168750511, 483.27, 573.29 }, + { 235671171071000, 483.00, 576.00 }, + { 235671179390000, 482.00, 588.00 }, + { 235671185417210, 481.31, 598.98 }, + { 235671188173000, 481.00, 604.00 }, + { 235671196371000, 480.00, 624.00 }, + { 235671202084196, 479.27, 639.98 }, + { 235671204235000, 479.00, 646.00 }, + { 235671212554000, 478.00, 673.00 }, + { 235671219471011, 476.39, 697.12 }, + { 235671221159000, 476.00, 703.00 }, + { 235671229592000, 474.00, 734.00 }, + { 235671236281462, 472.43, 758.38 }, + { 235671238098000, 472.00, 765.00 }, + { 235671246532000, 470.00, 799.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -262.80426); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -243.665344); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4215.682129); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4587.986816); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownSlow3) { + // Sailfish - fling down - slow - 3 + Position values[] = { + { 170983201000, 557.00, 533.00 }, + { 171000668000, 556.00, 534.00 }, + { 171007359750, 554.73, 535.27 }, + { 171011197000, 554.00, 536.00 }, + { 171017660000, 552.00, 540.00 }, + { 171024201831, 549.97, 544.73 }, + { 171027333000, 549.00, 547.00 }, + { 171034603000, 545.00, 557.00 }, + { 171041043371, 541.98, 567.55 }, + { 171043147000, 541.00, 571.00 }, + { 171051052000, 536.00, 586.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -723.413513); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -651.038452); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 2091.502441); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 1934.517456); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFaster1) { + // Sailfish - fling down - faster - 1 + Position values[] = { + { 235695280333000, 558.00, 451.00 }, + { 235695283971237, 558.43, 454.45 }, + { 235695289038000, 559.00, 462.00 }, + { 235695297388000, 561.00, 478.00 }, + { 235695300638465, 561.83, 486.25 }, + { 235695305265000, 563.00, 498.00 }, + { 235695313591000, 564.00, 521.00 }, + { 235695317305492, 564.43, 532.68 }, + { 235695322181000, 565.00, 548.00 }, + { 235695330709000, 565.00, 577.00 }, + { 235695333972227, 565.00, 588.10 }, + { 235695339250000, 565.00, 609.00 }, + { 235695347839000, 565.00, 642.00 }, + { 235695351313257, 565.00, 656.18 }, + { 235695356412000, 565.00, 677.00 }, + { 235695364899000, 563.00, 710.00 }, + { 235695368118682, 562.24, 722.52 }, + { 235695373403000, 564.00, 744.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4254.639648); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4698.415039); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFaster2) { + // Sailfish - fling down - faster - 2 + Position values[] = { + { 235709624766000, 535.00, 579.00 }, + { 235709642256000, 534.00, 580.00 }, + { 235709643350278, 533.94, 580.06 }, + { 235709650760000, 532.00, 584.00 }, + { 235709658615000, 530.00, 593.00 }, + { 235709660170495, 529.60, 594.78 }, + { 235709667095000, 527.00, 606.00 }, + { 235709675616000, 524.00, 628.00 }, + { 235709676983261, 523.52, 631.53 }, + { 235709684289000, 521.00, 652.00 }, + { 235709692763000, 518.00, 682.00 }, + { 235709693804993, 517.63, 685.69 }, + { 235709701438000, 515.00, 709.00 }, + { 235709709830000, 512.00, 739.00 }, + { 235709710626776, 511.72, 741.85 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -430.440247); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -447.600311); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3953.859375); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4316.155273); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFaster3) { + // Sailfish - fling down - faster - 3 + Position values[] = { + { 235727628927000, 540.00, 440.00 }, + { 235727636810000, 537.00, 454.00 }, + { 235727646176000, 536.00, 454.00 }, + { 235727653586628, 535.12, 456.65 }, + { 235727654557000, 535.00, 457.00 }, + { 235727663024000, 534.00, 465.00 }, + { 235727670410103, 533.04, 479.45 }, + { 235727670691000, 533.00, 480.00 }, + { 235727679255000, 531.00, 501.00 }, + { 235727687233704, 529.09, 526.73 }, + { 235727687628000, 529.00, 528.00 }, + { 235727696113000, 526.00, 558.00 }, + { 235727704057546, 523.18, 588.98 }, + { 235727704576000, 523.00, 591.00 }, + { 235727713099000, 520.00, 626.00 }, + { 235727720880776, 516.33, 655.36 }, + { 235727721580000, 516.00, 658.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4484.617676); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4927.92627); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFast1) { + // Sailfish - fling down - fast - 1 + Position values[] = { + { 235762352849000, 467.00, 286.00 }, + { 235762360250000, 443.00, 344.00 }, + { 235762362787412, 434.77, 363.89 }, + { 235762368807000, 438.00, 359.00 }, + { 235762377220000, 425.00, 423.00 }, + { 235762379608561, 421.31, 441.17 }, + { 235762385698000, 412.00, 528.00 }, + { 235762394133000, 406.00, 648.00 }, + { 235762396429369, 404.37, 680.67 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 19084.931641); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16064.685547); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFast2) { + // Sailfish - fling down - fast - 2 + Position values[] = { + { 235772487188000, 576.00, 204.00 }, + { 235772495159000, 553.00, 236.00 }, + { 235772503568000, 551.00, 240.00 }, + { 235772508192247, 545.55, 254.17 }, + { 235772512051000, 541.00, 266.00 }, + { 235772520794000, 520.00, 337.00 }, + { 235772525015263, 508.92, 394.43 }, + { 235772529174000, 498.00, 451.00 }, + { 235772537635000, 484.00, 589.00 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 18660.048828); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16918.439453); // lsq2 +} + + +TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) { + // Sailfish - fling down - fast - 3 + Position values[] = { + { 507650295000, 628.00, 233.00 }, + { 507658234000, 605.00, 269.00 }, + { 507666784000, 601.00, 274.00 }, + { 507669660483, 599.65, 275.68 }, + { 507675427000, 582.00, 308.00 }, + { 507683740000, 541.00, 404.00 }, + { 507686506238, 527.36, 435.95 }, + { 507692220000, 487.00, 581.00 }, + { 507700707000, 454.00, 792.00 }, + { 507703352649, 443.71, 857.77 }, + }; + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6772.508301); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6388.48877); // lsq2 + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 29765.908203); // impulse + computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2 +} + + +} // namespace android diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS new file mode 100644 index 0000000000..6a38a1ff14 --- /dev/null +++ b/libs/sensor/OWNERS @@ -0,0 +1,2 @@ +ashutoshj@google.com +pengxu@google.com diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 07aba321a8..abe856ef24 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -47,7 +47,7 @@ cc_library_shared { ], sanitize: { - //misc_undefined: ["integer"], + integer_overflow: true, }, srcs: [ @@ -74,6 +74,7 @@ cc_library_shared { shared_libs: [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.1", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", "libbase", @@ -94,6 +95,7 @@ cc_library_shared { ], header_libs: [ + "libbase_headers", "libnativebase_headers", "libhardware_headers", ], @@ -106,6 +108,7 @@ cc_library_shared { ], export_header_lib_headers: [ + "libbase_headers", "libnativebase_headers", "libhardware_headers", ], diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp index b67f4d9328..ff53aa8f25 100644 --- a/libs/ui/Fence.cpp +++ b/libs/ui/Fence.cpp @@ -37,18 +37,12 @@ namespace android { const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence); -Fence::Fence() : - mFenceFd(-1) { -} - Fence::Fence(int fenceFd) : mFenceFd(fenceFd) { } -Fence::~Fence() { - if (mFenceFd != -1) { - close(mFenceFd); - } +Fence::Fence(base::unique_fd fenceFd) : + mFenceFd(std::move(fenceFd)) { } status_t Fence::wait(int timeout) { @@ -68,7 +62,7 @@ status_t Fence::waitForever(const char* logname) { int warningTimeout = 3000; int err = sync_wait(mFenceFd, warningTimeout); if (err < 0 && errno == ETIME) { - ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd, + ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd.get(), warningTimeout); err = sync_wait(mFenceFd, TIMEOUT_NEVER); } @@ -94,7 +88,7 @@ sp<Fence> Fence::merge(const char* name, const sp<Fence>& f1, if (result == -1) { status_t err = -errno; ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)", - name, f1->mFenceFd, f2->mFenceFd, + name, f1->mFenceFd.get(), f2->mFenceFd.get(), strerror(-err), err); return NO_FENCE; } @@ -117,7 +111,7 @@ nsecs_t Fence::getSignalTime() const { struct sync_fence_info_data* finfo = sync_fence_info(mFenceFd); if (finfo == NULL) { - ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd); + ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd.get()); return SIGNAL_TIME_INVALID; } if (finfo->status != 1) { @@ -181,7 +175,7 @@ status_t Fence::unflatten(void const*& buffer, size_t& size, int const*& fds, si } if (numFds) { - mFenceFd = *fds++; + mFenceFd.reset(*fds++); count--; } diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp index 0eb08e59a9..1f746a2ed1 100644 --- a/libs/ui/Gralloc2.cpp +++ b/libs/ui/Gralloc2.cpp @@ -39,9 +39,15 @@ void Mapper::preload() { Mapper::Mapper() { mMapper = IMapper::getService(); - if (mMapper == nullptr || mMapper->isRemote()) { + if (mMapper == nullptr) { + LOG_ALWAYS_FATAL("gralloc-mapper is missing"); + } + if (mMapper->isRemote()) { LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode"); } + + // IMapper 2.1 is optional + mMapperV2_1 = hardware::graphics::mapper::V2_1::IMapper::castFrom(mMapper); } Error Mapper::createDescriptor( @@ -91,6 +97,50 @@ void Mapper::freeBuffer(buffer_handle_t bufferHandle) const buffer, error); } +Error Mapper::validateBufferSize(buffer_handle_t bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, + uint32_t stride) const +{ + if (mMapperV2_1 == nullptr) { + return Error::NONE; + } + + auto buffer = const_cast<native_handle_t*>(bufferHandle); + auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride); + + return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError; +} + +void Mapper::getTransportSize(buffer_handle_t bufferHandle, + uint32_t* outNumFds, uint32_t* outNumInts) const +{ + *outNumFds = uint32_t(bufferHandle->numFds); + *outNumInts = uint32_t(bufferHandle->numInts); + + if (mMapperV2_1 == nullptr) { + return; + } + + Error error; + auto buffer = const_cast<native_handle_t*>(bufferHandle); + auto ret = mMapperV2_1->getTransportSize(buffer, + [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) { + error = tmpError; + if (error != Error::NONE) { + return; + } + + *outNumFds = tmpNumFds; + *outNumInts = tmpNumInts; + }); + + if (!ret.isOk()) { + error = kTransactionError; + } + ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", + buffer, error); +} + Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const IMapper::Rect& accessRegion, int acquireFence, void** outData) const diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index c8805000a4..4ed2aa42fc 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -170,6 +170,8 @@ status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight, inUsage, &handle, &outStride, mId, std::move(requestorName)); if (err == NO_ERROR) { + mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts); + width = static_cast<int>(inWidth); height = static_cast<int>(inHeight); format = inFormat; @@ -199,7 +201,8 @@ status_t GraphicBuffer::initWithHandle(const native_handle_t* handle, if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) { buffer_handle_t importedHandle; - status_t err = mBufferMapper.importBuffer(handle, &importedHandle); + status_t err = mBufferMapper.importBuffer(handle, width, height, + layerCount, format, usage, stride, &importedHandle); if (err != NO_ERROR) { initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0); @@ -212,6 +215,7 @@ status_t GraphicBuffer::initWithHandle(const native_handle_t* handle, } handle = importedHandle; + mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts); } ANativeWindowBuffer::handle = handle; @@ -323,11 +327,11 @@ status_t GraphicBuffer::unlockAsync(int *fenceFd) } size_t GraphicBuffer::getFlattenedSize() const { - return static_cast<size_t>(13 + (handle ? handle->numInts : 0)) * sizeof(int); + return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int); } size_t GraphicBuffer::getFdCount() const { - return static_cast<size_t>(handle ? handle->numFds : 0); + return static_cast<size_t>(handle ? mTransportNumFds : 0); } status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const { @@ -353,18 +357,18 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& buf[12] = int(usage >> 32); // high 32-bits if (handle) { - buf[10] = handle->numFds; - buf[11] = handle->numInts; - memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int)); + buf[10] = int32_t(mTransportNumFds); + buf[11] = int32_t(mTransportNumInts); + memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int)); memcpy(buf + 13, handle->data + handle->numFds, - static_cast<size_t>(handle->numInts) * sizeof(int)); + static_cast<size_t>(mTransportNumInts) * sizeof(int)); } buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded); size -= sizeNeeded; if (handle) { - fds += handle->numFds; - count -= static_cast<size_t>(handle->numFds); + fds += mTransportNumFds; + count -= static_cast<size_t>(mTransportNumFds); } return NO_ERROR; @@ -457,7 +461,8 @@ status_t GraphicBuffer::unflatten( if (handle != 0) { buffer_handle_t importedHandle; - status_t err = mBufferMapper.importBuffer(handle, &importedHandle); + status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height), + uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle); if (err != NO_ERROR) { width = height = stride = format = usage_deprecated = 0; layerCount = 0; @@ -470,6 +475,7 @@ status_t GraphicBuffer::unflatten( native_handle_close(handle); native_handle_delete(const_cast<native_handle_t*>(handle)); handle = importedHandle; + mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts); } buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded); diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index d85448968a..2cac2874a8 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -52,17 +52,42 @@ GraphicBufferMapper::GraphicBufferMapper() } status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle, + uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, uint32_t stride, buffer_handle_t* outHandle) { ATRACE_CALL(); + buffer_handle_t bufferHandle; Gralloc2::Error error = mMapper->importBuffer( - hardware::hidl_handle(rawHandle), outHandle); + hardware::hidl_handle(rawHandle), &bufferHandle); + if (error != Gralloc2::Error::NONE) { + ALOGW("importBuffer(%p) failed: %d", rawHandle, error); + return static_cast<status_t>(error); + } + + Gralloc2::IMapper::BufferDescriptorInfo info = {}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast<Gralloc2::PixelFormat>(format); + info.usage = usage; + error = mMapper->validateBufferSize(bufferHandle, info, stride); + if (error != Gralloc2::Error::NONE) { + ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error); + freeBuffer(bufferHandle); + return static_cast<status_t>(error); + } - ALOGW_IF(error != Gralloc2::Error::NONE, "importBuffer(%p) failed: %d", - rawHandle, error); + *outHandle = bufferHandle; - return static_cast<status_t>(error); + return NO_ERROR; +} + +void GraphicBufferMapper::getTransportSize(buffer_handle_t handle, + uint32_t* outTransportNumFds, uint32_t* outTransportNumInts) +{ + mMapper->getTransportSize(handle, outTransportNumFds, outTransportNumInts); } status_t GraphicBufferMapper::freeBuffer(buffer_handle_t handle) diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h index 37811bcd7c..ec67fa972c 100644 --- a/libs/ui/include/ui/Fence.h +++ b/libs/ui/include/ui/Fence.h @@ -19,6 +19,7 @@ #include <stdint.h> +#include <android-base/unique_fd.h> #include <utils/Flattenable.h> #include <utils/RefBase.h> #include <utils/Timers.h> @@ -49,12 +50,13 @@ public: // Construct a new Fence object with an invalid file descriptor. This // should be done when the Fence object will be set up by unflattening // serialized data. - Fence(); + Fence() = default; // Construct a new Fence object to manage a given fence file descriptor. // When the new Fence object is destructed the file descriptor will be // closed. explicit Fence(int fenceFd); + explicit Fence(base::unique_fd fenceFd); // Not copyable or movable. Fence(const Fence& rhs) = delete; @@ -136,9 +138,9 @@ public: private: // Only allow instantiation using ref counting. friend class LightRefBase<Fence>; - ~Fence(); + ~Fence() = default; - int mFenceFd; + base::unique_fd mFenceFd; }; }; // namespace android diff --git a/libs/ui/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h index 270675cba2..6a7479a68a 100644 --- a/libs/ui/include/ui/FloatRect.h +++ b/libs/ui/include/ui/FloatRect.h @@ -27,6 +27,17 @@ public: float getWidth() const { return right - left; } float getHeight() const { return bottom - top; } + FloatRect intersect(const FloatRect& other) const { + return { + // Inline to avoid tromping on other min/max defines or adding a + // dependency on STL + (left > other.left) ? left : other.left, + (top > other.top) ? top : other.top, + (right < other.right) ? right : other.right, + (bottom < other.bottom) ? bottom : other.bottom + }; + } + float left = 0.0f; float top = 0.0f; float right = 0.0f; diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h index 8aee16033a..69c35f7dda 100644 --- a/libs/ui/include/ui/Gralloc2.h +++ b/libs/ui/include/ui/Gralloc2.h @@ -21,6 +21,7 @@ #include <android/hardware/graphics/allocator/2.0/IAllocator.h> #include <android/hardware/graphics/mapper/2.0/IMapper.h> +#include <android/hardware/graphics/mapper/2.1/IMapper.h> #include <utils/StrongPointer.h> namespace android { @@ -55,6 +56,13 @@ public: void freeBuffer(buffer_handle_t bufferHandle) const; + Error validateBufferSize(buffer_handle_t bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, + uint32_t stride) const; + + void getTransportSize(buffer_handle_t bufferHandle, + uint32_t* outNumFds, uint32_t* outNumInts) const; + // The ownership of acquireFence is always transferred to the callee, even // on errors. Error lock(buffer_handle_t bufferHandle, uint64_t usage, @@ -73,6 +81,7 @@ public: private: sp<IMapper> mMapper; + sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1; }; // A wrapper to IAllocator diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index 95c2d2272e..e794462f60 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -230,6 +230,10 @@ private: GraphicBufferMapper& mBufferMapper; ssize_t mInitCheck; + // numbers of fds/ints in native_handle_t to flatten + uint32_t mTransportNumFds; + uint32_t mTransportNumInts; + uint64_t mId; // Stores the generation number of this buffer. If this number does not diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h index 06961b11b5..7cf003dcba 100644 --- a/libs/ui/include/ui/GraphicBufferMapper.h +++ b/libs/ui/include/ui/GraphicBufferMapper.h @@ -22,6 +22,7 @@ #include <memory> +#include <ui/PixelFormat.h> #include <utils/Singleton.h> @@ -49,10 +50,15 @@ public: // The imported outHandle must be freed with freeBuffer when no longer // needed. rawHandle is owned by the caller. status_t importBuffer(buffer_handle_t rawHandle, + uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, uint32_t stride, buffer_handle_t* outHandle); status_t freeBuffer(buffer_handle_t handle); + void getTransportSize(buffer_handle_t handle, + uint32_t* outTransportNumFds, uint32_t* outTransportNumInts); + status_t lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr); diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h index b50e4ec656..0bec0b7f78 100644 --- a/libs/ui/include/ui/Rect.h +++ b/libs/ui/include/ui/Rect.h @@ -69,6 +69,15 @@ public: bottom = rb.y; } + inline explicit Rect(const FloatRect& floatRect) { + // Ideally we would use std::round, but we don't want to add an STL + // dependency here, so we use an approximation + left = static_cast<int32_t>(floatRect.left + 0.5f); + top = static_cast<int32_t>(floatRect.top + 0.5f); + right = static_cast<int32_t>(floatRect.right + 0.5f); + bottom = static_cast<int32_t>(floatRect.bottom + 0.5f); + } + void makeInvalid(); inline void clear() { @@ -86,15 +95,18 @@ public: } // rectangle's width + __attribute__((no_sanitize("signed-integer-overflow"))) inline int32_t getWidth() const { return right - left; } // rectangle's height + __attribute__((no_sanitize("signed-integer-overflow"))) inline int32_t getHeight() const { return bottom - top; } + __attribute__((no_sanitize("signed-integer-overflow"))) inline Rect getBounds() const { return Rect(right - left, bottom - top); } diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp index a2287e1127..9481c37475 100644 --- a/libs/vr/libbufferhub/Android.bp +++ b/libs/vr/libbufferhub/Android.bp @@ -29,6 +29,7 @@ staticLibraries = [ sharedLibraries = [ "libbase", + "libbinder", "libcutils", "libhardware", "liblog", @@ -63,10 +64,10 @@ cc_library { cc_test { tags: ["optional"], - srcs: ["bufferhub_tests.cpp"], + srcs: ["buffer_hub-test.cpp"], static_libs: ["libbufferhub"] + staticLibraries, shared_libs: sharedLibraries, header_libs: headerLibraries, - name: "bufferhub_tests", + name: "buffer_hub-test", } diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp index d0d3a73574..471ec7bf20 100644 --- a/libs/vr/libbufferhub/bufferhub_tests.cpp +++ b/libs/vr/libbufferhub/buffer_hub-test.cpp @@ -20,6 +20,10 @@ using android::dvr::BufferConsumer; using android::dvr::BufferHubDefs::kConsumerStateMask; using android::dvr::BufferHubDefs::kProducerStateBit; +using android::dvr::BufferHubDefs::IsBufferGained; +using android::dvr::BufferHubDefs::IsBufferPosted; +using android::dvr::BufferHubDefs::IsBufferAcquired; +using android::dvr::BufferHubDefs::IsBufferReleased; using android::dvr::BufferProducer; using android::pdx::LocalHandle; @@ -28,6 +32,8 @@ const int kHeight = 480; const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888; const int kUsage = 0; const uint64_t kContext = 42; +const size_t kMaxConsumerCount = 63; +const int kPollTimeoutMs = 100; using LibBufferHubTest = ::testing::Test; @@ -46,51 +52,51 @@ TEST_F(LibBufferHubTest, TestBasicUsage) { // Producer state mask is unique, i.e. 1. EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit); // Consumer state mask cannot have producer bit on. - EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0ULL); + EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0U); // Consumer state mask must be a single, i.e. power of 2. - EXPECT_NE(c->buffer_state_bit(), 0ULL); - EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0ULL); + EXPECT_NE(c->buffer_state_bit(), 0U); + EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0U); // Consumer state mask cannot have producer bit on. - EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0ULL); + EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0U); // Consumer state mask must be a single, i.e. power of 2. - EXPECT_NE(c2->buffer_state_bit(), 0ULL); - EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0ULL); + EXPECT_NE(c2->buffer_state_bit(), 0U); + EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0U); // Each consumer should have unique bit. - EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0ULL); + EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0U); // Initial state: producer not available, consumers not available. - EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100))); + EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); EXPECT_EQ(0, p->Post(LocalHandle(), kContext)); // New state: producer not available, consumers available. - EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); - EXPECT_EQ(1, RETRY_EINTR(c->Poll(100))); - EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100))); + EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(1, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); uint64_t context; LocalHandle fence; EXPECT_EQ(0, c->Acquire(&fence, &context)); EXPECT_EQ(kContext, context); - EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); - EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100))); + EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); EXPECT_EQ(0, c2->Acquire(&fence, &context)); EXPECT_EQ(kContext, context); - EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); + EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); EXPECT_EQ(0, c->Release(LocalHandle())); - EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); + EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); EXPECT_EQ(0, c2->Discard()); - EXPECT_EQ(1, RETRY_EINTR(p->Poll(100))); + EXPECT_EQ(1, RETRY_EINTR(p->Poll(kPollTimeoutMs))); EXPECT_EQ(0, p->Gain(&fence)); - EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); - EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100))); + EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); } TEST_F(LibBufferHubTest, TestEpoll) { @@ -132,7 +138,8 @@ TEST_F(LibBufferHubTest, TestEpoll) { // Post the producer and check for consumer signal. EXPECT_EQ(0, p->Post({}, kContext)); - ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); + ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); ASSERT_TRUE(events[0].events & EPOLLIN); ASSERT_EQ(c->event_fd(), events[0].data.fd); @@ -140,10 +147,14 @@ TEST_F(LibBufferHubTest, TestEpoll) { event = events[0]; // Check for events again. Edge-triggered mode should prevent any. - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); // Translate the events. auto event_status = c->GetEventMask(event.events); @@ -151,7 +162,8 @@ TEST_F(LibBufferHubTest, TestEpoll) { ASSERT_TRUE(event_status.get() & EPOLLIN); // Check for events again. Edge-triggered mode should prevent any. - EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); + EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), + kPollTimeoutMs)); } TEST_F(LibBufferHubTest, TestStateMask) { @@ -159,14 +171,14 @@ TEST_F(LibBufferHubTest, TestStateMask) { kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); ASSERT_TRUE(p.get() != nullptr); - // It's ok to create up to 63 consumer buffers. + // It's ok to create up to kMaxConsumerCount consumer buffers. uint64_t buffer_state_bits = p->buffer_state_bit(); - std::array<std::unique_ptr<BufferConsumer>, 63> cs; - for (size_t i = 0; i < 63; i++) { + std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs; + for (size_t i = 0; i < kMaxConsumerCount; i++) { cs[i] = BufferConsumer::Import(p->CreateConsumer()); ASSERT_TRUE(cs[i].get() != nullptr); // Expect all buffers have unique state mask. - EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0ULL); + EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U); buffer_state_bits |= cs[i]->buffer_state_bit(); } EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); @@ -176,13 +188,13 @@ TEST_F(LibBufferHubTest, TestStateMask) { EXPECT_EQ(state.error(), E2BIG); // Release any consumer should allow us to re-create. - for (size_t i = 0; i < 63; i++) { + for (size_t i = 0; i < kMaxConsumerCount; i++) { buffer_state_bits &= ~cs[i]->buffer_state_bit(); cs[i] = nullptr; cs[i] = BufferConsumer::Import(p->CreateConsumer()); ASSERT_TRUE(cs[i].get() != nullptr); // The released state mask will be reused. - EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0ULL); + EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U); buffer_state_bits |= cs[i]->buffer_state_bit(); EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); } @@ -224,7 +236,7 @@ TEST_F(LibBufferHubTest, TestStateTransitions) { // Release in acquired state should succeed. EXPECT_EQ(0, c->Release(LocalHandle())); - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); // Release, acquire, and post in released state should fail. EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); @@ -240,6 +252,223 @@ TEST_F(LibBufferHubTest, TestStateTransitions) { EXPECT_EQ(-EALREADY, p->Gain(&fence)); } +TEST_F(LibBufferHubTest, TestAsyncStateTransitions) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // The producer buffer starts in gained state. + + // Acquire, release, and gain in gained state should fail. + EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + + // Post in gained state should succeed. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_EQ(p->buffer_state(), c->buffer_state()); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + + // Post, release, and gain in posted state should fail. + EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + + // Acquire in posted state should succeed. + EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(p->buffer_state(), c->buffer_state()); + EXPECT_TRUE(IsBufferAcquired(p->buffer_state())); + + // Acquire, post, and gain in acquired state should fail. + EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + + // Release in acquired state should succeed. + EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_EQ(p->buffer_state(), c->buffer_state()); + EXPECT_TRUE(IsBufferReleased(p->buffer_state())); + + // Release, acquire, and post in released state should fail. + EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence)); + + // Gain in released state should succeed. + EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(p->buffer_state(), c->buffer_state()); + EXPECT_TRUE(IsBufferGained(p->buffer_state())); + + // Acquire, release, and gain in gained state should fail. + EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); + EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence)); + EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_FALSE(invalid_fence.IsValid()); +} + +TEST_F(LibBufferHubTest, TestZeroConsumer) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Newly created. + EXPECT_TRUE(IsBufferGained(p->buffer_state())); + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + + // The buffer should stay in posted stay until a consumer picks it up. + EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + + // A new consumer should still be able to acquire the buffer immediately. + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferAcquired(c->buffer_state())); +} + +TEST_F(LibBufferHubTest, TestMaxConsumers) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + + std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs; + for (size_t i = 0; i < kMaxConsumerCount; i++) { + cs[i] = BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(cs[i].get() != nullptr); + EXPECT_TRUE(IsBufferGained(cs[i]->buffer_state())); + } + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Post the producer should trigger all consumers to be available. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + for (size_t i = 0; i < kMaxConsumerCount; i++) { + EXPECT_TRUE(IsBufferPosted(cs[i]->buffer_state(), + cs[i]->buffer_state_bit())); + EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferAcquired(p->buffer_state())); + } + + // All consumers have to release before the buffer is considered to be + // released. + for (size_t i = 0; i < kMaxConsumerCount; i++) { + EXPECT_FALSE(IsBufferReleased(p->buffer_state())); + EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence)); + } + + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_TRUE(IsBufferReleased(p->buffer_state())); + + // Buffer state cross all clients must be consistent. + for (size_t i = 0; i < kMaxConsumerCount; i++) { + EXPECT_EQ(p->buffer_state(), cs[i]->buffer_state()); + } +} + +TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferGained) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + EXPECT_TRUE(IsBufferGained(p->buffer_state())); + + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + EXPECT_TRUE(IsBufferGained(c->buffer_state())); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Post the gained buffer should signal already created consumer. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferAcquired(c->buffer_state())); +} + +TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferPosted) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + EXPECT_TRUE(IsBufferGained(p->buffer_state())); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Post the gained buffer before any consumer gets created. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_TRUE(IsBufferPosted(p->buffer_state())); + + // Newly created consumer should be automatically sigalled. + std::unique_ptr<BufferConsumer> c = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c.get() != nullptr); + EXPECT_TRUE(IsBufferPosted(c->buffer_state())); + EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferAcquired(c->buffer_state())); +} + +TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) { + std::unique_ptr<BufferProducer> p = BufferProducer::Create( + kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); + ASSERT_TRUE(p.get() != nullptr); + + std::unique_ptr<BufferConsumer> c1 = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c1.get() != nullptr); + + DvrNativeBufferMetadata metadata; + LocalHandle invalid_fence; + + // Post, acquire, and release the buffer.. + EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); + EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs))); + EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence)); + EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence)); + + // Note that the next PDX call is on the producer channel, which may be + // executed before Release impulse gets executed by bufferhubd. Thus, here we + // need to wait until the releasd is confirmed before creating another + // consumer. + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); + EXPECT_TRUE(IsBufferReleased(p->buffer_state())); + + // Create another consumer immediately after the release, should not make the + // buffer un-released. + std::unique_ptr<BufferConsumer> c2 = + BufferConsumer::Import(p->CreateConsumer()); + ASSERT_TRUE(c2.get() != nullptr); + + EXPECT_TRUE(IsBufferReleased(p->buffer_state())); + EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence)); + EXPECT_TRUE(IsBufferGained(p->buffer_state())); +} + TEST_F(LibBufferHubTest, TestWithCustomMetadata) { struct Metadata { int64_t field1; @@ -254,7 +483,7 @@ TEST_F(LibBufferHubTest, TestWithCustomMetadata) { Metadata m = {1, 3}; EXPECT_EQ(0, p->Post(LocalHandle(), m)); - EXPECT_LE(0, RETRY_EINTR(c->Poll(10))); + EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); LocalHandle fence; Metadata m2 = {}; @@ -287,7 +516,7 @@ TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) { // buffer allocation. OverSizedMetadata evil_meta = {}; EXPECT_NE(0, p->Post(LocalHandle(), evil_meta)); - EXPECT_GE(0, RETRY_EINTR(c->Poll(10))); + EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); // It is ok to post metadata smaller than originally requested during // buffer allocation. @@ -422,7 +651,7 @@ TEST_F(LibBufferHubTest, TestRemovePersistentBuffer) { EXPECT_EQ(0, p->Post<void>(LocalHandle())); EXPECT_EQ(0, c->Acquire(&fence)); EXPECT_EQ(0, c->Release(LocalHandle())); - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); // Test that removing persistence and closing the producer orphans the // consumer. @@ -463,7 +692,7 @@ TEST_F(LibBufferHubTest, TestAcquireFence) { // Should acquire a valid fence. LocalHandle f2; - EXPECT_LT(0, RETRY_EINTR(c->Poll(10))); + EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); EXPECT_EQ(0, c->AcquireAsync(&meta, &f2)); EXPECT_TRUE(f2.IsValid()); // The original fence and acquired fence should have different fd number. @@ -473,14 +702,14 @@ TEST_F(LibBufferHubTest, TestAcquireFence) { // Signal the original fence will trigger the new fence. eventfd_write(f1.Get(), 1); // Now the original FD has been signaled. - EXPECT_LT(0, PollFd(f2.Get(), 10)); + EXPECT_LT(0, PollFd(f2.Get(), kPollTimeoutMs)); // Release the consumer with an invalid fence. EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle())); // Should gain an invalid fence. LocalHandle f3; - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); EXPECT_EQ(0, p->GainAsync(&meta, &f3)); EXPECT_FALSE(f3.IsValid()); @@ -489,10 +718,10 @@ TEST_F(LibBufferHubTest, TestAcquireFence) { // Should acquire a valid fence and it's already signalled. LocalHandle f4; - EXPECT_LT(0, RETRY_EINTR(c->Poll(10))); + EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs))); EXPECT_EQ(0, c->AcquireAsync(&meta, &f4)); EXPECT_TRUE(f4.IsValid()); - EXPECT_LT(0, PollFd(f4.Get(), 10)); + EXPECT_LT(0, PollFd(f4.Get(), kPollTimeoutMs)); // Release with an unsignalled fence and signal it immediately after release // without producer gainning. @@ -502,10 +731,10 @@ TEST_F(LibBufferHubTest, TestAcquireFence) { // Should gain a valid fence, which is already signaled. LocalHandle f6; - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); EXPECT_EQ(0, p->GainAsync(&meta, &f6)); EXPECT_TRUE(f6.IsValid()); - EXPECT_LT(0, PollFd(f6.Get(), 10)); + EXPECT_LT(0, PollFd(f6.Get(), kPollTimeoutMs)); } TEST_F(LibBufferHubTest, TestOrphanedAcquire) { @@ -521,12 +750,12 @@ TEST_F(LibBufferHubTest, TestOrphanedAcquire) { EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle())); LocalHandle fence; - EXPECT_LT(0, RETRY_EINTR(c1->Poll(10))); + EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs))); EXPECT_LE(0, c1->AcquireAsync(&meta, &fence)); // Destroy the consumer now will make it orphaned and the buffer is still // acquired. c1 = nullptr; - EXPECT_GE(0, RETRY_EINTR(p->Poll(10))); + EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); std::unique_ptr<BufferConsumer> c2 = BufferConsumer::Import(p->CreateConsumer()); @@ -535,13 +764,13 @@ TEST_F(LibBufferHubTest, TestOrphanedAcquire) { EXPECT_NE(consumer_state_bit1, consumer_state_bit2); // The new consumer is available for acquire. - EXPECT_LT(0, RETRY_EINTR(c2->Poll(10))); + EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs))); EXPECT_LE(0, c2->AcquireAsync(&meta, &fence)); // Releasing the consumer makes the buffer gainable. EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle())); // The buffer is now available for the producer to gain. - EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); + EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs))); // But if another consumer is created in released state. std::unique_ptr<BufferConsumer> c3 = @@ -550,7 +779,7 @@ TEST_F(LibBufferHubTest, TestOrphanedAcquire) { const uint64_t consumer_state_bit3 = c3->buffer_state_bit(); EXPECT_NE(consumer_state_bit2, consumer_state_bit3); // The consumer buffer is not acquirable. - EXPECT_GE(0, RETRY_EINTR(c3->Poll(10))); + EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs))); EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence)); // Producer should be able to gain no matter what. diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h index 1186f9348d..a356959a5d 100644 --- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h +++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h @@ -94,6 +94,9 @@ class BufferHubBuffer : public pdx::Client { int id() const { return id_; } + // Returns the buffer buffer state. + uint64_t buffer_state() { return buffer_state_->load(); }; + // A state mask which is unique to a buffer hub client among all its siblings // sharing the same concrete graphic buffer. uint64_t buffer_state_bit() const { return buffer_state_bit_; } diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp index b279875309..8241809775 100644 --- a/libs/vr/libbufferhubqueue/Android.bp +++ b/libs/vr/libbufferhubqueue/Android.bp @@ -14,6 +14,7 @@ sourceFiles = [ "buffer_hub_queue_client.cpp", + "buffer_hub_queue_parcelable.cpp", "buffer_hub_queue_producer.cpp", ] diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp index 8bea0cde7a..c75c67f6d8 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp @@ -31,20 +31,6 @@ namespace dvr { namespace { -// Polls an fd for the given events. -Status<int> PollEvents(int fd, short events) { - const int kTimeoutMs = 0; - pollfd pfd{fd, events, 0}; - const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs)); - if (count < 0) { - return ErrorStatus(errno); - } else if (count == 0) { - return ErrorStatus(ETIMEDOUT); - } else { - return {pfd.revents}; - } -} - std::pair<int32_t, int32_t> Unstuff(uint64_t value) { return {static_cast<int32_t>(value >> 32), static_cast<int32_t>(value & ((1ull << 32) - 1))}; @@ -137,6 +123,28 @@ Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle( return status; } +pdx::Status<ConsumerQueueParcelable> +BufferHubQueue::CreateConsumerQueueParcelable(bool silent) { + auto status = CreateConsumerQueueHandle(silent); + if (!status) + return status.error_status(); + + // A temporary consumer queue client to pull its channel parcelable. + auto consumer_queue = + std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take())); + ConsumerQueueParcelable queue_parcelable( + consumer_queue->GetChannel()->TakeChannelParcelable()); + + if (!queue_parcelable.IsValid()) { + ALOGE( + "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create " + "consumer queue parcelable."); + return ErrorStatus(EINVAL); + } + + return {std::move(queue_parcelable)}; +} + bool BufferHubQueue::WaitForBuffers(int timeout) { ATRACE_NAME("BufferHubQueue::WaitForBuffers"); std::array<epoll_event, kMaxEvents> events; @@ -555,6 +563,25 @@ pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue( return {std::move(buffer)}; } +pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() { + if (capacity() != 0) { + ALOGE( + "ProducerQueue::TakeAsParcelable: producer queue can only be taken out" + " as a parcelable when empty. Current queue capacity: %zu", + capacity()); + return ErrorStatus(EINVAL); + } + + std::unique_ptr<pdx::ClientChannel> channel = TakeChannel(); + ProducerQueueParcelable queue_parcelable(channel->TakeChannelParcelable()); + + // Here the queue parcelable is returned and holds the underlying system + // resources backing the queue; while the original client channel of this + // producer queue is destroyed in place so that this client can no longer + // provide producer operations. + return {std::move(queue_parcelable)}; +} + ConsumerQueue::ConsumerQueue(LocalChannelHandle handle) : BufferHubQueue(std::move(handle)) { auto status = ImportQueue(); @@ -629,27 +656,7 @@ Status<void> ConsumerQueue::AddBuffer( const std::shared_ptr<BufferConsumer>& buffer, size_t slot) { ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu", id(), buffer->id(), slot); - auto status = BufferHubQueue::AddBuffer(buffer, slot); - if (!status) - return status; - - // Check to see if the buffer is already signaled. This is necessary to catch - // cases where buffers are already available; epoll edge triggered mode does - // not fire until an edge transition when adding new buffers to the epoll - // set. Note that we only poll the fd events because HandleBufferEvent() takes - // care of checking the translated buffer events. - auto poll_status = PollEvents(buffer->event_fd(), POLLIN); - if (!poll_status && poll_status.error() != ETIMEDOUT) { - ALOGE("ConsumerQueue::AddBuffer: Failed to poll consumer buffer: %s", - poll_status.GetErrorMessage().c_str()); - return poll_status.error_status(); - } - - // Update accounting if the buffer is available. - if (poll_status) - return HandleBufferEvent(slot, buffer->event_fd(), poll_status.get()); - else - return {}; + return BufferHubQueue::AddBuffer(buffer, slot); } Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue( diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp new file mode 100644 index 0000000000..2cd7c452be --- /dev/null +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp @@ -0,0 +1,82 @@ +#include "include/private/dvr/buffer_hub_queue_parcelable.h" + +#include <binder/Parcel.h> +#include <pdx/default_transport/channel_parcelable.h> + +namespace android { +namespace dvr { + +template <BufferHubQueueParcelableMagic Magic> +bool BufferHubQueueParcelable<Magic>::IsValid() const { + return !!channel_parcelable_ && channel_parcelable_->IsValid(); +} + +template <BufferHubQueueParcelableMagic Magic> +pdx::LocalChannelHandle BufferHubQueueParcelable<Magic>::TakeChannelHandle() { + if (!IsValid()) { + ALOGE( + "BufferHubQueueParcelable::TakeChannelHandle: Invalid channel parcel."); + return {}; // Returns an empty channel handle. + } + + // Take channel handle out of the parcelable and reset the parcelable. + pdx::LocalChannelHandle handle = channel_parcelable_->TakeChannelHandle(); + // Now channel_parcelable_ should already be invalid, but reset it to release + // the invalid parcelable object from unique_ptr. + channel_parcelable_ = nullptr; + return handle; +} + +template <BufferHubQueueParcelableMagic Magic> +status_t BufferHubQueueParcelable<Magic>::writeToParcel(Parcel* parcel) const { + if (!IsValid()) { + ALOGE("BufferHubQueueParcelable::writeToParcel: Invalid channel."); + return -EINVAL; + } + + status_t res = parcel->writeUint32(Magic); + if (res != NO_ERROR) { + ALOGE("BufferHubQueueParcelable::writeToParcel: Cannot write magic."); + return res; + } + + return channel_parcelable_->writeToParcel(parcel); +} + +template <BufferHubQueueParcelableMagic Magic> +status_t BufferHubQueueParcelable<Magic>::readFromParcel(const Parcel* parcel) { + if (IsValid()) { + ALOGE( + "BufferHubQueueParcelable::readFromParcel: This parcelable object has " + "been initialized already."); + return -EINVAL; + } + + uint32_t out_magic = 0; + status_t res = NO_ERROR; + + res = parcel->readUint32(&out_magic); + if (res != NO_ERROR) + return res; + + if (out_magic != Magic) { + ALOGE( + "BufferHubQueueParcelable::readFromParcel: Unexpected magic: 0x%x, " + "epxected: 0x%x", + out_magic, Magic); + return -EINVAL; + } + + // (Re)Alocate channel parcelable object. + channel_parcelable_ = + std::make_unique<pdx::default_transport::ChannelParcelable>(); + return channel_parcelable_->readFromParcel(parcel); +} + +template class BufferHubQueueParcelable< + BufferHubQueueParcelableMagic::Producer>; +template class BufferHubQueueParcelable< + BufferHubQueueParcelableMagic::Consumer>; + +} // namespace dvr +} // namespace android diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp index 221bc4f9d2..ace01a6fcb 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp @@ -9,16 +9,6 @@ namespace android { namespace dvr { /* static */ -sp<BufferHubQueueProducer> BufferHubQueueProducer::Create() { - sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer; - auto config = ProducerQueueConfigBuilder() - .SetMetadata<DvrNativeBufferMetadata>() - .Build(); - producer->queue_ = ProducerQueue::Create(config, UsagePolicy{}); - return producer; -} - -/* static */ sp<BufferHubQueueProducer> BufferHubQueueProducer::Create( const std::shared_ptr<ProducerQueue>& queue) { if (queue->metadata_size() != sizeof(DvrNativeBufferMetadata)) { @@ -33,6 +23,19 @@ sp<BufferHubQueueProducer> BufferHubQueueProducer::Create( return producer; } +/* static */ +sp<BufferHubQueueProducer> BufferHubQueueProducer::Create( + ProducerQueueParcelable parcelable) { + if (!parcelable.IsValid()) { + ALOGE("BufferHubQueueProducer::Create: Invalid producer parcelable."); + return nullptr; + } + + sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer; + producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle()); + return producer; +} + status_t BufferHubQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot); @@ -475,6 +478,13 @@ status_t BufferHubQueueProducer::connect( return BAD_VALUE; } + if (!queue_->is_connected()) { + ALOGE( + "BufferHubQueueProducer::connect: This BufferHubQueueProducer is not " + "connected to bufferhud. Has it been taken out as a parcelable?"); + return BAD_VALUE; + } + switch (api) { case NATIVE_WINDOW_API_EGL: case NATIVE_WINDOW_API_CPU: @@ -617,6 +627,39 @@ status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const { return NO_ERROR; } +status_t BufferHubQueueProducer::TakeAsParcelable( + ProducerQueueParcelable* out_parcelable) { + if (!out_parcelable || out_parcelable->IsValid()) + return BAD_VALUE; + + if (connected_api_ != kNoConnectedApi) { + ALOGE( + "BufferHubQueueProducer::TakeAsParcelable: BufferHubQueueProducer has " + "connected client. Must disconnect first."); + return BAD_VALUE; + } + + if (!queue_->is_connected()) { + ALOGE( + "BufferHubQueueProducer::TakeAsParcelable: This BufferHubQueueProducer " + "is not connected to bufferhud. Has it been taken out as a " + "parcelable?"); + return BAD_VALUE; + } + + auto status = queue_->TakeAsParcelable(); + if (!status) { + ALOGE( + "BufferHubQueueProducer::TakeAsParcelable: Failed to take out " + "ProducuerQueueParcelable from the producer queue, error: %s.", + status.GetErrorMessage().c_str()); + return BAD_VALUE; + } + + *out_parcelable = status.take(); + return NO_ERROR; +} + status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, PixelFormat format, diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h index 6962d6c9f8..5b320a4508 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h @@ -6,6 +6,7 @@ #include <pdx/client.h> #include <pdx/status.h> #include <private/dvr/buffer_hub_client.h> +#include <private/dvr/buffer_hub_queue_parcelable.h> #include <private/dvr/bufferhub_rpc.h> #include <private/dvr/epoll_file_descriptor.h> #include <private/dvr/ring_buffer.h> @@ -54,6 +55,11 @@ class BufferHubQueue : public pdx::Client { pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle( bool silent = false); + // Creates a new consumer in parcelable form for immediate transport over + // Binder. + pdx::Status<ConsumerQueueParcelable> CreateConsumerQueueParcelable( + bool silent = false); + // Returns the number of buffers avaiable for dequeue. size_t count() const { return available_buffers_.size(); } @@ -68,7 +74,8 @@ class BufferHubQueue : public pdx::Client { return available_buffers_.size() >= kMaxQueueCapacity; } - explicit operator bool() const { return epoll_fd_.IsValid(); } + // Returns whether the buffer queue is connected to bufferhubd. + bool is_connected() const { return !!GetChannel(); } int GetBufferId(size_t slot) const { return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id() @@ -337,6 +344,11 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { return BufferHubQueue::Enqueue({buffer, slot, index}); } + // Takes out the current producer queue as a binder parcelable object. Note + // that the queue must be empty to be exportable. After successful export, the + // producer queue client should no longer be used. + pdx::Status<ProducerQueueParcelable> TakeAsParcelable(); + private: friend BASE; diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h new file mode 100644 index 0000000000..89baf92ac8 --- /dev/null +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h @@ -0,0 +1,60 @@ +#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_ +#define ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_ + +#include <pdx/channel_parcelable.h> + +namespace android { +namespace dvr { + +enum BufferHubQueueParcelableMagic : uint32_t { + Producer = 0x62687170, // 'bhqp' + Consumer = 0x62687163, // 'bhqc' +}; + +template <BufferHubQueueParcelableMagic Magic> +class BufferHubQueueParcelable : public Parcelable { + public: + BufferHubQueueParcelable() = default; + + BufferHubQueueParcelable(BufferHubQueueParcelable&& other) = default; + BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) = + default; + + // Constructs an parcelable contains the channel parcelable. + BufferHubQueueParcelable( + std::unique_ptr<pdx::ChannelParcelable> channel_parcelable) + : channel_parcelable_(std::move(channel_parcelable)) {} + + BufferHubQueueParcelable(const BufferHubQueueParcelable&) = delete; + void operator=(const BufferHubQueueParcelable&) = delete; + + bool IsValid() const; + + // Returns a channel handle constructed from this parcelable object and takes + // the ownership of all resources from the parcelable object. + pdx::LocalChannelHandle TakeChannelHandle(); + + // Serializes the queue parcelable into the given parcel. Note that no system + // resources are getting duplicated, nor did the parcel takes ownership of the + // queue parcelable. Thus, the parcelable object must remain valid for the + // lifetime of the parcel. + status_t writeToParcel(Parcel* parcel) const override; + + // Deserialize the queue parcelable from the given parcel. Note that system + // resources are duplicated from the parcel into the queue parcelable. Returns + // error if the targeting parcelable object is already valid. + status_t readFromParcel(const Parcel* parcel) override; + + private: + std::unique_ptr<pdx::ChannelParcelable> channel_parcelable_; +}; + +using ProducerQueueParcelable = + BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Producer>; +using ConsumerQueueParcelable = + BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Consumer>; + +} // namespace dvr +} // namespace android + +#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_ diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h index 7ed55fb533..9c85048648 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h @@ -3,6 +3,7 @@ #include <gui/IGraphicBufferProducer.h> #include <private/dvr/buffer_hub_queue_client.h> +#include <private/dvr/buffer_hub_queue_parcelable.h> namespace android { namespace dvr { @@ -17,14 +18,16 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer { // that. static constexpr int kDefaultUndequeuedBuffers = 1; - // Create a BufferHubQueueProducer instance by creating a new producer queue. - static sp<BufferHubQueueProducer> Create(); - - // Create a BufferHubQueueProducer instance by importing an existing prodcuer + // Creates a BufferHubQueueProducer instance by importing an existing prodcuer // queue. static sp<BufferHubQueueProducer> Create( const std::shared_ptr<ProducerQueue>& producer); + // Creates a BufferHubQueueProducer instance by importing an existing prodcuer + // parcelable. Note that this call takes the ownership of the parcelable + // object and is guaranteed to succeed if parcelable object is valid. + static sp<BufferHubQueueProducer> Create(ProducerQueueParcelable parcelable); + // See |IGraphicBufferProducer::requestBuffer| status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override; @@ -115,6 +118,14 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer { // See |IGraphicBufferProducer::getConsumerUsage| status_t getConsumerUsage(uint64_t* out_usage) const override; + // Takes out the current producer as a binder parcelable object. Note that the + // producer must be disconnected to be exportable. After successful export, + // the producer queue can no longer be connected again. Returns NO_ERROR when + // takeout is successful and out_parcelable will hold the new parcelable + // object. Also note that out_parcelable cannot be NULL and must points to an + // invalid parcelable. + status_t TakeAsParcelable(ProducerQueueParcelable* out_parcelable); + private: using LocalHandle = pdx::LocalHandle; diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp index d8a9b90ad6..5eba913ac3 100644 --- a/libs/vr/libbufferhubqueue/tests/Android.bp +++ b/libs/vr/libbufferhubqueue/tests/Android.bp @@ -12,6 +12,7 @@ shared_libraries = [ "libhardware", "libui", "libutils", + "libnativewindow", ] static_libraries = [ @@ -20,6 +21,7 @@ static_libraries = [ "libchrome", "libdvrcommon", "libpdx_default_transport", + "libperformance", ] cc_test { @@ -56,3 +58,19 @@ cc_test { name: "buffer_hub_queue_producer-test", tags: ["optional"], } + +cc_benchmark { + srcs: ["buffer_transport_benchmark.cpp"], + static_libs: static_libraries, + shared_libs: shared_libraries, + header_libs: header_libraries, + cflags: [ + "-DLOG_TAG=\"buffer_transport_benchmark\"", + "-DTRACE=0", + "-O2", + "-Wall", + "-Werror", + ], + name: "buffer_transport_benchmark", + tags: ["optional"], +} diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp index 8a72531ed5..47a27344bd 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp @@ -1,4 +1,5 @@ #include <base/logging.h> +#include <binder/Parcel.h> #include <private/dvr/buffer_hub_client.h> #include <private/dvr/buffer_hub_queue_client.h> @@ -14,6 +15,7 @@ namespace android { namespace dvr { +using pdx::LocalChannelHandle; using pdx::LocalHandle; namespace { @@ -23,6 +25,8 @@ constexpr uint32_t kBufferHeight = 1; constexpr uint32_t kBufferLayerCount = 1; constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY; +constexpr int kTimeoutMs = 100; +constexpr int kNoTimeout = 0; class BufferHubQueueTest : public ::testing::Test { public: @@ -82,41 +86,49 @@ class BufferHubQueueTest : public ::testing::Test { }; TEST_F(BufferHubQueueTest, TestDequeue) { - const size_t nb_dequeue_times = 16; + const int64_t nb_dequeue_times = 16; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<size_t>().Build(), - UsagePolicy{})); + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); // Allocate only one buffer. AllocateBuffer(); // But dequeue multiple times. - for (size_t i = 0; i < nb_dequeue_times; i++) { + for (int64_t i = 0; i < nb_dequeue_times; i++) { size_t slot; LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); - ASSERT_TRUE(p1_status.ok()); + DvrNativeBufferMetadata mi, mo; + + // Producer gains a buffer. + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_NE(nullptr, p1); - size_t mi = i; - ASSERT_EQ(p1->Post(LocalHandle(), &mi, sizeof(mi)), 0); - size_t mo; - auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); - ASSERT_TRUE(c1_status.ok()); + ASSERT_NE(p1, nullptr); + + // Producer posts the buffer. + mi.index = i; + EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0); + + // Consumer acquires a buffer. + auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(c1_status.ok()); auto c1 = c1_status.take(); - ASSERT_NE(nullptr, c1); - ASSERT_EQ(mi, mo); - c1->Release(LocalHandle()); + ASSERT_NE(c1, nullptr); + EXPECT_EQ(mi.index, i); + EXPECT_EQ(mo.index, i); + + // Consumer releases the buffer. + EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0); } } TEST_F(BufferHubQueueTest, TestProducerConsumer) { const size_t kBufferCount = 16; size_t slot; - uint64_t seq; + DvrNativeBufferMetadata mi, mo; + LocalHandle fence; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(), - UsagePolicy{})); + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); for (size_t i = 0; i < kBufferCount; i++) { AllocateBuffer(); @@ -131,8 +143,7 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { ASSERT_EQ(consumer_queue_->capacity(), i); // Dequeue returns timeout since no buffer is ready to consumer, but // this implicitly triggers buffer import and bump up |capacity|. - LocalHandle fence; - auto status = consumer_queue_->Dequeue(100, &slot, &seq, &fence); + auto status = consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence); ASSERT_FALSE(status.ok()); ASSERT_EQ(ETIMEDOUT, status.error()); ASSERT_EQ(consumer_queue_->capacity(), i + 1); @@ -142,37 +153,37 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); for (size_t i = 0; i < kBufferCount; i++) { - LocalHandle fence; - // First time there is no buffer available to dequeue. - auto consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence); + auto consumer_status = + consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence); ASSERT_FALSE(consumer_status.ok()); - ASSERT_EQ(ETIMEDOUT, consumer_status.error()); + ASSERT_EQ(consumer_status.error(), ETIMEDOUT); // Make sure Producer buffer is POSTED so that it's ready to Accquire // in the consumer's Dequeue() function. - auto producer_status = producer_queue_->Dequeue(100, &slot, &fence); + auto producer_status = + producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); auto producer = producer_status.take(); ASSERT_NE(nullptr, producer); - uint64_t seq_in = static_cast<uint64_t>(i); - ASSERT_EQ(producer->Post(post_fence, &seq_in, sizeof(seq_in)), 0); + mi.index = static_cast<int64_t>(i); + ASSERT_EQ(producer->PostAsync(&mi, post_fence), 0); // Second time the just the POSTED buffer should be dequeued. - uint64_t seq_out = 0; - consumer_status = consumer_queue_->Dequeue(100, &slot, &seq_out, &fence); + consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(consumer_status.ok()); EXPECT_TRUE(fence.IsValid()); auto consumer = consumer_status.take(); ASSERT_NE(nullptr, consumer); - ASSERT_EQ(seq_in, seq_out); + ASSERT_EQ(mi.index, mo.index); } } TEST_F(BufferHubQueueTest, TestRemoveBuffer) { ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); + DvrNativeBufferMetadata mo; // Allocate buffers. const size_t kBufferCount = 4u; @@ -201,7 +212,7 @@ TEST_F(BufferHubQueueTest, TestRemoveBuffer) { for (size_t i = 0; i < kBufferCount; i++) { Entry* entry = &buffers[i]; auto producer_status = producer_queue_->Dequeue( - /*timeout_ms=*/100, &entry->slot, &entry->fence); + kTimeoutMs, &entry->slot, &mo, &entry->fence); ASSERT_TRUE(producer_status.ok()); entry->buffer = producer_status.take(); ASSERT_NE(nullptr, entry->buffer); @@ -221,7 +232,7 @@ TEST_F(BufferHubQueueTest, TestRemoveBuffer) { buffers[0].buffer = nullptr; // Now the consumer queue should know it's gone. - EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100)); + EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs)); ASSERT_EQ(kBufferCount - 1, consumer_queue_->capacity()); // Allocate a new buffer. This should take the first empty slot. @@ -290,126 +301,156 @@ TEST_F(BufferHubQueueTest, TestMultipleConsumers) { ASSERT_NE(nullptr, silent_queue); // Check that silent queue doesn't import buffers on creation. - EXPECT_EQ(0, silent_queue->capacity()); + EXPECT_EQ(silent_queue->capacity(), 0U); // Dequeue and post a buffer. size_t slot; LocalHandle fence; + DvrNativeBufferMetadata mi, mo; auto producer_status = - producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence); - ASSERT_TRUE(producer_status.ok()); + producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(producer_status.ok()); auto producer_buffer = producer_status.take(); - ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post<void>({})); + ASSERT_NE(producer_buffer, nullptr); + EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0); // After post, check the number of remaining available buffers. - EXPECT_EQ(kBufferCount - 1, producer_queue_->count()); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); // Currently we expect no buffer to be available prior to calling // WaitForBuffers/HandleQueueEvents. // TODO(eieio): Note this behavior may change in the future. - EXPECT_EQ(0u, silent_queue->count()); + EXPECT_EQ(silent_queue->count(), 0U); EXPECT_FALSE(silent_queue->HandleQueueEvents()); - EXPECT_EQ(0u, silent_queue->count()); + EXPECT_EQ(silent_queue->count(), 0U); // Build a new consumer queue to test multi-consumer queue features. consumer_queue_ = silent_queue->CreateConsumerQueue(); - ASSERT_NE(nullptr, consumer_queue_); + ASSERT_NE(consumer_queue_, nullptr); // Check that buffers are correctly imported on construction. - EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); - EXPECT_EQ(1u, consumer_queue_->count()); + EXPECT_EQ(consumer_queue_->capacity(), kBufferCount); + // Buffers are only imported, but their availability is not checked until + // first call to Dequeue(). + EXPECT_EQ(consumer_queue_->count(), 0U); // Reclaim released/ignored buffers. - ASSERT_EQ(kBufferCount - 1, producer_queue_->count()); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); usleep(10000); - WaitAndHandleOnce(producer_queue_.get(), /*timeout_ms=*/100); - ASSERT_EQ(kBufferCount - 1, producer_queue_->count()); + WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); // Post another buffer. - producer_status = producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence); - ASSERT_TRUE(producer_status.ok()); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(producer_status.ok()); producer_buffer = producer_status.take(); - ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post<void>({})); + ASSERT_NE(producer_buffer, nullptr); + EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0); // Verify that the consumer queue receives it. size_t consumer_queue_count = consumer_queue_->count(); - WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100); - EXPECT_LT(consumer_queue_count, consumer_queue_->count()); + WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs); + EXPECT_GT(consumer_queue_->count(), consumer_queue_count); // Save the current consumer queue buffer count to compare after the dequeue. consumer_queue_count = consumer_queue_->count(); // Dequeue and acquire/release (discard) buffers on the consumer end. auto consumer_status = - consumer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence); - ASSERT_TRUE(consumer_status.ok()); + consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(consumer_status.ok()); auto consumer_buffer = consumer_status.take(); - ASSERT_NE(nullptr, consumer_buffer); + ASSERT_NE(consumer_buffer, nullptr); consumer_buffer->Discard(); // Buffer should be returned to the producer queue without being handled by // the silent consumer queue. - EXPECT_GT(consumer_queue_count, consumer_queue_->count()); - EXPECT_EQ(kBufferCount - 2, producer_queue_->count()); - EXPECT_TRUE(producer_queue_->HandleQueueEvents()); - EXPECT_EQ(kBufferCount - 1, producer_queue_->count()); + EXPECT_LT(consumer_queue_->count(), consumer_queue_count); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 2); + + WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs); + EXPECT_EQ(producer_queue_->count(), kBufferCount - 1); } -struct TestMetadata { +struct TestUserMetadata { char a; int32_t b; int64_t c; }; -TEST_F(BufferHubQueueTest, TestMetadata) { - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<TestMetadata>().Build(), - UsagePolicy{})); +constexpr uint64_t kUserMetadataSize = + static_cast<uint64_t>(sizeof(TestUserMetadata)); + +TEST_F(BufferHubQueueTest, TestUserMetadata) { + ASSERT_TRUE(CreateQueues( + config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{})); AllocateBuffer(); - std::vector<TestMetadata> ms = { + std::vector<TestUserMetadata> user_metadata_list = { {'0', 0, 0}, {'1', 10, 3333}, {'@', 123, 1000000000}}; - for (auto mi : ms) { + for (auto user_metadata : user_metadata_list) { size_t slot; LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); - ASSERT_TRUE(p1_status.ok()); + DvrNativeBufferMetadata mi, mo; + + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_NE(nullptr, p1); - ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0); - TestMetadata mo; - auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); - ASSERT_TRUE(c1_status.ok()); + ASSERT_NE(p1, nullptr); + + // TODO(b/69469185): Test against metadata from consumer once we implement + // release metadata properly. + // EXPECT_EQ(mo.user_metadata_ptr, 0U); + // EXPECT_EQ(mo.user_metadata_size, 0U); + + mi.user_metadata_size = kUserMetadataSize; + mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata); + EXPECT_EQ(p1->PostAsync(&mi, {}), 0); + auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(c1_status.ok()); auto c1 = c1_status.take(); - ASSERT_EQ(mi.a, mo.a); - ASSERT_EQ(mi.b, mo.b); - ASSERT_EQ(mi.c, mo.c); - c1->Release(LocalHandle(-1)); + ASSERT_NE(c1, nullptr); + + EXPECT_EQ(mo.user_metadata_size, kUserMetadataSize); + auto out_user_metadata = + reinterpret_cast<TestUserMetadata*>(mo.user_metadata_ptr); + EXPECT_EQ(user_metadata.a, out_user_metadata->a); + EXPECT_EQ(user_metadata.b, out_user_metadata->b); + EXPECT_EQ(user_metadata.c, out_user_metadata->c); + + // When release, empty metadata is also legit. + mi.user_metadata_size = 0U; + mi.user_metadata_ptr = 0U; + c1->ReleaseAsync(&mi, {}); } } -TEST_F(BufferHubQueueTest, TestMetadataMismatch) { - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{})); +TEST_F(BufferHubQueueTest, TestUserMetadataMismatch) { + ASSERT_TRUE(CreateQueues( + config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{})); AllocateBuffer(); - int64_t mi = 3; + TestUserMetadata user_metadata; size_t slot; LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); - ASSERT_TRUE(p1_status.ok()); + DvrNativeBufferMetadata mi, mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); + EXPECT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_NE(nullptr, p1); - ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0); - - int32_t mo; - // Acquire a buffer with mismatched metadata is not OK. - auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); - ASSERT_FALSE(c1_status.ok()); + ASSERT_NE(p1, nullptr); + + // Post with mismatched user metadata size will fail. But the producer buffer + // itself should stay untouched. + mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata); + mi.user_metadata_size = kUserMetadataSize + 1; + EXPECT_EQ(p1->PostAsync(&mi, {}), -E2BIG); + // Post with the exact same user metdata size can success. + mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata); + mi.user_metadata_size = kUserMetadataSize; + EXPECT_EQ(p1->PostAsync(&mi, {}), 0); } TEST_F(BufferHubQueueTest, TestEnqueue) { @@ -419,32 +460,32 @@ TEST_F(BufferHubQueueTest, TestEnqueue) { size_t slot; LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); + DvrNativeBufferMetadata mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); ASSERT_NE(nullptr, p1); - int64_t mo; producer_queue_->Enqueue(p1, slot, 0ULL); - auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); + auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_FALSE(c1_status.ok()); } TEST_F(BufferHubQueueTest, TestAllocateBuffer) { - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{})); + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); - size_t s1; + size_t ps1; AllocateBuffer(); LocalHandle fence; - auto p1_status = producer_queue_->Dequeue(100, &s1, &fence); + DvrNativeBufferMetadata mi, mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &ps1, &mo, &fence); ASSERT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_NE(nullptr, p1); + ASSERT_NE(p1, nullptr); // producer queue is exhausted - size_t s2; - auto p2_status = producer_queue_->Dequeue(100, &s2, &fence); + size_t ps2; + auto p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence); ASSERT_FALSE(p2_status.ok()); ASSERT_EQ(ETIMEDOUT, p2_status.error()); @@ -454,41 +495,43 @@ TEST_F(BufferHubQueueTest, TestAllocateBuffer) { ASSERT_EQ(producer_queue_->capacity(), 2U); // now we can dequeue again - p2_status = producer_queue_->Dequeue(100, &s2, &fence); + p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence); ASSERT_TRUE(p2_status.ok()); auto p2 = p2_status.take(); - ASSERT_NE(nullptr, p2); + ASSERT_NE(p2, nullptr); ASSERT_EQ(producer_queue_->count(), 0U); // p1 and p2 should have different slot number - ASSERT_NE(s1, s2); + ASSERT_NE(ps1, ps2); // Consumer queue does not import buffers until |Dequeue| or |ImportBuffers| // are called. So far consumer_queue_ should be empty. ASSERT_EQ(consumer_queue_->count(), 0U); int64_t seq = 1; - ASSERT_EQ(p1->Post(LocalHandle(), seq), 0); + mi.index = seq; + ASSERT_EQ(p1->PostAsync(&mi, {}), 0); + size_t cs1, cs2; - auto c1_status = consumer_queue_->Dequeue(100, &cs1, &seq, &fence); + auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &cs1, &mo, &fence); ASSERT_TRUE(c1_status.ok()); auto c1 = c1_status.take(); - ASSERT_NE(nullptr, c1); + ASSERT_NE(c1, nullptr); ASSERT_EQ(consumer_queue_->count(), 0U); ASSERT_EQ(consumer_queue_->capacity(), 2U); - ASSERT_EQ(cs1, s1); + ASSERT_EQ(cs1, ps1); - ASSERT_EQ(p2->Post(LocalHandle(), seq), 0); - auto c2_status = consumer_queue_->Dequeue(100, &cs2, &seq, &fence); + ASSERT_EQ(p2->PostAsync(&mi, {}), 0); + auto c2_status = consumer_queue_->Dequeue(kTimeoutMs, &cs2, &mo, &fence); ASSERT_TRUE(c2_status.ok()); auto c2 = c2_status.take(); - ASSERT_NE(nullptr, c2); - ASSERT_EQ(cs2, s2); + ASSERT_NE(c2, nullptr); + ASSERT_EQ(cs2, ps2); } TEST_F(BufferHubQueueTest, TestUsageSetMask) { const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{set_mask, 0, 0, 0})); + ASSERT_TRUE( + CreateQueues(config_builder_.Build(), UsagePolicy{set_mask, 0, 0, 0})); // When allocation, leave out |set_mask| from usage bits on purpose. auto status = producer_queue_->AllocateBuffer( @@ -498,7 +541,8 @@ TEST_F(BufferHubQueueTest, TestUsageSetMask) { LocalHandle fence; size_t slot; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); + DvrNativeBufferMetadata mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); ASSERT_EQ(p1->usage() & set_mask, set_mask); @@ -506,8 +550,8 @@ TEST_F(BufferHubQueueTest, TestUsageSetMask) { TEST_F(BufferHubQueueTest, TestUsageClearMask) { const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(), - UsagePolicy{0, clear_mask, 0, 0})); + ASSERT_TRUE( + CreateQueues(config_builder_.Build(), UsagePolicy{0, clear_mask, 0, 0})); // When allocation, add |clear_mask| into usage bits on purpose. auto status = producer_queue_->AllocateBuffer( @@ -517,10 +561,11 @@ TEST_F(BufferHubQueueTest, TestUsageClearMask) { LocalHandle fence; size_t slot; - auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); + DvrNativeBufferMetadata mo; + auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(p1_status.ok()); auto p1 = p1_status.take(); - ASSERT_EQ(0u, p1->usage() & clear_mask); + ASSERT_EQ(p1->usage() & clear_mask, 0U); } TEST_F(BufferHubQueueTest, TestUsageDenySetMask) { @@ -598,16 +643,15 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { EXPECT_EQ(producer_queue_->capacity(), num_buffers); size_t slot; - uint64_t seq; LocalHandle fence; pdx::Status<void> status; pdx::Status<std::shared_ptr<BufferConsumer>> consumer_status; pdx::Status<std::shared_ptr<BufferProducer>> producer_status; std::shared_ptr<BufferConsumer> consumer_buffer; std::shared_ptr<BufferProducer> producer_buffer; + DvrNativeBufferMetadata mi, mo; - ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(), - UsagePolicy{})); + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); // Free all buffers when buffers are avaible for dequeue. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); @@ -616,7 +660,7 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { // Free all buffers when one buffer is dequeued. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); status = producer_queue_->FreeAllBuffers(); EXPECT_TRUE(status.ok()); @@ -624,7 +668,7 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { // Free all buffers when all buffers are dequeued. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); for (size_t i = 0; i < kBufferCount; i++) { - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); } status = producer_queue_->FreeAllBuffers(); @@ -632,22 +676,22 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { // Free all buffers when one buffer is posted. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); producer_buffer = producer_status.take(); ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + ASSERT_EQ(0, producer_buffer->PostAsync(&mi, fence)); status = producer_queue_->FreeAllBuffers(); EXPECT_TRUE(status.ok()); // Free all buffers when all buffers are posted. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); for (size_t i = 0; i < kBufferCount; i++) { - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); producer_buffer = producer_status.take(); - ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); + ASSERT_NE(producer_buffer, nullptr); + ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0); } status = producer_queue_->FreeAllBuffers(); EXPECT_TRUE(status.ok()); @@ -655,12 +699,12 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { // Free all buffers when all buffers are acquired. CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); for (size_t i = 0; i < kBufferCount; i++) { - producer_status = producer_queue_->Dequeue(100, &slot, &fence); + producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(producer_status.ok()); producer_buffer = producer_status.take(); - ASSERT_NE(nullptr, producer_buffer); - ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); - consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence); + ASSERT_NE(producer_buffer, nullptr); + ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0); + consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence); ASSERT_TRUE(consumer_status.ok()); } @@ -680,6 +724,156 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { #undef CHECK_NO_BUFFER_THEN_ALLOCATE } +TEST_F(BufferHubQueueTest, TestProducerToParcelableNotEmpty) { + ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(), + UsagePolicy{})); + + // Allocate only one buffer. + AllocateBuffer(); + + // Export should fail as the queue is not empty. + auto status = producer_queue_->TakeAsParcelable(); + EXPECT_FALSE(status.ok()); +} + +TEST_F(BufferHubQueueTest, TestProducerExportToParcelable) { + ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{})); + + auto s1 = producer_queue_->TakeAsParcelable(); + EXPECT_TRUE(s1.ok()); + + ProducerQueueParcelable output_parcelable = s1.take(); + EXPECT_TRUE(output_parcelable.IsValid()); + + Parcel parcel; + status_t res; + res = output_parcelable.writeToParcel(&parcel); + EXPECT_EQ(res, NO_ERROR); + + // After written into parcelable, the output_parcelable is still valid has + // keeps the producer channel alive. + EXPECT_TRUE(output_parcelable.IsValid()); + + // Creating producer buffer should fail. + auto s2 = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, + kBufferLayerCount, kBufferFormat, + kBufferUsage); + ASSERT_FALSE(s2.ok()); + + // Reset the data position so that we can read back from the same parcel + // without doing actually Binder IPC. + parcel.setDataPosition(0); + producer_queue_ = nullptr; + + // Recreate the producer queue from the parcel. + ProducerQueueParcelable input_parcelable; + EXPECT_FALSE(input_parcelable.IsValid()); + + res = input_parcelable.readFromParcel(&parcel); + EXPECT_EQ(res, NO_ERROR); + EXPECT_TRUE(input_parcelable.IsValid()); + + EXPECT_EQ(producer_queue_, nullptr); + producer_queue_ = ProducerQueue::Import(input_parcelable.TakeChannelHandle()); + EXPECT_FALSE(input_parcelable.IsValid()); + ASSERT_NE(producer_queue_, nullptr); + + // Newly created queue from the parcel can allocate buffer, post buffer to + // consumer. + EXPECT_NO_FATAL_FAILURE(AllocateBuffer()); + EXPECT_EQ(producer_queue_->count(), 1U); + EXPECT_EQ(producer_queue_->capacity(), 1U); + + size_t slot; + DvrNativeBufferMetadata producer_meta; + DvrNativeBufferMetadata consumer_meta; + LocalHandle fence; + auto s3 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence); + EXPECT_TRUE(s3.ok()); + + std::shared_ptr<BufferProducer> p1 = s3.take(); + ASSERT_NE(p1, nullptr); + + producer_meta.timestamp = 42; + EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0); + + // Make sure the buffer can be dequeued from consumer side. + auto s4 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence); + EXPECT_TRUE(s4.ok()); + EXPECT_EQ(consumer_queue_->capacity(), 1U); + + auto consumer = s4.take(); + ASSERT_NE(consumer, nullptr); + EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp); +} + +TEST_F(BufferHubQueueTest, TestCreateConsumerParcelable) { + ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{})); + + auto s1 = producer_queue_->CreateConsumerQueueParcelable(); + EXPECT_TRUE(s1.ok()); + ConsumerQueueParcelable output_parcelable = s1.take(); + EXPECT_TRUE(output_parcelable.IsValid()); + + // Write to a Parcel new object. + Parcel parcel; + status_t res; + res = output_parcelable.writeToParcel(&parcel); + + // Reset the data position so that we can read back from the same parcel + // without doing actually Binder IPC. + parcel.setDataPosition(0); + + // No consumer queue created yet. + EXPECT_EQ(consumer_queue_, nullptr); + + // If the parcel contains a consumer queue, read into a + // ProducerQueueParcelable should fail. + ProducerQueueParcelable wrongly_typed_parcelable; + EXPECT_FALSE(wrongly_typed_parcelable.IsValid()); + res = wrongly_typed_parcelable.readFromParcel(&parcel); + EXPECT_EQ(res, -EINVAL); + parcel.setDataPosition(0); + + // Create the consumer queue from the parcel. + ConsumerQueueParcelable input_parcelable; + EXPECT_FALSE(input_parcelable.IsValid()); + + res = input_parcelable.readFromParcel(&parcel); + EXPECT_EQ(res, NO_ERROR); + EXPECT_TRUE(input_parcelable.IsValid()); + + consumer_queue_ = ConsumerQueue::Import(input_parcelable.TakeChannelHandle()); + EXPECT_FALSE(input_parcelable.IsValid()); + ASSERT_NE(consumer_queue_, nullptr); + + EXPECT_NO_FATAL_FAILURE(AllocateBuffer()); + EXPECT_EQ(producer_queue_->count(), 1U); + EXPECT_EQ(producer_queue_->capacity(), 1U); + + size_t slot; + DvrNativeBufferMetadata producer_meta; + DvrNativeBufferMetadata consumer_meta; + LocalHandle fence; + auto s2 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence); + EXPECT_TRUE(s2.ok()); + + std::shared_ptr<BufferProducer> p1 = s2.take(); + ASSERT_NE(p1, nullptr); + + producer_meta.timestamp = 42; + EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0); + + // Make sure the buffer can be dequeued from consumer side. + auto s3 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence); + EXPECT_TRUE(s3.ok()); + EXPECT_EQ(consumer_queue_->capacity(), 1U); + + auto consumer = s3.take(); + ASSERT_NE(consumer, nullptr); + EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp); +} + } // namespace } // namespace dvr diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp index 28cd63af2d..96f540421e 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp @@ -3,12 +3,15 @@ #include <base/logging.h> #include <gui/IProducerListener.h> #include <gui/Surface.h> +#include <pdx/default_transport/channel_parcelable.h> #include <gtest/gtest.h> namespace android { namespace dvr { +using pdx::LocalHandle; + namespace { // Default dimensions before setDefaultBufferSize is called by the consumer. @@ -92,7 +95,13 @@ class BufferHubQueueProducerTest : public ::testing::Test { ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); - mProducer = BufferHubQueueProducer::Create(); + auto config = ProducerQueueConfigBuilder() + .SetMetadata<DvrNativeBufferMetadata>() + .Build(); + auto queue = ProducerQueue::Create(config, UsagePolicy{}); + ASSERT_TRUE(queue != nullptr); + + mProducer = BufferHubQueueProducer::Create(std::move(queue)); ASSERT_TRUE(mProducer != nullptr); mSurface = new Surface(mProducer, true); ASSERT_TRUE(mSurface != nullptr); @@ -546,6 +555,55 @@ TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) { EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi)); } +TEST_F(BufferHubQueueProducerTest, TakeAsParcelable) { + // Connected producer cannot be taken out as a parcelable. + EXPECT_NO_FATAL_FAILURE(ConnectProducer()); + ProducerQueueParcelable producer_parcelable; + EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), BAD_VALUE); + + // Create a valid dummy producer parcelable. + auto dummy_channel_parcelable = + std::make_unique<pdx::default_transport::ChannelParcelable>( + LocalHandle(0), LocalHandle(0), LocalHandle(0)); + EXPECT_TRUE(dummy_channel_parcelable->IsValid()); + ProducerQueueParcelable dummy_producer_parcelable( + std::move(dummy_channel_parcelable)); + EXPECT_TRUE(dummy_producer_parcelable.IsValid()); + + // Disconnect producer can be taken out, but only to an invalid parcelable. + ASSERT_EQ(mProducer->disconnect(kTestApi), NO_ERROR); + EXPECT_EQ(mProducer->TakeAsParcelable(&dummy_producer_parcelable), BAD_VALUE); + EXPECT_FALSE(producer_parcelable.IsValid()); + EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), NO_ERROR); + EXPECT_TRUE(producer_parcelable.IsValid()); + + // Should still be able to query buffer dimension after disconnect. + int32_t value = -1; + EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_WIDTH, &value)); + EXPECT_EQ(static_cast<uint32_t>(value), kDefaultWidth); + + EXPECT_EQ(mProducer->query(NATIVE_WINDOW_HEIGHT, &value), NO_ERROR); + EXPECT_EQ(static_cast<uint32_t>(value), kDefaultHeight); + + EXPECT_EQ(mProducer->query(NATIVE_WINDOW_FORMAT, &value), NO_ERROR); + EXPECT_EQ(value, kDefaultFormat); + + // But connect to API will fail. + IGraphicBufferProducer::QueueBufferOutput output; + EXPECT_EQ(mProducer->connect(kDummyListener, kTestApi, kTestControlledByApp, + &output), + BAD_VALUE); + + // Create a new producer from the parcelable and connect to kTestApi should + // succeed. + sp<BufferHubQueueProducer> new_producer = + BufferHubQueueProducer::Create(std::move(producer_parcelable)); + ASSERT_TRUE(new_producer != nullptr); + EXPECT_EQ(new_producer->connect(kDummyListener, kTestApi, + kTestControlledByApp, &output), + NO_ERROR); +} + } // namespace } // namespace dvr diff --git a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp new file mode 100644 index 0000000000..d4d25b0013 --- /dev/null +++ b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp @@ -0,0 +1,536 @@ +#include <android/native_window.h> +#include <android-base/logging.h> +#include <benchmark/benchmark.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <dvr/dvr_api.h> +#include <dvr/performance_client_api.h> +#include <gui/BufferItem.h> +#include <gui/BufferItemConsumer.h> +#include <gui/Surface.h> +#include <private/dvr/buffer_hub_queue_producer.h> +#include <utils/Trace.h> + +#include <chrono> +#include <functional> +#include <iostream> +#include <thread> +#include <vector> + +#include <poll.h> +#include <sys/wait.h> + +// Use ALWAYS at the tag level. Control is performed manually during command +// line processing. +#ifdef ATRACE_TAG +#undef ATRACE_TAG +#endif +#define ATRACE_TAG ATRACE_TAG_ALWAYS + +using namespace android; +using namespace android::dvr; +using ::benchmark::State; + +static const String16 kBinderService = String16("bufferTransport"); +static const uint32_t kBufferWidth = 100; +static const uint32_t kBufferHeight = 1; +static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; +static const uint64_t kBufferUsage = + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; +static const int kMaxAcquiredImages = 1; +static const int kQueueDepth = 2; // We are double buffering for this test. +static const size_t kMaxQueueCounts = 128; + +enum BufferTransportServiceCode { + CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION, +}; + +// A binder services that minics a compositor that consumes buffers. It provides +// one Binder interface to create a new Surface for buffer producer to write +// into; while itself will carry out no-op buffer consuming by acquiring then +// releasing the buffer immediately. +class BufferTransportService : public BBinder { + public: + BufferTransportService() = default; + ~BufferTransportService() = default; + + virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags = 0) { + (void)flags; + (void)data; + switch (code) { + case CREATE_BUFFER_QUEUE: { + auto new_queue = std::make_shared<BufferQueueHolder>(this); + reply->writeStrongBinder( + IGraphicBufferProducer::asBinder(new_queue->producer_)); + buffer_queues_.push_back(new_queue); + return NO_ERROR; + } + default: + return UNKNOWN_TRANSACTION; + }; + } + + private: + struct FrameListener : public ConsumerBase::FrameAvailableListener { + public: + FrameListener(BufferTransportService* /*service*/, + sp<BufferItemConsumer> buffer_item_consumer) + : buffer_item_consumer_(buffer_item_consumer) {} + + void onFrameAvailable(const BufferItem& /*item*/) override { + BufferItem buffer; + status_t ret = 0; + { + ATRACE_NAME("AcquireBuffer"); + ret = buffer_item_consumer_->acquireBuffer(&buffer, /*presentWhen=*/0, + /*waitForFence=*/false); + } + + if (ret != NO_ERROR) { + LOG(ERROR) << "Failed to acquire next buffer."; + return; + } + + { + ATRACE_NAME("ReleaseBuffer"); + ret = buffer_item_consumer_->releaseBuffer(buffer); + } + + if (ret != NO_ERROR) { + LOG(ERROR) << "Failed to release buffer."; + return; + } + } + + private: + sp<BufferItemConsumer> buffer_item_consumer_; + }; + + struct BufferQueueHolder { + explicit BufferQueueHolder(BufferTransportService* service) { + BufferQueue::createBufferQueue(&producer_, &consumer_); + + sp<BufferItemConsumer> buffer_item_consumer = + new BufferItemConsumer(consumer_, kBufferUsage, kMaxAcquiredImages, + /*controlledByApp=*/true); + buffer_item_consumer->setName(String8("BinderBufferTransport")); + frame_listener_ = new FrameListener(service, buffer_item_consumer); + buffer_item_consumer->setFrameAvailableListener(frame_listener_); + } + + sp<IGraphicBufferProducer> producer_; + sp<IGraphicBufferConsumer> consumer_; + sp<FrameListener> frame_listener_; + }; + + std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_; +}; + +// A virtual interfaces that abstracts the common BufferQueue operations, so +// that the test suite can use the same test case to drive different types of +// transport backends. +class BufferTransport { + public: + virtual ~BufferTransport() {} + + virtual int Start() = 0; + virtual sp<Surface> CreateSurface() = 0; +}; + +// Binder-based buffer transport backend. +// +// On Start() a new process will be swapned to run a Binder server that +// actually consumes the buffer. +// On CreateSurface() a new Binder BufferQueue will be created, which the +// service holds the concrete binder node of the IGraphicBufferProducer while +// sending the binder proxy to the client. In another word, the producer side +// operations are carried out process while the consumer side operations are +// carried out within the BufferTransportService's own process. +class BinderBufferTransport : public BufferTransport { + public: + BinderBufferTransport() {} + + int Start() override { + sp<IServiceManager> sm = defaultServiceManager(); + service_ = sm->getService(kBinderService); + if (service_ == nullptr) { + LOG(ERROR) << "Failed to get the benchmark service."; + return -EIO; + } + + LOG(INFO) << "Binder server is ready for client."; + return 0; + } + + sp<Surface> CreateSurface() override { + Parcel data; + Parcel reply; + int error = service_->transact(CREATE_BUFFER_QUEUE, data, &reply); + if (error != NO_ERROR) { + LOG(ERROR) << "Failed to get buffer queue over binder."; + return nullptr; + } + + sp<IBinder> binder; + error = reply.readNullableStrongBinder(&binder); + if (error != NO_ERROR) { + LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder."; + return nullptr; + } + + auto producer = interface_cast<IGraphicBufferProducer>(binder); + if (producer == nullptr) { + LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder."; + return nullptr; + } + + sp<Surface> surface = new Surface(producer, /*controlledByApp=*/true); + + // Set buffer dimension. + ANativeWindow* window = static_cast<ANativeWindow*>(surface.get()); + ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight, + kBufferFormat); + + return surface; + } + + private: + sp<IBinder> service_; +}; + +// BufferHub/PDX-based buffer transport. +// +// On Start() a new thread will be swapned to run an epoll polling thread which +// minics the behavior of a compositor. Similar to Binder-based backend, the +// buffer available handler is also a no-op: Buffer gets acquired and released +// immediately. +// On CreateSurface() a pair of dvr::ProducerQueue and dvr::ConsumerQueue will +// be created. The epoll thread holds on the consumer queue and dequeues buffer +// from it; while the producer queue will be wrapped in a Surface and returned +// to test suite. +class BufferHubTransport : public BufferTransport { + public: + virtual ~BufferHubTransport() { + stopped_.store(true); + if (reader_thread_.joinable()) { + reader_thread_.join(); + } + } + + int Start() override { + int ret = epoll_fd_.Create(); + if (ret < 0) { + LOG(ERROR) << "Failed to create epoll fd: %s", strerror(-ret); + return -1; + } + + // Create the reader thread. + reader_thread_ = std::thread([this]() { + int ret = dvrSetSchedulerClass(0, "graphics"); + if (ret < 0) { + LOG(ERROR) << "Failed to set thread priority"; + return; + } + + + ret = dvrSetCpuPartition(0, "/system/performance"); + if (ret < 0) { + LOG(ERROR) << "Failed to set thread cpu partition"; + return; + } + + stopped_.store(false); + LOG(INFO) << "Reader Thread Running..."; + + while (!stopped_.load()) { + std::array<epoll_event, kMaxQueueCounts> events; + + // Don't sleep forever so that we will have a chance to wake up. + const int ret = epoll_fd_.Wait(events.data(), events.size(), + /*timeout=*/100); + if (ret < 0) { + LOG(ERROR) << "Error polling consumer queues."; + continue; + } + if (ret == 0) { + continue; + } + + const int num_events = ret; + for (int i = 0; i < num_events; i++) { + uint32_t surface_index = events[i].data.u32; + buffer_queues_[surface_index]->consumer_queue_->HandleQueueEvents(); + } + } + + LOG(INFO) << "Reader Thread Exiting..."; + }); + + return 0; + } + + sp<Surface> CreateSurface() override { + auto new_queue = std::make_shared<BufferQueueHolder>(); + if (new_queue->producer_ == nullptr) { + LOG(ERROR) << "Failed to create buffer producer."; + return nullptr; + } + + sp<Surface> surface = + new Surface(new_queue->producer_, /*controlledByApp=*/true); + + // Set buffer dimension. + ANativeWindow* window = static_cast<ANativeWindow*>(surface.get()); + ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight, + kBufferFormat); + + // Use the next position as buffer_queue index. + uint32_t index = buffer_queues_.size(); + epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u32 = index}}; + const int ret = epoll_fd_.Control( + EPOLL_CTL_ADD, new_queue->consumer_queue_->queue_fd(), &event); + if (ret < 0) { + LOG(ERROR) << "Failed to track consumer queue: " << strerror(-ret) + << ", consumer queue fd: " + << new_queue->consumer_queue_->queue_fd(); + return nullptr; + } + + new_queue->queue_index_ = index; + buffer_queues_.push_back(new_queue); + return surface; + } + + private: + struct BufferQueueHolder { + BufferQueueHolder() { + ProducerQueueConfigBuilder config_builder; + producer_queue_ = + ProducerQueue::Create(config_builder.SetDefaultWidth(kBufferWidth) + .SetDefaultHeight(kBufferHeight) + .SetDefaultFormat(kBufferFormat) + .SetMetadata<DvrNativeBufferMetadata>() + .Build(), + UsagePolicy{}); + consumer_queue_ = producer_queue_->CreateConsumerQueue(); + consumer_queue_->SetBufferAvailableCallback([this]() { + size_t index = 0; + pdx::LocalHandle fence; + DvrNativeBufferMetadata meta; + pdx::Status<std::shared_ptr<BufferConsumer>> status; + + { + ATRACE_NAME("AcquireBuffer"); + status = consumer_queue_->Dequeue(0, &index, &meta, &fence); + } + if (!status.ok()) { + LOG(ERROR) << "Failed to dequeue consumer buffer, error: " + << status.GetErrorMessage().c_str(); + return; + } + + auto buffer = status.take(); + + if (buffer) { + ATRACE_NAME("ReleaseBuffer"); + buffer->ReleaseAsync(); + } + }); + + producer_ = BufferHubQueueProducer::Create(producer_queue_); + } + + int count_ = 0; + int queue_index_; + std::shared_ptr<ProducerQueue> producer_queue_; + std::shared_ptr<ConsumerQueue> consumer_queue_; + sp<IGraphicBufferProducer> producer_; + }; + + std::atomic<bool> stopped_; + std::thread reader_thread_; + + EpollFileDescriptor epoll_fd_; + std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_; +}; + +enum TransportType { + kBinderBufferTransport, + kBufferHubTransport, +}; + +// Main test suite, which supports two transport backend: 1) BinderBufferQueue, +// 2) BufferHubQueue. The test case drives the producer end of both transport +// backend by queuing buffers into the buffer queue by using ANativeWindow API. +class BufferTransportBenchmark : public ::benchmark::Fixture { + public: + void SetUp(State& state) override { + if (state.thread_index == 0) { + const int transport = state.range(0); + switch (transport) { + case kBinderBufferTransport: + transport_.reset(new BinderBufferTransport); + break; + case kBufferHubTransport: + transport_.reset(new BufferHubTransport); + break; + default: + CHECK(false) << "Unknown test case."; + break; + } + + CHECK(transport_); + const int ret = transport_->Start(); + CHECK_EQ(ret, 0); + + LOG(INFO) << "Transport backend running, transport=" << transport << "."; + + // Create surfaces for each thread. + surfaces_.resize(state.threads); + for (int i = 0; i < state.threads; i++) { + // Common setup every thread needs. + surfaces_[i] = transport_->CreateSurface(); + CHECK(surfaces_[i]); + + LOG(INFO) << "Surface initialized on thread " << i << "."; + } + } + } + + void TearDown(State& state) override { + if (state.thread_index == 0) { + surfaces_.clear(); + transport_.reset(); + LOG(INFO) << "Tear down benchmark."; + } + } + + protected: + std::unique_ptr<BufferTransport> transport_; + std::vector<sp<Surface>> surfaces_; +}; + +BENCHMARK_DEFINE_F(BufferTransportBenchmark, Producers)(State& state) { + ANativeWindow* window = nullptr; + ANativeWindow_Buffer buffer; + int32_t error = 0; + double total_gain_buffer_us = 0; + double total_post_buffer_us = 0; + int iterations = 0; + + while (state.KeepRunning()) { + if (window == nullptr) { + CHECK(surfaces_[state.thread_index]); + window = static_cast<ANativeWindow*>(surfaces_[state.thread_index].get()); + + // Lock buffers a couple time from the queue, so that we have the buffer + // allocated. + for (int i = 0; i < kQueueDepth; i++) { + error = ANativeWindow_lock(window, &buffer, + /*inOutDirtyBounds=*/nullptr); + CHECK_EQ(error, 0); + error = ANativeWindow_unlockAndPost(window); + CHECK_EQ(error, 0); + } + } + + { + ATRACE_NAME("GainBuffer"); + auto t1 = std::chrono::high_resolution_clock::now(); + error = ANativeWindow_lock(window, &buffer, + /*inOutDirtyBounds=*/nullptr); + auto t2 = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double, std::micro> delta_us = t2 - t1; + total_gain_buffer_us += delta_us.count(); + } + CHECK_EQ(error, 0); + + { + ATRACE_NAME("PostBuffer"); + auto t1 = std::chrono::high_resolution_clock::now(); + error = ANativeWindow_unlockAndPost(window); + auto t2 = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double, std::micro> delta_us = t2 - t1; + total_post_buffer_us += delta_us.count(); + } + CHECK_EQ(error, 0); + + iterations++; + } + + state.counters["gain_buffer_us"] = ::benchmark::Counter( + total_gain_buffer_us / iterations, ::benchmark::Counter::kAvgThreads); + state.counters["post_buffer_us"] = ::benchmark::Counter( + total_post_buffer_us / iterations, ::benchmark::Counter::kAvgThreads); + state.counters["producer_us"] = ::benchmark::Counter( + (total_gain_buffer_us + total_post_buffer_us) / iterations, + ::benchmark::Counter::kAvgThreads); +} + +BENCHMARK_REGISTER_F(BufferTransportBenchmark, Producers) + ->Unit(::benchmark::kMicrosecond) + ->Ranges({{kBinderBufferTransport, kBufferHubTransport}}) + ->ThreadRange(1, 32); + +static void runBinderServer() { + ProcessState::self()->setThreadPoolMaxThreadCount(0); + ProcessState::self()->startThreadPool(); + + sp<IServiceManager> sm = defaultServiceManager(); + sp<BufferTransportService> service = new BufferTransportService; + sm->addService(kBinderService, service, false); + + LOG(INFO) << "Binder server running..."; + + while (true) { + int stat, retval; + retval = wait(&stat); + if (retval == -1 && errno == ECHILD) { + break; + } + } + + LOG(INFO) << "Service Exiting..."; +} + +// To run binder-based benchmark, use: +// adb shell buffer_transport_benchmark \ +// --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/0/" +// +// To run bufferhub-based benchmark, use: +// adb shell buffer_transport_benchmark \ +// --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/1/" +int main(int argc, char** argv) { + bool tracing_enabled = false; + + // Parse arguments in addition to "--benchmark_filter" paramters. + for (int i = 1; i < argc; i++) { + if (std::string(argv[i]) == "--help") { + std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl; + std::cout << "\t--trace: Enable systrace logging." + << std::endl; + return 0; + } + if (std::string(argv[i]) == "--trace") { + tracing_enabled = true; + continue; + } + } + + // Setup ATRACE/systrace based on command line. + atrace_setup(); + atrace_set_tracing_enabled(tracing_enabled); + + pid_t pid = fork(); + if (pid == 0) { + // parent, i.e. the client side. + ProcessState::self()->startThreadPool(); + + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); + } else { + LOG(INFO) << "Benchmark process pid: " << pid; + runBinderServer(); + } +} diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp index 8213ca24de..69dbc84459 100644 --- a/libs/vr/libdisplay/Android.bp +++ b/libs/vr/libdisplay/Android.bp @@ -26,6 +26,7 @@ localIncludeFiles = [ sharedLibraries = [ "libbase", + "libbinder", "libcutils", "liblog", "libutils", diff --git a/libs/vr/libpdx/private/pdx/channel_parcelable.h b/libs/vr/libpdx/private/pdx/channel_parcelable.h new file mode 100644 index 0000000000..59ef9d3119 --- /dev/null +++ b/libs/vr/libpdx/private/pdx/channel_parcelable.h @@ -0,0 +1,31 @@ +#ifndef ANDROID_PDX_CHANNEL_PARCELABLE_H_ +#define ANDROID_PDX_CHANNEL_PARCELABLE_H_ + +#include <binder/Parcelable.h> +#include <pdx/channel_handle.h> + +namespace android { +namespace pdx { + +/** + * A parcelable object holds all necessary objects to recreate a ClientChannel. + * In addition to the android::Parcelable interface, this interface exposees + * more PDX-related interface. + */ +class ChannelParcelable : public Parcelable { + public: + virtual ~ChannelParcelable() = default; + + // Returns whether the parcelable object holds a valid client channel. + virtual bool IsValid() const = 0; + + // Returns a channel handle constructed from this parcelable object and takes + // the ownership of all resources from the parcelable object. In another word, + // the parcelable object will become invalid after TakeChannelHandle returns. + virtual LocalChannelHandle TakeChannelHandle() = 0; +}; + +} // namespace pdx +} // namespace android + +#endif // ANDROID_PDX_CHANNEL_PARCELABLE_H_ diff --git a/libs/vr/libpdx/private/pdx/client_channel.h b/libs/vr/libpdx/private/pdx/client_channel.h index 10a49bb8d7..8f5fdfe71f 100644 --- a/libs/vr/libpdx/private/pdx/client_channel.h +++ b/libs/vr/libpdx/private/pdx/client_channel.h @@ -4,6 +4,7 @@ #include <vector> #include <pdx/channel_handle.h> +#include <pdx/channel_parcelable.h> #include <pdx/file_handle.h> #include <pdx/status.h> @@ -61,6 +62,11 @@ class ClientChannel { LocalHandle* handle) const = 0; virtual bool GetChannelHandle(void* transaction_state, ChannelReference ref, LocalChannelHandle* handle) const = 0; + + // Returns the internal state of the channel as a parcelable object. The + // ClientChannel is invalidated however, the channel is kept alive by the + // parcelable object and may be transferred to another process. + virtual std::unique_ptr<ChannelParcelable> TakeChannelParcelable() = 0; }; } // namespace pdx diff --git a/libs/vr/libpdx/private/pdx/mock_client_channel.h b/libs/vr/libpdx/private/pdx/mock_client_channel.h index 49e0682bc9..ecc20b3275 100644 --- a/libs/vr/libpdx/private/pdx/mock_client_channel.h +++ b/libs/vr/libpdx/private/pdx/mock_client_channel.h @@ -49,6 +49,7 @@ class MockClientChannel : public ClientChannel { MOCK_CONST_METHOD3(GetChannelHandle, bool(void* transaction_state, ChannelReference ref, LocalChannelHandle* handle)); + MOCK_METHOD0(TakeChannelParcelable, std::unique_ptr<ChannelParcelable>()); }; } // namespace pdx diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp index f891c59fde..cda3c95ca6 100644 --- a/libs/vr/libpdx_default_transport/Android.bp +++ b/libs/vr/libpdx_default_transport/Android.bp @@ -42,6 +42,7 @@ cc_binary { "pdx_tool.cpp", ], shared_libs: [ + "libbinder", "libcutils", "liblog", ], @@ -59,6 +60,7 @@ cc_binary { ], shared_libs: [ "libbase", + "libbinder", "libchrome", "libcutils", "liblog", diff --git a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h new file mode 100644 index 0000000000..a8623b25f7 --- /dev/null +++ b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h @@ -0,0 +1,17 @@ +#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_ +#define ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_ + +#include <servicefs/channel_parcelable.h> + +namespace android { +namespace pdx { +namespace default_transport { + +using ChannelParcelable = ::android::pdx::servicefs::ChannelParcelable; + +} // namespace default_transport +} // namespace pdx +} // namespace android + + +#endif // ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_ diff --git a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h new file mode 100644 index 0000000000..bcd74e6f25 --- /dev/null +++ b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h @@ -0,0 +1,17 @@ +#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_ +#define ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_ + +#include <uds/channel_parcelable.h> + +namespace android { +namespace pdx { +namespace default_transport { + +using ChannelParcelable = ::android::pdx::uds::ChannelParcelable; + +} // namespace default_transport +} // namespace pdx +} // namespace android + + +#endif // ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_ diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp index d0b7cab34f..d64095061e 100644 --- a/libs/vr/libpdx_uds/Android.bp +++ b/libs/vr/libpdx_uds/Android.bp @@ -13,6 +13,7 @@ cc_library_static { srcs: [ "channel_event_set.cpp", "channel_manager.cpp", + "channel_parcelable.cpp", "client_channel_factory.cpp", "client_channel.cpp", "ipc_helper.cpp", @@ -23,6 +24,9 @@ cc_library_static { "libbase", "libpdx", ], + shared_libs: [ + "libbinder", + ], whole_static_libs: [ "libselinux", ], @@ -52,5 +56,6 @@ cc_test { "libcutils", "liblog", "libutils", + "libbinder", ], } diff --git a/libs/vr/libpdx_uds/channel_parcelable.cpp b/libs/vr/libpdx_uds/channel_parcelable.cpp new file mode 100644 index 0000000000..e7bce27045 --- /dev/null +++ b/libs/vr/libpdx_uds/channel_parcelable.cpp @@ -0,0 +1,125 @@ +#include "uds/channel_parcelable.h" + +#include <binder/Parcel.h> +#include <uds/channel_manager.h> + +namespace android { +namespace pdx { +namespace uds { + +namespace { + +static constexpr uint32_t kUdsMagicParcelHeader = 0x7564736d; // 'udsm'. + +} // namespace + +ChannelParcelable::ChannelParcelable(LocalHandle data_fd, + LocalHandle pollin_event_fd, + LocalHandle pollhup_event_fd) + : data_fd_{std::move(data_fd)}, + pollin_event_fd_{std::move(pollin_event_fd)}, + pollhup_event_fd_{std::move(pollhup_event_fd)} {} + +bool ChannelParcelable::IsValid() const { + return !!data_fd_ && !!pollin_event_fd_ && !!pollhup_event_fd_; +} + +LocalChannelHandle ChannelParcelable::TakeChannelHandle() { + if (!IsValid()) { + ALOGE("ChannelParcelable::TakeChannelHandle: Invalid channel parcel."); + return {}; // Returns an empty channel handle. + } + + return ChannelManager::Get().CreateHandle(std::move(data_fd_), + std::move(pollin_event_fd_), + std::move(pollhup_event_fd_)); +} + +status_t ChannelParcelable::writeToParcel(Parcel* parcel) const { + status_t res = NO_ERROR; + + if (!IsValid()) { + ALOGE("ChannelParcelable::writeToParcel: Invalid channel parcel."); + return BAD_VALUE; + } + + res = parcel->writeUint32(kUdsMagicParcelHeader); + if (res != NO_ERROR) { + ALOGE("ChannelParcelable::writeToParcel: Cannot write magic: res=%d.", res); + return res; + } + + res = parcel->writeFileDescriptor(data_fd_.Get()); + if (res != NO_ERROR) { + ALOGE("ChannelParcelable::writeToParcel: Cannot write data fd: res=%d.", + res); + return res; + } + + res = parcel->writeFileDescriptor(pollin_event_fd_.Get()); + if (res != NO_ERROR) { + ALOGE( + "ChannelParcelable::writeToParcel: Cannot write pollin event fd: " + "res=%d.", + res); + return res; + } + + res = parcel->writeFileDescriptor(pollhup_event_fd_.Get()); + if (res != NO_ERROR) { + ALOGE( + "ChannelParcelable::writeToParcel: Cannot write pollhup event fd: " + "res=%d.", + res); + return res; + } + + return res; +} + +status_t ChannelParcelable::readFromParcel(const Parcel* parcel) { + uint32_t magic = 0; + status_t res = NO_ERROR; + + if (IsValid()) { + ALOGE( + "ChannelParcelable::readFromParcel: This channel parcel is already " + "initailzied."); + return ALREADY_EXISTS; + } + + res = parcel->readUint32(&magic); + if (res != NO_ERROR) { + ALOGE("ChannelParcelable::readFromParcel: Failed to read magic: res=%d.", + res); + return res; + } + + if (magic != kUdsMagicParcelHeader) { + ALOGE( + "ChannelParcelable::readFromParcel: Unknown magic: 0x%x, epxected: " + "0x%x", + magic, kUdsMagicParcelHeader); + return BAD_VALUE; + } + + // TODO(b/69010509): We have to dup() the FD from android::Parcel as it + // doesn't support taking out the FD's ownership. We can remove the dup() here + // once android::Parcel support such operation. + data_fd_.Reset(dup(parcel->readFileDescriptor())); + pollin_event_fd_.Reset(dup(parcel->readFileDescriptor())); + pollhup_event_fd_.Reset(dup(parcel->readFileDescriptor())); + if (!IsValid()) { + ALOGE( + "ChannelParcelable::readFromParcel: Cannot read fd from parcel: " + "data_fd=%d, pollin_event_fd=%d, pollhup_event_fd=%d.", + data_fd_.Get(), pollin_event_fd_.Get(), pollhup_event_fd_.Get()); + return DEAD_OBJECT; + } + + return res; +} + +} // namespace uds +} // namespace pdx +} // namespace android diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp index 2e9c1def3b..6073c3cd05 100644 --- a/libs/vr/libpdx_uds/client_channel.cpp +++ b/libs/vr/libpdx_uds/client_channel.cpp @@ -1,3 +1,4 @@ +#include "uds/channel_parcelable.h" #include "uds/client_channel.h" #include <errno.h> @@ -292,6 +293,29 @@ bool ClientChannel::GetChannelHandle(void* transaction_state, return state->GetLocalChannelHandle(ref, handle); } +std::unique_ptr<pdx::ChannelParcelable> ClientChannel::TakeChannelParcelable() + { + if (!channel_handle_) + return nullptr; + + if (auto* channel_data = + ChannelManager::Get().GetChannelData(channel_handle_.value())) { + auto fds = channel_data->TakeFds(); + auto parcelable = std::make_unique<ChannelParcelable>( + std::move(std::get<0>(fds)), std::move(std::get<1>(fds)), + std::move(std::get<2>(fds))); + + // Here we need to explicitly close the channel handle so that the channel + // won't get shutdown in the destructor, while the FDs in ChannelParcelable + // can keep the channel alive so that new client can be created from it + // later. + channel_handle_.Close(); + return parcelable; + } else { + return nullptr; + } +} + } // namespace uds } // namespace pdx } // namespace android diff --git a/libs/vr/libpdx_uds/private/uds/channel_event_set.h b/libs/vr/libpdx_uds/private/uds/channel_event_set.h index 99e75028d1..e960740787 100644 --- a/libs/vr/libpdx_uds/private/uds/channel_event_set.h +++ b/libs/vr/libpdx_uds/private/uds/channel_event_set.h @@ -54,6 +54,14 @@ class ChannelEventReceiver { BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); } BorrowedHandle data_fd() const { return data_fd_.Borrow(); } + // Moves file descriptors out of ChannelEventReceiver. Note these operations + // immediately invalidates the receiver. + std::tuple<LocalHandle, LocalHandle, LocalHandle> TakeFds() { + epoll_fd_.Close(); + return {std::move(data_fd_), std::move(pollin_event_fd_), + std::move(pollhup_event_fd_)}; + } + Status<int> GetPendingEvents() const; Status<int> PollPendingEvents(int timeout_ms) const; diff --git a/libs/vr/libpdx_uds/private/uds/channel_parcelable.h b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h new file mode 100644 index 0000000000..1c3fae91d8 --- /dev/null +++ b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h @@ -0,0 +1,35 @@ +#ifndef ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_ +#define ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_ + +#include <pdx/channel_parcelable.h> +#include <pdx/file_handle.h> + +namespace android { +namespace pdx { +namespace uds { + +class ChannelParcelable : public pdx::ChannelParcelable { + public: + ChannelParcelable() = default; + ChannelParcelable(LocalHandle data_fd, LocalHandle pollin_event_fd, + LocalHandle pollhup_event_fd); + + // Implements pdx::ChannelParcelable interface. + bool IsValid() const override; + LocalChannelHandle TakeChannelHandle() override; + + // Implements android::Parcelable interface. + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + + private: + LocalHandle data_fd_; + LocalHandle pollin_event_fd_; + LocalHandle pollhup_event_fd_; +}; + +} // namespace uds +} // namespace pdx +} // namespace android + +#endif // ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_ diff --git a/libs/vr/libpdx_uds/private/uds/client_channel.h b/libs/vr/libpdx_uds/private/uds/client_channel.h index 7a5ddf40eb..b5524d8a62 100644 --- a/libs/vr/libpdx_uds/private/uds/client_channel.h +++ b/libs/vr/libpdx_uds/private/uds/client_channel.h @@ -74,6 +74,8 @@ class ClientChannel : public pdx::ClientChannel { bool GetChannelHandle(void* transaction_state, ChannelReference ref, LocalChannelHandle* handle) const override; + std::unique_ptr<pdx::ChannelParcelable> TakeChannelParcelable() override; + private: explicit ClientChannel(LocalChannelHandle channel_handle); diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp index 6a4687629e..7c32dbbf7a 100644 --- a/libs/vr/libperformance/Android.bp +++ b/libs/vr/libperformance/Android.bp @@ -23,6 +23,7 @@ staticLibraries = ["libpdx_default_transport"] sharedLibraries = [ "libbase", + "libbinder", "libcutils", "liblog", "libutils", diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index ac68a5e3a4..a18ff1ac8a 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -38,10 +38,12 @@ namespace android { namespace dvr { DisplayService::DisplayService(Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback) : BASE("DisplayService", Endpoint::Create(display::DisplayProtocol::kClientPath)) { - hardware_composer_.Initialize(hidl, request_display_callback); + hardware_composer_.Initialize( + hidl, primary_display_id, request_display_callback); } bool DisplayService::IsInitialized() const { diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index 55e33ab852..a3ee7bb121 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -81,6 +81,7 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { using RequestDisplayCallback = std::function<void(bool)>; DisplayService(android::Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback); pdx::Status<BorrowedNativeBufferHandle> OnGetGlobalBuffer( diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index fb69d5cf59..be17ecfa82 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -121,7 +121,8 @@ HardwareComposer::~HardwareComposer(void) { } bool HardwareComposer::Initialize( - Hwc2::Composer* composer, RequestDisplayCallback request_display_callback) { + Hwc2::Composer* composer, hwc2_display_t primary_display_id, + RequestDisplayCallback request_display_callback) { if (initialized_) { ALOGE("HardwareComposer::Initialize: already initialized."); return false; @@ -134,7 +135,7 @@ bool HardwareComposer::Initialize( HWC::Error error = HWC::Error::None; Hwc2::Config config; - error = composer->getActiveConfig(HWC_DISPLAY_PRIMARY, &config); + error = composer->getActiveConfig(primary_display_id, &config); if (error != HWC::Error::None) { ALOGE("HardwareComposer: Failed to get current display config : %d", @@ -142,7 +143,7 @@ bool HardwareComposer::Initialize( return false; } - error = GetDisplayMetrics(composer, HWC_DISPLAY_PRIMARY, config, + error = GetDisplayMetrics(composer, primary_display_id, config, &native_display_metrics_); if (error != HWC::Error::None) { @@ -233,7 +234,10 @@ void HardwareComposer::OnPostThreadResumed() { composer_.reset(new Hwc2::Composer("default")); composer_callback_ = new ComposerCallback; composer_->registerCallback(composer_callback_); + LOG_ALWAYS_FATAL_IF(!composer_callback_->HasDisplayId(), + "Registered composer callback but didn't get primary display"); Layer::SetComposer(composer_.get()); + Layer::SetDisplayId(composer_callback_->GetDisplayId()); } else { SetPowerMode(true); } @@ -263,6 +267,7 @@ void HardwareComposer::OnPostThreadPaused() { composer_callback_ = nullptr; composer_.reset(nullptr); Layer::SetComposer(nullptr); + Layer::SetDisplayId(0); } else { SetPowerMode(false); } @@ -290,7 +295,7 @@ HWC::Error HardwareComposer::Validate(hwc2_display_t display) { HWC::Error HardwareComposer::EnableVsync(bool enabled) { return composer_->setVsyncEnabled( - HWC_DISPLAY_PRIMARY, + composer_callback_->GetDisplayId(), (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE : HWC2_VSYNC_DISABLE)); } @@ -298,7 +303,8 @@ HWC::Error HardwareComposer::EnableVsync(bool enabled) { HWC::Error HardwareComposer::SetPowerMode(bool active) { HWC::PowerMode power_mode = active ? HWC::PowerMode::On : HWC::PowerMode::Off; return composer_->setPowerMode( - HWC_DISPLAY_PRIMARY, power_mode.cast<Hwc2::IComposerClient::PowerMode>()); + composer_callback_->GetDisplayId(), + power_mode.cast<Hwc2::IComposerClient::PowerMode>()); } HWC::Error HardwareComposer::Present(hwc2_display_t display) { @@ -419,7 +425,7 @@ void HardwareComposer::PostLayers() { layer.Prepare(); } - HWC::Error error = Validate(HWC_DISPLAY_PRIMARY); + HWC::Error error = Validate(composer_callback_->GetDisplayId()); if (error != HWC::Error::None) { ALOGE("HardwareComposer::PostLayers: Validate failed: %s", error.to_string().c_str()); @@ -466,7 +472,7 @@ void HardwareComposer::PostLayers() { } #endif - error = Present(HWC_DISPLAY_PRIMARY); + error = Present(composer_callback_->GetDisplayId()); if (error != HWC::Error::None) { ALOGE("HardwareComposer::PostLayers: Present failed: %s", error.to_string().c_str()); @@ -475,8 +481,8 @@ void HardwareComposer::PostLayers() { std::vector<Hwc2::Layer> out_layers; std::vector<int> out_fences; - error = composer_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers, - &out_fences); + error = composer_->getReleaseFences(composer_callback_->GetDisplayId(), + &out_layers, &out_fences); ALOGE_IF(error != HWC::Error::None, "HardwareComposer::PostLayers: Failed to get release fences: %s", error.to_string().c_str()); @@ -570,6 +576,9 @@ void HardwareComposer::UpdateConfigBuffer() { // Copy from latest record in shared_config_ring_ to local copy. DvrConfig record; if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) { + ALOGI("DvrConfig updated: sequence %u, post offset %d", + shared_config_ring_sequence_, record.frame_post_offset_ns); + ++shared_config_ring_sequence_; post_thread_config_ = record; } } @@ -612,14 +621,6 @@ int HardwareComposer::PostThreadPollInterruptible( } } -Status<int64_t> HardwareComposer::GetVSyncTime() { - auto status = composer_callback_->GetVsyncTime(HWC_DISPLAY_PRIMARY); - ALOGE_IF(!status, - "HardwareComposer::GetVSyncTime: Failed to get vsync timestamp: %s", - status.GetErrorMessage().c_str()); - return status; -} - // Waits for the next vsync and returns the timestamp of the vsync event. If // vsync already passed since the last call, returns the latest vsync timestamp // instead of blocking. @@ -792,8 +793,7 @@ void HardwareComposer::PostThread() { // Signal all of the vsync clients. Because absolute time is used for the // wakeup time below, this can take a little time if necessary. if (vsync_callback_) - vsync_callback_(HWC_DISPLAY_PRIMARY, vsync_timestamp, - /*frame_time_estimate*/ 0, vsync_count_); + vsync_callback_(vsync_timestamp, /*frame_time_estimate*/ 0, vsync_count_); { // Sleep until shortly before vsync. @@ -816,7 +816,7 @@ void HardwareComposer::PostThread() { // If the layer config changed we need to validateDisplay() even if // we're going to drop the frame, to flush the Composer object's // internal command buffer and apply our layer changes. - Validate(HWC_DISPLAY_PRIMARY); + Validate(composer_callback_->GetDisplayId()); } continue; } @@ -824,7 +824,7 @@ void HardwareComposer::PostThread() { } { - auto status = GetVSyncTime(); + auto status = composer_callback_->GetVsyncTime(); if (!status) { ALOGE("HardwareComposer::PostThread: Failed to get VSYNC time: %s", status.GetErrorMessage().c_str()); @@ -943,10 +943,17 @@ void HardwareComposer::SetBacklightBrightness(int brightness) { } Return<void> HardwareComposer::ComposerCallback::onHotplug( - Hwc2::Display display, IComposerCallback::Connection /*conn*/) { - // See if the driver supports the vsync_event node in sysfs. - if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES && - !displays_[display].driver_vsync_event_fd) { + Hwc2::Display display, IComposerCallback::Connection conn) { + // Our first onHotplug callback is always for the primary display. + // + // Ignore any other hotplug callbacks since the primary display is never + // disconnected and we don't care about other displays. + if (!has_display_id_) { + LOG_ALWAYS_FATAL_IF(conn != IComposerCallback::Connection::CONNECTED, + "Initial onHotplug callback should be primary display connected"); + has_display_id_ = true; + display_id_ = display; + std::array<char, 1024> buffer; snprintf(buffer.data(), buffer.size(), "/sys/class/graphics/fb%" PRIu64 "/vsync_event", display); @@ -955,7 +962,7 @@ Return<void> HardwareComposer::ComposerCallback::onHotplug( "HardwareComposer::ComposerCallback::onHotplug: Driver supports " "vsync_event node for display %" PRIu64, display); - displays_[display].driver_vsync_event_fd = std::move(handle); + driver_vsync_event_fd_ = std::move(handle); } else { ALOGI( "HardwareComposer::ComposerCallback::onHotplug: Driver does not " @@ -974,36 +981,23 @@ Return<void> HardwareComposer::ComposerCallback::onRefresh( Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display, int64_t timestamp) { - TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|", - display, timestamp); - if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES) { - displays_[display].callback_vsync_timestamp = timestamp; - } else { - ALOGW( - "HardwareComposer::ComposerCallback::onVsync: Received vsync on " - "non-physical display: display=%" PRId64, - display); + // Ignore any onVsync callbacks for the non-primary display. + if (has_display_id_ && display == display_id_) { + TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|", + display, timestamp); + callback_vsync_timestamp_ = timestamp; } return Void(); } -Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime( - Hwc2::Display display) { - if (display >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) { - ALOGE( - "HardwareComposer::ComposerCallback::GetVsyncTime: Invalid physical " - "display requested: display=%" PRIu64, - display); - return ErrorStatus(EINVAL); - } - +Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime() { // See if the driver supports direct vsync events. - LocalHandle& event_fd = displays_[display].driver_vsync_event_fd; + LocalHandle& event_fd = driver_vsync_event_fd_; if (!event_fd) { // Fall back to returning the last timestamp returned by the vsync // callback. std::lock_guard<std::mutex> autolock(vsync_mutex_); - return displays_[display].callback_vsync_timestamp; + return callback_vsync_timestamp_; } // When the driver supports the vsync_event sysfs node we can use it to @@ -1053,10 +1047,11 @@ Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime( Hwc2::Composer* Layer::composer_{nullptr}; HWCDisplayMetrics Layer::display_metrics_{0, 0, {0, 0}, 0}; +hwc2_display_t Layer::display_id_{0}; void Layer::Reset() { if (hardware_composer_layer_) { - composer_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_); + composer_->destroyLayer(display_id_, hardware_composer_layer_); hardware_composer_layer_ = 0; } @@ -1151,17 +1146,16 @@ void Layer::UpdateVisibilitySettings() { pending_visibility_settings_ = false; HWC::Error error; - hwc2_display_t display = HWC_DISPLAY_PRIMARY; error = composer_->setLayerBlendMode( - display, hardware_composer_layer_, + display_id_, hardware_composer_layer_, blending_.cast<Hwc2::IComposerClient::BlendMode>()); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer blend mode: %s", error.to_string().c_str()); - error = - composer_->setLayerZOrder(display, hardware_composer_layer_, z_order_); + error = composer_->setLayerZOrder(display_id_, hardware_composer_layer_, + z_order_); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting z_ order: %s", error.to_string().c_str()); @@ -1170,36 +1164,35 @@ void Layer::UpdateVisibilitySettings() { void Layer::UpdateLayerSettings() { HWC::Error error; - hwc2_display_t display = HWC_DISPLAY_PRIMARY; UpdateVisibilitySettings(); // TODO(eieio): Use surface attributes or some other mechanism to control // the layer display frame. error = composer_->setLayerDisplayFrame( - display, hardware_composer_layer_, + display_id_, hardware_composer_layer_, {0, 0, display_metrics_.width, display_metrics_.height}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer display frame: %s", error.to_string().c_str()); error = composer_->setLayerVisibleRegion( - display, hardware_composer_layer_, + display_id_, hardware_composer_layer_, {{0, 0, display_metrics_.width, display_metrics_.height}}); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer visible region: %s", error.to_string().c_str()); - error = - composer_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f); + error = composer_->setLayerPlaneAlpha(display_id_, hardware_composer_layer_, + 1.0f); ALOGE_IF(error != HWC::Error::None, "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s", error.to_string().c_str()); } void Layer::CommonLayerSetup() { - HWC::Error error = - composer_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_); + HWC::Error error = composer_->createLayer(display_id_, + &hardware_composer_layer_); ALOGE_IF(error != HWC::Error::None, "Layer::CommonLayerSetup: Failed to create layer on primary " "display: %s", @@ -1243,10 +1236,10 @@ void Layer::Prepare() { if (composition_type_ == HWC::Composition::Invalid) { composition_type_ = HWC::Composition::SolidColor; composer_->setLayerCompositionType( - HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + display_id_, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0}; - composer_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + composer_->setLayerColor(display_id_, hardware_composer_layer_, layer_color); } else { // The composition type is already set. Nothing else to do until a @@ -1256,7 +1249,7 @@ void Layer::Prepare() { if (composition_type_ != target_composition_type_) { composition_type_ = target_composition_type_; composer_->setLayerCompositionType( - HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + display_id_, hardware_composer_layer_, composition_type_.cast<Hwc2::IComposerClient::Composition>()); } @@ -1267,7 +1260,7 @@ void Layer::Prepare() { HWC::Error error{HWC::Error::None}; error = - composer_->setLayerBuffer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_, + composer_->setLayerBuffer(display_id_, hardware_composer_layer_, slot, handle, acquire_fence_.Get()); ALOGE_IF(error != HWC::Error::None, @@ -1277,7 +1270,7 @@ void Layer::Prepare() { if (!surface_rect_functions_applied_) { const float float_right = right; const float float_bottom = bottom; - error = composer_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY, + error = composer_->setLayerSourceCrop(display_id_, hardware_composer_layer_, {0, 0, float_right, float_bottom}); diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index 7010db9630..9ed4b22a1d 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -152,6 +152,11 @@ class Layer { display_metrics_ = display_metrics; } + // Sets the display id used by all Layer instances. + static void SetDisplayId(hwc2_display_t display_id) { + display_id_ = display_id; + } + private: void CommonLayerSetup(); @@ -180,6 +185,11 @@ class Layer { // thereafter. static HWCDisplayMetrics display_metrics_; + // Id of the primary display. Shared by all instances of Layer. This must be + // set whenever the primary display id changes. This can be left unset as long + // as there are no instances of Layer that might need to use it. + static hwc2_display_t display_id_; + // The hardware composer layer and metrics to use during the prepare cycle. hwc2_layer_t hardware_composer_layer_ = 0; @@ -298,13 +308,14 @@ class Layer { class HardwareComposer { public: // Type for vsync callback. - using VSyncCallback = std::function<void(int, int64_t, int64_t, uint32_t)>; + using VSyncCallback = std::function<void(int64_t, int64_t, uint32_t)>; using RequestDisplayCallback = std::function<void(bool)>; HardwareComposer(); ~HardwareComposer(); bool Initialize(Hwc2::Composer* composer, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback); bool IsInitialized() const { return initialized_; } @@ -362,16 +373,16 @@ class HardwareComposer { hardware::Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override; - pdx::Status<int64_t> GetVsyncTime(Hwc2::Display display); + bool HasDisplayId() { return has_display_id_; } + hwc2_display_t GetDisplayId() { return display_id_; } + pdx::Status<int64_t> GetVsyncTime(); private: std::mutex vsync_mutex_; - - struct Display { - pdx::LocalHandle driver_vsync_event_fd; - int64_t callback_vsync_timestamp{0}; - }; - std::array<Display, HWC_NUM_PHYSICAL_DISPLAY_TYPES> displays_; + bool has_display_id_ = false; + hwc2_display_t display_id_; + pdx::LocalHandle driver_vsync_event_fd_; + int64_t callback_vsync_timestamp_{0}; }; HWC::Error Validate(hwc2_display_t display); @@ -412,7 +423,6 @@ class HardwareComposer { // kPostThreadInterrupted. int ReadWaitPPState(); pdx::Status<int64_t> WaitForVSync(); - pdx::Status<int64_t> GetVSyncTime(); int SleepUntil(int64_t wakeup_timestamp); // Reconfigures the layer stack if the display surfaces changed since the last diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h index 33cbc84d7d..c740dde3d6 100644 --- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h +++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h @@ -4,6 +4,12 @@ #include <thread> #include <memory> +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + #include <pdx/service_dispatcher.h> #include <vr/vr_manager/vr_manager.h> @@ -21,7 +27,9 @@ class VrFlinger { public: using RequestDisplayCallback = std::function<void(bool)>; static std::unique_ptr<VrFlinger> Create( - Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback); + Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, + RequestDisplayCallback request_display_callback); ~VrFlinger(); // These functions are all called on surface flinger's main thread. @@ -35,6 +43,7 @@ class VrFlinger { private: VrFlinger(); bool Init(Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback); // Needs to be a separate class for binder's ref counting diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp index 85dc586eae..5e7abd7d96 100644 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ b/libs/vr/libvrflinger/vr_flinger.cpp @@ -29,9 +29,10 @@ namespace android { namespace dvr { std::unique_ptr<VrFlinger> VrFlinger::Create( - Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) { + Hwc2::Composer* hidl, hwc2_display_t primary_display_id, + RequestDisplayCallback request_display_callback) { std::unique_ptr<VrFlinger> vr_flinger(new VrFlinger); - if (vr_flinger->Init(hidl, request_display_callback)) + if (vr_flinger->Init(hidl, primary_display_id, request_display_callback)) return vr_flinger; else return nullptr; @@ -56,6 +57,7 @@ VrFlinger::~VrFlinger() { } bool VrFlinger::Init(Hwc2::Composer* hidl, + hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback) { if (!hidl || !request_display_callback) return false; @@ -74,8 +76,8 @@ bool VrFlinger::Init(Hwc2::Composer* hidl, dispatcher_ = android::pdx::ServiceDispatcher::Create(); CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher."); - display_service_ = - android::dvr::DisplayService::Create(hidl, request_display_callback); + display_service_ = android::dvr::DisplayService::Create( + hidl, primary_display_id, request_display_callback); CHECK_ERROR(!display_service_, error, "Failed to create display service."); dispatcher_->AddService(display_service_); @@ -91,7 +93,7 @@ bool VrFlinger::Init(Hwc2::Composer* hidl, std::bind(&android::dvr::VSyncService::VSyncEvent, std::static_pointer_cast<android::dvr::VSyncService>(service), std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4)); + std::placeholders::_3)); dispatcher_thread_ = std::thread([this]() { prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0); diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp index fdeb899f66..b8d8b08b5f 100644 --- a/libs/vr/libvrflinger/vsync_service.cpp +++ b/libs/vr/libvrflinger/vsync_service.cpp @@ -32,21 +32,19 @@ VSyncService::VSyncService() VSyncService::~VSyncService() {} -void VSyncService::VSyncEvent(int display, int64_t timestamp_ns, +void VSyncService::VSyncEvent(int64_t timestamp_ns, int64_t compositor_time_ns, uint32_t vsync_count) { ATRACE_NAME("VSyncService::VSyncEvent"); std::lock_guard<std::mutex> autolock(mutex_); - if (display == HWC_DISPLAY_PRIMARY) { - last_vsync_ = current_vsync_; - current_vsync_ = timestamp_ns; - compositor_time_ns_ = compositor_time_ns; - current_vsync_count_ = vsync_count; + last_vsync_ = current_vsync_; + current_vsync_ = timestamp_ns; + compositor_time_ns_ = compositor_time_ns; + current_vsync_count_ = vsync_count; - NotifyWaiters(); - UpdateClients(); - } + NotifyWaiters(); + UpdateClients(); } std::shared_ptr<Channel> VSyncService::OnChannelOpen(pdx::Message& message) { diff --git a/libs/vr/libvrflinger/vsync_service.h b/libs/vr/libvrflinger/vsync_service.h index 215948eb05..822f02b266 100644 --- a/libs/vr/libvrflinger/vsync_service.h +++ b/libs/vr/libvrflinger/vsync_service.h @@ -63,9 +63,10 @@ class VSyncService : public pdx::ServiceBase<VSyncService> { const std::shared_ptr<pdx::Channel>& channel) override; // Called by the hardware composer HAL, or similar, whenever a vsync event - // occurs. |compositor_time_ns| is the number of ns before the next vsync when - // the compositor will preempt the GPU to do EDS and lens warp. - void VSyncEvent(int display, int64_t timestamp_ns, int64_t compositor_time_ns, + // occurs on the primary display. |compositor_time_ns| is the number of ns + // before the next vsync when the compositor will preempt the GPU to do EDS + // and lens warp. + void VSyncEvent(int64_t timestamp_ns, int64_t compositor_time_ns, uint32_t vsync_count); private: diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp index e92178a43e..fe54b4bb0c 100644 --- a/libs/vr/libvrsensor/Android.bp +++ b/libs/vr/libvrsensor/Android.bp @@ -14,7 +14,6 @@ sourceFiles = [ "pose_client.cpp", - "sensor_client.cpp", "latency_model.cpp", ] @@ -33,6 +32,7 @@ staticLibraries = [ sharedLibraries = [ "libbase", + "libbinder", "libcutils", "libhardware", "liblog", diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h b/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h deleted file mode 100644 index b2ebd95060..0000000000 --- a/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ANDROID_DVR_SENSOR_IPC_H_ -#define ANDROID_DVR_SENSOR_IPC_H_ - -#define DVR_SENSOR_SERVICE_BASE "system/vr/sensors" - -#define DVR_SENSOR_SERVICE_CLIENT (DVR_SENSOR_SERVICE_BASE "/client") - -/* - * Endpoint ops - */ -enum { - DVR_SENSOR_START = 0, - DVR_SENSOR_STOP, - DVR_SENSOR_POLL, -}; - -#endif // ANDROID_DVR_SENSOR_IPC_H_ diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor_client.h b/libs/vr/libvrsensor/include/private/dvr/sensor_client.h deleted file mode 100644 index 15a9b8f5d1..0000000000 --- a/libs/vr/libvrsensor/include/private/dvr/sensor_client.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef ANDROID_DVR_SENSOR_CLIENT_H_ -#define ANDROID_DVR_SENSOR_CLIENT_H_ - -#include <hardware/sensors.h> -#include <pdx/client.h> -#include <poll.h> - -namespace android { -namespace dvr { - -// SensorClient is a remote interface to the sensor service in sensord. -class SensorClient : public pdx::ClientBase<SensorClient> { - public: - ~SensorClient(); - - int StartSensor(); - int StopSensor(); - int Poll(sensors_event_t* events, int max_count); - - private: - friend BASE; - - // Set up a channel associated with the sensor of the indicated type. - // NOTE(segal): If our hardware ends up with multiple sensors of the same - // type, we'll have to change this. - explicit SensorClient(int sensor_type); - - int sensor_type_; - - SensorClient(const SensorClient&); - SensorClient& operator=(const SensorClient&); -}; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_SENSOR_CLIENT_H_ diff --git a/libs/vr/libvrsensor/sensor_client.cpp b/libs/vr/libvrsensor/sensor_client.cpp deleted file mode 100644 index 04e88cc9a1..0000000000 --- a/libs/vr/libvrsensor/sensor_client.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#define LOG_TAG "SensorClient" -#include <private/dvr/sensor_client.h> - -#include <log/log.h> -#include <poll.h> - -#include <pdx/default_transport/client_channel_factory.h> -#include <private/dvr/sensor-ipc.h> - -using android::pdx::Transaction; - -namespace android { -namespace dvr { - -SensorClient::SensorClient(int sensor_type) - : BASE(pdx::default_transport::ClientChannelFactory::Create( - DVR_SENSOR_SERVICE_CLIENT)), - sensor_type_(sensor_type) {} - -SensorClient::~SensorClient() {} - -int SensorClient::StartSensor() { - Transaction trans{*this}; - auto status = trans.Send<int>(DVR_SENSOR_START, &sensor_type_, - sizeof(sensor_type_), nullptr, 0); - ALOGE_IF(!status, "startSensor() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); -} - -int SensorClient::StopSensor() { - Transaction trans{*this}; - auto status = trans.Send<int>(DVR_SENSOR_STOP); - ALOGE_IF(!status, "stopSensor() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); -} - -int SensorClient::Poll(sensors_event_t* events, int max_events) { - int num_events = 0; - struct iovec rvec[] = { - {.iov_base = &num_events, .iov_len = sizeof(int)}, - {.iov_base = events, .iov_len = max_events * sizeof(sensors_event_t)}, - }; - Transaction trans{*this}; - auto status = trans.SendVector<int>(DVR_SENSOR_POLL, nullptr, rvec); - ALOGE_IF(!status, "Sensor poll() failed because: %s\n", - status.GetErrorMessage().c_str()); - return !status ? -status.error() : num_events; -} - -} // namespace dvr -} // namespace android - -// Entrypoints to simplify using the library when programmatically dynamicly -// loading it. -// Allows us to call this library without linking it, as, for instance, -// when compiling GVR in Google3. -// NOTE(segal): It's kind of a hack. - -extern "C" uint64_t dvrStartSensor(int type) { - android::dvr::SensorClient* service = - android::dvr::SensorClient::Create(type).release(); - service->StartSensor(); - return (uint64_t)service; -} - -extern "C" void dvrStopSensor(uint64_t service) { - android::dvr::SensorClient* iss = - reinterpret_cast<android::dvr::SensorClient*>(service); - iss->StopSensor(); - delete iss; -} - -extern "C" int dvrPollSensor(uint64_t service, int max_count, - sensors_event_t* events) { - return reinterpret_cast<android::dvr::SensorClient*>(service)->Poll( - events, max_count); -} diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 32c2d7e0d5..d43c1648be 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -122,6 +122,16 @@ cc_library_static { }, } +cc_library_static { + name: "libEGL_blobCache", + defaults: ["egl_libs_defaults"], + srcs: [ + "EGL/BlobCache.cpp", + "EGL/FileBlobCache.cpp", + ], + export_include_dirs: ["EGL"], +} + cc_library_shared { name: "libEGL", defaults: ["egl_libs_defaults"], @@ -133,7 +143,6 @@ cc_library_shared { "EGL/egl.cpp", "EGL/eglApi.cpp", "EGL/Loader.cpp", - "EGL/BlobCache.cpp", ], shared_libs: [ "libvndksupport", @@ -143,7 +152,10 @@ cc_library_shared { "libhidltransport", "libutils", ], - static_libs: ["libEGL_getProcAddress"], + static_libs: [ + "libEGL_getProcAddress", + "libEGL_blobCache", + ], ldflags: ["-Wl,--exclude-libs=ALL"], export_include_dirs: ["EGL/include"], } diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp index 0624b609ce..b3752f5bcc 100644 --- a/opengl/libs/EGL/BlobCache.cpp +++ b/opengl/libs/EGL/BlobCache.cpp @@ -37,9 +37,9 @@ static const uint32_t blobCacheVersion = 3; static const uint32_t blobCacheDeviceVersion = 1; BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize): + mMaxTotalSize(maxTotalSize), mMaxKeySize(maxKeySize), mMaxValueSize(maxValueSize), - mMaxTotalSize(maxTotalSize), mTotalSize(0) { int64_t now = std::chrono::steady_clock::now().time_since_epoch().count(); #ifdef _WIN32 diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h index a0a270a5fe..1f5d5357e6 100644 --- a/opengl/libs/EGL/BlobCache.h +++ b/opengl/libs/EGL/BlobCache.h @@ -97,6 +97,14 @@ public: // int unflatten(void const* buffer, size_t size); +protected: + // mMaxTotalSize is the maximum size that all cache entries can occupy. This + // includes space for both keys and values. When a call to BlobCache::set + // would otherwise cause this limit to be exceeded, either the key/value + // pair passed to BlobCache::set will not be cached or other cache entries + // will be evicted from the cache to make room for the new entry. + const size_t mMaxTotalSize; + private: // Copying is disallowed. BlobCache(const BlobCache&); @@ -220,13 +228,6 @@ private: // simply not add the key/value pair to the cache. const size_t mMaxValueSize; - // mMaxTotalSize is the maximum size that all cache entries can occupy. This - // includes space for both keys and values. When a call to BlobCache::set - // would otherwise cause this limit to be exceeded, either the key/value - // pair passed to BlobCache::set will not be cached or other cache entries - // will be evicted from the cache to make room for the new entry. - const size_t mMaxTotalSize; - // mTotalSize is the total combined size of all keys and values currently in // the cache. size_t mTotalSize; diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp new file mode 100644 index 0000000000..ff608a38a4 --- /dev/null +++ b/opengl/libs/EGL/FileBlobCache.cpp @@ -0,0 +1,185 @@ +/* + ** Copyright 2017, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include "FileBlobCache.h" + +#include <inttypes.h> +#include <log/log.h> +#include <sys/mman.h> +#include <sys/stat.h> + + +// Cache file header +static const char* cacheFileMagic = "EGL$"; +static const size_t cacheFileHeaderSize = 8; + +namespace android { + +static uint32_t crc32c(const uint8_t* buf, size_t len) { + const uint32_t polyBits = 0x82F63B78; + uint32_t r = 0; + for (size_t i = 0; i < len; i++) { + r ^= buf[i]; + for (int j = 0; j < 8; j++) { + if (r & 1) { + r = (r >> 1) ^ polyBits; + } else { + r >>= 1; + } + } + } + return r; +} + +FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize, + const std::string& filename) + : BlobCache(maxKeySize, maxValueSize, maxTotalSize) + , mFilename(filename) { + if (mFilename.length() > 0) { + size_t headerSize = cacheFileHeaderSize; + + int fd = open(mFilename.c_str(), O_RDONLY, 0); + if (fd == -1) { + if (errno != ENOENT) { + ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(), + strerror(errno), errno); + } + return; + } + + struct stat statBuf; + if (fstat(fd, &statBuf) == -1) { + ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno); + close(fd); + return; + } + + // Sanity check the size before trying to mmap it. + size_t fileSize = statBuf.st_size; + if (fileSize > mMaxTotalSize * 2) { + ALOGE("cache file is too large: %#" PRIx64, + static_cast<off64_t>(statBuf.st_size)); + close(fd); + return; + } + + uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize, + PROT_READ, MAP_PRIVATE, fd, 0)); + if (buf == MAP_FAILED) { + ALOGE("error mmaping cache file: %s (%d)", strerror(errno), + errno); + close(fd); + return; + } + + // Check the file magic and CRC + size_t cacheSize = fileSize - headerSize; + if (memcmp(buf, cacheFileMagic, 4) != 0) { + ALOGE("cache file has bad mojo"); + close(fd); + return; + } + uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); + if (crc32c(buf + headerSize, cacheSize) != *crc) { + ALOGE("cache file failed CRC check"); + close(fd); + return; + } + + int err = unflatten(buf + headerSize, cacheSize); + if (err < 0) { + ALOGE("error reading cache contents: %s (%d)", strerror(-err), + -err); + munmap(buf, fileSize); + close(fd); + return; + } + + munmap(buf, fileSize); + close(fd); + } +} + +void FileBlobCache::writeToFile() { + if (mFilename.length() > 0) { + size_t cacheSize = getFlattenedSize(); + size_t headerSize = cacheFileHeaderSize; + const char* fname = mFilename.c_str(); + + // Try to create the file with no permissions so we can write it + // without anyone trying to read it. + int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); + if (fd == -1) { + if (errno == EEXIST) { + // The file exists, delete it and try again. + if (unlink(fname) == -1) { + // No point in retrying if the unlink failed. + ALOGE("error unlinking cache file %s: %s (%d)", fname, + strerror(errno), errno); + return; + } + // Retry now that we've unlinked the file. + fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); + } + if (fd == -1) { + ALOGE("error creating cache file %s: %s (%d)", fname, + strerror(errno), errno); + return; + } + } + + size_t fileSize = headerSize + cacheSize; + + uint8_t* buf = new uint8_t [fileSize]; + if (!buf) { + ALOGE("error allocating buffer for cache contents: %s (%d)", + strerror(errno), errno); + close(fd); + unlink(fname); + return; + } + + int err = flatten(buf + headerSize, cacheSize); + if (err < 0) { + ALOGE("error writing cache contents: %s (%d)", strerror(-err), + -err); + delete [] buf; + close(fd); + unlink(fname); + return; + } + + // Write the file magic and CRC + memcpy(buf, cacheFileMagic, 4); + uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); + *crc = crc32c(buf + headerSize, cacheSize); + + if (write(fd, buf, fileSize) == -1) { + ALOGE("error writing cache file: %s (%d)", strerror(errno), + errno); + delete [] buf; + close(fd); + unlink(fname); + return; + } + + delete [] buf; + fchmod(fd, S_IRUSR); + close(fd); + } +} + +}
\ No newline at end of file diff --git a/opengl/libs/EGL/FileBlobCache.h b/opengl/libs/EGL/FileBlobCache.h new file mode 100644 index 0000000000..393703f234 --- /dev/null +++ b/opengl/libs/EGL/FileBlobCache.h @@ -0,0 +1,43 @@ +/* + ** Copyright 2017, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#ifndef ANDROID_FILE_BLOB_CACHE_H +#define ANDROID_FILE_BLOB_CACHE_H + +#include "BlobCache.h" +#include <string> + +namespace android { + +class FileBlobCache : public BlobCache { +public: + // FileBlobCache attempts to load the saved cache contents from disk into + // BlobCache. + FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize, + const std::string& filename); + + // writeToFile attempts to save the current contents of BlobCache to + // disk. + void writeToFile(); + +private: + // mFilename is the name of the file for storing cache contents. + std::string mFilename; +}; + +} // namespace android + +#endif // ANDROID_BLOB_CACHE_H diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp index 579e422c1a..ec548f3121 100644 --- a/opengl/libs/EGL/egl_cache.cpp +++ b/opengl/libs/EGL/egl_cache.cpp @@ -20,12 +20,8 @@ #include "egl_display.h" - #include <private/EGL/cache.h> -#include <inttypes.h> -#include <sys/mman.h> -#include <sys/stat.h> #include <unistd.h> #include <thread> @@ -37,10 +33,6 @@ static const size_t maxKeySize = 12 * 1024; static const size_t maxValueSize = 64 * 1024; static const size_t maxTotalSize = 2 * 1024 * 1024; -// Cache file header -static const char* cacheFileMagic = "EGL$"; -static const size_t cacheFileHeaderSize = 8; - // The time in seconds to wait before saving newly inserted cache entries. static const unsigned int deferredSaveDelay = 4; @@ -124,7 +116,9 @@ void egl_cache_t::initialize(egl_display_t *display) { void egl_cache_t::terminate() { std::lock_guard<std::mutex> lock(mMutex); - saveBlobCacheLocked(); + if (mBlobCache) { + mBlobCache->writeToFile(); + } mBlobCache = NULL; } @@ -146,8 +140,8 @@ void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, std::thread deferredSaveThread([this]() { sleep(deferredSaveDelay); std::lock_guard<std::mutex> lock(mMutex); - if (mInitialized) { - saveBlobCacheLocked(); + if (mInitialized && mBlobCache) { + mBlobCache->writeToFile(); } mSavePending = false; }); @@ -179,163 +173,11 @@ void egl_cache_t::setCacheFilename(const char* filename) { BlobCache* egl_cache_t::getBlobCacheLocked() { if (mBlobCache == nullptr) { - mBlobCache.reset(new BlobCache(maxKeySize, maxValueSize, maxTotalSize)); - loadBlobCacheLocked(); + mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename)); } return mBlobCache.get(); } -static uint32_t crc32c(const uint8_t* buf, size_t len) { - const uint32_t polyBits = 0x82F63B78; - uint32_t r = 0; - for (size_t i = 0; i < len; i++) { - r ^= buf[i]; - for (int j = 0; j < 8; j++) { - if (r & 1) { - r = (r >> 1) ^ polyBits; - } else { - r >>= 1; - } - } - } - return r; -} - -void egl_cache_t::saveBlobCacheLocked() { - if (mFilename.length() > 0 && mBlobCache != NULL) { - size_t cacheSize = mBlobCache->getFlattenedSize(); - size_t headerSize = cacheFileHeaderSize; - const char* fname = mFilename.c_str(); - - // Try to create the file with no permissions so we can write it - // without anyone trying to read it. - int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); - if (fd == -1) { - if (errno == EEXIST) { - // The file exists, delete it and try again. - if (unlink(fname) == -1) { - // No point in retrying if the unlink failed. - ALOGE("error unlinking cache file %s: %s (%d)", fname, - strerror(errno), errno); - return; - } - // Retry now that we've unlinked the file. - fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); - } - if (fd == -1) { - ALOGE("error creating cache file %s: %s (%d)", fname, - strerror(errno), errno); - return; - } - } - - size_t fileSize = headerSize + cacheSize; - - uint8_t* buf = new uint8_t [fileSize]; - if (!buf) { - ALOGE("error allocating buffer for cache contents: %s (%d)", - strerror(errno), errno); - close(fd); - unlink(fname); - return; - } - - int err = mBlobCache->flatten(buf + headerSize, cacheSize); - if (err < 0) { - ALOGE("error writing cache contents: %s (%d)", strerror(-err), - -err); - delete [] buf; - close(fd); - unlink(fname); - return; - } - - // Write the file magic and CRC - memcpy(buf, cacheFileMagic, 4); - uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); - *crc = crc32c(buf + headerSize, cacheSize); - - if (write(fd, buf, fileSize) == -1) { - ALOGE("error writing cache file: %s (%d)", strerror(errno), - errno); - delete [] buf; - close(fd); - unlink(fname); - return; - } - - delete [] buf; - fchmod(fd, S_IRUSR); - close(fd); - } -} - -void egl_cache_t::loadBlobCacheLocked() { - if (mFilename.length() > 0) { - size_t headerSize = cacheFileHeaderSize; - - int fd = open(mFilename.c_str(), O_RDONLY, 0); - if (fd == -1) { - if (errno != ENOENT) { - ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(), - strerror(errno), errno); - } - return; - } - - struct stat statBuf; - if (fstat(fd, &statBuf) == -1) { - ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno); - close(fd); - return; - } - - // Sanity check the size before trying to mmap it. - size_t fileSize = statBuf.st_size; - if (fileSize > maxTotalSize * 2) { - ALOGE("cache file is too large: %#" PRIx64, - static_cast<off64_t>(statBuf.st_size)); - close(fd); - return; - } - - uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize, - PROT_READ, MAP_PRIVATE, fd, 0)); - if (buf == MAP_FAILED) { - ALOGE("error mmaping cache file: %s (%d)", strerror(errno), - errno); - close(fd); - return; - } - - // Check the file magic and CRC - size_t cacheSize = fileSize - headerSize; - if (memcmp(buf, cacheFileMagic, 4) != 0) { - ALOGE("cache file has bad mojo"); - close(fd); - return; - } - uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); - if (crc32c(buf + headerSize, cacheSize) != *crc) { - ALOGE("cache file failed CRC check"); - close(fd); - return; - } - - int err = mBlobCache->unflatten(buf + headerSize, cacheSize); - if (err < 0) { - ALOGE("error reading cache contents: %s (%d)", strerror(-err), - -err); - munmap(buf, fileSize); - close(fd); - return; - } - - munmap(buf, fileSize); - close(fd); - } -} - // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h index 56360f0bc8..7382b913fa 100644 --- a/opengl/libs/EGL/egl_cache.h +++ b/opengl/libs/EGL/egl_cache.h @@ -20,7 +20,7 @@ #include <EGL/egl.h> #include <EGL/eglext.h> -#include "BlobCache.h" +#include "FileBlobCache.h" #include <memory> #include <mutex> @@ -82,14 +82,6 @@ private: // possible. BlobCache* getBlobCacheLocked(); - // saveBlobCache attempts to save the current contents of mBlobCache to - // disk. - void saveBlobCacheLocked(); - - // loadBlobCache attempts to load the saved cache contents from disk into - // mBlobCache. - void loadBlobCacheLocked(); - // mInitialized indicates whether the egl_cache_t is in the initialized // state. It is initialized to false at construction time, and gets set to // true when initialize is called. It is set back to false when terminate @@ -101,7 +93,7 @@ private: // mBlobCache is the cache in which the key/value blob pairs are stored. It // is initially NULL, and will be initialized by getBlobCacheLocked the // first time it's needed. - std::unique_ptr<BlobCache> mBlobCache; + std::unique_ptr<FileBlobCache> mBlobCache; // mFilename is the name of the file for storing cache contents in between // program invocations. It is initialized to an empty string at diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp index 142894524d..2b76279801 100644 --- a/opengl/tests/lib/WindowSurface.cpp +++ b/opengl/tests/lib/WindowSurface.cpp @@ -62,19 +62,10 @@ WindowSurface::WindowSurface() { return; } - SurfaceComposerClient::openGlobalTransaction(); - err = sc->setLayer(0x7FFFFFFF); // always on top - if (err != NO_ERROR) { - fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err); - return; - } - - err = sc->show(); - if (err != NO_ERROR) { - fprintf(stderr, "SurfaceComposer::show error: %#x\n", err); - return; - } - SurfaceComposerClient::closeGlobalTransaction(); + SurfaceComposerClient::Transaction{} + .setLayer(sc, 0x7FFFFFFF) + .show(sc) + .apply(); mSurfaceControl = sc; } diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp index 22b084abc6..12ad47e15a 100644 --- a/services/audiomanager/Android.bp +++ b/services/audiomanager/Android.bp @@ -3,7 +3,6 @@ cc_library_shared { srcs: [ "IAudioManager.cpp", - "IPlayer.cpp", ], shared_libs: [ diff --git a/services/audiomanager/IPlayer.cpp b/services/audiomanager/IPlayer.cpp deleted file mode 100644 index e8a9c3472f..0000000000 --- a/services/audiomanager/IPlayer.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* -** -** Copyright 2017, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#define LOG_TAG "IPlayer" -//#define LOG_NDEBUG 0 -#include <utils/Log.h> - -#include <stdint.h> -#include <sys/types.h> - -#include <binder/Parcel.h> - -#include <audiomanager/IPlayer.h> - -namespace android { - -enum { - START = IBinder::FIRST_CALL_TRANSACTION, - PAUSE = IBinder::FIRST_CALL_TRANSACTION + 1, - STOP = IBinder::FIRST_CALL_TRANSACTION + 2, - SET_VOLUME = IBinder::FIRST_CALL_TRANSACTION + 3, - SET_PAN = IBinder::FIRST_CALL_TRANSACTION + 4, - SET_START_DELAY_MS = IBinder::FIRST_CALL_TRANSACTION + 5, - APPLY_VOLUME_SHAPER = IBinder::FIRST_CALL_TRANSACTION + 6, -}; - -class BpPlayer : public BpInterface<IPlayer> -{ -public: - explicit BpPlayer(const sp<IBinder>& impl) - : BpInterface<IPlayer>(impl) - { - } - - virtual void start() - { - Parcel data, reply; - data.writeInterfaceToken(IPlayer::getInterfaceDescriptor()); - remote()->transact(START, data, &reply); - } - - virtual void pause() - { - Parcel data, reply; - data.writeInterfaceToken(IPlayer::getInterfaceDescriptor()); - remote()->transact(PAUSE, data, &reply); - } - - virtual void stop() - { - Parcel data, reply; - data.writeInterfaceToken(IPlayer::getInterfaceDescriptor()); - remote()->transact(STOP, data, &reply); - } - - virtual void setVolume(float vol) - { - Parcel data, reply; - data.writeInterfaceToken(IPlayer::getInterfaceDescriptor()); - data.writeFloat(vol); - remote()->transact(SET_VOLUME, data, &reply); - } - - virtual void setPan(float pan) - { - Parcel data, reply; - data.writeInterfaceToken(IPlayer::getInterfaceDescriptor()); - data.writeFloat(pan); - remote()->transact(SET_PAN, data, &reply); - } - - virtual void setStartDelayMs(int32_t delayMs) { - Parcel data, reply; - data.writeInterfaceToken(IPlayer::getInterfaceDescriptor()); - data.writeInt32(delayMs); - remote()->transact(SET_START_DELAY_MS, data, &reply); - } - - virtual void applyVolumeShaper( - const sp<VolumeShaper::Configuration>& configuration, - const sp<VolumeShaper::Operation>& operation) { - Parcel data, reply; - data.writeInterfaceToken(IPlayer::getInterfaceDescriptor()); - - status_t status = configuration.get() == nullptr - ? data.writeInt32(0) - : data.writeInt32(1) - ?: configuration->writeToParcel(&data); - if (status != NO_ERROR) { - ALOGW("applyVolumeShaper failed configuration parceling: %d", status); - return; // ignore error - } - - status = operation.get() == nullptr - ? status = data.writeInt32(0) - : data.writeInt32(1) - ?: operation->writeToParcel(&data); - if (status != NO_ERROR) { - ALOGW("applyVolumeShaper failed operation parceling: %d", status); - return; // ignore error - } - - status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply); - - ALOGW_IF(status != NO_ERROR, "applyVolumeShaper failed transact: %d", status); - return; // one way transaction, ignore error - } -}; - -IMPLEMENT_META_INTERFACE(Player, "android.media.IPlayer"); - -// ---------------------------------------------------------------------- - -status_t BnPlayer::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch (code) { - case START: { - CHECK_INTERFACE(IPlayer, data, reply); - start(); - return NO_ERROR; - } break; - case PAUSE: { - CHECK_INTERFACE(IPlayer, data, reply); - pause(); - return NO_ERROR; - } - case STOP: { - CHECK_INTERFACE(IPlayer, data, reply); - stop(); - return NO_ERROR; - } break; - case SET_VOLUME: { - CHECK_INTERFACE(IPlayer, data, reply); - setVolume(data.readFloat()); - return NO_ERROR; - } break; - case SET_PAN: { - CHECK_INTERFACE(IPlayer, data, reply); - setPan(data.readFloat()); - return NO_ERROR; - } break; - case SET_START_DELAY_MS: { - CHECK_INTERFACE(IPlayer, data, reply); - setStartDelayMs(data.readInt32()); - return NO_ERROR; - } break; - case APPLY_VOLUME_SHAPER: { - CHECK_INTERFACE(IPlayer, data, reply); - sp<VolumeShaper::Configuration> configuration; - sp<VolumeShaper::Operation> operation; - - int32_t present; - status_t status = data.readInt32(&present); - if (status == NO_ERROR && present != 0) { - configuration = new VolumeShaper::Configuration(); - status = configuration->readFromParcel(data); - } - status = status ?: data.readInt32(&present); - if (status == NO_ERROR && present != 0) { - operation = new VolumeShaper::Operation(); - status = operation->readFromParcel(data); - } - if (status == NO_ERROR) { - // one way transaction, no error returned - applyVolumeShaper(configuration, operation); - } - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -} // namespace android diff --git a/services/batteryservice/Android.bp b/services/batteryservice/Android.bp index 4c7265b654..186f399286 100644 --- a/services/batteryservice/Android.bp +++ b/services/batteryservice/Android.bp @@ -5,29 +5,3 @@ cc_library_headers { header_libs: ["libbinder_headers"], export_header_lib_headers: ["libbinder_headers"], } - -cc_library { - name: "libbatteryservice", - - srcs: [ - "BatteryProperties.cpp", - "BatteryProperty.cpp", - "IBatteryPropertiesListener.cpp", - "IBatteryPropertiesRegistrar.cpp", - ], - - header_libs: ["libbatteryservice_headers"], - export_header_lib_headers: ["libbatteryservice_headers"], - - shared_libs: [ - "libutils", - "libbinder", - ], - - cflags: [ - "-Wall", - "-Werror", - "-Wunused", - "-Wunreachable-code", - ], -} diff --git a/services/batteryservice/BatteryProperties.cpp b/services/batteryservice/BatteryProperties.cpp deleted file mode 100644 index 8fa111d19d..0000000000 --- a/services/batteryservice/BatteryProperties.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdint.h> -#include <sys/types.h> -#include <batteryservice/BatteryService.h> -#include <binder/Parcel.h> -#include <utils/Errors.h> -#include <utils/String8.h> -#include <utils/String16.h> - -namespace android { - -/* - * Parcel read/write code must be kept in sync with - * frameworks/base/core/java/android/os/BatteryProperties.java - */ - -status_t BatteryProperties::readFromParcel(Parcel* p) { - chargerAcOnline = p->readInt32() == 1 ? true : false; - chargerUsbOnline = p->readInt32() == 1 ? true : false; - chargerWirelessOnline = p->readInt32() == 1 ? true : false; - maxChargingCurrent = p->readInt32(); - maxChargingVoltage = p->readInt32(); - batteryStatus = p->readInt32(); - batteryHealth = p->readInt32(); - batteryPresent = p->readInt32() == 1 ? true : false; - batteryLevel = p->readInt32(); - batteryVoltage = p->readInt32(); - batteryTemperature = p->readInt32(); - batteryFullCharge = p->readInt32(); - batteryChargeCounter = p->readInt32(); - batteryTechnology = String8((p->readString16()).string()); - return OK; -} - -status_t BatteryProperties::writeToParcel(Parcel* p) const { - p->writeInt32(chargerAcOnline ? 1 : 0); - p->writeInt32(chargerUsbOnline ? 1 : 0); - p->writeInt32(chargerWirelessOnline ? 1 : 0); - p->writeInt32(maxChargingCurrent); - p->writeInt32(maxChargingVoltage); - p->writeInt32(batteryStatus); - p->writeInt32(batteryHealth); - p->writeInt32(batteryPresent ? 1 : 0); - p->writeInt32(batteryLevel); - p->writeInt32(batteryVoltage); - p->writeInt32(batteryTemperature); - p->writeInt32(batteryFullCharge); - p->writeInt32(batteryChargeCounter); - p->writeString16(String16(batteryTechnology)); - return OK; -} - -}; // namespace android diff --git a/services/batteryservice/BatteryProperty.cpp b/services/batteryservice/BatteryProperty.cpp deleted file mode 100644 index 483d92585c..0000000000 --- a/services/batteryservice/BatteryProperty.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdint.h> -#include <sys/types.h> -#include <batteryservice/BatteryService.h> -#include <binder/Parcel.h> -#include <utils/Errors.h> - -namespace android { - -/* - * Parcel read/write code must be kept in sync with - * frameworks/base/core/java/android/os/BatteryProperty.java - */ - -status_t BatteryProperty::readFromParcel(Parcel* p) { - valueInt64 = p->readInt64(); - return OK; -} - -status_t BatteryProperty::writeToParcel(Parcel* p) const { - p->writeInt64(valueInt64); - return OK; -} - -}; // namespace android diff --git a/services/batteryservice/IBatteryPropertiesListener.cpp b/services/batteryservice/IBatteryPropertiesListener.cpp deleted file mode 100644 index 6e5bcfeede..0000000000 --- a/services/batteryservice/IBatteryPropertiesListener.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdint.h> -#include <sys/types.h> -#include <batteryservice/IBatteryPropertiesListener.h> -#include <binder/Parcel.h> - -namespace android { - -class BpBatteryPropertiesListener : public BpInterface<IBatteryPropertiesListener> -{ -public: - explicit BpBatteryPropertiesListener(const sp<IBinder>& impl) - : BpInterface<IBatteryPropertiesListener>(impl) - { - } - - void batteryPropertiesChanged(struct BatteryProperties props) - { - Parcel data, reply; - data.writeInterfaceToken(IBatteryPropertiesListener::getInterfaceDescriptor()); - data.writeInt32(1); - props.writeToParcel(&data); - remote()->transact(TRANSACT_BATTERYPROPERTIESCHANGED, data, &reply, IBinder::FLAG_ONEWAY); - } -}; - -IMPLEMENT_META_INTERFACE(BatteryPropertiesListener, "android.os.IBatteryPropertiesListener"); - -// ---------------------------------------------------------------------------- - -status_t BnBatteryPropertiesListener::onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags) -{ - switch(code) { - case TRANSACT_BATTERYPROPERTIESCHANGED: { - CHECK_INTERFACE(IBatteryPropertiesListener, data, reply); - struct BatteryProperties props = {}; - if (data.readInt32() != 0) { - props.readFromParcel((Parcel*)&data); - } - batteryPropertiesChanged(props); - return NO_ERROR; - } - default: - return BBinder::onTransact(code, data, reply, flags); - } -}; - -}; // namespace android diff --git a/services/batteryservice/IBatteryPropertiesRegistrar.cpp b/services/batteryservice/IBatteryPropertiesRegistrar.cpp deleted file mode 100644 index 01a65ae27d..0000000000 --- a/services/batteryservice/IBatteryPropertiesRegistrar.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "IBatteryPropertiesRegistrar" -//#define LOG_NDEBUG 0 -#include <utils/Log.h> - -#include <batteryservice/IBatteryPropertiesListener.h> -#include <batteryservice/IBatteryPropertiesRegistrar.h> -#include <stdint.h> -#include <sys/types.h> -#include <binder/Parcel.h> - -namespace android { - -class BpBatteryPropertiesRegistrar : public BpInterface<IBatteryPropertiesRegistrar> { -public: - explicit BpBatteryPropertiesRegistrar(const sp<IBinder>& impl) - : BpInterface<IBatteryPropertiesRegistrar>(impl) {} - - void registerListener(const sp<IBatteryPropertiesListener>& listener) { - Parcel data; - data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor()); - data.writeStrongBinder(IInterface::asBinder(listener)); - remote()->transact(REGISTER_LISTENER, data, NULL); - } - - void unregisterListener(const sp<IBatteryPropertiesListener>& listener) { - Parcel data; - data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor()); - data.writeStrongBinder(IInterface::asBinder(listener)); - remote()->transact(UNREGISTER_LISTENER, data, NULL); - } - - status_t getProperty(int id, struct BatteryProperty *val) { - Parcel data, reply; - data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor()); - data.writeInt32(id); - remote()->transact(GET_PROPERTY, data, &reply); - int32_t ret = reply.readExceptionCode(); - if (ret != 0) { - return ret; - } - ret = reply.readInt32(); - int parcelpresent = reply.readInt32(); - if (parcelpresent) - val->readFromParcel(&reply); - return ret; - } - - void scheduleUpdate() { - Parcel data; - data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor()); - remote()->transact(SCHEDULE_UPDATE, data, NULL); - } -}; - -IMPLEMENT_META_INTERFACE(BatteryPropertiesRegistrar, "android.os.IBatteryPropertiesRegistrar"); - -status_t BnBatteryPropertiesRegistrar::onTransact(uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags) -{ - switch(code) { - case REGISTER_LISTENER: { - CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply); - sp<IBatteryPropertiesListener> listener = - interface_cast<IBatteryPropertiesListener>(data.readStrongBinder()); - registerListener(listener); - return OK; - } - - case UNREGISTER_LISTENER: { - CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply); - sp<IBatteryPropertiesListener> listener = - interface_cast<IBatteryPropertiesListener>(data.readStrongBinder()); - unregisterListener(listener); - return OK; - } - - case GET_PROPERTY: { - CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply); - int id = data.readInt32(); - struct BatteryProperty val; - status_t result = getProperty(id, &val); - reply->writeNoException(); - reply->writeInt32(result); - reply->writeInt32(1); - val.writeToParcel(reply); - return OK; - } - - case SCHEDULE_UPDATE: { - CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply); - scheduleUpdate(); - return OK; - } - } - return BBinder::onTransact(code, data, reply, flags); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 238cba362c..a9e5a4339c 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -26,6 +26,7 @@ cc_library_shared { ], shared_libs: [ + "libbase", "libbinder", "libcrypto", "libcutils", diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp index 99fe0f5d55..4d9a2a0254 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -39,6 +39,7 @@ #include <hardware_legacy/power.h> +#include <android-base/stringprintf.h> #include <cutils/properties.h> #include <openssl/sha.h> #include <utils/Log.h> @@ -64,6 +65,8 @@ #define INDENT2 " " #define INDENT3 " " +using android::base::StringPrintf; + namespace android { static const char *WAKE_LOCK_ID = "KeyEvents"; @@ -1733,43 +1736,43 @@ void EventHub::requestReopenDevices() { mNeedToReopenDevices = true; } -void EventHub::dump(String8& dump) { - dump.append("Event Hub State:\n"); +void EventHub::dump(std::string& dump) { + dump += "Event Hub State:\n"; { // acquire lock AutoMutex _l(mLock); - dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); + dump += StringPrintf(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); - dump.append(INDENT "Devices:\n"); + dump += INDENT "Devices:\n"; for (size_t i = 0; i < mDevices.size(); i++) { const Device* device = mDevices.valueAt(i); if (mBuiltInKeyboardId == device->id) { - dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", + dump += StringPrintf(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", device->id, device->identifier.name.string()); } else { - dump.appendFormat(INDENT2 "%d: %s\n", device->id, + dump += StringPrintf(INDENT2 "%d: %s\n", device->id, device->identifier.name.string()); } - dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); - dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); - dump.appendFormat(INDENT3 "Enabled: %s\n", toString(device->enabled)); - dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string()); - dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); - dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber); - dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string()); - dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " + dump += StringPrintf(INDENT3 "Classes: 0x%08x\n", device->classes); + dump += StringPrintf(INDENT3 "Path: %s\n", device->path.string()); + dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(device->enabled)); + dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string()); + dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.string()); + dump += StringPrintf(INDENT3 "ControllerNumber: %d\n", device->controllerNumber); + dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string()); + dump += StringPrintf(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " "product=0x%04x, version=0x%04x\n", device->identifier.bus, device->identifier.vendor, device->identifier.product, device->identifier.version); - dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", + dump += StringPrintf(INDENT3 "KeyLayoutFile: %s\n", device->keyMap.keyLayoutFile.string()); - dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n", + dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n", device->keyMap.keyCharacterMapFile.string()); - dump.appendFormat(INDENT3 "ConfigurationFile: %s\n", + dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n", device->configurationFile.string()); - dump.appendFormat(INDENT3 "HaveKeyboardLayoutOverlay: %s\n", + dump += StringPrintf(INDENT3 "HaveKeyboardLayoutOverlay: %s\n", toString(device->overlayKeyMap != NULL)); } } // release lock diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index 727b73aeb8..66bc29456b 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -24,7 +24,6 @@ #include <input/KeyLayoutMap.h> #include <input/KeyCharacterMap.h> #include <input/VirtualKeyMap.h> -#include <utils/String8.h> #include <utils/Mutex.h> #include <utils/Log.h> #include <utils/List.h> @@ -262,7 +261,7 @@ public: virtual void wake() = 0; /* Dump EventHub state to a string. */ - virtual void dump(String8& dump) = 0; + virtual void dump(std::string& dump) = 0; /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; @@ -333,7 +332,7 @@ public: virtual void wake(); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void monitor(); protected: diff --git a/services/inputflinger/InputApplication.h b/services/inputflinger/InputApplication.h index 1f5504c2d2..724fc2c4f4 100644 --- a/services/inputflinger/InputApplication.h +++ b/services/inputflinger/InputApplication.h @@ -18,10 +18,8 @@ #define _UI_INPUT_APPLICATION_H #include <input/Input.h> - #include <utils/RefBase.h> #include <utils/Timers.h> -#include <utils/String8.h> namespace android { @@ -29,7 +27,7 @@ namespace android { * Describes the properties of an application that can receive input. */ struct InputApplicationInfo { - String8 name; + std::string name; nsecs_t dispatchingTimeout; }; @@ -46,8 +44,8 @@ public: return mInfo; } - inline String8 getName() const { - return mInfo ? mInfo->name : String8("<invalid>"); + inline std::string getName() const { + return mInfo ? mInfo->name : "<invalid>"; } inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 98e135d530..4194dea8a9 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -47,10 +47,12 @@ #include <errno.h> #include <limits.h> +#include <sstream> #include <stddef.h> #include <time.h> #include <unistd.h> +#include <android-base/stringprintf.h> #include <log/log.h> #include <utils/Trace.h> #include <powermanager/PowerManager.h> @@ -61,6 +63,8 @@ #define INDENT3 " " #define INDENT4 " " +using android::base::StringPrintf; + namespace android { // Default input dispatching timeout if there is no focused application or paused window @@ -176,9 +180,9 @@ static bool isMainDisplay(int32_t displayId) { return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE; } -static void dumpRegion(String8& dump, const Region& region) { +static void dumpRegion(std::string& dump, const Region& region) { if (region.isEmpty()) { - dump.append("<empty>"); + dump += "<empty>"; return; } @@ -189,9 +193,9 @@ static void dumpRegion(String8& dump, const Region& region) { if (first) { first = false; } else { - dump.append("|"); + dump += "|"; } - dump.appendFormat("[%d,%d][%d,%d]", cur->left, cur->top, cur->right, cur->bottom); + dump += StringPrintf("[%d,%d][%d,%d]", cur->left, cur->top, cur->right, cur->bottom); cur++; } } @@ -685,7 +689,7 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t cu bool InputDispatcher::dispatchConfigurationChangedLocked( nsecs_t currentTime, ConfigurationChangedEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime); + ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry->eventTime); #endif // Reset key repeating in case a keyboard device was added or removed or something. @@ -701,7 +705,8 @@ bool InputDispatcher::dispatchConfigurationChangedLocked( bool InputDispatcher::dispatchDeviceResetLocked( nsecs_t currentTime, DeviceResetEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId); + ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry->eventTime, + entry->deviceId); #endif CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, @@ -811,9 +816,9 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " + ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " - "repeatCount=%d, downTime=%lld", + "repeatCount=%d, downTime=%" PRId64, prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, @@ -884,10 +889,10 @@ bool InputDispatcher::dispatchMotionLocked( void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " + ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, actionButton=0x%x, flags=0x%x, " "metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action, entry->actionButton, entry->flags, @@ -936,7 +941,7 @@ void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, #if DEBUG_FOCUS ALOGD("Dropping event delivery to target with channel '%s' because it " "is no longer registered with the input dispatcher.", - inputTarget.inputChannel->getName().string()); + inputTarget.inputChannel->getName().c_str()); #endif } } @@ -962,7 +967,7 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { #if DEBUG_FOCUS ALOGD("Waiting for application to become ready for input: %s. Reason: %s", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), + getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(), reason); #endif nsecs_t timeout; @@ -1069,7 +1074,7 @@ void InputDispatcher::resetANRTimeoutsLocked() { int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { int32_t injectionResult; - String8 reason; + std::string reason; // If there is no currently focused window and no focused application // then drop the event. @@ -1097,9 +1102,9 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, // Check whether the window is ready for more input. reason = checkWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry, "focused"); - if (!reason.isEmpty()) { + if (!reason.empty()) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string()); + mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str()); goto Unresponsive; } @@ -1308,8 +1313,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, && newTouchedWindowHandle != NULL) { #if DEBUG_FOCUS ALOGD("Touch is slipping out of window %s into window %s.", - oldTouchedWindowHandle->getName().string(), - newTouchedWindowHandle->getName().string()); + oldTouchedWindowHandle->getName().c_str(), + newTouchedWindowHandle->getName().c_str()); #endif // Make a slippery exit from the old window. mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, @@ -1343,7 +1348,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (mLastHoverWindowHandle != NULL) { #if DEBUG_HOVER ALOGD("Sending hover exit event to window %s.", - mLastHoverWindowHandle->getName().string()); + mLastHoverWindowHandle->getName().c_str()); #endif mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); @@ -1353,7 +1358,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (newHoverWindowHandle != NULL) { #if DEBUG_HOVER ALOGD("Sending hover enter event to window %s.", - newHoverWindowHandle->getName().string()); + newHoverWindowHandle->getName().c_str()); #endif mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); @@ -1411,11 +1416,11 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { // Check whether the window is ready for more input. - String8 reason = checkWindowReadyForMoreInputLocked(currentTime, + std::string reason = checkWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry, "touched"); - if (!reason.isEmpty()) { + if (!reason.empty()) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.windowHandle, nextWakeupTime, reason.string()); + NULL, touchedWindow.windowHandle, nextWakeupTime, reason.c_str()); goto Unresponsive; } } @@ -1603,7 +1608,7 @@ bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& wind ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " "owned by uid %d", injectionState->injectorPid, injectionState->injectorUid, - windowHandle->getName().string(), + windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid); } else { ALOGW("Permission denied: injecting event from pid %d uid %d", @@ -1655,18 +1660,18 @@ bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& window return false; } -String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, +std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, const char* targetType) { // If the window is paused then keep waiting. if (windowHandle->getInfo()->paused) { - return String8::format("Waiting because the %s window is paused.", targetType); + return StringPrintf("Waiting because the %s window is paused.", targetType); } // If the window's connection is not registered then keep waiting. ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel()); if (connectionIndex < 0) { - return String8::format("Waiting because the %s window's input channel is not " + return StringPrintf("Waiting because the %s window's input channel is not " "registered with the input dispatcher. The window may be in the process " "of being removed.", targetType); } @@ -1674,14 +1679,14 @@ String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, // If the connection is dead then keep waiting. sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->status != Connection::STATUS_NORMAL) { - return String8::format("Waiting because the %s window's input connection is %s." + return StringPrintf("Waiting because the %s window's input connection is %s." "The window may be in the process of being removed.", targetType, connection->getStatusLabel()); } // If the connection is backed up then keep waiting. if (connection->inputPublisherBlocked) { - return String8::format("Waiting because the %s window's input channel is full. " + return StringPrintf("Waiting because the %s window's input channel is full. " "Outbound queue length: %d. Wait queue length: %d.", targetType, connection->outboundQueue.count(), connection->waitQueue.count()); } @@ -1700,7 +1705,7 @@ String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, // To obtain this behavior, we must serialize key events with respect to all // prior input events. if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) { - return String8::format("Waiting to send key event because the %s window has not " + return StringPrintf("Waiting to send key event because the %s window has not " "finished processing all of the input events that were previously " "delivered to it. Outbound queue length: %d. Wait queue length: %d.", targetType, connection->outboundQueue.count(), connection->waitQueue.count()); @@ -1724,7 +1729,7 @@ String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, if (!connection->waitQueue.isEmpty() && currentTime >= connection->waitQueue.head->deliveryTime + STREAM_AHEAD_EVENT_TIMEOUT) { - return String8::format("Waiting to send non-key event because the %s window has not " + return StringPrintf("Waiting to send non-key event because the %s window has not " "finished processing certain input events that were delivered to it over " "%0.1fms ago. Wait queue length: %d. Wait queue head age: %0.1fms.", targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f, @@ -1732,17 +1737,17 @@ String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, (currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f); } } - return String8::empty(); + return ""; } -String8 InputDispatcher::getApplicationWindowLabelLocked( +std::string InputDispatcher::getApplicationWindowLabelLocked( const sp<InputApplicationHandle>& applicationHandle, const sp<InputWindowHandle>& windowHandle) { if (applicationHandle != NULL) { if (windowHandle != NULL) { - String8 label(applicationHandle->getName()); - label.append(" - "); - label.append(windowHandle->getName()); + std::string label(applicationHandle->getName()); + label += " - "; + label += windowHandle->getName(); return label; } else { return applicationHandle->getName(); @@ -1750,7 +1755,7 @@ String8 InputDispatcher::getApplicationWindowLabelLocked( } else if (windowHandle != NULL) { return windowHandle->getName(); } else { - return String8("<unknown application or window>"); + return "<unknown application or window>"; } } @@ -1759,7 +1764,7 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { const InputWindowInfo* info = mFocusedWindowHandle->getInfo(); if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) { #if DEBUG_DISPATCH_CYCLE - ALOGD("Not poking user activity: disabled by window '%s'.", info->name.string()); + ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str()); #endif return; } @@ -1992,10 +1997,10 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const PointerCoords* usingCoords = motionEntry->pointerCoords; // Set the X and Y offset depending on the input source. - float xOffset, yOffset, scaleFactor; + float xOffset, yOffset; if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { - scaleFactor = dispatchEntry->scaleFactor; + float scaleFactor = dispatchEntry->scaleFactor; xOffset = dispatchEntry->xOffset * scaleFactor; yOffset = dispatchEntry->yOffset * scaleFactor; if (scaleFactor != 1.0f) { @@ -2008,7 +2013,6 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } else { xOffset = 0.0f; yOffset = 0.0f; - scaleFactor = 1.0f; // We don't want the dispatch target to know. if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { @@ -2231,7 +2235,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( if (!cancelationEvents.isEmpty()) { #if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync " + ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync " "with reality: %s, mode=%d.", connection->getInputChannelName(), cancelationEvents.size(), options.reason, options.mode); @@ -2367,7 +2371,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime); + ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime); #endif bool needWake; @@ -2385,8 +2389,9 @@ void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChange void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " - "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", + ALOGD("notifyKey - eventTime=%" PRId64 + ", deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " + "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64, args->eventTime, args->deviceId, args->source, args->policyFlags, args->action, args->flags, args->keyCode, args->scanCode, args->metaState, args->downTime); @@ -2480,9 +2485,9 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " + ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, args->eventTime, args->deviceId, args->source, args->policyFlags, args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); @@ -2560,9 +2565,9 @@ bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchValues=0x%08x, switchMask=0x%08x", - args->eventTime, args->policyFlags, - args->switchValues, args->switchMask); + ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, " + "switchMask=0x%08x", + args->eventTime, args->policyFlags, args->switchValues, args->switchMask); #endif uint32_t policyFlags = args->policyFlags; @@ -2573,7 +2578,7 @@ void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d", + ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args->eventTime, args->deviceId); #endif @@ -2881,7 +2886,7 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inpu if (mFocusedWindowHandle != NULL) { #if DEBUG_FOCUS ALOGD("Focus left window: %s", - mFocusedWindowHandle->getName().string()); + mFocusedWindowHandle->getName().c_str()); #endif sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel(); if (focusedInputChannel != NULL) { @@ -2894,7 +2899,7 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inpu if (newFocusedWindowHandle != NULL) { #if DEBUG_FOCUS ALOGD("Focus entered window: %s", - newFocusedWindowHandle->getName().string()); + newFocusedWindowHandle->getName().c_str()); #endif } mFocusedWindowHandle = newFocusedWindowHandle; @@ -2907,7 +2912,7 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inpu if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS ALOGD("Touched window was removed: %s", - touchedWindow.windowHandle->getName().string()); + touchedWindow.windowHandle->getName().c_str()); #endif sp<InputChannel> touchedInputChannel = touchedWindow.windowHandle->getInputChannel(); @@ -2932,7 +2937,7 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inpu const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i); if (!hasWindowHandleLocked(oldWindowHandle)) { #if DEBUG_FOCUS - ALOGD("Window went away: %s", oldWindowHandle->getName().string()); + ALOGD("Window went away: %s", oldWindowHandle->getName().c_str()); #endif oldWindowHandle->releaseInfo(); } @@ -3034,7 +3039,7 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, const sp<InputChannel>& toChannel) { #if DEBUG_FOCUS ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s", - fromChannel->getName().string(), toChannel->getName().string()); + fromChannel->getName().c_str(), toChannel->getName().c_str()); #endif { // acquire lock AutoMutex _l(mLock); @@ -3131,72 +3136,68 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { } void InputDispatcher::logDispatchStateLocked() { - String8 dump; + std::string dump; dumpDispatchStateLocked(dump); - char* text = dump.lockBuffer(dump.size()); - char* start = text; - while (*start != '\0') { - char* end = strchr(start, '\n'); - if (*end == '\n') { - *(end++) = '\0'; - } - ALOGD("%s", start); - start = end; + std::istringstream stream(dump); + std::string line; + + while (std::getline(stream, line, '\n')) { + ALOGD("%s", line.c_str()); } } -void InputDispatcher::dumpDispatchStateLocked(String8& dump) { - dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); - dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); +void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { + dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); + dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); if (mFocusedApplicationHandle != NULL) { - dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", - mFocusedApplicationHandle->getName().string(), + dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", + mFocusedApplicationHandle->getName().c_str(), mFocusedApplicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); } else { - dump.append(INDENT "FocusedApplication: <null>\n"); + dump += StringPrintf(INDENT "FocusedApplication: <null>\n"); } - dump.appendFormat(INDENT "FocusedWindow: name='%s'\n", - mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : "<null>"); + dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n", + mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().c_str() : "<null>"); if (!mTouchStatesByDisplay.isEmpty()) { - dump.appendFormat(INDENT "TouchStatesByDisplay:\n"); + dump += StringPrintf(INDENT "TouchStatesByDisplay:\n"); for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) { const TouchState& state = mTouchStatesByDisplay.valueAt(i); - dump.appendFormat(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n", + dump += StringPrintf(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n", state.displayId, toString(state.down), toString(state.split), state.deviceId, state.source); if (!state.windows.isEmpty()) { - dump.append(INDENT3 "Windows:\n"); + dump += INDENT3 "Windows:\n"; for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; - dump.appendFormat(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.windowHandle->getName().string(), + dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", + i, touchedWindow.windowHandle->getName().c_str(), touchedWindow.pointerIds.value, touchedWindow.targetFlags); } } else { - dump.append(INDENT3 "Windows: <none>\n"); + dump += INDENT3 "Windows: <none>\n"; } } } else { - dump.append(INDENT "TouchStates: <no displays touched>\n"); + dump += INDENT "TouchStates: <no displays touched>\n"; } if (!mWindowHandles.isEmpty()) { - dump.append(INDENT "Windows:\n"); + dump += INDENT "Windows:\n"; for (size_t i = 0; i < mWindowHandles.size(); i++) { const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* windowInfo = windowHandle->getInfo(); - dump.appendFormat(INDENT2 "%zu: name='%s', displayId=%d, " + dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, " "paused=%s, hasFocus=%s, hasWallpaper=%s, " "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " "frame=[%d,%d][%d,%d], scale=%f, " "touchableRegion=", - i, windowInfo->name.string(), windowInfo->displayId, + i, windowInfo->name.c_str(), windowInfo->displayId, toString(windowInfo->paused), toString(windowInfo->hasFocus), toString(windowInfo->hasWallpaper), @@ -3208,140 +3209,140 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { windowInfo->frameRight, windowInfo->frameBottom, windowInfo->scaleFactor); dumpRegion(dump, windowInfo->touchableRegion); - dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures); - dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", + dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures); + dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", windowInfo->ownerPid, windowInfo->ownerUid, windowInfo->dispatchingTimeout / 1000000.0); } } else { - dump.append(INDENT "Windows: <none>\n"); + dump += INDENT "Windows: <none>\n"; } if (!mMonitoringChannels.isEmpty()) { - dump.append(INDENT "MonitoringChannels:\n"); + dump += INDENT "MonitoringChannels:\n"; for (size_t i = 0; i < mMonitoringChannels.size(); i++) { const sp<InputChannel>& channel = mMonitoringChannels[i]; - dump.appendFormat(INDENT2 "%zu: '%s'\n", i, channel->getName().string()); + dump += StringPrintf(INDENT2 "%zu: '%s'\n", i, channel->getName().c_str()); } } else { - dump.append(INDENT "MonitoringChannels: <none>\n"); + dump += INDENT "MonitoringChannels: <none>\n"; } nsecs_t currentTime = now(); // Dump recently dispatched or dropped events from oldest to newest. if (!mRecentQueue.isEmpty()) { - dump.appendFormat(INDENT "RecentQueue: length=%u\n", mRecentQueue.count()); + dump += StringPrintf(INDENT "RecentQueue: length=%u\n", mRecentQueue.count()); for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) { - dump.append(INDENT2); + dump += INDENT2; entry->appendDescription(dump); - dump.appendFormat(", age=%0.1fms\n", + dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); } } else { - dump.append(INDENT "RecentQueue: <empty>\n"); + dump += INDENT "RecentQueue: <empty>\n"; } // Dump event currently being dispatched. if (mPendingEvent) { - dump.append(INDENT "PendingEvent:\n"); - dump.append(INDENT2); + dump += INDENT "PendingEvent:\n"; + dump += INDENT2; mPendingEvent->appendDescription(dump); - dump.appendFormat(", age=%0.1fms\n", + dump += StringPrintf(", age=%0.1fms\n", (currentTime - mPendingEvent->eventTime) * 0.000001f); } else { - dump.append(INDENT "PendingEvent: <none>\n"); + dump += INDENT "PendingEvent: <none>\n"; } // Dump inbound events from oldest to newest. if (!mInboundQueue.isEmpty()) { - dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count()); + dump += StringPrintf(INDENT "InboundQueue: length=%u\n", mInboundQueue.count()); for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) { - dump.append(INDENT2); + dump += INDENT2; entry->appendDescription(dump); - dump.appendFormat(", age=%0.1fms\n", + dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); } } else { - dump.append(INDENT "InboundQueue: <empty>\n"); + dump += INDENT "InboundQueue: <empty>\n"; } if (!mReplacedKeys.isEmpty()) { - dump.append(INDENT "ReplacedKeys:\n"); + dump += INDENT "ReplacedKeys:\n"; for (size_t i = 0; i < mReplacedKeys.size(); i++) { const KeyReplacement& replacement = mReplacedKeys.keyAt(i); int32_t newKeyCode = mReplacedKeys.valueAt(i); - dump.appendFormat(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", + dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", i, replacement.keyCode, replacement.deviceId, newKeyCode); } } else { - dump.append(INDENT "ReplacedKeys: <empty>\n"); + dump += INDENT "ReplacedKeys: <empty>\n"; } if (!mConnectionsByFd.isEmpty()) { - dump.append(INDENT "Connections:\n"); + dump += INDENT "Connections:\n"; for (size_t i = 0; i < mConnectionsByFd.size(); i++) { const sp<Connection>& connection = mConnectionsByFd.valueAt(i); - dump.appendFormat(INDENT2 "%zu: channelName='%s', windowName='%s', " + dump += StringPrintf(INDENT2 "%zu: channelName='%s', windowName='%s', " "status=%s, monitor=%s, inputPublisherBlocked=%s\n", i, connection->getInputChannelName(), connection->getWindowName(), connection->getStatusLabel(), toString(connection->monitor), toString(connection->inputPublisherBlocked)); if (!connection->outboundQueue.isEmpty()) { - dump.appendFormat(INDENT3 "OutboundQueue: length=%u\n", + dump += StringPrintf(INDENT3 "OutboundQueue: length=%u\n", connection->outboundQueue.count()); for (DispatchEntry* entry = connection->outboundQueue.head; entry; entry = entry->next) { dump.append(INDENT4); entry->eventEntry->appendDescription(dump); - dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", + dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", entry->targetFlags, entry->resolvedAction, (currentTime - entry->eventEntry->eventTime) * 0.000001f); } } else { - dump.append(INDENT3 "OutboundQueue: <empty>\n"); + dump += INDENT3 "OutboundQueue: <empty>\n"; } if (!connection->waitQueue.isEmpty()) { - dump.appendFormat(INDENT3 "WaitQueue: length=%u\n", + dump += StringPrintf(INDENT3 "WaitQueue: length=%u\n", connection->waitQueue.count()); for (DispatchEntry* entry = connection->waitQueue.head; entry; entry = entry->next) { - dump.append(INDENT4); + dump += INDENT4; entry->eventEntry->appendDescription(dump); - dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, " + dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, " "age=%0.1fms, wait=%0.1fms\n", entry->targetFlags, entry->resolvedAction, (currentTime - entry->eventEntry->eventTime) * 0.000001f, (currentTime - entry->deliveryTime) * 0.000001f); } } else { - dump.append(INDENT3 "WaitQueue: <empty>\n"); + dump += INDENT3 "WaitQueue: <empty>\n"; } } } else { - dump.append(INDENT "Connections: <none>\n"); + dump += INDENT "Connections: <none>\n"; } if (isAppSwitchPendingLocked()) { - dump.appendFormat(INDENT "AppSwitch: pending, due in %0.1fms\n", + dump += StringPrintf(INDENT "AppSwitch: pending, due in %0.1fms\n", (mAppSwitchDueTime - now()) / 1000000.0); } else { - dump.append(INDENT "AppSwitch: not pending\n"); + dump += INDENT "AppSwitch: not pending\n"; } - dump.append(INDENT "Configuration:\n"); - dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", + dump += INDENT "Configuration:\n"; + dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f); - dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", + dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f); } status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { #if DEBUG_REGISTRATION - ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(), + ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().c_str(), toString(monitor)); #endif @@ -3350,7 +3351,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan if (getConnectionIndexLocked(inputChannel) >= 0) { ALOGW("Attempted to register already registered input channel '%s'", - inputChannel->getName().string()); + inputChannel->getName().c_str()); return BAD_VALUE; } @@ -3373,7 +3374,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) { #if DEBUG_REGISTRATION - ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string()); + ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().c_str()); #endif { // acquire lock @@ -3396,7 +3397,7 @@ status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& i ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex < 0) { ALOGW("Attempted to unregister already unregistered input channel '%s'", - inputChannel->getName().string()); + inputChannel->getName().c_str()); return BAD_VALUE; } @@ -3465,7 +3466,7 @@ void InputDispatcher::onANRLocked( float waitDuration = (currentTime - waitStartTime) * 0.000001f; ALOGI("Application is not responding: %s. " "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), + getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(), dispatchLatency, waitDuration, reason); // Capture a record of the InputDispatcher state at the time of the ANR. @@ -3475,13 +3476,13 @@ void InputDispatcher::onANRLocked( char timestr[64]; strftime(timestr, sizeof(timestr), "%F %T", &tm); mLastANRState.clear(); - mLastANRState.append(INDENT "ANR:\n"); - mLastANRState.appendFormat(INDENT2 "Time: %s\n", timestr); - mLastANRState.appendFormat(INDENT2 "Window: %s\n", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string()); - mLastANRState.appendFormat(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); - mLastANRState.appendFormat(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); - mLastANRState.appendFormat(INDENT2 "Reason: %s\n", reason); + mLastANRState += INDENT "ANR:\n"; + mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr); + mLastANRState += StringPrintf(INDENT2 "Window: %s\n", + getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str()); + mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); + mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); + mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason); dumpDispatchStateLocked(mLastANRState); CommandEntry* commandEntry = postCommandLocked( @@ -3565,11 +3566,11 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( if (dispatchEntry) { nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { - String8 msg; - msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ", + std::string msg = + StringPrintf("Window '%s' spent %0.1fms processing the last input event: ", connection->getWindowName(), eventDuration * 0.000001f); dispatchEntry->eventEntry->appendDescription(msg); - ALOGI("%s", msg.string()); + ALOGI("%s", msg.c_str()); } bool restartEvent; @@ -3736,15 +3737,15 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con #if DEBUG_OUTBOUND_EVENT_DETAILS { - String8 msg; + std::string msg; const KeyedVector<int32_t, int32_t>& fallbackKeys = connection->inputState.getFallbackKeys(); for (size_t i = 0; i < fallbackKeys.size(); i++) { - msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i), + msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i)); } - ALOGD("Unhandled key event: %d currently tracked fallback keys%s.", - fallbackKeys.size(), msg.string()); + ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.", + fallbackKeys.size(), msg.c_str()); } #endif @@ -3823,15 +3824,15 @@ void InputDispatcher::traceWaitQueueLengthLocked(const sp<Connection>& connectio } } -void InputDispatcher::dump(String8& dump) { +void InputDispatcher::dump(std::string& dump) { AutoMutex _l(mLock); - dump.append("Input Dispatcher State:\n"); + dump += "Input Dispatcher State:\n"; dumpDispatchStateLocked(dump); - if (!mLastANRState.isEmpty()) { - dump.append("\nInput Dispatcher State at time of last ANR:\n"); - dump.append(mLastANRState); + if (!mLastANRState.empty()) { + dump += "\nInput Dispatcher State at time of last ANR:\n"; + dump += mLastANRState; } } @@ -3903,9 +3904,8 @@ InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(nsecs_t ev InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { } -void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const { - msg.append("ConfigurationChangedEvent(), policyFlags=0x%08x", - policyFlags); +void InputDispatcher::ConfigurationChangedEntry::appendDescription(std::string& msg) const { + msg += StringPrintf("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags); } @@ -3919,8 +3919,8 @@ InputDispatcher::DeviceResetEntry::DeviceResetEntry(nsecs_t eventTime, int32_t d InputDispatcher::DeviceResetEntry::~DeviceResetEntry() { } -void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const { - msg.appendFormat("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", +void InputDispatcher::DeviceResetEntry::appendDescription(std::string& msg) const { + msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", deviceId, policyFlags); } @@ -3942,8 +3942,8 @@ InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime, InputDispatcher::KeyEntry::~KeyEntry() { } -void InputDispatcher::KeyEntry::appendDescription(String8& msg) const { - msg.appendFormat("KeyEvent(deviceId=%d, source=0x%08x, action=%d, " +void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const { + msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, action=%d, " "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, " "repeatCount=%d), policyFlags=0x%08x", deviceId, source, action, flags, keyCode, scanCode, metaState, @@ -3987,20 +3987,20 @@ InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId, InputDispatcher::MotionEntry::~MotionEntry() { } -void InputDispatcher::MotionEntry::appendDescription(String8& msg) const { - msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, " +void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const { + msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, " "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, " "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[", deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags, xPrecision, yPrecision, displayId); for (uint32_t i = 0; i < pointerCount; i++) { if (i) { - msg.append(", "); + msg += ", "; } - msg.appendFormat("%d: (%.1f, %.1f)", pointerProperties[i].id, + msg += StringPrintf("%d: (%.1f, %.1f)", pointerProperties[i].id, pointerCoords[i].getX(), pointerCoords[i].getY()); } - msg.appendFormat("]), policyFlags=0x%08x", policyFlags); + msg += StringPrintf("]), policyFlags=0x%08x", policyFlags); } @@ -4399,7 +4399,7 @@ InputDispatcher::Connection::~Connection() { const char* InputDispatcher::Connection::getWindowName() const { if (inputWindowHandle != NULL) { - return inputWindowHandle->getName().string(); + return inputWindowHandle->getName().c_str(); } if (monitor) { return "monitor"; diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 90c69ce581..92b3a9cfeb 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -24,7 +24,6 @@ #include <utils/threads.h> #include <utils/Timers.h> #include <utils/RefBase.h> -#include <utils/String8.h> #include <utils/Looper.h> #include <utils/BitSet.h> #include <cutils/atomic.h> @@ -209,7 +208,7 @@ public: * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, const sp<InputWindowHandle>& inputWindowHandle, - const String8& reason) = 0; + const std::string& reason) = 0; /* Notifies the system that an input channel is unrecoverably broken. */ virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0; @@ -281,7 +280,7 @@ public: /* Dumps the state of the input dispatcher. * * This method may be called on any thread (usually by the input manager). */ - virtual void dump(String8& dump) = 0; + virtual void dump(std::string& dump) = 0; /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ virtual void monitor() = 0; @@ -373,7 +372,7 @@ protected: public: explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void monitor(); virtual void dispatchOnce(); @@ -446,7 +445,7 @@ private: void release(); - virtual void appendDescription(String8& msg) const = 0; + virtual void appendDescription(std::string& msg) const = 0; protected: EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags); @@ -456,7 +455,7 @@ private: struct ConfigurationChangedEntry : EventEntry { explicit ConfigurationChangedEntry(nsecs_t eventTime); - virtual void appendDescription(String8& msg) const; + virtual void appendDescription(std::string& msg) const; protected: virtual ~ConfigurationChangedEntry(); @@ -466,7 +465,7 @@ private: int32_t deviceId; DeviceResetEntry(nsecs_t eventTime, int32_t deviceId); - virtual void appendDescription(String8& msg) const; + virtual void appendDescription(std::string& msg) const; protected: virtual ~DeviceResetEntry(); @@ -498,7 +497,7 @@ private: int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime); - virtual void appendDescription(String8& msg) const; + virtual void appendDescription(std::string& msg) const; void recycle(); protected: @@ -531,7 +530,7 @@ private: int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xOffset, float yOffset); - virtual void appendDescription(String8& msg) const; + virtual void appendDescription(std::string& msg) const; protected: virtual ~MotionEntry(); @@ -602,7 +601,7 @@ private: KeyEntry* keyEntry; sp<InputApplicationHandle> inputApplicationHandle; sp<InputWindowHandle> inputWindowHandle; - String8 reason; + std::string reason; int32_t userActivityEventType; uint32_t seq; bool handled; @@ -832,7 +831,7 @@ private: explicit Connection(const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor); - inline const char* getInputChannelName() const { return inputChannel->getName().string(); } + inline const char* getInputChannelName() const { return inputChannel->getName().c_str(); } const char* getWindowName() const; const char* getStatusLabel() const; @@ -994,7 +993,7 @@ private: sp<InputApplicationHandle> mFocusedApplicationHandle; // Dispatcher state at time of last ANR. - String8 mLastANRState; + std::string mLastANRState; // Dispatch inbound events. bool dispatchConfigurationChangedLocked( @@ -1055,10 +1054,10 @@ private: bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const; bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const; - String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle, + std::string getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle, const sp<InputWindowHandle>& windowHandle); - String8 checkWindowReadyForMoreInputLocked(nsecs_t currentTime, + std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime, const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, const char* targetType); @@ -1096,7 +1095,7 @@ private: void resetAndDropEverythingLocked(const char* reason); // Dump state. - void dumpDispatchStateLocked(String8& dump); + void dumpDispatchStateLocked(std::string& dump); void logDispatchStateLocked(); // Registration. diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 420d06b671..76ea889dc5 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -54,6 +54,7 @@ #include <log/log.h> +#include <android-base/stringprintf.h> #include <input/Keyboard.h> #include <input/VirtualKeyMap.h> @@ -63,6 +64,8 @@ #define INDENT4 " " #define INDENT5 " " +using android::base::StringPrintf; + namespace android { // --- Constants --- @@ -290,19 +293,19 @@ void InputReaderConfiguration::setVirtualDisplayViewports( mVirtualDisplays = viewports; } -void InputReaderConfiguration::dump(String8& dump) const { - dump.append(INDENT4 "ViewportInternal:\n"); +void InputReaderConfiguration::dump(std::string& dump) const { + dump += INDENT4 "ViewportInternal:\n"; dumpViewport(dump, mInternalDisplay); - dump.append(INDENT4 "ViewportExternal:\n"); + dump += INDENT4 "ViewportExternal:\n"; dumpViewport(dump, mExternalDisplay); - dump.append(INDENT4 "ViewportVirtual:\n"); + dump += INDENT4 "ViewportVirtual:\n"; for (const DisplayViewport& viewport : mVirtualDisplays) { dumpViewport(dump, viewport); } } -void InputReaderConfiguration::dumpViewport(String8& dump, const DisplayViewport& viewport) const { - dump.appendFormat(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', " +void InputReaderConfiguration::dumpViewport(std::string& dump, const DisplayViewport& viewport) const { + dump += StringPrintf(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', " "logicalFrame=[%d, %d, %d, %d], " "physicalFrame=[%d, %d, %d, %d], " "deviceSize=[%d, %d]\n", @@ -429,7 +432,7 @@ void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { batchSize += 1; } #if DEBUG_RAW_EVENTS - ALOGD("BatchSize: %d Count: %d", batchSize, count); + ALOGD("BatchSize: %zu Count: %zu", batchSize, count); #endif processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { @@ -873,71 +876,71 @@ bool InputReader::isInputDeviceEnabled(int32_t deviceId) { return false; } -void InputReader::dump(String8& dump) { +void InputReader::dump(std::string& dump) { AutoMutex _l(mLock); mEventHub->dump(dump); - dump.append("\n"); + dump += "\n"; - dump.append("Input Reader State:\n"); + dump += "Input Reader State:\n"; for (size_t i = 0; i < mDevices.size(); i++) { mDevices.valueAt(i)->dump(dump); } - dump.append(INDENT "Configuration:\n"); - dump.append(INDENT2 "ExcludedDeviceNames: ["); + dump += INDENT "Configuration:\n"; + dump += INDENT2 "ExcludedDeviceNames: ["; for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { if (i != 0) { - dump.append(", "); + dump += ", "; } - dump.append(mConfig.excludedDeviceNames.itemAt(i).string()); + dump += mConfig.excludedDeviceNames.itemAt(i).string(); } - dump.append("]\n"); - dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", + dump += "]\n"; + dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", mConfig.virtualKeyQuietTime * 0.000001f); - dump.appendFormat(INDENT2 "PointerVelocityControlParameters: " + dump += StringPrintf(INDENT2 "PointerVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.pointerVelocityControlParameters.scale, mConfig.pointerVelocityControlParameters.lowThreshold, mConfig.pointerVelocityControlParameters.highThreshold, mConfig.pointerVelocityControlParameters.acceleration); - dump.appendFormat(INDENT2 "WheelVelocityControlParameters: " + dump += StringPrintf(INDENT2 "WheelVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.wheelVelocityControlParameters.scale, mConfig.wheelVelocityControlParameters.lowThreshold, mConfig.wheelVelocityControlParameters.highThreshold, mConfig.wheelVelocityControlParameters.acceleration); - dump.appendFormat(INDENT2 "PointerGesture:\n"); - dump.appendFormat(INDENT3 "Enabled: %s\n", + dump += StringPrintf(INDENT2 "PointerGesture:\n"); + dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(mConfig.pointerGesturesEnabled)); - dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n", + dump += StringPrintf(INDENT3 "QuietInterval: %0.1fms\n", mConfig.pointerGestureQuietInterval * 0.000001f); - dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", + dump += StringPrintf(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", mConfig.pointerGestureDragMinSwitchSpeed); - dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n", + dump += StringPrintf(INDENT3 "TapInterval: %0.1fms\n", mConfig.pointerGestureTapInterval * 0.000001f); - dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n", + dump += StringPrintf(INDENT3 "TapDragInterval: %0.1fms\n", mConfig.pointerGestureTapDragInterval * 0.000001f); - dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n", + dump += StringPrintf(INDENT3 "TapSlop: %0.1fpx\n", mConfig.pointerGestureTapSlop); - dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n", + dump += StringPrintf(INDENT3 "MultitouchSettleInterval: %0.1fms\n", mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); - dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n", + dump += StringPrintf(INDENT3 "MultitouchMinDistance: %0.1fpx\n", mConfig.pointerGestureMultitouchMinDistance); - dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", + dump += StringPrintf(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", mConfig.pointerGestureSwipeTransitionAngleCosine); - dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", + dump += StringPrintf(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", mConfig.pointerGestureSwipeMaxWidthRatio); - dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n", + dump += StringPrintf(INDENT3 "MovementSpeedRatio: %0.1f\n", mConfig.pointerGestureMovementSpeedRatio); - dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n", + dump += StringPrintf(INDENT3 "ZoomSpeedRatio: %0.1f\n", mConfig.pointerGestureZoomSpeedRatio); - dump.append(INDENT3 "Viewports:\n"); + dump += INDENT3 "Viewports:\n"; mConfig.dump(dump); } @@ -1069,21 +1072,21 @@ void InputDevice::setEnabled(bool enabled, nsecs_t when) { bumpGeneration(); } -void InputDevice::dump(String8& dump) { +void InputDevice::dump(std::string& dump) { InputDeviceInfo deviceInfo; getDeviceInfo(& deviceInfo); - dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), + dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(), deviceInfo.getDisplayName().string()); - dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration); - dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); - dump.appendFormat(INDENT2 "HasMic: %s\n", toString(mHasMic)); - dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); - dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); + dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration); + dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); + dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic)); + dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); + dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); if (!ranges.isEmpty()) { - dump.append(INDENT2 "Motion Ranges:\n"); + dump += INDENT2 "Motion Ranges:\n"; for (size_t i = 0; i < ranges.size(); i++) { const InputDeviceInfo::MotionRange& range = ranges.itemAt(i); const char* label = getAxisLabel(range.axis); @@ -1094,7 +1097,7 @@ void InputDevice::dump(String8& dump) { } else { snprintf(name, sizeof(name), "%d", range.axis); } - dump.appendFormat(INDENT3 "%s: source=0x%08x, " + dump += StringPrintf(INDENT3 "%s: source=0x%08x, " "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n", name, range.source, range.min, range.max, range.flat, range.fuzz, range.resolution); @@ -1176,7 +1179,7 @@ void InputDevice::process(const RawEvent* rawEvents, size_t count) { size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { #if DEBUG_RAW_EVENTS - ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld", + ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64, rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, rawEvent->when); #endif @@ -1852,7 +1855,7 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { #if DEBUG_POINTERS if (newSlot) { ALOGW("MultiTouch device emitted invalid slot index %d but it " - "should be between 0 and %d; ignoring this slot.", + "should be between 0 and %zd; ignoring this slot.", mCurrentSlot, mSlotCount - 1); } #endif @@ -1982,7 +1985,7 @@ void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addSource(getSources()); } -void InputMapper::dump(String8& dump) { +void InputMapper::dump(std::string& dump) { } void InputMapper::configure(nsecs_t when, @@ -2044,21 +2047,21 @@ void InputMapper::bumpGeneration() { mDevice->bumpGeneration(); } -void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, +void InputMapper::dumpRawAbsoluteAxisInfo(std::string& dump, const RawAbsoluteAxisInfo& axis, const char* name) { if (axis.valid) { - dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", + dump += StringPrintf(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); } else { - dump.appendFormat(INDENT4 "%s: unknown range\n", name); + dump += StringPrintf(INDENT4 "%s: unknown range\n", name); } } -void InputMapper::dumpStylusState(String8& dump, const StylusState& state) { - dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when); - dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure); - dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons); - dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); +void InputMapper::dumpStylusState(std::string& dump, const StylusState& state) { + dump += StringPrintf(INDENT4 "When: %" PRId64 "\n", state.when); + dump += StringPrintf(INDENT4 "Pressure: %f\n", state.pressure); + dump += StringPrintf(INDENT4 "Button State: 0x%08x\n", state.buttons); + dump += StringPrintf(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); } // --- SwitchInputMapper --- @@ -2112,9 +2115,9 @@ int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCod return getEventHub()->getSwitchState(getDeviceId(), switchCode); } -void SwitchInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Switch Input Mapper:\n"); - dump.appendFormat(INDENT3 "SwitchValues: %x\n", mSwitchValues); +void SwitchInputMapper::dump(std::string& dump) { + dump += INDENT2 "Switch Input Mapper:\n"; + dump += StringPrintf(INDENT3 "SwitchValues: %x\n", mSwitchValues); } // --- VibratorInputMapper --- @@ -2143,15 +2146,15 @@ void VibratorInputMapper::process(const RawEvent* rawEvent) { void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { #if DEBUG_VIBRATOR - String8 patternStr; + std::string patternStr; for (size_t i = 0; i < patternSize; i++) { if (i != 0) { - patternStr.append(", "); + patternStr += ", "; } - patternStr.appendFormat("%lld", pattern[i]); + patternStr += StringPrintf("%" PRId64, pattern[i]); } - ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d", - getDeviceId(), patternStr.string(), repeat, token); + ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", + getDeviceId(), patternStr.c_str(), repeat, token); #endif mVibrating = true; @@ -2199,8 +2202,7 @@ void VibratorInputMapper::nextStep() { nsecs_t duration = mPattern[mIndex]; if (vibratorOn) { #if DEBUG_VIBRATOR - ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld", - getDeviceId(), duration); + ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration); #endif getEventHub()->vibrate(getDeviceId(), duration); } else { @@ -2225,9 +2227,9 @@ void VibratorInputMapper::stopVibrating() { getEventHub()->cancelVibrate(getDeviceId()); } -void VibratorInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Vibrator Input Mapper:\n"); - dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating)); +void VibratorInputMapper::dump(std::string& dump) { + dump += INDENT2 "Vibrator Input Mapper:\n"; + dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating)); } @@ -2253,14 +2255,14 @@ void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); } -void KeyboardInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Keyboard Input Mapper:\n"); +void KeyboardInputMapper::dump(std::string& dump) { + dump += INDENT2 "Keyboard Input Mapper:\n"; dumpParameters(dump); - dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); - dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); - dump.appendFormat(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size()); - dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState); - dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime); + dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType); + dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation); + dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size()); + dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState); + dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); } @@ -2320,13 +2322,13 @@ void KeyboardInputMapper::configureParameters() { mParameters.handlesKeyRepeat); } -void KeyboardInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", +void KeyboardInputMapper::dumpParameters(std::string& dump) { + dump += INDENT3 "Parameters:\n"; + dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n", toString(mParameters.hasAssociatedDisplay)); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", + dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); - dump.appendFormat(INDENT4 "HandlesKeyRepeat: %s\n", + dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n", toString(mParameters.handlesKeyRepeat)); } @@ -2605,23 +2607,23 @@ void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { } } -void CursorInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Cursor Input Mapper:\n"); +void CursorInputMapper::dump(std::string& dump) { + dump += INDENT2 "Cursor Input Mapper:\n"; dumpParameters(dump); - dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale); - dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale); - dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); - dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); - dump.appendFormat(INDENT3 "HaveVWheel: %s\n", + dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale); + dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale); + dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision); + dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision); + dump += StringPrintf(INDENT3 "HaveVWheel: %s\n", toString(mCursorScrollAccumulator.haveRelativeVWheel())); - dump.appendFormat(INDENT3 "HaveHWheel: %s\n", + dump += StringPrintf(INDENT3 "HaveHWheel: %s\n", toString(mCursorScrollAccumulator.haveRelativeHWheel())); - dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); - dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); - dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); - dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState); - dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); - dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime); + dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); + dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); + dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation); + dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState); + dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); + dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); } void CursorInputMapper::configure(nsecs_t when, @@ -2729,26 +2731,26 @@ void CursorInputMapper::configureParameters() { } } -void CursorInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", +void CursorInputMapper::dumpParameters(std::string& dump) { + dump += INDENT3 "Parameters:\n"; + dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n", toString(mParameters.hasAssociatedDisplay)); switch (mParameters.mode) { case Parameters::MODE_POINTER: - dump.append(INDENT4 "Mode: pointer\n"); + dump += INDENT4 "Mode: pointer\n"; break; case Parameters::MODE_POINTER_RELATIVE: - dump.append(INDENT4 "Mode: relative pointer\n"); + dump += INDENT4 "Mode: relative pointer\n"; break; case Parameters::MODE_NAVIGATION: - dump.append(INDENT4 "Mode: navigation\n"); + dump += INDENT4 "Mode: navigation\n"; break; default: ALOG_ASSERT(false); } - dump.appendFormat(INDENT4 "OrientationAware: %s\n", + dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } @@ -3001,9 +3003,9 @@ void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { } } -void RotaryEncoderInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Rotary Encoder Input Mapper:\n"); - dump.appendFormat(INDENT3 "HaveWheel: %s\n", +void RotaryEncoderInputMapper::dump(std::string& dump) { + dump += INDENT2 "Rotary Encoder Input Mapper:\n"; + dump += StringPrintf(INDENT3 "HaveWheel: %s\n", toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel())); } @@ -3152,8 +3154,8 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { } } -void TouchInputMapper::dump(String8& dump) { - dump.appendFormat(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode)); +void TouchInputMapper::dump(std::string& dump) { + dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode)); dumpParameters(dump); dumpVirtualKeys(dump); dumpRawPointerAxes(dump); @@ -3161,30 +3163,30 @@ void TouchInputMapper::dump(String8& dump) { dumpAffineTransformation(dump); dumpSurface(dump); - dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n"); - dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate); - dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate); - dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale); - dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale); - dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision); - dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision); - dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); - dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale); - dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale); - dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); - dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); - dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); - dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); - dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); - dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); - dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - - dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState); - dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n", + dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n"); + dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate); + dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate); + dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale); + dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale); + dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision); + dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision); + dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); + dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale); + dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale); + dump += StringPrintf(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); + dump += StringPrintf(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); + dump += StringPrintf(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); + dump += StringPrintf(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); + dump += StringPrintf(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); + dump += StringPrintf(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); + dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); + + dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState); + dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n", mLastRawState.rawPointerData.pointerCount); for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; - dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " + dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " "toolType=%d, isHovering=%s\n", i, @@ -3195,14 +3197,14 @@ void TouchInputMapper::dump(String8& dump) { pointer.toolType, toString(pointer.isHovering)); } - dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState); - dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n", + dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState); + dump += StringPrintf(INDENT3 "Last Cooked Touch: pointerCount=%d\n", mLastCookedState.cookedPointerData.pointerCount); for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { const PointerProperties& pointerProperties = mLastCookedState.cookedPointerData.pointerProperties[i]; const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; - dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " + dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " "toolType=%d, isHovering=%s\n", i, @@ -3221,26 +3223,26 @@ void TouchInputMapper::dump(String8& dump) { toString(mLastCookedState.cookedPointerData.isHovering(i))); } - dump.append(INDENT3 "Stylus Fusion:\n"); - dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n", + dump += INDENT3 "Stylus Fusion:\n"; + dump += StringPrintf(INDENT4 "ExternalStylusConnected: %s\n", toString(mExternalStylusConnected)); - dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); - dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", + dump += StringPrintf(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); + dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", mExternalStylusFusionTimeout); - dump.append(INDENT3 "External Stylus State:\n"); + dump += INDENT3 "External Stylus State:\n"; dumpStylusState(dump, mExternalStylusState); if (mDeviceMode == DEVICE_MODE_POINTER) { - dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); - dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", + dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n"); + dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n", mPointerXMovementScale); - dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n", + dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n", mPointerYMovementScale); - dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n", + dump += StringPrintf(INDENT4 "XZoomScale: %0.3f\n", mPointerXZoomScale); - dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n", + dump += StringPrintf(INDENT4 "YZoomScale: %0.3f\n", mPointerYZoomScale); - dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n", + dump += StringPrintf(INDENT4 "MaxSwipeWidth: %f\n", mPointerGestureMaxSwipeWidth); } } @@ -3401,15 +3403,15 @@ void TouchInputMapper::configureParameters() { mParameters.wake); } -void TouchInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); +void TouchInputMapper::dumpParameters(std::string& dump) { + dump += INDENT3 "Parameters:\n"; switch (mParameters.gestureMode) { case Parameters::GESTURE_MODE_SINGLE_TOUCH: - dump.append(INDENT4 "GestureMode: single-touch\n"); + dump += INDENT4 "GestureMode: single-touch\n"; break; case Parameters::GESTURE_MODE_MULTI_TOUCH: - dump.append(INDENT4 "GestureMode: multi-touch\n"); + dump += INDENT4 "GestureMode: multi-touch\n"; break; default: assert(false); @@ -3417,27 +3419,27 @@ void TouchInputMapper::dumpParameters(String8& dump) { switch (mParameters.deviceType) { case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - dump.append(INDENT4 "DeviceType: touchScreen\n"); + dump += INDENT4 "DeviceType: touchScreen\n"; break; case Parameters::DEVICE_TYPE_TOUCH_PAD: - dump.append(INDENT4 "DeviceType: touchPad\n"); + dump += INDENT4 "DeviceType: touchPad\n"; break; case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: - dump.append(INDENT4 "DeviceType: touchNavigation\n"); + dump += INDENT4 "DeviceType: touchNavigation\n"; break; case Parameters::DEVICE_TYPE_POINTER: - dump.append(INDENT4 "DeviceType: pointer\n"); + dump += INDENT4 "DeviceType: pointer\n"; break; default: ALOG_ASSERT(false); } - dump.appendFormat( + dump += StringPrintf( INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, displayId='%s'\n", toString(mParameters.hasAssociatedDisplay), toString(mParameters.associatedDisplayIsExternal), mParameters.uniqueDisplayId.c_str()); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", + dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } @@ -3445,8 +3447,8 @@ void TouchInputMapper::configureRawPointerAxes() { mRawPointerAxes.clear(); } -void TouchInputMapper::dumpRawPointerAxes(String8& dump) { - dump.append(INDENT3 "Raw Touch Axes:\n"); +void TouchInputMapper::dumpRawPointerAxes(std::string& dump) { + dump += INDENT3 "Raw Touch Axes:\n"; dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); @@ -3703,11 +3705,13 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { // Pressure factors. mPressureScale = 0; + float pressureMax = 1.0; if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL || mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { if (mCalibration.havePressureScale) { mPressureScale = mCalibration.pressureScale; + pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue; } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) { mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; @@ -3717,7 +3721,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; mOrientedRanges.pressure.source = mSource; mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = 1.0; + mOrientedRanges.pressure.max = pressureMax; mOrientedRanges.pressure.flat = 0; mOrientedRanges.pressure.fuzz = 0; mOrientedRanges.pressure.resolution = 0; @@ -3891,8 +3895,8 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { } } -void TouchInputMapper::dumpSurface(String8& dump) { - dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, " +void TouchInputMapper::dumpSurface(std::string& dump) { + dump += StringPrintf(INDENT3 "Viewport: displayId=%d, orientation=%d, " "logicalFrame=[%d, %d, %d, %d], " "physicalFrame=[%d, %d, %d, %d], " "deviceSize=[%d, %d]\n", @@ -3903,11 +3907,11 @@ void TouchInputMapper::dumpSurface(String8& dump) { mViewport.physicalRight, mViewport.physicalBottom, mViewport.deviceWidth, mViewport.deviceHeight); - dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); - dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); - dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); - dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); - dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); + dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); + dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); + dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); + dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); + dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); } void TouchInputMapper::configureVirtualKeys() { @@ -3964,13 +3968,13 @@ void TouchInputMapper::configureVirtualKeys() { } } -void TouchInputMapper::dumpVirtualKeys(String8& dump) { +void TouchInputMapper::dumpVirtualKeys(std::string& dump) { if (!mVirtualKeys.isEmpty()) { - dump.append(INDENT3 "Virtual Keys:\n"); + dump += INDENT3 "Virtual Keys:\n"; for (size_t i = 0; i < mVirtualKeys.size(); i++) { const VirtualKey& virtualKey = mVirtualKeys.itemAt(i); - dump.appendFormat(INDENT4 "%zu: scanCode=%d, keyCode=%d, " + dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, " "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", i, virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft, virtualKey.hitRight, @@ -4119,75 +4123,75 @@ void TouchInputMapper::resolveCalibration() { } } -void TouchInputMapper::dumpCalibration(String8& dump) { - dump.append(INDENT3 "Calibration:\n"); +void TouchInputMapper::dumpCalibration(std::string& dump) { + dump += INDENT3 "Calibration:\n"; // Size switch (mCalibration.sizeCalibration) { case Calibration::SIZE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.size.calibration: none\n"); + dump += INDENT4 "touch.size.calibration: none\n"; break; case Calibration::SIZE_CALIBRATION_GEOMETRIC: - dump.append(INDENT4 "touch.size.calibration: geometric\n"); + dump += INDENT4 "touch.size.calibration: geometric\n"; break; case Calibration::SIZE_CALIBRATION_DIAMETER: - dump.append(INDENT4 "touch.size.calibration: diameter\n"); + dump += INDENT4 "touch.size.calibration: diameter\n"; break; case Calibration::SIZE_CALIBRATION_BOX: - dump.append(INDENT4 "touch.size.calibration: box\n"); + dump += INDENT4 "touch.size.calibration: box\n"; break; case Calibration::SIZE_CALIBRATION_AREA: - dump.append(INDENT4 "touch.size.calibration: area\n"); + dump += INDENT4 "touch.size.calibration: area\n"; break; default: ALOG_ASSERT(false); } if (mCalibration.haveSizeScale) { - dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n", + dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale); } if (mCalibration.haveSizeBias) { - dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n", + dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", mCalibration.sizeBias); } if (mCalibration.haveSizeIsSummed) { - dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n", + dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n", toString(mCalibration.sizeIsSummed)); } // Pressure switch (mCalibration.pressureCalibration) { case Calibration::PRESSURE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.pressure.calibration: none\n"); + dump += INDENT4 "touch.pressure.calibration: none\n"; break; case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - dump.append(INDENT4 "touch.pressure.calibration: physical\n"); + dump += INDENT4 "touch.pressure.calibration: physical\n"; break; case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - dump.append(INDENT4 "touch.pressure.calibration: amplitude\n"); + dump += INDENT4 "touch.pressure.calibration: amplitude\n"; break; default: ALOG_ASSERT(false); } if (mCalibration.havePressureScale) { - dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n", + dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", mCalibration.pressureScale); } // Orientation switch (mCalibration.orientationCalibration) { case Calibration::ORIENTATION_CALIBRATION_NONE: - dump.append(INDENT4 "touch.orientation.calibration: none\n"); + dump += INDENT4 "touch.orientation.calibration: none\n"; break; case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - dump.append(INDENT4 "touch.orientation.calibration: interpolated\n"); + dump += INDENT4 "touch.orientation.calibration: interpolated\n"; break; case Calibration::ORIENTATION_CALIBRATION_VECTOR: - dump.append(INDENT4 "touch.orientation.calibration: vector\n"); + dump += INDENT4 "touch.orientation.calibration: vector\n"; break; default: ALOG_ASSERT(false); @@ -4196,41 +4200,41 @@ void TouchInputMapper::dumpCalibration(String8& dump) { // Distance switch (mCalibration.distanceCalibration) { case Calibration::DISTANCE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.distance.calibration: none\n"); + dump += INDENT4 "touch.distance.calibration: none\n"; break; case Calibration::DISTANCE_CALIBRATION_SCALED: - dump.append(INDENT4 "touch.distance.calibration: scaled\n"); + dump += INDENT4 "touch.distance.calibration: scaled\n"; break; default: ALOG_ASSERT(false); } if (mCalibration.haveDistanceScale) { - dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n", + dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale); } switch (mCalibration.coverageCalibration) { case Calibration::COVERAGE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.coverage.calibration: none\n"); + dump += INDENT4 "touch.coverage.calibration: none\n"; break; case Calibration::COVERAGE_CALIBRATION_BOX: - dump.append(INDENT4 "touch.coverage.calibration: box\n"); + dump += INDENT4 "touch.coverage.calibration: box\n"; break; default: ALOG_ASSERT(false); } } -void TouchInputMapper::dumpAffineTransformation(String8& dump) { - dump.append(INDENT3 "Affine Transformation:\n"); +void TouchInputMapper::dumpAffineTransformation(std::string& dump) { + dump += INDENT3 "Affine Transformation:\n"; - dump.appendFormat(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale); - dump.appendFormat(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix); - dump.appendFormat(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset); - dump.appendFormat(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix); - dump.appendFormat(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale); - dump.appendFormat(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset); + dump += StringPrintf(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale); + dump += StringPrintf(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix); + dump += StringPrintf(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset); + dump += StringPrintf(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix); + dump += StringPrintf(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale); + dump += StringPrintf(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset); } void TouchInputMapper::updateAffineTransformation() { @@ -5510,18 +5514,15 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // Otherwise choose an arbitrary remaining pointer. // This guarantees we always have an active touch id when there is at least one pointer. // We keep the same active touch id for as long as possible. - bool activeTouchChanged = false; int32_t lastActiveTouchId = mPointerGesture.activeTouchId; int32_t activeTouchId = lastActiveTouchId; if (activeTouchId < 0) { if (!mCurrentCookedState.fingerIdBits.isEmpty()) { - activeTouchChanged = true; activeTouchId = mPointerGesture.activeTouchId = mCurrentCookedState.fingerIdBits.firstMarkedBit(); mPointerGesture.firstTouchTime = when; } } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { - activeTouchChanged = true; if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchId = mPointerGesture.activeTouchId = mCurrentCookedState.fingerIdBits.firstMarkedBit(); @@ -5617,7 +5618,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } if (bestId >= 0 && bestId != activeTouchId) { mPointerGesture.activeTouchId = activeTouchId = bestId; - activeTouchChanged = true; #if DEBUG_GESTURES ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); @@ -6632,7 +6632,7 @@ void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", + ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); } @@ -6678,7 +6678,7 @@ void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", + ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); } @@ -6704,7 +6704,8 @@ void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) usedIdBits.markBit(id); #if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", + ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32 + ", id=%" PRIu32 ", distance=%" PRIu64, lastPointerIndex, currentPointerIndex, id, heap[0].distance); #endif break; @@ -6722,8 +6723,7 @@ void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) current->rawPointerData.isHovering(currentPointerIndex)); #if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - assigned: cur=%d, id=%d", - currentPointerIndex, id); + ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, id); #endif } } @@ -7010,11 +7010,11 @@ void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); } -void ExternalStylusInputMapper::dump(String8& dump) { - dump.append(INDENT2 "External Stylus Input Mapper:\n"); - dump.append(INDENT3 "Raw Stylus Axes:\n"); +void ExternalStylusInputMapper::dump(std::string& dump) { + dump += INDENT2 "External Stylus Input Mapper:\n"; + dump += INDENT3 "Raw Stylus Axes:\n"; dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); - dump.append(INDENT3 "Stylus State:\n"); + dump += INDENT3 "Stylus State:\n"; dumpStylusState(dump, mStylusState); } @@ -7119,37 +7119,37 @@ int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { return -1; } -void JoystickInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Joystick Input Mapper:\n"); +void JoystickInputMapper::dump(std::string& dump) { + dump += INDENT2 "Joystick Input Mapper:\n"; - dump.append(INDENT3 "Axes:\n"); + dump += INDENT3 "Axes:\n"; size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { const Axis& axis = mAxes.valueAt(i); const char* label = getAxisLabel(axis.axisInfo.axis); if (label) { - dump.appendFormat(INDENT4 "%s", label); + dump += StringPrintf(INDENT4 "%s", label); } else { - dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis); + dump += StringPrintf(INDENT4 "%d", axis.axisInfo.axis); } if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { label = getAxisLabel(axis.axisInfo.highAxis); if (label) { - dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue); + dump += StringPrintf(" / %s (split at %d)", label, axis.axisInfo.splitValue); } else { - dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis, + dump += StringPrintf(" / %d (split at %d)", axis.axisInfo.highAxis, axis.axisInfo.splitValue); } } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { - dump.append(" (invert)"); + dump += " (invert)"; } - dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", + dump += StringPrintf(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, " + dump += StringPrintf(INDENT4 " scale=%0.5f, offset=%0.5f, " "highScale=%0.5f, highOffset=%0.5f\n", axis.scale, axis.offset, axis.highScale, axis.highOffset); - dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " + dump += StringPrintf(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution); diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index a6b9798759..4f48262910 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -32,7 +32,6 @@ #include <utils/Mutex.h> #include <utils/Timers.h> #include <utils/RefBase.h> -#include <utils/String8.h> #include <utils/BitSet.h> #include <utils/SortedVector.h> @@ -207,8 +206,8 @@ struct InputReaderConfiguration { void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports); - void dump(String8& dump) const; - void dumpViewport(String8& dump, const DisplayViewport& viewport) const; + void dump(std::string& dump) const; + void dumpViewport(std::string& dump, const DisplayViewport& viewport) const; private: DisplayViewport mInternalDisplay; @@ -292,7 +291,7 @@ public: /* Dumps the state of the input reader. * * This method may be called on any thread (usually by the input manager). */ - virtual void dump(String8& dump) = 0; + virtual void dump(std::string& dump) = 0; /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; @@ -412,7 +411,7 @@ public: const sp<InputListenerInterface>& listener); virtual ~InputReader(); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void monitor(); virtual void loopOnce(); @@ -569,7 +568,7 @@ public: bool isEnabled(); void setEnabled(bool enabled, nsecs_t when); - void dump(String8& dump); + void dump(std::string& dump); void addMapper(InputMapper* mapper); void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); void reset(nsecs_t when); @@ -987,7 +986,7 @@ public: virtual uint32_t getSources() = 0; virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent) = 0; @@ -1017,9 +1016,9 @@ protected: status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); void bumpGeneration(); - static void dumpRawAbsoluteAxisInfo(String8& dump, + static void dumpRawAbsoluteAxisInfo(std::string& dump, const RawAbsoluteAxisInfo& axis, const char* name); - static void dumpStylusState(String8& dump, const StylusState& state); + static void dumpStylusState(std::string& dump, const StylusState& state); }; @@ -1032,7 +1031,7 @@ public: virtual void process(const RawEvent* rawEvent); virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); private: uint32_t mSwitchValues; @@ -1056,7 +1055,7 @@ public: int32_t token); virtual void cancelVibrate(int32_t token); virtual void timeoutExpired(nsecs_t when); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); private: bool mVibrating; @@ -1079,7 +1078,7 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); @@ -1125,7 +1124,7 @@ private: } mParameters; void configureParameters(); - void dumpParameters(String8& dump); + void dumpParameters(std::string& dump); bool isKeyboardOrGamepadKey(int32_t scanCode); bool isMediaKey(int32_t keyCode); @@ -1151,7 +1150,7 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); @@ -1204,7 +1203,7 @@ private: nsecs_t mDownTime; void configureParameters(); - void dumpParameters(String8& dump); + void dumpParameters(std::string& dump); void sync(nsecs_t when); }; @@ -1217,7 +1216,7 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); @@ -1239,7 +1238,7 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); @@ -1482,18 +1481,18 @@ protected: Vector<VirtualKey> mVirtualKeys; virtual void configureParameters(); - virtual void dumpParameters(String8& dump); + virtual void dumpParameters(std::string& dump); virtual void configureRawPointerAxes(); - virtual void dumpRawPointerAxes(String8& dump); + virtual void dumpRawPointerAxes(std::string& dump); virtual void configureSurface(nsecs_t when, bool* outResetNeeded); - virtual void dumpSurface(String8& dump); + virtual void dumpSurface(std::string& dump); virtual void configureVirtualKeys(); - virtual void dumpVirtualKeys(String8& dump); + virtual void dumpVirtualKeys(std::string& dump); virtual void parseCalibration(); virtual void resolveCalibration(); - virtual void dumpCalibration(String8& dump); + virtual void dumpCalibration(std::string& dump); virtual void updateAffineTransformation(); - virtual void dumpAffineTransformation(String8& dump); + virtual void dumpAffineTransformation(std::string& dump); virtual void resolveExternalStylusPresence(); virtual bool hasStylus() const = 0; virtual bool hasExternalStylus() const; @@ -1904,7 +1903,7 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); @@ -1926,7 +1925,7 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); + virtual void dump(std::string& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h index 9eb27983cd..5a48375910 100644 --- a/services/inputflinger/InputWindow.h +++ b/services/inputflinger/InputWindow.h @@ -23,7 +23,6 @@ #include <ui/Region.h> #include <utils/RefBase.h> #include <utils/Timers.h> -#include <utils/String8.h> #include "InputApplication.h" @@ -116,7 +115,7 @@ struct InputWindowInfo { }; sp<InputChannel> inputChannel; - String8 name; + std::string name; int32_t layoutParamsFlags; int32_t layoutParamsType; nsecs_t dispatchingTimeout; @@ -173,8 +172,8 @@ public: return mInfo ? mInfo->inputChannel : NULL; } - inline String8 getName() const { - return mInfo ? mInfo->name : String8("<invalid>"); + inline std::string getName() const { + return mInfo ? mInfo->name : "<invalid>"; } inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index a49c8c84c7..8a35509822 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -19,7 +19,6 @@ cc_test { "libhardware", "libhardware_legacy", "libui", - "libskia", "libinput", "libinputflinger", "libinputservice", diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 7ae36d86f1..aa6df244e2 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -54,7 +54,7 @@ private: virtual nsecs_t notifyANR(const sp<InputApplicationHandle>&, const sp<InputWindowHandle>&, - const String8&) { + const std::string&) { return 0; } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 76291a5786..63c92d1dc7 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -798,7 +798,7 @@ private: return false; } - virtual void dump(String8&) { + virtual void dump(std::string&) { } virtual void monitor() { @@ -2954,8 +2954,8 @@ const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0; const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31; const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0; const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15; -const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN; -const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX; +const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = 0; +const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = 255; const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7; const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7; const int32_t TouchInputMapperTest::RAW_DISTANCE_MIN = 0; @@ -5316,6 +5316,12 @@ TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) { addConfigurationProperty("touch.pressure.scale", "0.01"); addMapperAndConfigure(mapper); + InputDeviceInfo info; + mapper->populateDeviceInfo(&info); + ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, + AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TOUCHSCREEN, + 0.0f, RAW_PRESSURE_MAX * 0.01, 0.0f, 0.0f)); + // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS new file mode 100644 index 0000000000..6a38a1ff14 --- /dev/null +++ b/services/sensorservice/OWNERS @@ -0,0 +1,2 @@ +ashutoshj@google.com +pengxu@google.com diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 535d0db2d2..fdb69d3ecc 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -217,8 +217,13 @@ ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) { } void SensorDevice::autoDisable(void *ident, int handle) { - Info& info( mActivationCount.editValueFor(handle) ); Mutex::Autolock _l(mLock); + ssize_t activationIndex = mActivationCount.indexOfKey(handle); + if (activationIndex < 0) { + ALOGW("Handle %d cannot be found in activation record", handle); + return; + } + Info& info(mActivationCount.editValueAt(activationIndex)); info.removeBatchParamsForIdent(ident); } @@ -229,7 +234,12 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) { bool actuateHardware = false; Mutex::Autolock _l(mLock); - Info& info( mActivationCount.editValueFor(handle) ); + ssize_t activationIndex = mActivationCount.indexOfKey(handle); + if (activationIndex < 0) { + ALOGW("Handle %d cannot be found in activation record", handle); + return BAD_VALUE; + } + Info& info(mActivationCount.editValueAt(activationIndex)); ALOGD_IF(DEBUG_CONNECTIONS, "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu", @@ -323,7 +333,12 @@ status_t SensorDevice::batch( ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs); Mutex::Autolock _l(mLock); - Info& info(mActivationCount.editValueFor(handle)); + ssize_t activationIndex = mActivationCount.indexOfKey(handle); + if (activationIndex < 0) { + ALOGW("Handle %d cannot be found in activation record", handle); + return BAD_VALUE; + } + Info& info(mActivationCount.editValueAt(activationIndex)); if (info.batchParams.indexOfKey(ident) < 0) { BatchParams params(samplingPeriodNs, maxBatchReportLatencyNs); diff --git a/services/sensorservice/SensorDeviceUtils.cpp b/services/sensorservice/SensorDeviceUtils.cpp index b1344becd7..dbafffe303 100644 --- a/services/sensorservice/SensorDeviceUtils.cpp +++ b/services/sensorservice/SensorDeviceUtils.cpp @@ -28,8 +28,13 @@ using namespace android::hardware::sensors::V1_0; namespace android { namespace SensorDeviceUtils { -HidlServiceRegistrationWaiter::HidlServiceRegistrationWaiter() - : mRegistered(ISensors::registerForNotifications("default", this)) { +HidlServiceRegistrationWaiter::HidlServiceRegistrationWaiter() { +} + +void HidlServiceRegistrationWaiter::onFirstRef() { + // Creating sp<...>(this) in the constructor should be avoided, hence + // registerForNotifications is called in onFirstRef callback. + mRegistered = ISensors::registerForNotifications("default", this); } Return<void> HidlServiceRegistrationWaiter::onRegistration( diff --git a/services/sensorservice/SensorDeviceUtils.h b/services/sensorservice/SensorDeviceUtils.h index da36928105..e2eb606b9a 100644 --- a/services/sensorservice/SensorDeviceUtils.h +++ b/services/sensorservice/SensorDeviceUtils.h @@ -46,8 +46,10 @@ public: * @return true if service is restart since last reset(); false otherwise. */ bool wait(); +protected: + void onFirstRef() override; private: - const bool mRegistered; + bool mRegistered; std::mutex mLock; std::condition_variable mCondition; diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 4775e4ef54..bd7f0ea364 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -1,6 +1,8 @@ cc_library_static { name: "libsurfaceflingerincludes", export_include_dirs: ["."], + static_libs = ["libserviceutils"], + export_static_lib_headers = ["libserviceutils"], } -subdirs = ["tests/fakehwc"]
\ No newline at end of file +subdirs = ["tests/fakehwc", "layerproto"]
\ No newline at end of file diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 38529b6d0a..5b6c1ca211 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -14,31 +14,38 @@ LOCAL_SRC_FILES := \ FrameTracker.cpp \ GpuService.cpp \ Layer.cpp \ - LayerDim.cpp \ + BufferLayer.cpp \ + BufferLayerConsumer.cpp \ + ColorLayer.cpp \ LayerRejecter.cpp \ LayerVector.cpp \ MessageQueue.cpp \ MonitoredProducer.cpp \ - SurfaceFlingerConsumer.cpp \ + SurfaceFlinger.cpp \ SurfaceInterceptor.cpp \ + SurfaceTracing.cpp \ Transform.cpp \ DisplayHardware/ComposerHal.cpp \ DisplayHardware/FramebufferSurface.cpp \ DisplayHardware/HWC2.cpp \ + DisplayHardware/HWComposer.cpp \ DisplayHardware/HWComposerBufferCache.cpp \ - DisplayHardware/PowerHAL.cpp \ DisplayHardware/VirtualDisplaySurface.cpp \ Effects/Daltonizer.cpp \ EventLog/EventLogTags.logtags \ EventLog/EventLog.cpp \ RenderEngine/Description.cpp \ + RenderEngine/Image.cpp \ RenderEngine/Mesh.cpp \ RenderEngine/Program.cpp \ RenderEngine/ProgramCache.cpp \ RenderEngine/GLExtensions.cpp \ RenderEngine/RenderEngine.cpp \ + RenderEngine/Surface.cpp \ RenderEngine/Texture.cpp \ RenderEngine/GLES20RenderEngine.cpp \ + LayerProtoHelper.cpp \ + RenderArea.cpp \ LOCAL_MODULE := libsurfaceflinger LOCAL_C_INCLUDES := \ @@ -49,17 +56,6 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -ifeq ($(TARGET_USES_HWC2),true) - LOCAL_CFLAGS += -DUSE_HWC2 - LOCAL_SRC_FILES += \ - SurfaceFlinger.cpp \ - DisplayHardware/HWComposer.cpp -else - LOCAL_SRC_FILES += \ - SurfaceFlinger_hwc1.cpp \ - DisplayHardware/HWComposer_hwc1.cpp -endif - LOCAL_CFLAGS += -fvisibility=hidden -Werror=format LOCAL_STATIC_LIBRARIES := \ @@ -67,7 +63,10 @@ LOCAL_STATIC_LIBRARIES := \ libtrace_proto \ libvkjson \ libvr_manager \ - libvrflinger + libvrflinger \ + libserviceutils + +LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libserviceutils LOCAL_SHARED_LIBRARIES := \ android.frameworks.vr.composer@1.0 \ @@ -90,12 +89,12 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libui \ libgui \ - libpowermanager \ libvulkan \ libsync \ libprotobuf-cpp-lite \ libbase \ - android.hardware.power@1.0 + android.hardware.power@1.0 \ + liblayers_proto LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ android.hardware.graphics.allocator@2.0 \ @@ -120,10 +119,6 @@ LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" LOCAL_INIT_RC := surfaceflinger.rc -ifeq ($(TARGET_USES_HWC2),true) - LOCAL_CFLAGS += -DUSE_HWC2 -endif - LOCAL_SRC_FILES := \ main_surfaceflinger.cpp @@ -142,10 +137,12 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libui \ libgui \ - libdl + libdl \ + liblayers_proto LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain -LOCAL_STATIC_LIBRARIES := libtrace_proto +LOCAL_STATIC_LIBRARIES := libtrace_proto \ + libserviceutils LOCAL_MODULE := surfaceflinger @@ -153,7 +150,7 @@ ifdef TARGET_32_BIT_SURFACEFLINGER LOCAL_32_BIT_ONLY := true endif -LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code +LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -std=c++1z include $(BUILD_EXECUTABLE) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp new file mode 100644 index 0000000000..5f70ab54da --- /dev/null +++ b/services/surfaceflinger/BufferLayer.cpp @@ -0,0 +1,945 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "BufferLayer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "BufferLayer.h" +#include "Colorizer.h" +#include "DisplayDevice.h" +#include "LayerRejecter.h" +#include "clz.h" + +#include "RenderEngine/RenderEngine.h" + +#include <gui/BufferItem.h> +#include <gui/BufferQueue.h> +#include <gui/LayerDebugInfo.h> +#include <gui/Surface.h> + +#include <ui/DebugUtils.h> + +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/NativeHandle.h> +#include <utils/StopWatch.h> +#include <utils/Trace.h> + +#include <cutils/compiler.h> +#include <cutils/native_handle.h> +#include <cutils/properties.h> + +#include <math.h> +#include <stdlib.h> +#include <mutex> + +namespace android { + +BufferLayer::BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, + uint32_t w, uint32_t h, uint32_t flags) + : Layer(flinger, client, name, w, h, flags), + mConsumer(nullptr), + mTextureName(UINT32_MAX), + mFormat(PIXEL_FORMAT_NONE), + mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mBufferLatched(false), + mPreviousFrameNumber(0), + mUpdateTexImageFailed(false), + mRefreshPending(false) { + ALOGV("Creating Layer %s", name.string()); + + mFlinger->getRenderEngine().genTextures(1, &mTextureName); + mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName); + + if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false; + + mCurrentState.requested = mCurrentState.active; + + // drawing state & current state are identical + mDrawingState = mCurrentState; +} + +BufferLayer::~BufferLayer() { + mFlinger->deleteTextureAsync(mTextureName); + + if (!getBE().mHwcLayers.empty()) { + ALOGE("Found stale hardware composer layers when destroying " + "surface flinger layer %s", + mName.string()); + destroyAllHwcLayers(); + } +} + +void BufferLayer::useSurfaceDamage() { + if (mFlinger->mForceFullDamage) { + surfaceDamageRegion = Region::INVALID_REGION; + } else { + surfaceDamageRegion = mConsumer->getSurfaceDamage(); + } +} + +void BufferLayer::useEmptyDamage() { + surfaceDamageRegion.clear(); +} + +bool BufferLayer::isProtected() const { + const sp<GraphicBuffer>& buffer(getBE().compositionInfo.mBuffer); + return (buffer != 0) && + (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); +} + +bool BufferLayer::isVisible() const { + return !(isHiddenByPolicy()) && getAlpha() > 0.0f && + (getBE().compositionInfo.mBuffer != NULL || getBE().compositionInfo.hwc.sidebandStream != NULL); +} + +bool BufferLayer::isFixedSize() const { + return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE; +} + +status_t BufferLayer::setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { + uint32_t const maxSurfaceDims = + min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims()); + + // never allow a surface larger than what our underlying GL implementation + // can handle. + if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) { + ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h)); + return BAD_VALUE; + } + + mFormat = format; + + mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false; + mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false; + mCurrentOpacity = getOpacityForFormat(format); + + mConsumer->setDefaultBufferSize(w, h); + mConsumer->setDefaultBufferFormat(format); + mConsumer->setConsumerUsageBits(getEffectiveUsage(0)); + + return NO_ERROR; +} + +static constexpr mat4 inverseOrientation(uint32_t transform) { + const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); + const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + mat4 tr; + + if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + tr = tr * rot90; + } + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { + tr = tr * flipH; + } + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { + tr = tr * flipV; + } + return inverse(tr); +} + +/* + * onDraw will draw the current layer onto the presentable buffer + */ +void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform) const { + ATRACE_CALL(); + + if (CC_UNLIKELY(getBE().compositionInfo.mBuffer == 0)) { + // the texture has not been created yet, this Layer has + // in fact never been drawn into. This happens frequently with + // SurfaceView because the WindowManager can't know when the client + // has drawn the first time. + + // If there is nothing under us, we paint the screen in black, otherwise + // we just skip this update. + + // figure out if there is something below us + Region under; + bool finished = false; + mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) { + if (finished || layer == static_cast<BufferLayer const*>(this)) { + finished = true; + return; + } + under.orSelf(renderArea.getTransform().transform(layer->visibleRegion)); + }); + // if not everything below us is covered, we plug the holes! + Region holes(clip.subtract(under)); + if (!holes.isEmpty()) { + clearWithOpenGL(renderArea, 0, 0, 0, 1); + } + return; + } + + // Bind the current buffer to the GL texture, and wait for it to be + // ready for us to draw into. + status_t err = mConsumer->bindTextureImage(); + if (err != NO_ERROR) { + ALOGW("onDraw: bindTextureImage failed (err=%d)", err); + // Go ahead and draw the buffer anyway; no matter what we do the screen + // is probably going to have something visibly wrong. + } + + bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure()); + + RenderEngine& engine(mFlinger->getRenderEngine()); + + if (!blackOutLayer) { + // TODO: we could be more subtle with isFixedSize() + const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize(); + + // Query the texture matrix given our current filtering mode. + float textureMatrix[16]; + mConsumer->setFilteringEnabled(useFiltering); + mConsumer->getTransformMatrix(textureMatrix); + + if (getTransformToDisplayInverse()) { + /* + * the code below applies the primary display's inverse transform to + * the texture transform + */ + uint32_t transform = DisplayDevice::getPrimaryDisplayOrientationTransform(); + mat4 tr = inverseOrientation(transform); + + /** + * TODO(b/36727915): This is basically a hack. + * + * Ensure that regardless of the parent transformation, + * this buffer is always transformed from native display + * orientation to display orientation. For example, in the case + * of a camera where the buffer remains in native orientation, + * we want the pixels to always be upright. + */ + sp<Layer> p = mDrawingParent.promote(); + if (p != nullptr) { + const auto parentTransform = p->getTransform(); + tr = tr * inverseOrientation(parentTransform.getOrientation()); + } + + // and finally apply it to the original texture matrix + const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr); + memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); + } + + // Set things up for texturing. + mTexture.setDimensions(getBE().compositionInfo.mBuffer->getWidth(), + getBE().compositionInfo.mBuffer->getHeight()); + mTexture.setFiltering(useFiltering); + mTexture.setMatrix(textureMatrix); + + engine.setupLayerTexturing(mTexture); + } else { + engine.setupLayerBlackedOut(); + } + drawWithOpenGL(renderArea, useIdentityTransform); + engine.disableTexturing(); +} + +void BufferLayer::onLayerDisplayed(const sp<Fence>& releaseFence) { + mConsumer->setReleaseFence(releaseFence); +} + +void BufferLayer::abandon() { + mConsumer->abandon(); +} + +bool BufferLayer::shouldPresentNow(const DispSync& dispSync) const { + if (mSidebandStreamChanged || mAutoRefresh) { + return true; + } + + Mutex::Autolock lock(mQueueItemLock); + if (mQueueItems.empty()) { + return false; + } + auto timestamp = mQueueItems[0].mTimestamp; + nsecs_t expectedPresent = mConsumer->computeExpectedPresent(dispSync); + + // Ignore timestamps more than a second in the future + bool isPlausible = timestamp < (expectedPresent + s2ns(1)); + ALOGW_IF(!isPlausible, + "[%s] Timestamp %" PRId64 " seems implausible " + "relative to expectedPresent %" PRId64, + mName.string(), timestamp, expectedPresent); + + bool isDue = timestamp < expectedPresent; + return isDue || !isPlausible; +} + +void BufferLayer::setTransformHint(uint32_t orientation) const { + mConsumer->setTransformHint(orientation); +} + +bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) { + if (mBufferLatched) { + Mutex::Autolock lock(mFrameEventHistoryMutex); + mFrameEventHistory.addPreComposition(mCurrentFrameNumber, + refreshStartTime); + } + mRefreshPending = false; + return mQueuedFrames > 0 || mSidebandStreamChanged || + mAutoRefresh; +} +bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence, + const std::shared_ptr<FenceTime>& presentFence, + const CompositorTiming& compositorTiming) { + // mFrameLatencyNeeded is true when a new frame was latched for the + // composition. + if (!mFrameLatencyNeeded) return false; + + // Update mFrameEventHistory. + { + Mutex::Autolock lock(mFrameEventHistoryMutex); + mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, + presentFence, compositorTiming); + } + + // Update mFrameTracker. + nsecs_t desiredPresentTime = mConsumer->getTimestamp(); + mFrameTracker.setDesiredPresentTime(desiredPresentTime); + + std::shared_ptr<FenceTime> frameReadyFence = mConsumer->getCurrentFenceTime(); + if (frameReadyFence->isValid()) { + mFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); + } else { + // There was no fence for this frame, so assume that it was ready + // to be presented at the desired present time. + mFrameTracker.setFrameReadyTime(desiredPresentTime); + } + + if (presentFence->isValid()) { + mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); + } else { + // The HWC doesn't support present fences, so use the refresh + // timestamp instead. + mFrameTracker.setActualPresentTime( + mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY)); + } + + mFrameTracker.advanceFrame(); + mFrameLatencyNeeded = false; + return true; +} + +std::vector<OccupancyTracker::Segment> BufferLayer::getOccupancyHistory(bool forceFlush) { + std::vector<OccupancyTracker::Segment> history; + status_t result = mConsumer->getOccupancyHistory(forceFlush, &history); + if (result != NO_ERROR) { + ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result); + return {}; + } + return history; +} + +bool BufferLayer::getTransformToDisplayInverse() const { + return mConsumer->getTransformToDisplayInverse(); +} + +void BufferLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { + if (!mConsumer->releasePendingBuffer()) { + return; + } + + auto releaseFenceTime = + std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence()); + mReleaseTimeline.updateSignalTimes(); + mReleaseTimeline.push(releaseFenceTime); + + Mutex::Autolock lock(mFrameEventHistoryMutex); + if (mPreviousFrameNumber != 0) { + mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime, + std::move(releaseFenceTime)); + } +} + +Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) { + ATRACE_CALL(); + + if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) { + // mSidebandStreamChanged was true + mSidebandStream = mConsumer->getSidebandStream(); + // replicated in LayerBE until FE/BE is ready to be synchronized + getBE().compositionInfo.hwc.sidebandStream = mSidebandStream; + if (getBE().compositionInfo.hwc.sidebandStream != NULL) { + setTransactionFlags(eTransactionNeeded); + mFlinger->setTransactionFlags(eTraversalNeeded); + } + recomputeVisibleRegions = true; + + const State& s(getDrawingState()); + return getTransform().transform(Region(Rect(s.active.w, s.active.h))); + } + + Region outDirtyRegion; + if (mQueuedFrames <= 0 && !mAutoRefresh) { + return outDirtyRegion; + } + + // if we've already called updateTexImage() without going through + // a composition step, we have to skip this layer at this point + // because we cannot call updateTeximage() without a corresponding + // compositionComplete() call. + // we'll trigger an update in onPreComposition(). + if (mRefreshPending) { + return outDirtyRegion; + } + + // If the head buffer's acquire fence hasn't signaled yet, return and + // try again later + if (!headFenceHasSignaled()) { + mFlinger->signalLayerUpdate(); + return outDirtyRegion; + } + + // Capture the old state of the layer for comparisons later + const State& s(getDrawingState()); + const bool oldOpacity = isOpaque(s); + sp<GraphicBuffer> oldBuffer = getBE().compositionInfo.mBuffer; + + if (!allTransactionsSignaled()) { + mFlinger->signalLayerUpdate(); + return outDirtyRegion; + } + + // This boolean is used to make sure that SurfaceFlinger's shadow copy + // of the buffer queue isn't modified when the buffer queue is returning + // BufferItem's that weren't actually queued. This can happen in shared + // buffer mode. + bool queuedBuffer = false; + LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions, + getProducerStickyTransform() != 0, mName.string(), + mOverrideScalingMode, mFreezeGeometryUpdates); + status_t updateResult = + mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync, + &mAutoRefresh, &queuedBuffer, + mLastFrameNumberReceived); + if (updateResult == BufferQueue::PRESENT_LATER) { + // Producer doesn't want buffer to be displayed yet. Signal a + // layer update so we check again at the next opportunity. + mFlinger->signalLayerUpdate(); + return outDirtyRegion; + } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) { + // If the buffer has been rejected, remove it from the shadow queue + // and return early + if (queuedBuffer) { + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.removeAt(0); + android_atomic_dec(&mQueuedFrames); + } + return outDirtyRegion; + } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) { + // This can occur if something goes wrong when trying to create the + // EGLImage for this buffer. If this happens, the buffer has already + // been released, so we need to clean up the queue and bug out + // early. + if (queuedBuffer) { + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.clear(); + android_atomic_and(0, &mQueuedFrames); + } + + // Once we have hit this state, the shadow queue may no longer + // correctly reflect the incoming BufferQueue's contents, so even if + // updateTexImage starts working, the only safe course of action is + // to continue to ignore updates. + mUpdateTexImageFailed = true; + + return outDirtyRegion; + } + + if (queuedBuffer) { + // Autolock scope + auto currentFrameNumber = mConsumer->getFrameNumber(); + + Mutex::Autolock lock(mQueueItemLock); + + // Remove any stale buffers that have been dropped during + // updateTexImage + while (mQueueItems[0].mFrameNumber != currentFrameNumber) { + mQueueItems.removeAt(0); + android_atomic_dec(&mQueuedFrames); + } + + mQueueItems.removeAt(0); + } + + // Decrement the queued-frames count. Signal another event if we + // have more frames pending. + if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || + mAutoRefresh) { + mFlinger->signalLayerUpdate(); + } + + // update the active buffer + getBE().compositionInfo.mBuffer = + mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot); + // replicated in LayerBE until FE/BE is ready to be synchronized + mActiveBuffer = getBE().compositionInfo.mBuffer; + if (getBE().compositionInfo.mBuffer == NULL) { + // this can only happen if the very first buffer was rejected. + return outDirtyRegion; + } + + mBufferLatched = true; + mPreviousFrameNumber = mCurrentFrameNumber; + mCurrentFrameNumber = mConsumer->getFrameNumber(); + + { + Mutex::Autolock lock(mFrameEventHistoryMutex); + mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime); + } + + mRefreshPending = true; + mFrameLatencyNeeded = true; + if (oldBuffer == NULL) { + // the first time we receive a buffer, we need to trigger a + // geometry invalidation. + recomputeVisibleRegions = true; + } + + setDataSpace(mConsumer->getCurrentDataSpace()); + + Rect crop(mConsumer->getCurrentCrop()); + const uint32_t transform(mConsumer->getCurrentTransform()); + const uint32_t scalingMode(mConsumer->getCurrentScalingMode()); + if ((crop != mCurrentCrop) || + (transform != mCurrentTransform) || + (scalingMode != mCurrentScalingMode)) { + mCurrentCrop = crop; + mCurrentTransform = transform; + mCurrentScalingMode = scalingMode; + recomputeVisibleRegions = true; + } + + if (oldBuffer != NULL) { + uint32_t bufWidth = getBE().compositionInfo.mBuffer->getWidth(); + uint32_t bufHeight = getBE().compositionInfo.mBuffer->getHeight(); + if (bufWidth != uint32_t(oldBuffer->width) || + bufHeight != uint32_t(oldBuffer->height)) { + recomputeVisibleRegions = true; + } + } + + mCurrentOpacity = getOpacityForFormat(getBE().compositionInfo.mBuffer->format); + if (oldOpacity != isOpaque(s)) { + recomputeVisibleRegions = true; + } + + // Remove any sync points corresponding to the buffer which was just + // latched + { + Mutex::Autolock lock(mLocalSyncPointMutex); + auto point = mLocalSyncPoints.begin(); + while (point != mLocalSyncPoints.end()) { + if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) { + // This sync point must have been added since we started + // latching. Don't drop it yet. + ++point; + continue; + } + + if ((*point)->getFrameNumber() <= mCurrentFrameNumber) { + point = mLocalSyncPoints.erase(point); + } else { + ++point; + } + } + } + + // FIXME: postedRegion should be dirty & bounds + Region dirtyRegion(Rect(s.active.w, s.active.h)); + + // transform the dirty region to window-manager space + outDirtyRegion = (getTransform().transform(dirtyRegion)); + + return outDirtyRegion; +} + +void BufferLayer::setDefaultBufferSize(uint32_t w, uint32_t h) { + mConsumer->setDefaultBufferSize(w, h); +} + +void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) { + // Apply this display's projection's viewport to the visible region + // before giving it to the HWC HAL. + const Transform& tr = displayDevice->getTransform(); + const auto& viewport = displayDevice->getViewport(); + Region visible = tr.transform(visibleRegion.intersect(viewport)); + auto hwcId = displayDevice->getHwcDisplayId(); + auto& hwcInfo = getBE().mHwcLayers[hwcId]; + auto& hwcLayer = hwcInfo.layer; + auto error = hwcLayer->setVisibleRegion(visible); + if (error != HWC2::Error::None) { + ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(), + to_string(error).c_str(), static_cast<int32_t>(error)); + visible.dump(LOG_TAG); + } + + error = hwcLayer->setSurfaceDamage(surfaceDamageRegion); + if (error != HWC2::Error::None) { + ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(), + to_string(error).c_str(), static_cast<int32_t>(error)); + surfaceDamageRegion.dump(LOG_TAG); + } + + // Sideband layers + if (getBE().compositionInfo.hwc.sidebandStream.get()) { + setCompositionType(hwcId, HWC2::Composition::Sideband); + ALOGV("[%s] Requesting Sideband composition", mName.string()); + error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle()); + if (error != HWC2::Error::None) { + ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(), + getBE().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(), + static_cast<int32_t>(error)); + } + return; + } + + // Device or Cursor layers + if (mPotentialCursor) { + ALOGV("[%s] Requesting Cursor composition", mName.string()); + setCompositionType(hwcId, HWC2::Composition::Cursor); + } else { + ALOGV("[%s] Requesting Device composition", mName.string()); + setCompositionType(hwcId, HWC2::Composition::Device); + } + + ALOGV("setPerFrameData: dataspace = %d", mCurrentState.dataSpace); + error = hwcLayer->setDataspace(mCurrentState.dataSpace); + if (error != HWC2::Error::None) { + ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentState.dataSpace, + to_string(error).c_str(), static_cast<int32_t>(error)); + } + + uint32_t hwcSlot = 0; + sp<GraphicBuffer> hwcBuffer; + hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot, + getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer); + + auto acquireFence = mConsumer->getCurrentFence(); + error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence); + if (error != HWC2::Error::None) { + ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), + getBE().compositionInfo.mBuffer->handle, to_string(error).c_str(), + static_cast<int32_t>(error)); + } +} + +bool BufferLayer::isOpaque(const Layer::State& s) const { + // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the + // layer's opaque flag. + if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (getBE().compositionInfo.mBuffer == nullptr)) { + return false; + } + + // if the layer has the opaque flag, then we're always opaque, + // otherwise we use the current buffer's format. + return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity; +} + +void BufferLayer::onFirstRef() { + // Creates a custom BufferQueue for SurfaceFlingerConsumer to use + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer, true); + mProducer = new MonitoredProducer(producer, mFlinger, this); + mConsumer = new BufferLayerConsumer(consumer, + mFlinger->getRenderEngine(), mTextureName, this); + mConsumer->setConsumerUsageBits(getEffectiveUsage(0)); + mConsumer->setContentsChangedListener(this); + mConsumer->setName(mName); + + if (mFlinger->isLayerTripleBufferingDisabled()) { + mProducer->setMaxDequeuedBufferCount(2); + } + + const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice()); + updateTransformHint(hw); +} + +// --------------------------------------------------------------------------- +// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener +// --------------------------------------------------------------------------- + +void BufferLayer::onFrameAvailable(const BufferItem& item) { + // Add this buffer from our internal queue tracker + { // Autolock scope + Mutex::Autolock lock(mQueueItemLock); + mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(), + item.mGraphicBuffer->getHeight(), + item.mFrameNumber); + // Reset the frame number tracker when we receive the first buffer after + // a frame number reset + if (item.mFrameNumber == 1) { + mLastFrameNumberReceived = 0; + } + + // Ensure that callbacks are handled in order + while (item.mFrameNumber != mLastFrameNumberReceived + 1) { + status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, + ms2ns(500)); + if (result != NO_ERROR) { + ALOGE("[%s] Timed out waiting on callback", mName.string()); + } + } + + mQueueItems.push_back(item); + android_atomic_inc(&mQueuedFrames); + + // Wake up any pending callbacks + mLastFrameNumberReceived = item.mFrameNumber; + mQueueItemCondition.broadcast(); + } + + mFlinger->signalLayerUpdate(); +} + +void BufferLayer::onFrameReplaced(const BufferItem& item) { + { // Autolock scope + Mutex::Autolock lock(mQueueItemLock); + + // Ensure that callbacks are handled in order + while (item.mFrameNumber != mLastFrameNumberReceived + 1) { + status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, + ms2ns(500)); + if (result != NO_ERROR) { + ALOGE("[%s] Timed out waiting on callback", mName.string()); + } + } + + if (mQueueItems.empty()) { + ALOGE("Can't replace a frame on an empty queue"); + return; + } + mQueueItems.editItemAt(mQueueItems.size() - 1) = item; + + // Wake up any pending callbacks + mLastFrameNumberReceived = item.mFrameNumber; + mQueueItemCondition.broadcast(); + } +} + +void BufferLayer::onSidebandStreamChanged() { + if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) { + // mSidebandStreamChanged was false + mFlinger->signalLayerUpdate(); + } +} + +bool BufferLayer::needsFiltering(const RenderArea& renderArea) const { + return mNeedsFiltering || renderArea.needsFiltering(); +} + +// As documented in libhardware header, formats in the range +// 0x100 - 0x1FF are specific to the HAL implementation, and +// are known to have no alpha channel +// TODO: move definition for device-specific range into +// hardware.h, instead of using hard-coded values here. +#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF) + +bool BufferLayer::getOpacityForFormat(uint32_t format) { + if (HARDWARE_IS_DEVICE_FORMAT(format)) { + return true; + } + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_FP16: + case HAL_PIXEL_FORMAT_RGBA_1010102: + return false; + } + // in all other case, we have no blending (also for unknown formats) + return true; +} + +void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const { + const State& s(getDrawingState()); + + computeGeometry(renderArea, getBE().mMesh, useIdentityTransform); + + /* + * NOTE: the way we compute the texture coordinates here produces + * different results than when we take the HWC path -- in the later case + * the "source crop" is rounded to texel boundaries. + * This can produce significantly different results when the texture + * is scaled by a large amount. + * + * The GL code below is more logical (imho), and the difference with + * HWC is due to a limitation of the HWC API to integers -- a question + * is suspend is whether we should ignore this problem or revert to + * GL composition when a buffer scaling is applied (maybe with some + * minimal value)? Or, we could make GL behave like HWC -- but this feel + * like more of a hack. + */ + const Rect bounds{computeBounds()}; // Rounds from FloatRect + + Transform t = getTransform(); + Rect win = bounds; + if (!s.finalCrop.isEmpty()) { + win = t.transform(win); + if (!win.intersect(s.finalCrop, &win)) { + win.clear(); + } + win = t.inverse().transform(win); + if (!win.intersect(bounds, &win)) { + win.clear(); + } + } + + float left = float(win.left) / float(s.active.w); + float top = float(win.top) / float(s.active.h); + float right = float(win.right) / float(s.active.w); + float bottom = float(win.bottom) / float(s.active.h); + + // TODO: we probably want to generate the texture coords with the mesh + // here we assume that we only have 4 vertices + Mesh::VertexArray<vec2> texCoords(getBE().mMesh.getTexCoordArray<vec2>()); + texCoords[0] = vec2(left, 1.0f - top); + texCoords[1] = vec2(left, 1.0f - bottom); + texCoords[2] = vec2(right, 1.0f - bottom); + texCoords[3] = vec2(right, 1.0f - top); + + RenderEngine& engine(mFlinger->getRenderEngine()); + engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */, + getColor()); + engine.setSourceDataSpace(mCurrentState.dataSpace); + engine.drawMesh(getBE().mMesh); + engine.disableBlending(); +} + +uint32_t BufferLayer::getProducerStickyTransform() const { + int producerStickyTransform = 0; + int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform); + if (ret != OK) { + ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__, + strerror(-ret), ret); + return 0; + } + return static_cast<uint32_t>(producerStickyTransform); +} + +bool BufferLayer::latchUnsignaledBuffers() { + static bool propertyLoaded = false; + static bool latch = false; + static std::mutex mutex; + std::lock_guard<std::mutex> lock(mutex); + if (!propertyLoaded) { + char value[PROPERTY_VALUE_MAX] = {}; + property_get("debug.sf.latch_unsignaled", value, "0"); + latch = atoi(value); + propertyLoaded = true; + } + return latch; +} + +uint64_t BufferLayer::getHeadFrameNumber() const { + Mutex::Autolock lock(mQueueItemLock); + if (!mQueueItems.empty()) { + return mQueueItems[0].mFrameNumber; + } else { + return mCurrentFrameNumber; + } +} + +bool BufferLayer::headFenceHasSignaled() const { + if (latchUnsignaledBuffers()) { + return true; + } + + Mutex::Autolock lock(mQueueItemLock); + if (mQueueItems.empty()) { + return true; + } + if (mQueueItems[0].mIsDroppable) { + // Even though this buffer's fence may not have signaled yet, it could + // be replaced by another buffer before it has a chance to, which means + // that it's possible to get into a situation where a buffer is never + // able to be latched. To avoid this, grab this buffer anyway. + return true; + } + return mQueueItems[0].mFenceTime->getSignalTime() != + Fence::SIGNAL_TIME_PENDING; +} + +uint32_t BufferLayer::getEffectiveScalingMode() const { + if (mOverrideScalingMode >= 0) { + return mOverrideScalingMode; + } + return mCurrentScalingMode; +} + +// ---------------------------------------------------------------------------- +// transaction +// ---------------------------------------------------------------------------- + +void BufferLayer::notifyAvailableFrames() { + auto headFrameNumber = getHeadFrameNumber(); + bool headFenceSignaled = headFenceHasSignaled(); + Mutex::Autolock lock(mLocalSyncPointMutex); + for (auto& point : mLocalSyncPoints) { + if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) { + point->setFrameAvailable(); + } + } +} + +sp<IGraphicBufferProducer> BufferLayer::getProducer() const { + return mProducer; +} + +// --------------------------------------------------------------------------- +// h/w composer set-up +// --------------------------------------------------------------------------- + +bool BufferLayer::allTransactionsSignaled() { + auto headFrameNumber = getHeadFrameNumber(); + bool matchingFramesFound = false; + bool allTransactionsApplied = true; + Mutex::Autolock lock(mLocalSyncPointMutex); + + for (auto& point : mLocalSyncPoints) { + if (point->getFrameNumber() > headFrameNumber) { + break; + } + matchingFramesFound = true; + + if (!point->frameIsAvailable()) { + // We haven't notified the remote layer that the frame for + // this point is available yet. Notify it now, and then + // abort this attempt to latch. + point->setFrameAvailable(); + allTransactionsApplied = false; + break; + } + + allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied(); + } + return !matchingFramesFound || allTransactionsApplied; +} + +} // namespace android + +#if defined(__gl_h_) +#error "don't include gl/gl.h in this file" +#endif + +#if defined(__gl2_h_) +#error "don't include gl2/gl2.h in this file" +#endif diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h new file mode 100644 index 0000000000..6b02f8c128 --- /dev/null +++ b/services/surfaceflinger/BufferLayer.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "BufferLayerConsumer.h" +#include "Client.h" +#include "Layer.h" +#include "DisplayHardware/HWComposer.h" +#include "DisplayHardware/HWComposerBufferCache.h" +#include "FrameTracker.h" +#include "LayerVector.h" +#include "MonitoredProducer.h" +#include "RenderEngine/Mesh.h" +#include "RenderEngine/Texture.h" +#include "SurfaceFlinger.h" +#include "Transform.h" + +#include <gui/ISurfaceComposerClient.h> +#include <gui/LayerState.h> + +#include <ui/FrameStats.h> +#include <ui/GraphicBuffer.h> +#include <ui/PixelFormat.h> +#include <ui/Region.h> + +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/Timers.h> + +#include <stdint.h> +#include <sys/types.h> +#include <list> + +namespace android { + +/* + * A new BufferQueue and a new BufferLayerConsumer are created when the + * BufferLayer is first referenced. + * + * This also implements onFrameAvailable(), which notifies SurfaceFlinger + * that new data has arrived. + */ +class BufferLayer : public Layer, public BufferLayerConsumer::ContentsChangedListener { +public: + BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, + uint32_t h, uint32_t flags); + + ~BufferLayer() override; + + // If we have received a new buffer this frame, we will pass its surface + // damage down to hardware composer. Otherwise, we must send a region with + // one empty rect. + void useSurfaceDamage(); + void useEmptyDamage(); + + // ----------------------------------------------------------------------- + // Overriden from Layer + // ----------------------------------------------------------------------- + + /* + * getTypeId - Provide unique string for each class type in the Layer + * hierarchy + */ + const char* getTypeId() const override { return "BufferLayer"; } + + /* + * isProtected - true if the layer may contain protected content in the + * GRALLOC_USAGE_PROTECTED sense. + */ + bool isProtected() const; + + /* + * isVisible - true if this layer is visible, false otherwise + */ + bool isVisible() const override; + + /* + * isFixedSize - true if content has a fixed size + */ + bool isFixedSize() const override; + + // the this layer's size and format + status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); + + /* + * onDraw - draws the surface. + */ + void onDraw(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform) const override; + + void onLayerDisplayed(const sp<Fence>& releaseFence) override; + + void abandon() override; + bool shouldPresentNow(const DispSync& dispSync) const override; + void setTransformHint(uint32_t orientation) const override; + bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence, + const std::shared_ptr<FenceTime>& presentFence, + const CompositorTiming& compositorTiming) override; + std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override; + bool getTransformToDisplayInverse() const override; + +public: + bool onPreComposition(nsecs_t refreshStartTime) override; + + // If a buffer was replaced this frame, release the former buffer + void releasePendingBuffer(nsecs_t dequeueReadyTime); + + /* + * latchBuffer - called each time the screen is redrawn and returns whether + * the visible regions need to be recomputed (this is a fairly heavy + * operation, so this should be set only if needed). Typically this is used + * to figure out if the content or size of a surface has changed. + */ + Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override; + bool isBufferLatched() const override { return mRefreshPending; } + void setDefaultBufferSize(uint32_t w, uint32_t h) override; + + void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override; + + bool isOpaque(const Layer::State& s) const override; + +private: + void onFirstRef() override; + + // Interface implementation for + // BufferLayerConsumer::ContentsChangedListener + void onFrameAvailable(const BufferItem& item) override; + void onFrameReplaced(const BufferItem& item) override; + void onSidebandStreamChanged() override; + + // needsLinearFiltering - true if this surface's state requires filtering + bool needsFiltering(const RenderArea& renderArea) const; + + static bool getOpacityForFormat(uint32_t format); + + // drawing + void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const; + + // Temporary - Used only for LEGACY camera mode. + uint32_t getProducerStickyTransform() const; + + // Loads the corresponding system property once per process + static bool latchUnsignaledBuffers(); + + uint64_t getHeadFrameNumber() const; + bool headFenceHasSignaled() const; + + // Returns the current scaling mode, unless mOverrideScalingMode + // is set, in which case, it returns mOverrideScalingMode + uint32_t getEffectiveScalingMode() const override; + +public: + void notifyAvailableFrames() override; + + PixelFormat getPixelFormat() const override { return mFormat; } + sp<IGraphicBufferProducer> getProducer() const; + +private: + sp<BufferLayerConsumer> mConsumer; + + // Check all of the local sync points to ensure that all transactions + // which need to have been applied prior to the frame which is about to + // be latched have signaled + bool allTransactionsSignaled(); + sp<IGraphicBufferProducer> mProducer; + + // constants + uint32_t mTextureName; // from GLES + PixelFormat mFormat; + + // main thread + uint32_t mCurrentScalingMode; + bool mBufferLatched = false; // TODO: Use mActiveBuffer? + uint64_t mPreviousFrameNumber; // Only accessed on the main thread. + // The texture used to draw the layer in GLES composition mode + mutable Texture mTexture; + + bool mUpdateTexImageFailed; // This is only accessed on the main thread. + bool mRefreshPending; +}; + +} // namespace android diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp new file mode 100644 index 0000000000..976dde24ce --- /dev/null +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "BufferLayerConsumer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#include "BufferLayerConsumer.h" + +#include "DispSync.h" +#include "Layer.h" +#include "RenderEngine/RenderEngine.h" + +#include <inttypes.h> + +#include <cutils/compiler.h> + +#include <hardware/hardware.h> + +#include <math/mat4.h> + +#include <gui/BufferItem.h> +#include <gui/GLConsumer.h> +#include <gui/ISurfaceComposer.h> +#include <gui/SurfaceComposerClient.h> + +#include <private/gui/ComposerService.h> +#include <private/gui/SyncFeatures.h> + +#include <utils/Log.h> +#include <utils/String8.h> +#include <utils/Trace.h> + +namespace android { + +// Macros for including the BufferLayerConsumer name in log messages +#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) +#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) +#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) + +static const mat4 mtxIdentity; + +BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RenderEngine& engine, + uint32_t tex, Layer* layer) + : ConsumerBase(bq, false), + mCurrentCrop(Rect::EMPTY_RECT), + mCurrentTransform(0), + mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mCurrentFence(Fence::NO_FENCE), + mCurrentTimestamp(0), + mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), + mCurrentFrameNumber(0), + mCurrentTransformToDisplayInverse(false), + mCurrentSurfaceDamage(), + mDefaultWidth(1), + mDefaultHeight(1), + mFilteringEnabled(true), + mRE(engine), + mTexName(tex), + mLayer(layer), + mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) { + BLC_LOGV("BufferLayerConsumer"); + + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); + + mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); +} + +status_t BufferLayerConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + BLC_LOGE("setDefaultBufferSize: BufferLayerConsumer is abandoned!"); + return NO_INIT; + } + mDefaultWidth = w; + mDefaultHeight = h; + return mConsumer->setDefaultBufferSize(w, h); +} + +void BufferLayerConsumer::setContentsChangedListener(const wp<ContentsChangedListener>& listener) { + setFrameAvailableListener(listener); + Mutex::Autolock lock(mMutex); + mContentsChangedListener = listener; +} + +// We need to determine the time when a buffer acquired now will be +// displayed. This can be calculated: +// time when previous buffer's actual-present fence was signaled +// + current display refresh rate * HWC latency +// + a little extra padding +// +// Buffer producers are expected to set their desired presentation time +// based on choreographer time stamps, which (coming from vsync events) +// will be slightly later then the actual-present timing. If we get a +// desired-present time that is unintentionally a hair after the next +// vsync, we'll hold the frame when we really want to display it. We +// need to take the offset between actual-present and reported-vsync +// into account. +// +// If the system is configured without a DispSync phase offset for the app, +// we also want to throw in a bit of padding to avoid edge cases where we +// just barely miss. We want to do it here, not in every app. A major +// source of trouble is the app's use of the display's ideal refresh time +// (via Display.getRefreshRate()), which could be off of the actual refresh +// by a few percent, with the error multiplied by the number of frames +// between now and when the buffer should be displayed. +// +// If the refresh reported to the app has a phase offset, we shouldn't need +// to tweak anything here. +nsecs_t BufferLayerConsumer::computeExpectedPresent(const DispSync& dispSync) { + // The HWC doesn't currently have a way to report additional latency. + // Assume that whatever we submit now will appear right after the flip. + // For a smart panel this might be 1. This is expressed in frames, + // rather than time, because we expect to have a constant frame delay + // regardless of the refresh rate. + const uint32_t hwcLatency = 0; + + // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC). + const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency); + + // The DispSync time is already adjusted for the difference between + // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so + // we don't need to factor that in here. Pad a little to avoid + // weird effects if apps might be requesting times right on the edge. + nsecs_t extraPadding = 0; + if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) { + extraPadding = 1000000; // 1ms (6% of 60Hz) + } + + return nextRefresh + extraPadding; +} + +status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, + bool* autoRefresh, bool* queuedBuffer, + uint64_t maxFrameNumber) { + ATRACE_CALL(); + BLC_LOGV("updateTexImage"); + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + BLC_LOGE("updateTexImage: BufferLayerConsumer is abandoned!"); + return NO_INIT; + } + + // Make sure RenderEngine is current + if (!mRE.isCurrent()) { + BLC_LOGE("updateTexImage: RenderEngine is not current"); + return INVALID_OPERATION; + } + + BufferItem item; + + // Acquire the next buffer. + // In asynchronous mode the list is guaranteed to be one buffer + // deep, while in synchronous mode we use the oldest buffer. + status_t err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber); + if (err != NO_ERROR) { + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + err = NO_ERROR; + } else if (err == BufferQueue::PRESENT_LATER) { + // return the error, without logging + } else { + BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); + } + return err; + } + + if (autoRefresh) { + *autoRefresh = item.mAutoRefresh; + } + + if (queuedBuffer) { + *queuedBuffer = item.mQueuedBuffer; + } + + // We call the rejecter here, in case the caller has a reason to + // not accept this buffer. This is used by SurfaceFlinger to + // reject buffers which have the wrong size + int slot = item.mSlot; + if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) { + releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer); + return BUFFER_REJECTED; + } + + // Release the previous buffer. + err = updateAndReleaseLocked(item, &mPendingRelease); + if (err != NO_ERROR) { + return err; + } + + if (!SyncFeatures::getInstance().useNativeFenceSync()) { + // Bind the new buffer to the GL texture. + // + // Older devices require the "implicit" synchronization provided + // by glEGLImageTargetTexture2DOES, which this method calls. Newer + // devices will either call this in Layer::onDraw, or (if it's not + // a GL-composited layer) not at all. + err = bindTextureImageLocked(); + } + + return err; +} + +status_t BufferLayerConsumer::bindTextureImage() { + Mutex::Autolock lock(mMutex); + return bindTextureImageLocked(); +} + +void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) { + if (!fence->isValid()) { + return; + } + + auto slot = mPendingRelease.isPending ? mPendingRelease.currentTexture : mCurrentTexture; + if (slot == BufferQueue::INVALID_BUFFER_SLOT) { + return; + } + + auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer + : mCurrentTextureImage->graphicBuffer(); + auto err = addReleaseFence(slot, buffer, fence); + if (err != OK) { + BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); + } +} + +bool BufferLayerConsumer::releasePendingBuffer() { + if (!mPendingRelease.isPending) { + BLC_LOGV("Pending buffer already released"); + return false; + } + BLC_LOGV("Releasing pending buffer"); + Mutex::Autolock lock(mMutex); + status_t result = + releaseBufferLocked(mPendingRelease.currentTexture, mPendingRelease.graphicBuffer); + if (result < NO_ERROR) { + BLC_LOGE("releasePendingBuffer failed: %s (%d)", strerror(-result), result); + } + mPendingRelease = PendingRelease(); + return true; +} + +sp<Fence> BufferLayerConsumer::getPrevFinalReleaseFence() const { + Mutex::Autolock lock(mMutex); + return ConsumerBase::mPrevFinalReleaseFence; +} + +status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, + uint64_t maxFrameNumber) { + status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber); + if (err != NO_ERROR) { + return err; + } + + // If item->mGraphicBuffer is not null, this buffer has not been acquired + // before, so any prior EglImage created is using a stale buffer. This + // replaces any old EglImage with a new one (using the new buffer). + if (item->mGraphicBuffer != NULL) { + mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE); + } + + return NO_ERROR; +} + +bool BufferLayerConsumer::canUseImageCrop(const Rect& crop) const { + // If the crop rect is not at the origin, we can't set the crop on the + // EGLImage because that's not allowed by the EGL_ANDROID_image_crop + // extension. In the future we can add a layered extension that + // removes this restriction if there is hardware that can support it. + return mRE.supportsImageCrop() && crop.left == 0 && crop.top == 0; +} + +status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, + PendingRelease* pendingRelease) { + status_t err = NO_ERROR; + + int slot = item.mSlot; + + // Do whatever sync ops we need to do before releasing the old slot. + if (slot != mCurrentTexture) { + err = syncForReleaseLocked(); + if (err != NO_ERROR) { + // Release the buffer we just acquired. It's not safe to + // release the old buffer, so instead we just drop the new frame. + // As we are still under lock since acquireBuffer, it is safe to + // release by slot. + releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer); + return err; + } + } + + BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, + mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, slot, + mSlots[slot].mGraphicBuffer->handle); + + // Hang onto the pointer so that it isn't freed in the call to + // releaseBufferLocked() if we're in shared buffer mode and both buffers are + // the same. + sp<Image> nextTextureImage = mImages[slot]; + + // release old buffer + if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { + if (pendingRelease == nullptr) { + status_t status = + releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer()); + if (status < NO_ERROR) { + BLC_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->isPending = true; + } + } + + // Update the BufferLayerConsumer state. + mCurrentTexture = slot; + mCurrentTextureImage = nextTextureImage; + mCurrentCrop = item.mCrop; + mCurrentTransform = item.mTransform; + mCurrentScalingMode = item.mScalingMode; + mCurrentTimestamp = item.mTimestamp; + mCurrentDataSpace = item.mDataSpace; + mCurrentFence = item.mFence; + mCurrentFenceTime = item.mFenceTime; + mCurrentFrameNumber = item.mFrameNumber; + mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse; + mCurrentSurfaceDamage = item.mSurfaceDamage; + + computeCurrentTransformMatrixLocked(); + + return err; +} + +status_t BufferLayerConsumer::bindTextureImageLocked() { + mRE.checkErrors(); + + if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) { + BLC_LOGE("bindTextureImage: no currently-bound texture"); + mRE.bindExternalTextureImage(mTexName, RE::Image(mRE)); + return NO_INIT; + } + + const Rect& imageCrop = canUseImageCrop(mCurrentCrop) ? mCurrentCrop : Rect::EMPTY_RECT; + status_t err = mCurrentTextureImage->createIfNeeded(imageCrop); + if (err != NO_ERROR) { + BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture); + mRE.bindExternalTextureImage(mTexName, RE::Image(mRE)); + return UNKNOWN_ERROR; + } + + mRE.bindExternalTextureImage(mTexName, mCurrentTextureImage->image()); + + // Wait for the new buffer to be ready. + return doFenceWaitLocked(); +} + +status_t BufferLayerConsumer::syncForReleaseLocked() { + BLC_LOGV("syncForReleaseLocked"); + + if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { + if (SyncFeatures::getInstance().useNativeFenceSync()) { + base::unique_fd fenceFd = mRE.flush(); + if (fenceFd == -1) { + BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine"); + return UNKNOWN_ERROR; + } + sp<Fence> fence(new Fence(std::move(fenceFd))); + status_t err = addReleaseFenceLocked(mCurrentTexture, + mCurrentTextureImage->graphicBuffer(), fence); + if (err != OK) { + BLC_LOGE("syncForReleaseLocked: error adding release fence: " + "%s (%d)", + strerror(-err), err); + return err; + } + } + } + + return OK; +} + +void BufferLayerConsumer::getTransformMatrix(float mtx[16]) { + Mutex::Autolock lock(mMutex); + memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); +} + +void BufferLayerConsumer::setFilteringEnabled(bool enabled) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + BLC_LOGE("setFilteringEnabled: BufferLayerConsumer is abandoned!"); + return; + } + bool needsRecompute = mFilteringEnabled != enabled; + mFilteringEnabled = enabled; + + if (needsRecompute && mCurrentTextureImage == NULL) { + BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); + } + + if (needsRecompute && mCurrentTextureImage != NULL) { + computeCurrentTransformMatrixLocked(); + } +} + +void BufferLayerConsumer::computeCurrentTransformMatrixLocked() { + BLC_LOGV("computeCurrentTransformMatrixLocked"); + sp<GraphicBuffer> buf = + (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer(); + if (buf == nullptr) { + BLC_LOGD("computeCurrentTransformMatrixLocked: " + "mCurrentTextureImage is NULL"); + } + const Rect& cropRect = canUseImageCrop(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop; + GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, cropRect, mCurrentTransform, + mFilteringEnabled); +} + +nsecs_t BufferLayerConsumer::getTimestamp() { + BLC_LOGV("getTimestamp"); + Mutex::Autolock lock(mMutex); + return mCurrentTimestamp; +} + +android_dataspace BufferLayerConsumer::getCurrentDataSpace() { + BLC_LOGV("getCurrentDataSpace"); + Mutex::Autolock lock(mMutex); + return mCurrentDataSpace; +} + +uint64_t BufferLayerConsumer::getFrameNumber() { + BLC_LOGV("getFrameNumber"); + Mutex::Autolock lock(mMutex); + return mCurrentFrameNumber; +} + +bool BufferLayerConsumer::getTransformToDisplayInverse() const { + Mutex::Autolock lock(mMutex); + return mCurrentTransformToDisplayInverse; +} + +const Region& BufferLayerConsumer::getSurfaceDamage() const { + return mCurrentSurfaceDamage; +} + +sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const { + Mutex::Autolock lock(mMutex); + + if (outSlot != nullptr) { + *outSlot = mCurrentTexture; + } + + return (mCurrentTextureImage == nullptr) ? NULL : mCurrentTextureImage->graphicBuffer(); +} + +Rect BufferLayerConsumer::getCurrentCrop() const { + Mutex::Autolock lock(mMutex); + return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) + ? GLConsumer::scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight) + : mCurrentCrop; +} + +uint32_t BufferLayerConsumer::getCurrentTransform() const { + Mutex::Autolock lock(mMutex); + return mCurrentTransform; +} + +uint32_t BufferLayerConsumer::getCurrentScalingMode() const { + Mutex::Autolock lock(mMutex); + return mCurrentScalingMode; +} + +sp<Fence> BufferLayerConsumer::getCurrentFence() const { + Mutex::Autolock lock(mMutex); + return mCurrentFence; +} + +std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const { + Mutex::Autolock lock(mMutex); + return mCurrentFenceTime; +} + +status_t BufferLayerConsumer::doFenceWaitLocked() const { + if (!mRE.isCurrent()) { + BLC_LOGE("doFenceWait: RenderEngine is not current"); + return INVALID_OPERATION; + } + + if (mCurrentFence->isValid()) { + if (SyncFeatures::getInstance().useWaitSync()) { + base::unique_fd fenceFd(mCurrentFence->dup()); + if (fenceFd == -1) { + BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno); + return -errno; + } + if (!mRE.waitFence(std::move(fenceFd))) { + BLC_LOGE("doFenceWait: failed to wait on fence fd"); + return UNKNOWN_ERROR; + } + } else { + status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked"); + if (err != NO_ERROR) { + BLC_LOGE("doFenceWait: error waiting for fence: %d", err); + return err; + } + } + } + + return NO_ERROR; +} + +void BufferLayerConsumer::freeBufferLocked(int slotIndex) { + BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); + if (slotIndex == mCurrentTexture) { + mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; + } + mImages[slotIndex].clear(); + ConsumerBase::freeBufferLocked(slotIndex); +} + +void BufferLayerConsumer::onDisconnect() { + sp<Layer> l = mLayer.promote(); + if (l.get()) { + l->onDisconnect(); + } +} + +void BufferLayerConsumer::onSidebandStreamChanged() { + FrameAvailableListener* unsafeFrameAvailableListener = nullptr; + { + Mutex::Autolock lock(mFrameAvailableMutex); + unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get(); + } + sp<ContentsChangedListener> listener; + { // scope for the lock + Mutex::Autolock lock(mMutex); + ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get()); + listener = mContentsChangedListener.promote(); + } + + if (listener != NULL) { + listener->onSidebandStreamChanged(); + } +} + +void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, + FrameEventHistoryDelta* outDelta) { + sp<Layer> l = mLayer.promote(); + if (l.get()) { + l->addAndGetFrameTimestamps(newTimestamps, outDelta); + } +} + +void BufferLayerConsumer::abandonLocked() { + BLC_LOGV("abandonLocked"); + mCurrentTextureImage.clear(); + ConsumerBase::abandonLocked(); +} + +status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) { + return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); +} + +void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const { + result.appendFormat("%smTexName=%d mCurrentTexture=%d\n" + "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", + prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, + mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, + mCurrentTransform); + + ConsumerBase::dumpLocked(result, prefix); +} + +BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer, const RenderEngine& engine) + : mGraphicBuffer(graphicBuffer), + mImage{engine}, + mCreated(false), + mCropWidth(0), + mCropHeight(0) {} + +status_t BufferLayerConsumer::Image::createIfNeeded(const Rect& imageCrop) { + const int32_t cropWidth = imageCrop.width(); + const int32_t cropHeight = imageCrop.height(); + if (mCreated && mCropWidth == cropWidth && mCropHeight == cropHeight) { + return OK; + } + + mCreated = mImage.setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(), + mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED, + cropWidth, cropHeight); + if (mCreated) { + mCropWidth = cropWidth; + mCropHeight = cropHeight; + } else { + mCropWidth = 0; + mCropHeight = 0; + + const sp<GraphicBuffer>& buffer = mGraphicBuffer; + ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d", + buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(), + buffer->getPixelFormat()); + } + + return mCreated ? OK : UNKNOWN_ERROR; +} + +}; // namespace android diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h new file mode 100644 index 0000000000..9b1860833e --- /dev/null +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BUFFERLAYERCONSUMER_H +#define ANDROID_BUFFERLAYERCONSUMER_H + +#include "RenderEngine/Image.h" + +#include <gui/BufferQueueDefs.h> +#include <gui/ConsumerBase.h> + +#include <ui/FenceTime.h> +#include <ui/GraphicBuffer.h> +#include <ui/Region.h> + +#include <utils/String8.h> +#include <utils/Vector.h> +#include <utils/threads.h> + +namespace android { +// ---------------------------------------------------------------------------- + +class DispSync; +class Layer; +class RenderEngine; +class String8; + +/* + * BufferLayerConsumer consumes buffers of graphics data from a BufferQueue, + * and makes them available to RenderEngine as a texture. + * + * A typical usage pattern is to call updateTexImage() when a new frame is + * desired. If a new frame is available, the frame is latched. If not, the + * previous contents are retained. The texture is attached and updated after + * bindTextureImage() is called. + * + * All calls to updateTexImage must be made with RenderEngine being current. + * The texture is attached to the TEXTURE_EXTERNAL texture target. + */ +class BufferLayerConsumer : public ConsumerBase { +public: + static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; + + class BufferRejecter { + friend class BufferLayerConsumer; + virtual bool reject(const sp<GraphicBuffer>& buf, const BufferItem& item) = 0; + + protected: + virtual ~BufferRejecter() {} + }; + + struct ContentsChangedListener : public FrameAvailableListener { + virtual void onSidebandStreamChanged() = 0; + }; + + // BufferLayerConsumer constructs a new BufferLayerConsumer object. The + // tex parameter indicates the name of the RenderEngine texture to which + // images are to be streamed. + BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RenderEngine& engine, uint32_t tex, + Layer* layer); + + // Sets the contents changed listener. This should be used instead of + // ConsumerBase::setFrameAvailableListener(). + void setContentsChangedListener(const wp<ContentsChangedListener>& listener); + + nsecs_t computeExpectedPresent(const DispSync& dispSync); + + // updateTexImage acquires the most recently queued buffer, and sets the + // image contents of the target texture to it. + // + // This call may only be made while RenderEngine is current. + // + // This calls doFenceWait to ensure proper synchronization unless native + // fence is supported. + // + // Unlike the GLConsumer version, this version takes a functor that may be + // used to reject the newly acquired buffer. It also does not bind the + // RenderEngine texture until bindTextureImage is called. + status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh, + bool* queuedBuffer, uint64_t maxFrameNumber); + + // See BufferLayerConsumer::bindTextureImageLocked(). + status_t bindTextureImage(); + + // setReleaseFence stores a fence that will signal when the current buffer + // is no longer being read. This fence will be returned to the producer + // when the current buffer is released by updateTexImage(). Multiple + // fences can be set for a given buffer; they will be merged into a single + // union fence. + void setReleaseFence(const sp<Fence>& fence); + + bool releasePendingBuffer(); + + sp<Fence> getPrevFinalReleaseFence() const; + + // See GLConsumer::getTransformMatrix. + void getTransformMatrix(float mtx[16]); + + // getTimestamp retrieves the timestamp associated with the texture image + // set by the most recent call to updateTexImage. + // + // The timestamp is in nanoseconds, and is monotonically increasing. Its + // other semantics (zero point, etc) are source-dependent and should be + // documented by the source. + int64_t getTimestamp(); + + // getDataSpace retrieves the DataSpace associated with the texture image + // set by the most recent call to updateTexImage. + android_dataspace getCurrentDataSpace(); + + // getFrameNumber retrieves the frame number associated with the texture + // image set by the most recent call to updateTexImage. + // + // The frame number is an incrementing counter set to 0 at the creation of + // the BufferQueue associated with this consumer. + uint64_t getFrameNumber(); + + bool getTransformToDisplayInverse() const; + + // must be called from SF main thread + const Region& getSurfaceDamage() const; + + // See GLConsumer::setDefaultBufferSize. + status_t setDefaultBufferSize(uint32_t width, uint32_t height); + + // setFilteringEnabled sets whether the transform matrix should be computed + // for use with bilinear filtering. + void setFilteringEnabled(bool enabled); + + // getCurrentBuffer returns the buffer associated with the current image. + // When outSlot is not nullptr, the current buffer slot index is also + // returned. + sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr) const; + + // getCurrentCrop returns the cropping rectangle of the current buffer. + Rect getCurrentCrop() const; + + // getCurrentTransform returns the transform of the current buffer. + uint32_t getCurrentTransform() const; + + // getCurrentScalingMode returns the scaling mode of the current buffer. + uint32_t getCurrentScalingMode() const; + + // getCurrentFence returns the fence indicating when the current buffer is + // ready to be read from. + sp<Fence> getCurrentFence() const; + + // getCurrentFence returns the FenceTime indicating when the current + // buffer is ready to be read from. + std::shared_ptr<FenceTime> getCurrentFenceTime() const; + + // setConsumerUsageBits overrides the ConsumerBase method to OR + // DEFAULT_USAGE_FLAGS to usage. + status_t setConsumerUsageBits(uint64_t usage); + +protected: + // abandonLocked overrides the ConsumerBase method to clear + // mCurrentTextureImage in addition to the ConsumerBase behavior. + virtual void abandonLocked(); + + // dumpLocked overrides the ConsumerBase method to dump BufferLayerConsumer- + // specific info in addition to the ConsumerBase behavior. + virtual void dumpLocked(String8& result, const char* prefix) const; + + // acquireBufferLocked overrides the ConsumerBase method to update the + // mImages array in addition to the ConsumerBase behavior. + virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) override; + + bool canUseImageCrop(const Rect& crop) const; + + struct PendingRelease { + PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer() {} + + bool isPending; + int currentTexture; + sp<GraphicBuffer> graphicBuffer; + }; + + // 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. 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 TEXTURE_EXTERNAL target. Uses + // mCurrentTexture if it's set, mCurrentTextureImage if not. If the + // bind succeeds, this calls doFenceWait. + status_t bindTextureImageLocked(); + +private: + // Image is a utility class for tracking and creating RE::Images. There + // is primarily just one image per slot, but there is also special cases: + // - After freeBuffer, we must still keep the current image/buffer + // Reference counting RE::Images lets us handle all these cases easily while + // also only creating new RE::Images from buffers when required. + class Image : public LightRefBase<Image> { + public: + Image(sp<GraphicBuffer> graphicBuffer, const RenderEngine& engine); + + Image(const Image& rhs) = delete; + Image& operator=(const Image& rhs) = delete; + + // createIfNeeded creates an RE::Image if required (we haven't created + // one yet, or the crop-rect has changed). + status_t createIfNeeded(const Rect& imageCrop); + + const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; } + const native_handle* graphicBufferHandle() { + return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle; + } + + const RE::Image& image() const { return mImage; } + + private: + // Only allow instantiation using ref counting. + friend class LightRefBase<Image>; + virtual ~Image() = default; + + // mGraphicBuffer is the buffer that was used to create this image. + sp<GraphicBuffer> mGraphicBuffer; + + // mImage is the image created from mGraphicBuffer. + RE::Image mImage; + bool mCreated; + int32_t mCropWidth; + int32_t mCropHeight; + }; + + // freeBufferLocked frees up the given buffer slot. If the slot has been + // initialized this will release the reference to the GraphicBuffer in + // that slot and destroy the RE::Image in that slot. Otherwise it has no + // effect. + // + // This method must be called with mMutex locked. + virtual void freeBufferLocked(int slotIndex); + + // IConsumerListener interface + void onDisconnect() override; + void onSidebandStreamChanged() override; + void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, + FrameEventHistoryDelta* outDelta) override; + + // computeCurrentTransformMatrixLocked computes the transform matrix for the + // current texture. It uses mCurrentTransform and the current GraphicBuffer + // to compute this matrix and stores it in mCurrentTransformMatrix. + // mCurrentTextureImage must not be NULL. + void computeCurrentTransformMatrixLocked(); + + // doFenceWaitLocked inserts a wait command into the RenderEngine command + // stream to ensure that it is safe for future RenderEngine commands to + // access the current texture buffer. + status_t doFenceWaitLocked() const; + + // syncForReleaseLocked performs the synchronization needed to release the + // current slot from RenderEngine. If needed it will set the current + // slot's fence to guard against a producer accessing the buffer before + // the outstanding accesses have completed. + status_t syncForReleaseLocked(); + + // The default consumer usage flags that BufferLayerConsumer always sets on its + // BufferQueue instance; these will be OR:d with any additional flags passed + // from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always + // consume buffers as hardware textures. + static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; + + // mCurrentTextureImage is the Image/buffer of the current texture. It's + // possible that this buffer is not associated with any buffer slot, so we + // must track it separately in order to support the getCurrentBuffer method. + sp<Image> mCurrentTextureImage; + + // mCurrentCrop is the crop rectangle that applies to the current texture. + // It gets set each time updateTexImage is called. + Rect mCurrentCrop; + + // mCurrentTransform is the transform identifier for the current texture. It + // gets set each time updateTexImage is called. + uint32_t mCurrentTransform; + + // mCurrentScalingMode is the scaling mode for the current texture. It gets + // set each time updateTexImage is called. + uint32_t mCurrentScalingMode; + + // mCurrentFence is the fence received from BufferQueue in updateTexImage. + sp<Fence> mCurrentFence; + + // The FenceTime wrapper around mCurrentFence. + std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE}; + + // mCurrentTransformMatrix is the transform matrix for the current texture. + // It gets computed by computeTransformMatrix each time updateTexImage is + // called. + float mCurrentTransformMatrix[16]; + + // mCurrentTimestamp is the timestamp for the current texture. It + // gets set each time updateTexImage is called. + int64_t mCurrentTimestamp; + + // mCurrentDataSpace is the dataspace for the current texture. It + // gets set each time updateTexImage is called. + android_dataspace mCurrentDataSpace; + + // mCurrentFrameNumber is the frame counter for the current texture. + // It gets set each time updateTexImage is called. + uint64_t mCurrentFrameNumber; + + // Indicates this buffer must be transformed by the inverse transform of the screen + // it is displayed onto. This is applied after BufferLayerConsumer::mCurrentTransform. + // This must be set/read from SurfaceFlinger's main thread. + bool mCurrentTransformToDisplayInverse; + + // The portion of this surface that has changed since the previous frame + Region mCurrentSurfaceDamage; + + uint32_t mDefaultWidth, mDefaultHeight; + + // mFilteringEnabled indicates whether the transform matrix is computed for + // use with bilinear filtering. It defaults to true and is changed by + // setFilteringEnabled(). + bool mFilteringEnabled; + + RenderEngine& mRE; + + // mTexName is the name of the RenderEngine texture to which streamed + // images will be bound when bindTexImage is called. It is set at + // construction time. + const uint32_t mTexName; + + // The layer for this BufferLayerConsumer + const wp<Layer> mLayer; + + wp<ContentsChangedListener> mContentsChangedListener; + + // mImages stores the buffers that have been allocated by the BufferQueue + // for each buffer slot. It is initialized to null pointers, and gets + // filled in with the result of BufferQueue::acquire when the + // client dequeues a buffer from a + // slot that has not yet been used. The buffer allocated to a slot will also + // be replaced if the requested buffer usage or geometry differs from that + // of the buffer allocated to a slot. + sp<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS]; + + // mCurrentTexture is the buffer slot index of the buffer that is currently + // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT, + // indicating that no buffer slot is currently bound to the texture. Note, + // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean + // that no buffer is bound to the texture. A call to setBufferCount will + // reset mCurrentTexture to INVALID_BUFFER_SLOT. + int mCurrentTexture; + + // A release that is pending on the receipt of a new release fence from + // presentDisplay + PendingRelease mPendingRelease; +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_BUFFERLAYERCONSUMER_H diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 8ba6cb9ba7..ea6541a734 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -140,7 +140,8 @@ status_t Client::createSurface( { sp<Layer> parent = nullptr; if (parentHandle != nullptr) { - parent = getLayerUser(parentHandle); + auto layerHandle = reinterpret_cast<Layer::Handle*>(parentHandle.get()); + parent = layerHandle->owner.promote(); if (parent == nullptr) { return NAME_NOT_FOUND; } diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp new file mode 100644 index 0000000000..b784c8d956 --- /dev/null +++ b/services/surfaceflinger/ColorLayer.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "ColorLayer" + +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/Log.h> + +#include <ui/GraphicBuffer.h> + +#include "ColorLayer.h" +#include "DisplayDevice.h" +#include "RenderEngine/RenderEngine.h" +#include "SurfaceFlinger.h" + +namespace android { +// --------------------------------------------------------------------------- + +ColorLayer::ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, + uint32_t w, uint32_t h, uint32_t flags) + : Layer(flinger, client, name, w, h, flags) { + // drawing state & current state are identical + mDrawingState = mCurrentState; +} + +void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */, + bool useIdentityTransform) const { + const State& s(getDrawingState()); + if (s.color.a > 0) { + Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2); + computeGeometry(renderArea, mesh, useIdentityTransform); + RenderEngine& engine(mFlinger->getRenderEngine()); + engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */, + true /* disableTexture */, s.color); + engine.drawMesh(mesh); + engine.disableBlending(); + } +} + +bool ColorLayer::isVisible() const { + const Layer::State& s(getDrawingState()); + return !isHiddenByPolicy() && s.color.a; +} + +void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) { + const Transform& tr = displayDevice->getTransform(); + const auto& viewport = displayDevice->getViewport(); + Region visible = tr.transform(visibleRegion.intersect(viewport)); + auto hwcId = displayDevice->getHwcDisplayId(); + auto& hwcInfo = getBE().mHwcLayers[hwcId]; + auto& hwcLayer = hwcInfo.layer; + auto error = hwcLayer->setVisibleRegion(visible); + + setCompositionType(hwcId, HWC2::Composition::SolidColor); + + half4 color = getColor(); + error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)), + static_cast<uint8_t>(std::round(255.0f * color.g)), + static_cast<uint8_t>(std::round(255.0f * color.b)), 255}); + if (error != HWC2::Error::None) { + ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(), + static_cast<int32_t>(error)); + } + + // Clear out the transform, because it doesn't make sense absent a source buffer + error = hwcLayer->setTransform(HWC2::Transform::None); + if (error != HWC2::Error::None) { + ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(), + static_cast<int32_t>(error)); + } +} + +// --------------------------------------------------------------------------- + +}; // namespace android diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h new file mode 100644 index 0000000000..4022b319fa --- /dev/null +++ b/services/surfaceflinger/ColorLayer.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_COLOR_LAYER_H +#define ANDROID_COLOR_LAYER_H + +#include <stdint.h> +#include <sys/types.h> + +#include "Layer.h" + +// --------------------------------------------------------------------------- + +namespace android { + +class ColorLayer : public Layer { +public: + ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, + uint32_t h, uint32_t flags); + virtual ~ColorLayer() = default; + + virtual const char* getTypeId() const { return "ColorLayer"; } + virtual void onDraw(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform) const; + bool isVisible() const override; + virtual bool isOpaque(const Layer::State&) const { return false; } + virtual bool isFixedSize() const { return true; } + + void notifyAvailableFrames() override {} + PixelFormat getPixelFormat() const override { return PIXEL_FORMAT_NONE; } + uint32_t getEffectiveScalingMode() const override { return 0; } + void releasePendingBuffer(nsecs_t) override {} + Region latchBuffer(bool&, nsecs_t) override { return Region(); } + void useSurfaceDamage() override {} + void useEmptyDamage() override {} + bool isBufferLatched() const override { return false; } + bool onPreComposition(nsecs_t) override { return true; } + void abandon() override {} + void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override; + void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) override {} + bool shouldPresentNow(const DispSync& /*dispSync*/) const override { return false; } + bool onPostComposition(const std::shared_ptr<FenceTime>& /*glDoneFence*/, + const std::shared_ptr<FenceTime>& /*presentFence*/, + const CompositorTiming& /*compositorTiming*/) override { + return false; + } + void setTransformHint(uint32_t /*orientation*/) const override {} + std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) override { + return {}; + } + bool getTransformToDisplayInverse() const override { return false; } +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_COLOR_LAYER_H diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 95802bd726..2753f11097 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -28,6 +28,7 @@ #include <utils/RefBase.h> #include <utils/Log.h> +#include <ui/DebugUtils.h> #include <ui/DisplayInfo.h> #include <ui/PixelFormat.h> @@ -37,9 +38,7 @@ #include "DisplayHardware/DisplaySurface.h" #include "DisplayHardware/HWComposer.h" -#ifdef USE_HWC2 #include "DisplayHardware/HWC2.h" -#endif #include "RenderEngine/RenderEngine.h" #include "clz.h" @@ -54,12 +53,6 @@ using namespace android; // ---------------------------------------------------------------------------- -#ifdef EGL_ANDROID_swap_rectangle -static constexpr bool kEGLAndroidSwapRectangle = true; -#else -static constexpr bool kEGLAndroidSwapRectangle = false; -#endif - // retrieve triple buffer setting from configstore using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; @@ -67,12 +60,6 @@ using namespace android::hardware::configstore::V1_0; static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) >= 3; -#if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle) -// Dummy implementation in case it is missing. -inline void eglSetSwapRectangleANDROID (EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) { -} -#endif - /* * Initialize the display to the specified values. * @@ -85,14 +72,10 @@ DisplayDevice::DisplayDevice( const sp<SurfaceFlinger>& flinger, DisplayType type, int32_t hwcId, -#ifndef USE_HWC2 - int format, -#endif bool isSecure, const wp<IBinder>& displayToken, const sp<DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer, - EGLConfig config, bool supportWideColor) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), @@ -100,14 +83,9 @@ DisplayDevice::DisplayDevice( mHwcDisplayId(hwcId), mDisplayToken(displayToken), mDisplaySurface(displaySurface), - mDisplay(EGL_NO_DISPLAY), - mSurface(EGL_NO_SURFACE), + mSurface{flinger->getRenderEngine()}, mDisplayWidth(), mDisplayHeight(), -#ifndef USE_HWC2 - mFormat(), -#endif - mFlags(), mPageFlipCount(), mIsSecure(isSecure), mLayerStack(NO_LAYER_STACK), @@ -120,30 +98,16 @@ DisplayDevice::DisplayDevice( mNativeWindow = surface = new Surface(producer, false); ANativeWindow* const window = mNativeWindow.get(); -#ifdef USE_HWC2 mActiveColorMode = HAL_COLOR_MODE_NATIVE; mDisplayHasWideColor = supportWideColor; -#else - (void) supportWideColor; -#endif /* * Create our display's surface */ - - EGLSurface eglSurface; - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (config == EGL_NO_CONFIG) { -#ifdef USE_HWC2 - config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888, - /*logConfig*/ false); -#else - config = RenderEngine::chooseEglConfig(display, format, - /*logConfig*/ false); -#endif - } - eglSurface = eglCreateWindowSurface(display, config, window, NULL); - eglQuerySurface(display, eglSurface, EGL_WIDTH, &mDisplayWidth); - eglQuerySurface(display, eglSurface, EGL_HEIGHT, &mDisplayHeight); + mSurface.setCritical(mType == DisplayDevice::DISPLAY_PRIMARY); + mSurface.setAsync(mType >= DisplayDevice::DISPLAY_VIRTUAL); + mSurface.setNativeWindow(window); + mDisplayWidth = mSurface.queryWidth(); + mDisplayHeight = mSurface.queryHeight(); // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. We have to do this @@ -155,12 +119,6 @@ DisplayDevice::DisplayDevice( if (mType >= DisplayDevice::DISPLAY_VIRTUAL) window->setSwapInterval(window, 0); - mConfig = config; - mDisplay = display; - mSurface = eglSurface; -#ifndef USE_HWC2 - mFormat = format; -#endif mPageFlipCount = 0; mViewport.makeInvalid(); mFrame.makeInvalid(); @@ -192,19 +150,11 @@ DisplayDevice::DisplayDevice( } DisplayDevice::~DisplayDevice() { - if (mSurface != EGL_NO_SURFACE) { - eglDestroySurface(mDisplay, mSurface); - mSurface = EGL_NO_SURFACE; - } } void DisplayDevice::disconnect(HWComposer& hwc) { if (mHwcDisplayId >= 0) { hwc.disconnectDisplay(mHwcDisplayId); -#ifndef USE_HWC2 - if (mHwcDisplayId >= DISPLAY_VIRTUAL) - hwc.freeDisplayId(mHwcDisplayId); -#endif mHwcDisplayId = -1; } } @@ -221,16 +171,6 @@ int DisplayDevice::getHeight() const { return mDisplayHeight; } -#ifndef USE_HWC2 -PixelFormat DisplayDevice::getFormat() const { - return mFormat; -} -#endif - -EGLSurface DisplayDevice::getEGLSurface() const { - return mSurface; -} - void DisplayDevice::setDisplayName(const String8& displayName) { if (!displayName.isEmpty()) { // never override the name with an empty name @@ -242,25 +182,9 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mPageFlipCount; } -#ifndef USE_HWC2 -status_t DisplayDevice::compositionComplete() const { - return mDisplaySurface->compositionComplete(); -} -#endif - -void DisplayDevice::flip(const Region& dirty) const +void DisplayDevice::flip() const { mFlinger->getRenderEngine().checkErrors(); - - if (kEGLAndroidSwapRectangle) { - if (mFlags & SWAP_RECTANGLE) { - const Region newDirty(dirty.intersect(bounds())); - const Rect b(newDirty.getBounds()); - eglSetSwapRectangleANDROID(mDisplay, mSurface, - b.left, b.top, b.width(), b.height()); - } - } - mPageFlipCount++; } @@ -268,7 +192,6 @@ status_t DisplayDevice::beginFrame(bool mustRecompose) const { return mDisplaySurface->beginFrame(mustRecompose); } -#ifdef USE_HWC2 status_t DisplayDevice::prepareFrame(HWComposer& hwc) { status_t error = hwc.prepare(*this); if (error != NO_ERROR) { @@ -292,53 +215,10 @@ status_t DisplayDevice::prepareFrame(HWComposer& hwc) { } return mDisplaySurface->prepareFrame(compositionType); } -#else -status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const { - DisplaySurface::CompositionType compositionType; - bool haveGles = hwc.hasGlesComposition(mHwcDisplayId); - bool haveHwc = hwc.hasHwcComposition(mHwcDisplayId); - if (haveGles && haveHwc) { - compositionType = DisplaySurface::COMPOSITION_MIXED; - } else if (haveGles) { - compositionType = DisplaySurface::COMPOSITION_GLES; - } else if (haveHwc) { - compositionType = DisplaySurface::COMPOSITION_HWC; - } else { - // Nothing to do -- when turning the screen off we get a frame like - // this. Call it a HWC frame since we won't be doing any GLES work but - // will do a prepare/set cycle. - compositionType = DisplaySurface::COMPOSITION_HWC; - } - return mDisplaySurface->prepareFrame(compositionType); -} -#endif void DisplayDevice::swapBuffers(HWComposer& hwc) const { -#ifdef USE_HWC2 if (hwc.hasClientComposition(mHwcDisplayId)) { -#else - // We need to call eglSwapBuffers() if: - // (1) we don't have a hardware composer, or - // (2) we did GLES composition this frame, and either - // (a) we have framebuffer target support (not present on legacy - // devices, where HWComposer::commit() handles things); or - // (b) this is a virtual display - if (hwc.initCheck() != NO_ERROR || - (hwc.hasGlesComposition(mHwcDisplayId) && - (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) { -#endif - EGLBoolean success = eglSwapBuffers(mDisplay, mSurface); - if (!success) { - EGLint error = eglGetError(); - if (error == EGL_CONTEXT_LOST || - mType == DisplayDevice::DISPLAY_PRIMARY) { - LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x", - mDisplay, mSurface, error); - } else { - ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x", - mDisplay, mSurface, error); - } - } + mSurface.swapBuffers(); } status_t result = mDisplaySurface->advanceFrame(); @@ -348,35 +228,14 @@ void DisplayDevice::swapBuffers(HWComposer& hwc) const { } } -#ifdef USE_HWC2 void DisplayDevice::onSwapBuffersCompleted() const { mDisplaySurface->onFrameCommitted(); } -#else -void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const { - if (hwc.initCheck() == NO_ERROR) { - mDisplaySurface->onFrameCommitted(); - } -} -#endif - -uint32_t DisplayDevice::getFlags() const -{ - return mFlags; -} -EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const { - EGLBoolean result = EGL_TRUE; - EGLSurface sur = eglGetCurrentSurface(EGL_DRAW); - if (sur != mSurface) { - result = eglMakeCurrent(dpy, mSurface, mSurface, ctx); - if (result == EGL_TRUE) { - if (mType >= DisplayDevice::DISPLAY_VIRTUAL) - eglSwapInterval(dpy, 0); - } - } +bool DisplayDevice::makeCurrent() const { + bool success = mFlinger->getRenderEngine().setCurrentSurface(mSurface); setViewportAndProjection(); - return result; + return success; } void DisplayDevice::setViewportAndProjection() const { @@ -444,7 +303,6 @@ int DisplayDevice::getActiveConfig() const { } // ---------------------------------------------------------------------------- -#ifdef USE_HWC2 void DisplayDevice::setActiveColorMode(android_color_mode_t mode) { mActiveColorMode = mode; } @@ -457,7 +315,6 @@ void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) { ANativeWindow* const window = mNativeWindow.get(); native_window_set_buffers_data_space(window, dataspace); } -#endif // ---------------------------------------------------------------------------- @@ -514,17 +371,14 @@ status_t DisplayDevice::orientationToTransfrom( void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) { dirtyRegion.set(getBounds()); - if (mSurface != EGL_NO_SURFACE) { - eglDestroySurface(mDisplay, mSurface); - mSurface = EGL_NO_SURFACE; - } + mSurface.setNativeWindow(nullptr); mDisplaySurface->resizeBuffers(newWidth, newHeight); ANativeWindow* const window = mNativeWindow.get(); - mSurface = eglCreateWindowSurface(mDisplay, mConfig, window, NULL); - eglQuerySurface(mDisplay, mSurface, EGL_WIDTH, &mDisplayWidth); - eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mDisplayHeight); + mSurface.setNativeWindow(window); + mDisplayWidth = mSurface.queryWidth(); + mDisplayHeight = mSurface.queryHeight(); LOG_FATAL_IF(mDisplayWidth != newWidth, "Unable to set new width to %d", newWidth); @@ -625,18 +479,15 @@ uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() { void DisplayDevice::dump(String8& result) const { const Transform& tr(mGlobalTransform); - EGLint redSize, greenSize, blueSize, alphaSize; - eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize); - eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize); - eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &blueSize); - eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &alphaSize); + ANativeWindow* const window = mNativeWindow.get(); result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string()); result.appendFormat(" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p " "(%d:%d:%d:%d), orient=%2d (type=%08x), " "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n", - mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, - mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation, - tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, + mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window, + mSurface.queryRedSize(), mSurface.queryGreenSize(), mSurface.queryBlueSize(), + mSurface.queryAlphaSize(), mOrientation, tr.getType(), + getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, mVisibleLayersSortedByZ.size()); result.appendFormat(" 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", @@ -644,6 +495,9 @@ void DisplayDevice::dump(String8& result) const { mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]); + auto const surface = static_cast<Surface*>(window); + android_dataspace dataspace = surface->getBuffersDataSpace(); + result.appendFormat(" dataspace: %s (%d)\n", dataspaceDetails(dataspace).c_str(), dataspace); String8 surfaceDump; mDisplaySurface->dumpAsString(surfaceDump); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index e8a5929ee0..499bf8e6a0 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -21,27 +21,20 @@ #include <stdlib.h> -#ifndef USE_HWC2 -#include <ui/PixelFormat.h> -#endif #include <ui/Region.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#ifdef USE_HWC2 #include <binder/IBinder.h> #include <utils/RefBase.h> -#endif #include <utils/Mutex.h> #include <utils/String8.h> #include <utils/Timers.h> +#include <gui/ISurfaceComposer.h> #include <hardware/hwcomposer_defs.h> +#include "RenderArea.h" +#include "RenderEngine/Surface.h" -#ifdef USE_HWC2 #include <memory> -#endif struct ANativeWindow; @@ -61,8 +54,6 @@ public: // region in layer-stack space mutable Region dirtyRegion; // region in screen space - mutable Region swapRegion; - // region in screen space Region undefinedRegion; bool lastCompositionHadVisibleLayers; @@ -75,11 +66,6 @@ public: }; enum { - PARTIAL_UPDATES = 0x00020000, // video driver feature - SWAP_RECTANGLE = 0x00080000, - }; - - enum { NO_LAYER_STACK = 0xFFFFFFFF, }; @@ -88,14 +74,10 @@ public: const sp<SurfaceFlinger>& flinger, DisplayType type, int32_t hwcId, -#ifndef USE_HWC2 - int format, -#endif bool isSecure, const wp<IBinder>& displayToken, const sp<DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer, - EGLConfig config, bool supportWideColor); // clang-format on @@ -111,16 +93,10 @@ public: // Flip the front and back buffers if the back buffer is "dirty". Might // be instantaneous, might involve copying the frame buffer around. - void flip(const Region& dirty) const; + void flip() const; int getWidth() const; int getHeight() const; -#ifndef USE_HWC2 - PixelFormat getFormat() const; -#endif - uint32_t getFlags() const; - - EGLSurface getEGLSurface() const; void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers); const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const; @@ -150,24 +126,13 @@ public: // We pass in mustRecompose so we can keep VirtualDisplaySurface's state // machine happy without actually queueing a buffer if nothing has changed status_t beginFrame(bool mustRecompose) const; -#ifdef USE_HWC2 status_t prepareFrame(HWComposer& hwc); bool getWideColorSupport() const { return mDisplayHasWideColor; } -#else - status_t prepareFrame(const HWComposer& hwc) const; -#endif void swapBuffers(HWComposer& hwc) const; -#ifndef USE_HWC2 - status_t compositionComplete() const; -#endif // called after h/w composer has completed its set() call -#ifdef USE_HWC2 void onSwapBuffersCompleted() const; -#else - void onSwapBuffersCompleted(HWComposer& hwc) const; -#endif Rect getBounds() const { return Rect(mDisplayWidth, mDisplayHeight); @@ -177,7 +142,7 @@ public: void setDisplayName(const String8& displayName); const String8& getDisplayName() const { return mDisplayName; } - EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const; + bool makeCurrent() const; void setViewportAndProjection() const; const sp<Fence>& getClientTargetAcquireFence() const; @@ -189,11 +154,9 @@ public: void setPowerMode(int mode); bool isDisplayOn() const; -#ifdef USE_HWC2 android_color_mode_t getActiveColorMode() const; void setActiveColorMode(android_color_mode_t mode); void setCompositionDataSpace(android_dataspace dataspace); -#endif /* ------------------------------------------------------------------------ * Display active config management. @@ -223,15 +186,9 @@ private: sp<ANativeWindow> mNativeWindow; sp<DisplaySurface> mDisplaySurface; - EGLConfig mConfig; - EGLDisplay mDisplay; - EGLSurface mSurface; + RE::Surface mSurface; int mDisplayWidth; int mDisplayHeight; -#ifndef USE_HWC2 - PixelFormat mFormat; -#endif - uint32_t mFlags; mutable uint32_t mPageFlipCount; String8 mDisplayName; bool mIsSecure; @@ -271,7 +228,6 @@ private: int mPowerMode; // Current active config int mActiveConfig; -#ifdef USE_HWC2 // current active color mode android_color_mode_t mActiveColorMode; @@ -279,7 +235,6 @@ private: // Initialized by SurfaceFlinger when the DisplayDevice is created. // Fed to RenderEngine during composition. bool mDisplayHasWideColor; -#endif }; struct DisplayDeviceState { @@ -304,6 +259,33 @@ struct DisplayDeviceState { bool isSecure = false; }; +class DisplayRenderArea : public RenderArea { +public: + DisplayRenderArea(const sp<const DisplayDevice> device, + ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone) + : DisplayRenderArea(device, device->getBounds(), device->getHeight(), device->getWidth(), + rotation) {} + DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqHeight, + uint32_t reqWidth, ISurfaceComposer::Rotation rotation) + : RenderArea(reqHeight, reqWidth, rotation), mDevice(device), mSourceCrop(sourceCrop) {} + + const Transform& getTransform() const override { return mDevice->getTransform(); } + Rect getBounds() const override { return mDevice->getBounds(); } + int getHeight() const override { return mDevice->getHeight(); } + int getWidth() const override { return mDevice->getWidth(); } + bool isSecure() const override { return mDevice->isSecure(); } + bool needsFiltering() const override { return mDevice->needsFiltering(); } + Rect getSourceCrop() const override { return mSourceCrop; } + bool getWideColorSupport() const override { return mDevice->getWideColorSupport(); } + android_color_mode_t getActiveColorMode() const override { + return mDevice->getActiveColorMode(); + } + +private: + const sp<const DisplayDevice> mDevice; + const Rect mSourceCrop; +}; + }; // namespace android #endif // ANDROID_DISPLAY_DEVICE_H diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 7d6d9886f6..c707e3cc65 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -223,6 +223,10 @@ void Composer::resetCommands() { mWriter.reset(); } +Error Composer::executeCommands() { + return execute(); +} + uint32_t Composer::getMaxVirtualDisplayCount() { auto ret = mClient->getMaxVirtualDisplayCount(); @@ -750,6 +754,11 @@ Error Composer::execute() } } + if (commandLength == 0) { + mWriter.reset(); + return Error::NONE; + } + Error error = kDefaultError; auto ret = mClient->executeCommands(commandLength, commandHandles, [&](const auto& tmpError, const auto& tmpOutChanged, diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 31a3c1d785..104ca608e6 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -152,6 +152,9 @@ public: // skip a frame but have already queued some commands. void resetCommands(); + // Explicitly flush all pending commands in the command buffer. + Error executeCommands(); + uint32_t getMaxVirtualDisplayCount(); bool isUsingVrComposer() const { return mIsUsingVrComposer; } Error createVirtualDisplay(uint32_t width, uint32_t height, diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h index cb08f084fe..f744f5cf21 100644 --- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h @@ -50,14 +50,6 @@ public: }; virtual status_t prepareFrame(CompositionType compositionType) = 0; -#ifndef USE_HWC2 - // Should be called when composition rendering is complete for a frame (but - // eglSwapBuffers hasn't necessarily been called). Required by certain - // older drivers for synchronization. - // TODO: Remove this when we drop support for HWC 1.0. - virtual status_t compositionComplete() = 0; -#endif - // Inform the surface that GLES composition is complete for this frame, and // the surface should make sure that HWComposer has the correct buffer for // this frame. Some implementations may only push a new buffer to diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 93c6d5486f..8b5d4c974b 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -27,8 +27,6 @@ #include <utils/String8.h> #include <log/log.h> -#include <EGL/egl.h> - #include <hardware/hardware.h> #include <gui/BufferItem.h> #include <gui/BufferQueue.h> @@ -59,32 +57,21 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp, mCurrentBufferSlot(-1), mCurrentBuffer(), mCurrentFence(Fence::NO_FENCE), -#ifdef USE_HWC2 mHwc(hwc), mHasPendingRelease(false), mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT), mPreviousBuffer() -#else - mHwc(hwc) -#endif { -#ifdef USE_HWC2 ALOGV("Creating for display %d", disp); -#endif mName = "FramebufferSurface"; mConsumer->setConsumerName(mName); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); -#ifdef USE_HWC2 const auto& activeConfig = mHwc.getActiveConfig(disp); mConsumer->setDefaultBufferSize(activeConfig->getWidth(), activeConfig->getHeight()); -#else - mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp)); - mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); -#endif mConsumer->setMaxAcquiredBufferCount( SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1); } @@ -98,7 +85,6 @@ status_t FramebufferSurface::prepareFrame(CompositionType /*compositionType*/) { } status_t FramebufferSurface::advanceFrame() { -#ifdef USE_HWC2 uint32_t slot = 0; sp<GraphicBuffer> buf; sp<Fence> acquireFence(Fence::NO_FENCE); @@ -110,32 +96,18 @@ status_t FramebufferSurface::advanceFrame() { strerror(-result), result); } return result; -#else - // Once we remove FB HAL support, we can call nextBuffer() from here - // instead of using onFrameAvailable(). No real benefit, except it'll be - // more like VirtualDisplaySurface. - return NO_ERROR; -#endif } -#ifdef USE_HWC2 status_t FramebufferSurface::nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence, android_dataspace_t& outDataspace) { -#else -status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) { -#endif Mutex::Autolock lock(mMutex); BufferItem item; status_t err = acquireBufferLocked(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { -#ifdef USE_HWC2 mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer); -#else - outBuffer = mCurrentBuffer; -#endif return NO_ERROR; } else if (err != NO_ERROR) { ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err); @@ -152,26 +124,15 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& // had released the old buffer first. if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && item.mSlot != mCurrentBufferSlot) { -#ifdef USE_HWC2 mHasPendingRelease = true; mPreviousBufferSlot = mCurrentBufferSlot; mPreviousBuffer = mCurrentBuffer; -#else - // Release the previous buffer. - err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - if (err < NO_ERROR) { - ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); - return err; - } -#endif } mCurrentBufferSlot = item.mSlot; mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; mCurrentFence = item.mFence; outFence = item.mFence; -#ifdef USE_HWC2 mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer); outDataspace = item.mDataSpace; @@ -181,31 +142,10 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& ALOGE("error posting framebuffer: %d", result); return result; } -#else - outBuffer = mCurrentBuffer; -#endif return NO_ERROR; } -#ifndef USE_HWC2 -// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl. -void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) { - sp<GraphicBuffer> buf; - sp<Fence> acquireFence; - status_t err = nextBuffer(buf, acquireFence); - if (err != NO_ERROR) { - ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)", - strerror(-err), err); - return; - } - err = mHwc.fbPost(mDisplayType, acquireFence, buf); - if (err != NO_ERROR) { - ALOGE("error posting framebuffer: %d", err); - } -} -#endif - void FramebufferSurface::freeBufferLocked(int slotIndex) { ConsumerBase::freeBufferLocked(slotIndex); if (slotIndex == mCurrentBufferSlot) { @@ -214,7 +154,6 @@ void FramebufferSurface::freeBufferLocked(int slotIndex) { } void FramebufferSurface::onFrameCommitted() { -#ifdef USE_HWC2 if (mHasPendingRelease) { sp<Fence> fence = mHwc.getPresentFence(mDisplayType); if (fence->isValid()) { @@ -223,32 +162,14 @@ void FramebufferSurface::onFrameCommitted() { ALOGE_IF(result != NO_ERROR, "onFrameCommitted: failed to add the" " fence: %s (%d)", strerror(-result), result); } - status_t result = releaseBufferLocked(mPreviousBufferSlot, - mPreviousBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + status_t result = releaseBufferLocked(mPreviousBufferSlot, mPreviousBuffer); ALOGE_IF(result != NO_ERROR, "onFrameCommitted: error releasing buffer:" " %s (%d)", strerror(-result), result); mPreviousBuffer.clear(); mHasPendingRelease = false; } -#else - sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType); - if (fence->isValid() && - mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { - status_t err = addReleaseFence(mCurrentBufferSlot, - mCurrentBuffer, fence); - ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", - strerror(-err), err); - } -#endif -} - -#ifndef USE_HWC2 -status_t FramebufferSurface::compositionComplete() -{ - return mHwc.fbCompositionComplete(); } -#endif void FramebufferSurface::dumpAsString(String8& result) const { Mutex::Autolock lock(mMutex); @@ -259,9 +180,6 @@ void FramebufferSurface::dumpAsString(String8& result) const { void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const { -#ifndef USE_HWC2 - mHwc.fbDump(result); -#endif ConsumerBase::dumpLocked(result, prefix); } diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index a1756ca3c2..4186b7aac4 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -42,9 +42,6 @@ public: virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); -#ifndef USE_HWC2 - virtual status_t compositionComplete(); -#endif virtual status_t advanceFrame(); virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; @@ -58,9 +55,6 @@ public: private: virtual ~FramebufferSurface() { }; // this class cannot be overloaded -#ifndef USE_HWC2 - virtual void onFrameAvailable(const BufferItem& item); -#endif virtual void freeBufferLocked(int slotIndex); virtual void dumpLocked(String8& result, const char* prefix) const; @@ -68,12 +62,8 @@ private: // nextBuffer waits for and then latches the next buffer from the // BufferQueue and releases the previously latched buffer to the // BufferQueue. The new buffer is returned in the 'buffer' argument. -#ifdef USE_HWC2 status_t nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence, android_dataspace_t& outDataspace); -#else - status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence); -#endif // mDisplayType must match one of the HWC display types int mDisplayType; @@ -100,14 +90,12 @@ private: // Hardware composer, owned by SurfaceFlinger. HWComposer& mHwc; -#ifdef USE_HWC2 HWComposerBufferCache mHwcBufferCache; // Previous buffer to release after getting an updated retire fence bool mHasPendingRelease; int mPreviousBufferSlot; sp<GraphicBuffer> mPreviousBuffer; -#endif }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 78c0c8567a..ab4a4b23bc 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -221,6 +221,11 @@ void Device::loadCapabilities() } } +Error Device::flushCommands() +{ + return static_cast<Error>(mComposer->executeCommands()); +} + // Display methods Display::Display(android::Hwc2::Composer& composer, @@ -632,11 +637,6 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests return error; } -void Display::discardCommands() -{ - mComposer.resetCommands(); -} - // For use by Device void Display::setConnected(bool connected) { diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index fbe4c7ebed..a15c6d940c 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -106,6 +106,11 @@ public: android::Hwc2::Composer* getComposer() { return mComposer.get(); } + // We buffer most state changes and flush them implicitly with + // Display::validate, Display::present, and Display::presentOrValidate. + // This method provides an explicit way to flush state changes to HWC. + Error flushCommands(); + private: // Initialization methods @@ -244,12 +249,6 @@ public: uint32_t* outNumRequests, android::sp<android::Fence>* outPresentFence, uint32_t* state); - // Most methods in this class write a command to a command buffer. The - // command buffer is implicitly submitted in validate, present, and - // presentOrValidate. This method provides a way to discard the commands, - // which can be used to discard stale commands. - void discardCommands(); - // Other Display methods hwc2_display_t getId() const { return mId; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index a16c040bc2..c0f8f96478 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -611,8 +611,11 @@ status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) { auto& hwcDisplay = displayData.hwcDisplay; if (displayData.validateWasSkipped) { - hwcDisplay->discardCommands(); - auto error = displayData.presentError; + // explicitly flush all pending commands + auto error = mHwcDevice->flushCommands(); + if (displayData.presentError != HWC2::Error::None) { + error = displayData.presentError; + } if (error != HWC2::Error::None) { ALOGE("skipValidate: failed for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast<int32_t>(error)); @@ -871,6 +874,14 @@ void HWComposer::dump(String8& result) const { result.append(mHwcDevice->dump().c_str()); } +std::optional<hwc2_display_t> +HWComposer::getHwcDisplayId(int32_t displayId) const { + if (!isValidDisplay(displayId)) { + return {}; + } + return mDisplayData[displayId].hwcDisplay->getId(); +} + // --------------------------------------------------------------------------- HWComposer::DisplayData::DisplayData() diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 3640bb5a98..74b3a38b6a 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -14,10 +14,6 @@ * limitations under the License. */ -#ifndef USE_HWC2 -#include "HWComposer_hwc1.h" -#else - #ifndef ANDROID_SF_HWCOMPOSER_H #define ANDROID_SF_HWCOMPOSER_H @@ -37,6 +33,7 @@ #include <utils/Vector.h> #include <memory> +#include <optional> #include <set> #include <vector> @@ -165,6 +162,8 @@ public: void dump(String8& out) const; android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); } + + std::optional<hwc2_display_t> getHwcDisplayId(int32_t displayId) const; private: static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2; @@ -219,5 +218,3 @@ private: }; // namespace android #endif // ANDROID_SF_HWCOMPOSER_H - -#endif // #ifdef USE_HWC2 diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp deleted file mode 100644 index dcb29135b9..0000000000 --- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp +++ /dev/null @@ -1,1346 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include <inttypes.h> -#include <math.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/misc.h> -#include <utils/NativeHandle.h> -#include <utils/String8.h> -#include <utils/Thread.h> -#include <utils/Trace.h> -#include <utils/Vector.h> - -#include <ui/GraphicBuffer.h> - -#include <hardware/hardware.h> -#include <hardware/hwcomposer.h> - -#include <android/configuration.h> - -#include <cutils/properties.h> -#include <log/log.h> - -#include <system/graphics.h> - -#include "HWComposer.h" - -#include "../Layer.h" // needed only for debugging -#include "../SurfaceFlinger.h" - -namespace android { - -#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION - -static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) { - uint32_t hwcVersion = hwc->common.version; - return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK; -} - -static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) { - uint32_t hwcVersion = hwc->common.version; - return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK; -} - -static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc, - uint32_t version) { - return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK); -} - -// --------------------------------------------------------------------------- - -struct HWComposer::cb_context { - struct callbacks : public hwc_procs_t { - // these are here to facilitate the transition when adding - // new callbacks (an implementation can check for NULL before - // calling a new callback). - void (*zero[4])(void); - }; - callbacks procs; - HWComposer* hwc; -}; - -// --------------------------------------------------------------------------- - -HWComposer::HWComposer( - const sp<SurfaceFlinger>& flinger, - EventHandler& handler) - : mFlinger(flinger), - mFbDev(0), mHwc(0), mNumDisplays(1), - mCBContext(new cb_context), - mEventHandler(handler), - mDebugForceFakeVSync(false) -{ - for (size_t i =0 ; i<MAX_HWC_DISPLAYS ; i++) { - mLists[i] = 0; - } - - for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) { - mLastHwVSync[i] = 0; - mVSyncCounts[i] = 0; - } - - char value[PROPERTY_VALUE_MAX]; - property_get("debug.sf.no_hw_vsync", value, "0"); - mDebugForceFakeVSync = atoi(value); - - bool needVSyncThread = true; - - // Note: some devices may insist that the FB HAL be opened before HWC. - int fberr = loadFbHalModule(); - loadHwcModule(); - - if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - // close FB HAL if we don't needed it. - // FIXME: this is temporary until we're not forced to open FB HAL - // before HWC. - framebuffer_close(mFbDev); - mFbDev = NULL; - } - - // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory. - if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) - && !mFbDev) { - ALOGE("ERROR: failed to open framebuffer (%s), aborting", - strerror(-fberr)); - abort(); - } - - // these display IDs are always reserved - for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) { - mAllocatedDisplayIDs.markBit(i); - } - - if (mHwc) { - ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER, - (hwcApiVersion(mHwc) >> 24) & 0xff, - (hwcApiVersion(mHwc) >> 16) & 0xff); - if (mHwc->registerProcs) { - mCBContext->hwc = this; - mCBContext->procs.invalidate = &hook_invalidate; - mCBContext->procs.vsync = &hook_vsync; - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) - mCBContext->procs.hotplug = &hook_hotplug; - else - mCBContext->procs.hotplug = NULL; - memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero)); - mHwc->registerProcs(mHwc, &mCBContext->procs); - } - - // don't need a vsync thread if we have a hardware composer - needVSyncThread = false; - // always turn vsync off when we start - eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0); - - // the number of displays we actually have depends on the - // hw composer version - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { - // 1.3 adds support for virtual displays - mNumDisplays = MAX_HWC_DISPLAYS; - } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - // 1.1 adds support for multiple displays - mNumDisplays = NUM_BUILTIN_DISPLAYS; - } else { - mNumDisplays = 1; - } - } - - if (mFbDev) { - ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)), - "should only have fbdev if no hwc or hwc is 1.0"); - - DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]); - disp.connected = true; - disp.format = mFbDev->format; - DisplayConfig config = DisplayConfig(); - config.width = mFbDev->width; - config.height = mFbDev->height; - config.xdpi = mFbDev->xdpi; - config.ydpi = mFbDev->ydpi; - config.refresh = nsecs_t(1e9 / mFbDev->fps); - disp.configs.push_back(config); - disp.currentConfig = 0; - } else if (mHwc) { - // here we're guaranteed to have at least HWC 1.1 - for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) { - queryDisplayProperties(i); - } - } - - if (needVSyncThread) { - // we don't have VSYNC support, we need to fake it - mVSyncThread = new VSyncThread(*this); - } -} - -HWComposer::~HWComposer() { - if (mHwc) { - eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0); - } - if (mVSyncThread != NULL) { - mVSyncThread->requestExitAndWait(); - } - if (mHwc) { - hwc_close_1(mHwc); - } - if (mFbDev) { - framebuffer_close(mFbDev); - } - delete mCBContext; -} - -// Load and prepare the hardware composer module. Sets mHwc. -void HWComposer::loadHwcModule() -{ - hw_module_t const* module; - - if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) { - ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID); - return; - } - - int err = hwc_open_1(module, &mHwc); - if (err) { - ALOGE("%s device failed to initialize (%s)", - HWC_HARDWARE_COMPOSER, strerror(-err)); - return; - } - - if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) || - hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION || - hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) { - ALOGE("%s device version %#x unsupported, will not be used", - HWC_HARDWARE_COMPOSER, mHwc->common.version); - hwc_close_1(mHwc); - mHwc = NULL; - return; - } -} - -// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev. -int HWComposer::loadFbHalModule() -{ - hw_module_t const* module; - - int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); - if (err != 0) { - ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID); - return err; - } - - return framebuffer_open(module, &mFbDev); -} - -status_t HWComposer::initCheck() const { - return mHwc ? NO_ERROR : NO_INIT; -} - -void HWComposer::hook_invalidate(const struct hwc_procs* procs) { - cb_context* ctx = reinterpret_cast<cb_context*>( - const_cast<hwc_procs_t*>(procs)); - ctx->hwc->invalidate(); -} - -void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp, - int64_t timestamp) { - cb_context* ctx = reinterpret_cast<cb_context*>( - const_cast<hwc_procs_t*>(procs)); - ctx->hwc->vsync(disp, timestamp); -} - -void HWComposer::hook_hotplug(const struct hwc_procs* procs, int disp, - int connected) { - cb_context* ctx = reinterpret_cast<cb_context*>( - const_cast<hwc_procs_t*>(procs)); - ctx->hwc->hotplug(disp, connected); -} - -void HWComposer::invalidate() { - mEventHandler.onInvalidateReceived(this); -} - -void HWComposer::vsync(int disp, int64_t timestamp) { - if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) { - { - Mutex::Autolock _l(mLock); - - // There have been reports of HWCs that signal several vsync events - // with the same timestamp when turning the display off and on. This - // is a bug in the HWC implementation, but filter the extra events - // out here so they don't cause havoc downstream. - if (timestamp == mLastHwVSync[disp]) { - ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")", - timestamp); - return; - } - - mLastHwVSync[disp] = timestamp; - } - - char tag[16]; - snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp); - ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); - - mEventHandler.onVSyncReceived(this, disp, timestamp); - } -} - -void HWComposer::hotplug(int disp, int connected) { - if (disp >= VIRTUAL_DISPLAY_ID_BASE) { - ALOGE("hotplug event received for invalid display: disp=%d connected=%d", - disp, connected); - return; - } - queryDisplayProperties(disp); - // Do not teardown or recreate the primary display - if (disp != HWC_DISPLAY_PRIMARY) { - mEventHandler.onHotplugReceived(this, disp, bool(connected)); - } -} - -static float getDefaultDensity(uint32_t width, uint32_t height) { - // 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 just report - // accurate DPI information to begin with. This is also used for virtual - // displays and even primary displays with older hwcomposers, so be - // careful about orientation. - - uint32_t h = width < height ? width : height; - if (h >= 1080) return ACONFIGURATION_DENSITY_XHIGH; - else return ACONFIGURATION_DENSITY_TV; -} - -static const uint32_t DISPLAY_ATTRIBUTES[] = { - HWC_DISPLAY_VSYNC_PERIOD, - HWC_DISPLAY_WIDTH, - HWC_DISPLAY_HEIGHT, - HWC_DISPLAY_DPI_X, - HWC_DISPLAY_DPI_Y, - HWC_DISPLAY_COLOR_TRANSFORM, - HWC_DISPLAY_NO_ATTRIBUTE, -}; -#define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0]) - -static const uint32_t PRE_HWC15_DISPLAY_ATTRIBUTES[] = { - HWC_DISPLAY_VSYNC_PERIOD, - HWC_DISPLAY_WIDTH, - HWC_DISPLAY_HEIGHT, - HWC_DISPLAY_DPI_X, - HWC_DISPLAY_DPI_Y, - HWC_DISPLAY_NO_ATTRIBUTE, -}; - -status_t HWComposer::queryDisplayProperties(int disp) { - - LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)); - - // use zero as default value for unspecified attributes - int32_t values[NUM_DISPLAY_ATTRIBUTES - 1]; - memset(values, 0, sizeof(values)); - - const size_t MAX_NUM_CONFIGS = 128; - uint32_t configs[MAX_NUM_CONFIGS] = {0}; - size_t numConfigs = MAX_NUM_CONFIGS; - status_t err = mHwc->getDisplayConfigs(mHwc, disp, configs, &numConfigs); - if (err != NO_ERROR) { - // this can happen if an unpluggable display is not connected - mDisplayData[disp].connected = false; - return err; - } - - mDisplayData[disp].currentConfig = 0; - for (size_t c = 0; c < numConfigs; ++c) { - err = mHwc->getDisplayAttributes(mHwc, disp, configs[c], - DISPLAY_ATTRIBUTES, values); - // If this is a pre-1.5 HWC, it may not know about color transform, so - // try again with a smaller set of attributes - if (err != NO_ERROR) { - err = mHwc->getDisplayAttributes(mHwc, disp, configs[c], - PRE_HWC15_DISPLAY_ATTRIBUTES, values); - } - if (err != NO_ERROR) { - // we can't get this display's info. turn it off. - mDisplayData[disp].connected = false; - return err; - } - - DisplayConfig config = DisplayConfig(); - for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { - switch (DISPLAY_ATTRIBUTES[i]) { - case HWC_DISPLAY_VSYNC_PERIOD: - config.refresh = nsecs_t(values[i]); - break; - case HWC_DISPLAY_WIDTH: - config.width = values[i]; - break; - case HWC_DISPLAY_HEIGHT: - config.height = values[i]; - break; - case HWC_DISPLAY_DPI_X: - config.xdpi = values[i] / 1000.0f; - break; - case HWC_DISPLAY_DPI_Y: - config.ydpi = values[i] / 1000.0f; - break; - case HWC_DISPLAY_COLOR_TRANSFORM: - config.colorMode = static_cast<android_color_mode_t>(values[i]); - break; - default: - ALOG_ASSERT(false, "unknown display attribute[%zu] %#x", - i, DISPLAY_ATTRIBUTES[i]); - break; - } - } - - if (config.xdpi == 0.0f || config.ydpi == 0.0f) { - float dpi = getDefaultDensity(config.width, config.height); - config.xdpi = dpi; - config.ydpi = dpi; - } - - mDisplayData[disp].configs.push_back(config); - } - - // FIXME: what should we set the format to? - mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888; - mDisplayData[disp].connected = true; - return NO_ERROR; -} - -status_t HWComposer::setVirtualDisplayProperties(int32_t id, - uint32_t w, uint32_t h, uint32_t format) { - if (id < VIRTUAL_DISPLAY_ID_BASE || id >= int32_t(mNumDisplays) || - !mAllocatedDisplayIDs.hasBit(id)) { - return BAD_INDEX; - } - size_t configId = mDisplayData[id].currentConfig; - mDisplayData[id].format = format; - DisplayConfig& config = mDisplayData[id].configs.editItemAt(configId); - config.width = w; - config.height = h; - config.xdpi = config.ydpi = getDefaultDensity(w, h); - return NO_ERROR; -} - -int32_t HWComposer::allocateDisplayId() { - if (mAllocatedDisplayIDs.count() >= mNumDisplays) { - return NO_MEMORY; - } - int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit(); - mAllocatedDisplayIDs.markBit(id); - mDisplayData[id].connected = true; - mDisplayData[id].configs.resize(1); - mDisplayData[id].currentConfig = 0; - return id; -} - -status_t HWComposer::freeDisplayId(int32_t id) { - if (id < NUM_BUILTIN_DISPLAYS) { - // cannot free the reserved IDs - return BAD_VALUE; - } - if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { - return BAD_INDEX; - } - mAllocatedDisplayIDs.clearBit(id); - mDisplayData[id].connected = false; - return NO_ERROR; -} - -nsecs_t HWComposer::getRefreshTimestamp(int disp) const { - // this returns the last refresh timestamp. - // if the last one is not available, we estimate it based on - // the refresh period and whatever closest timestamp we have. - Mutex::Autolock _l(mLock); - nsecs_t now = systemTime(CLOCK_MONOTONIC); - size_t configId = mDisplayData[disp].currentConfig; - return now - ((now - mLastHwVSync[disp]) % - mDisplayData[disp].configs[configId].refresh); -} - -sp<Fence> HWComposer::getDisplayFence(int disp) const { - return mDisplayData[disp].lastDisplayFence; -} - -uint32_t HWComposer::getFormat(int disp) const { - if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) { - return HAL_PIXEL_FORMAT_RGBA_8888; - } else { - return mDisplayData[disp].format; - } -} - -bool HWComposer::isConnected(int disp) const { - return mDisplayData[disp].connected; -} - -uint32_t HWComposer::getWidth(int disp) const { - size_t currentConfig = mDisplayData[disp].currentConfig; - return mDisplayData[disp].configs[currentConfig].width; -} - -uint32_t HWComposer::getHeight(int disp) const { - size_t currentConfig = mDisplayData[disp].currentConfig; - return mDisplayData[disp].configs[currentConfig].height; -} - -float HWComposer::getDpiX(int disp) const { - size_t currentConfig = mDisplayData[disp].currentConfig; - return mDisplayData[disp].configs[currentConfig].xdpi; -} - -float HWComposer::getDpiY(int disp) const { - size_t currentConfig = mDisplayData[disp].currentConfig; - return mDisplayData[disp].configs[currentConfig].ydpi; -} - -nsecs_t HWComposer::getRefreshPeriod(int disp) const { - size_t currentConfig = mDisplayData[disp].currentConfig; - return mDisplayData[disp].configs[currentConfig].refresh; -} - -android_color_mode_t HWComposer::getColorMode(int disp) const { - size_t currentConfig = mDisplayData[disp].currentConfig; - return mDisplayData[disp].configs[currentConfig].colorMode; -} - -const Vector<HWComposer::DisplayConfig>& HWComposer::getConfigs(int disp) const { - return mDisplayData[disp].configs; -} - -size_t HWComposer::getCurrentConfig(int disp) const { - return mDisplayData[disp].currentConfig; -} - -void HWComposer::eventControl(int disp, int event, int enabled) { - if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) { - ALOGD("eventControl ignoring event %d on unallocated disp %d (en=%d)", - event, disp, enabled); - return; - } - if (event != EVENT_VSYNC) { - ALOGW("eventControl got unexpected event %d (disp=%d en=%d)", - event, disp, enabled); - return; - } - status_t err = NO_ERROR; - if (mHwc && !mDebugForceFakeVSync) { - // NOTE: we use our own internal lock here because we have to call - // into the HWC with the lock held, and we want to make sure - // that even if HWC blocks (which it shouldn't), it won't - // affect other threads. - Mutex::Autolock _l(mEventControlLock); - const int32_t eventBit = 1UL << event; - const int32_t newValue = enabled ? eventBit : 0; - const int32_t oldValue = mDisplayData[disp].events & eventBit; - if (newValue != oldValue) { - ATRACE_CALL(); - err = mHwc->eventControl(mHwc, disp, event, enabled); - if (!err) { - int32_t& events(mDisplayData[disp].events); - events = (events & ~eventBit) | newValue; - - char tag[16]; - snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp); - ATRACE_INT(tag, enabled); - } - } - // error here should not happen -- not sure what we should - // do if it does. - ALOGE_IF(err, "eventControl(%d, %d) failed %s", - event, enabled, strerror(-err)); - } - - if (err == NO_ERROR && mVSyncThread != NULL) { - mVSyncThread->setEnabled(enabled); - } -} - -status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { - if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { - return BAD_INDEX; - } - - if (mHwc) { - DisplayData& disp(mDisplayData[id]); - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - // we need space for the HWC_FRAMEBUFFER_TARGET - numLayers++; - } - if (disp.capacity < numLayers || disp.list == NULL) { - size_t size = sizeof(hwc_display_contents_1_t) - + numLayers * sizeof(hwc_layer_1_t); - free(disp.list); - disp.list = (hwc_display_contents_1_t*)malloc(size); - disp.capacity = numLayers; - } - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1]; - memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t)); - const DisplayConfig& currentConfig = - disp.configs[disp.currentConfig]; - const hwc_rect_t r = { 0, 0, - (int) currentConfig.width, (int) currentConfig.height }; - disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET; - disp.framebufferTarget->hints = 0; - disp.framebufferTarget->flags = 0; - disp.framebufferTarget->handle = disp.fbTargetHandle; - disp.framebufferTarget->transform = 0; - disp.framebufferTarget->blending = HWC_BLENDING_PREMULT; - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { - disp.framebufferTarget->sourceCropf.left = 0; - disp.framebufferTarget->sourceCropf.top = 0; - disp.framebufferTarget->sourceCropf.right = - currentConfig.width; - disp.framebufferTarget->sourceCropf.bottom = - currentConfig.height; - } else { - disp.framebufferTarget->sourceCrop = r; - } - disp.framebufferTarget->displayFrame = r; - disp.framebufferTarget->visibleRegionScreen.numRects = 1; - disp.framebufferTarget->visibleRegionScreen.rects = - &disp.framebufferTarget->displayFrame; - disp.framebufferTarget->acquireFenceFd = -1; - disp.framebufferTarget->releaseFenceFd = -1; - disp.framebufferTarget->planeAlpha = 0xFF; - } - disp.list->retireFenceFd = -1; - disp.list->flags = HWC_GEOMETRY_CHANGED; - disp.list->numHwLayers = numLayers; - } - return NO_ERROR; -} - -status_t HWComposer::setFramebufferTarget(int32_t id, - const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf) { - if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { - return BAD_INDEX; - } - DisplayData& disp(mDisplayData[id]); - if (!disp.framebufferTarget) { - // this should never happen, but apparently eglCreateWindowSurface() - // triggers a Surface::queueBuffer() on some - // devices (!?) -- log and ignore. - ALOGE("HWComposer: framebufferTarget is null"); - return NO_ERROR; - } - - int acquireFenceFd = -1; - if (acquireFence->isValid()) { - acquireFenceFd = acquireFence->dup(); - } - - // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd); - disp.fbTargetHandle = buf->handle; - disp.framebufferTarget->handle = disp.fbTargetHandle; - disp.framebufferTarget->acquireFenceFd = acquireFenceFd; - return NO_ERROR; -} - -status_t HWComposer::prepare() { - Mutex::Autolock _l(mDisplayLock); - for (size_t i=0 ; i<mNumDisplays ; i++) { - DisplayData& disp(mDisplayData[i]); - if (disp.framebufferTarget) { - // make sure to reset the type to HWC_FRAMEBUFFER_TARGET - // DO NOT reset the handle field to NULL, because it's possible - // that we have nothing to redraw (eg: eglSwapBuffers() not called) - // in which case, we should continue to use the same buffer. - LOG_FATAL_IF(disp.list == NULL); - disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET; - } - if (!disp.connected && disp.list != NULL) { - ALOGW("WARNING: disp %zu: connected, non-null list, layers=%zu", - i, disp.list->numHwLayers); - } - mLists[i] = disp.list; - if (mLists[i]) { - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { - mLists[i]->outbuf = disp.outbufHandle; - mLists[i]->outbufAcquireFenceFd = -1; - } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - // garbage data to catch improper use - mLists[i]->dpy = (hwc_display_t)0xDEADBEEF; - mLists[i]->sur = (hwc_surface_t)0xDEADBEEF; - } else { - mLists[i]->dpy = EGL_NO_DISPLAY; - mLists[i]->sur = EGL_NO_SURFACE; - } - } - } - - int err = mHwc->prepare(mHwc, mNumDisplays, mLists); - ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err)); - - if (err == NO_ERROR) { - // here we're just making sure that "skip" layers are set - // to HWC_FRAMEBUFFER and we're also counting how many layers - // we have of each type. - // - // If there are no window layers, we treat the display has having FB - // composition, because SurfaceFlinger will use GLES to draw the - // wormhole region. - for (size_t i=0 ; i<mNumDisplays ; i++) { - DisplayData& disp(mDisplayData[i]); - disp.hasFbComp = false; - disp.hasOvComp = false; - if (disp.list) { - for (size_t i=0 ; i<disp.list->numHwLayers ; i++) { - hwc_layer_1_t& l = disp.list->hwLayers[i]; - - //ALOGD("prepare: %d, type=%d, handle=%p", - // i, l.compositionType, l.handle); - - if (l.flags & HWC_SKIP_LAYER) { - l.compositionType = HWC_FRAMEBUFFER; - } - if (l.compositionType == HWC_FRAMEBUFFER) { - disp.hasFbComp = true; - } - if (l.compositionType == HWC_OVERLAY) { - disp.hasOvComp = true; - } - if (l.compositionType == HWC_CURSOR_OVERLAY) { - disp.hasOvComp = true; - } - } - if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) { - disp.hasFbComp = true; - } - } else { - disp.hasFbComp = true; - } - } - } - return (status_t)err; -} - -bool HWComposer::hasHwcComposition(int32_t id) const { - if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) - return false; - return mDisplayData[id].hasOvComp; -} - -bool HWComposer::hasGlesComposition(int32_t id) const { - if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) - return true; - return mDisplayData[id].hasFbComp; -} - -sp<Fence> HWComposer::getAndResetReleaseFence(int32_t id) { - if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) - return Fence::NO_FENCE; - - int fd = INVALID_OPERATION; - if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - const DisplayData& disp(mDisplayData[id]); - if (disp.framebufferTarget) { - fd = disp.framebufferTarget->releaseFenceFd; - disp.framebufferTarget->acquireFenceFd = -1; - disp.framebufferTarget->releaseFenceFd = -1; - } - } - return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE; -} - -status_t HWComposer::commit() { - int err = NO_ERROR; - if (mHwc) { - if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - // On version 1.0, the OpenGL ES target surface is communicated - // by the (dpy, sur) fields and we are guaranteed to have only - // a single display. - mLists[0]->dpy = eglGetCurrentDisplay(); - mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW); - } - - for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) { - DisplayData& disp(mDisplayData[i]); - if (disp.outbufHandle) { - mLists[i]->outbuf = disp.outbufHandle; - mLists[i]->outbufAcquireFenceFd = - disp.outbufAcquireFence->dup(); - } - } - - err = mHwc->set(mHwc, mNumDisplays, mLists); - - for (size_t i=0 ; i<mNumDisplays ; i++) { - DisplayData& disp(mDisplayData[i]); - disp.lastDisplayFence = disp.lastRetireFence; - disp.lastRetireFence = Fence::NO_FENCE; - if (disp.list) { - if (disp.list->retireFenceFd != -1) { - disp.lastRetireFence = new Fence(disp.list->retireFenceFd); - disp.list->retireFenceFd = -1; - } - disp.list->flags &= ~HWC_GEOMETRY_CHANGED; - } - } - } - return (status_t)err; -} - -status_t HWComposer::setPowerMode(int disp, int mode) { - LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE); - if (mHwc) { - if (mode == HWC_POWER_MODE_OFF) { - eventControl(disp, HWC_EVENT_VSYNC, 0); - } - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { - return (status_t)mHwc->setPowerMode(mHwc, disp, mode); - } else { - return (status_t)mHwc->blank(mHwc, disp, - mode == HWC_POWER_MODE_OFF ? 1 : 0); - } - } - return NO_ERROR; -} - -status_t HWComposer::setActiveConfig(int disp, int mode) { - LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE); - DisplayData& dd(mDisplayData[disp]); - dd.currentConfig = mode; - if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { - return (status_t)mHwc->setActiveConfig(mHwc, disp, mode); - } else { - LOG_FATAL_IF(mode != 0); - } - return NO_ERROR; -} - -void HWComposer::disconnectDisplay(int disp) { - LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY); - DisplayData& dd(mDisplayData[disp]); - free(dd.list); - dd.list = NULL; - dd.framebufferTarget = NULL; // points into dd.list - dd.fbTargetHandle = NULL; - dd.outbufHandle = NULL; - dd.lastRetireFence = Fence::NO_FENCE; - dd.lastDisplayFence = Fence::NO_FENCE; - dd.outbufAcquireFence = Fence::NO_FENCE; - // clear all the previous configs and repopulate when a new - // device is added - dd.configs.clear(); -} - -int HWComposer::getVisualID() const { - if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED - // is supported by the implementation. we can only be in this case - // if we have HWC 1.1 - return HAL_PIXEL_FORMAT_RGBA_8888; - //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; - } else { - return mFbDev->format; - } -} - -bool HWComposer::supportsFramebufferTarget() const { - return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)); -} - -int HWComposer::fbPost(int32_t id, - const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) { - if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - return setFramebufferTarget(id, acquireFence, buffer); - } else { - acquireFence->waitForever("HWComposer::fbPost"); - return mFbDev->post(mFbDev, buffer->handle); - } -} - -int HWComposer::fbCompositionComplete() { - if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) - return NO_ERROR; - - if (mFbDev->compositionComplete) { - return mFbDev->compositionComplete(mFbDev); - } else { - return INVALID_OPERATION; - } -} - -void HWComposer::fbDump(String8& result) { - if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) { - const size_t SIZE = 4096; - char buffer[SIZE]; - mFbDev->dump(mFbDev, buffer, SIZE); - result.append(buffer); - } -} - -status_t HWComposer::setOutputBuffer(int32_t id, const sp<Fence>& acquireFence, - const sp<GraphicBuffer>& buf) { - if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) - return BAD_INDEX; - if (id < VIRTUAL_DISPLAY_ID_BASE) - return INVALID_OPERATION; - - DisplayData& disp(mDisplayData[id]); - disp.outbufHandle = buf->handle; - disp.outbufAcquireFence = acquireFence; - return NO_ERROR; -} - -sp<Fence> HWComposer::getLastRetireFence(int32_t id) const { - if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) - return Fence::NO_FENCE; - return mDisplayData[id].lastRetireFence; -} - -status_t HWComposer::setCursorPositionAsync(int32_t id, const Rect& pos) -{ - if (mHwc->setCursorPositionAsync) { - return (status_t)mHwc->setCursorPositionAsync(mHwc, id, pos.left, pos.top); - } - else { - return NO_ERROR; - } -} - -/* - * Helper template to implement a concrete HWCLayer - * This holds the pointer to the concrete hwc layer type - * and implements the "iterable" side of HWCLayer. - */ -template<typename CONCRETE, typename HWCTYPE> -class Iterable : public HWComposer::HWCLayer { -protected: - HWCTYPE* const mLayerList; - HWCTYPE* mCurrentLayer; - explicit Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer), - mIndex(0) { } - inline HWCTYPE const * getLayer() const { return mCurrentLayer; } - inline HWCTYPE* getLayer() { return mCurrentLayer; } - virtual ~Iterable() { } - size_t mIndex; -private: - // returns a copy of ourselves - virtual HWComposer::HWCLayer* dup() { - return new CONCRETE( static_cast<const CONCRETE&>(*this) ); - } - virtual status_t setLayer(size_t index) { - mIndex = index; - mCurrentLayer = &mLayerList[index]; - return NO_ERROR; - } -}; - -/* - * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0. - * This implements the HWCLayer side of HWCIterableLayer. - */ -class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> { - struct hwc_composer_device_1* mHwc; -public: - HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer, - Vector<Region>* visibleRegions, - Vector<Region>* surfaceDamageRegions) - : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc), - mVisibleRegions(visibleRegions), - mSurfaceDamageRegions(surfaceDamageRegions) {} - - virtual int32_t getCompositionType() const { - return getLayer()->compositionType; - } - virtual uint32_t getHints() const { - return getLayer()->hints; - } - virtual sp<Fence> getAndResetReleaseFence() { - int fd = getLayer()->releaseFenceFd; - getLayer()->releaseFenceFd = -1; - return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE; - } - virtual void setAcquireFenceFd(int fenceFd) { - getLayer()->acquireFenceFd = fenceFd; - } - virtual void setPerFrameDefaultState() { - //getLayer()->compositionType = HWC_FRAMEBUFFER; - } - virtual void setPlaneAlpha(uint8_t alpha) { - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) { - getLayer()->planeAlpha = alpha; - } else { - if (alpha < 0xFF) { - getLayer()->flags |= HWC_SKIP_LAYER; - } - } - } - virtual void setDefaultState() { - hwc_layer_1_t* const l = getLayer(); - l->compositionType = HWC_FRAMEBUFFER; - l->hints = 0; - l->flags = HWC_SKIP_LAYER; - l->handle = 0; - l->transform = 0; - l->blending = HWC_BLENDING_NONE; - l->visibleRegionScreen.numRects = 0; - l->visibleRegionScreen.rects = NULL; - l->acquireFenceFd = -1; - l->releaseFenceFd = -1; - l->planeAlpha = 0xFF; - } - virtual void setSkip(bool skip) { - if (skip) { - getLayer()->flags |= HWC_SKIP_LAYER; - } else { - getLayer()->flags &= ~HWC_SKIP_LAYER; - } - } - virtual void setIsCursorLayerHint(bool isCursor) { - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { - if (isCursor) { - getLayer()->flags |= HWC_IS_CURSOR_LAYER; - } - else { - getLayer()->flags &= ~HWC_IS_CURSOR_LAYER; - } - } - } - virtual void setBlending(uint32_t blending) { - getLayer()->blending = blending; - } - virtual void setTransform(uint32_t transform) { - getLayer()->transform = transform; - } - virtual void setFrame(const Rect& frame) { - getLayer()->displayFrame = reinterpret_cast<hwc_rect_t const&>(frame); - } - virtual void setCrop(const FloatRect& crop) { - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { - getLayer()->sourceCropf = reinterpret_cast<hwc_frect_t const&>(crop); - } else { - /* - * Since h/w composer didn't support a flot crop rect before version 1.3, - * using integer coordinates instead produces a different output from the GL code in - * Layer::drawWithOpenGL(). The difference can be large if the buffer crop to - * window size ratio is large and a window crop is defined - * (i.e.: if we scale the buffer a lot and we also crop it with a window crop). - */ - hwc_rect_t& r = getLayer()->sourceCrop; - r.left = int(ceilf(crop.left)); - r.top = int(ceilf(crop.top)); - r.right = int(floorf(crop.right)); - r.bottom= int(floorf(crop.bottom)); - } - } - virtual void setVisibleRegionScreen(const Region& reg) { - hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen; - mVisibleRegions->editItemAt(mIndex) = reg; - visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>( - mVisibleRegions->itemAt(mIndex).getArray( - &visibleRegion.numRects)); - } - virtual void setSurfaceDamage(const Region& reg) { - if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) { - return; - } - hwc_region_t& surfaceDamage = getLayer()->surfaceDamage; - // We encode default full-screen damage as INVALID_RECT upstream, but as - // 0 rects for HWComposer - if (reg.isRect() && reg.getBounds() == Rect::INVALID_RECT) { - surfaceDamage.numRects = 0; - surfaceDamage.rects = NULL; - return; - } - mSurfaceDamageRegions->editItemAt(mIndex) = reg; - surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>( - mSurfaceDamageRegions->itemAt(mIndex).getArray( - &surfaceDamage.numRects)); - } - virtual void setSidebandStream(const sp<NativeHandle>& stream) { - ALOG_ASSERT(stream->handle() != NULL); - getLayer()->compositionType = HWC_SIDEBAND; - getLayer()->sidebandStream = stream->handle(); - } - virtual void setBuffer(const sp<GraphicBuffer>& buffer) { - if (buffer == 0 || buffer->handle == 0) { - getLayer()->compositionType = HWC_FRAMEBUFFER; - getLayer()->flags |= HWC_SKIP_LAYER; - getLayer()->handle = 0; - } else { - if (getLayer()->compositionType == HWC_SIDEBAND) { - // If this was a sideband layer but the stream was removed, reset - // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare. - getLayer()->compositionType = HWC_FRAMEBUFFER; - } - getLayer()->handle = buffer->handle; - } - } - virtual void onDisplayed() { - getLayer()->acquireFenceFd = -1; - } - -protected: - // Pointers to the vectors of Region backing-memory held in DisplayData. - // Only the Region at mIndex corresponds to this Layer. - Vector<Region>* mVisibleRegions; - Vector<Region>* mSurfaceDamageRegions; -}; - -/* - * returns an iterator initialized at a given index in the layer list - */ -HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) { - if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { - return LayerListIterator(); - } - DisplayData& disp(mDisplayData[id]); - if (!mHwc || !disp.list || index > disp.list->numHwLayers) { - return LayerListIterator(); - } - if (disp.visibleRegions.size() < disp.list->numHwLayers) { - disp.visibleRegions.resize(disp.list->numHwLayers); - } - if (disp.surfaceDamageRegions.size() < disp.list->numHwLayers) { - disp.surfaceDamageRegions.resize(disp.list->numHwLayers); - } - return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers, - &disp.visibleRegions, &disp.surfaceDamageRegions), index); -} - -/* - * returns an iterator on the beginning of the layer list - */ -HWComposer::LayerListIterator HWComposer::begin(int32_t id) { - return getLayerIterator(id, 0); -} - -/* - * returns an iterator on the end of the layer list - */ -HWComposer::LayerListIterator HWComposer::end(int32_t id) { - size_t numLayers = 0; - if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) { - const DisplayData& disp(mDisplayData[id]); - if (mHwc && disp.list) { - numLayers = disp.list->numHwLayers; - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { - // with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET, - // which we ignore when iterating through the layer list. - ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id); - if (numLayers) { - numLayers--; - } - } - } - } - return getLayerIterator(id, numLayers); -} - -// Converts a PixelFormat to a human-readable string. Max 11 chars. -// (Could use a table of prefab String8 objects.) -static String8 getFormatStr(PixelFormat format) { - switch (format) { - case PIXEL_FORMAT_RGBA_8888: return String8("RGBA_8888"); - case PIXEL_FORMAT_RGBX_8888: return String8("RGBx_8888"); - case PIXEL_FORMAT_RGBA_FP16: return String8("RGBA_FP16"); - case PIXEL_FORMAT_RGBA_1010102: return String8("RGBA_1010102"); - case PIXEL_FORMAT_RGB_888: return String8("RGB_888"); - case PIXEL_FORMAT_RGB_565: return String8("RGB_565"); - case PIXEL_FORMAT_BGRA_8888: return String8("BGRA_8888"); - case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: - return String8("ImplDef"); - default: - String8 result; - result.appendFormat("? %08x", format); - return result; - } -} - -void HWComposer::dump(String8& result) const { - Mutex::Autolock _l(mDisplayLock); - if (mHwc) { - result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc)); - result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync); - for (size_t i=0 ; i<mNumDisplays ; i++) { - const DisplayData& disp(mDisplayData[i]); - if (!disp.connected) - continue; - - const Vector< sp<Layer> >& visibleLayersSortedByZ = - mFlinger->getLayerSortedByZForHwcDisplay(i); - - - result.appendFormat(" Display[%zd] configurations (* current):\n", i); - for (size_t c = 0; c < disp.configs.size(); ++c) { - const DisplayConfig& config(disp.configs[c]); - result.appendFormat(" %s%zd: %ux%u, xdpi=%f, ydpi=%f" - ", refresh=%" PRId64 ", colorMode=%d\n", - c == disp.currentConfig ? "* " : "", c, - config.width, config.height, config.xdpi, config.ydpi, - config.refresh, config.colorMode); - } - - if (disp.list) { - result.appendFormat( - " numHwLayers=%zu, flags=%08x\n", - disp.list->numHwLayers, disp.list->flags); - - result.append( - " type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name \n" - "-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------\n"); - // " _________ | ________ | ____ | ____ | __ | ____ | ___________ |_____._,_____._,_____._,_____._ |_____,_____,_____,_____ | ___... - for (size_t i=0 ; i<disp.list->numHwLayers ; i++) { - const hwc_layer_1_t&l = disp.list->hwLayers[i]; - int32_t format = -1; - String8 name("unknown"); - - if (i < visibleLayersSortedByZ.size()) { - const sp<Layer>& layer(visibleLayersSortedByZ[i]); - const sp<GraphicBuffer>& buffer( - layer->getActiveBuffer()); - if (buffer != NULL) { - format = buffer->getPixelFormat(); - } - name = layer->getName(); - } - - int type = l.compositionType; - if (type == HWC_FRAMEBUFFER_TARGET) { - name = "HWC_FRAMEBUFFER_TARGET"; - format = disp.format; - } - - static char const* compositionTypeName[] = { - "GLES", - "HWC", - "BKGND", - "FB TARGET", - "SIDEBAND", - "HWC_CURSOR", - "UNKNOWN"}; - if (type >= NELEM(compositionTypeName)) - type = NELEM(compositionTypeName) - 1; - - String8 formatStr = getFormatStr(format); - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { - result.appendFormat( - " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7.1f,%7.1f,%7.1f,%7.1f |%5d,%5d,%5d,%5d | %s\n", - compositionTypeName[type], - intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(), - l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom, - l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom, - name.string()); - } else { - result.appendFormat( - " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7d,%7d,%7d,%7d |%5d,%5d,%5d,%5d | %s\n", - compositionTypeName[type], - intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(), - l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom, - l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom, - name.string()); - } - } - } - } - } - - if (mHwc && mHwc->dump) { - const size_t SIZE = 4096; - char buffer[SIZE]; - mHwc->dump(mHwc, buffer, SIZE); - result.append(buffer); - } -} - -// --------------------------------------------------------------------------- - -HWComposer::VSyncThread::VSyncThread(HWComposer& hwc) - : mHwc(hwc), mEnabled(false), - mNextFakeVSync(0), - mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY)) -{ -} - -void HWComposer::VSyncThread::setEnabled(bool enabled) { - Mutex::Autolock _l(mLock); - if (mEnabled != enabled) { - mEnabled = enabled; - mCondition.signal(); - } -} - -void HWComposer::VSyncThread::onFirstRef() { - run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); -} - -bool HWComposer::VSyncThread::threadLoop() { - { // scope for lock - Mutex::Autolock _l(mLock); - while (!mEnabled) { - mCondition.wait(mLock); - } - } - - const nsecs_t period = mRefreshPeriod; - const nsecs_t now = systemTime(CLOCK_MONOTONIC); - nsecs_t next_vsync = mNextFakeVSync; - nsecs_t sleep = next_vsync - now; - if (sleep < 0) { - // we missed, find where the next vsync should be - sleep = (period - ((now - next_vsync) % period)); - next_vsync = now + sleep; - } - mNextFakeVSync = next_vsync + period; - - struct timespec spec; - spec.tv_sec = next_vsync / 1000000000; - spec.tv_nsec = next_vsync % 1000000000; - - int err; - do { - err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); - } while (err<0 && errno == EINTR); - - if (err == 0) { - mHwc.mEventHandler.onVSyncReceived(&mHwc, 0, next_vsync); - } - - return true; -} - -HWComposer::DisplayData::DisplayData() -: configs(), - currentConfig(0), - format(HAL_PIXEL_FORMAT_RGBA_8888), - connected(false), - hasFbComp(false), hasOvComp(false), - capacity(0), list(NULL), - framebufferTarget(NULL), fbTargetHandle(0), - lastRetireFence(Fence::NO_FENCE), lastDisplayFence(Fence::NO_FENCE), - outbufHandle(NULL), outbufAcquireFence(Fence::NO_FENCE), - events(0) -{} - -HWComposer::DisplayData::~DisplayData() { - free(list); -} - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp b/services/surfaceflinger/DisplayHardware/PowerHAL.cpp deleted file mode 100644 index a6f076e74f..0000000000 --- a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <android/hardware/power/1.0/IPower.h> -#include <stdint.h> -#include <sys/types.h> - -#include <android/log.h> -#include <utils/Errors.h> - -#include <binder/IServiceManager.h> -#include <powermanager/IPowerManager.h> -#include <powermanager/PowerManager.h> - -#include "PowerHAL.h" - -using android::hardware::power::V1_0::PowerHint; -namespace android { -// --------------------------------------------------------------------------- - -status_t PowerHAL::vsyncHint(bool enabled) { - Mutex::Autolock _l(mlock); - if (mPowerManager == NULL) { - const String16 serviceName("power"); - sp<IBinder> bs = defaultServiceManager()->checkService(serviceName); - if (bs == NULL) { - return NAME_NOT_FOUND; - } - mPowerManager = interface_cast<IPowerManager>(bs); - } - status_t status; - status = mPowerManager->powerHint(static_cast<int>(PowerHint::VSYNC), - enabled ? 1 : 0); - if(status == DEAD_OBJECT) { - mPowerManager = NULL; - } - return status; -} - -// --------------------------------------------------------------------------- -}; // namespace android - diff --git a/services/surfaceflinger/DisplayHardware/PowerHAL.h b/services/surfaceflinger/DisplayHardware/PowerHAL.h deleted file mode 100644 index e5f82a97fc..0000000000 --- a/services/surfaceflinger/DisplayHardware/PowerHAL.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_SF_POWER_HAL_H -#define ANDROID_SF_POWER_HAL_H - -#include <stdint.h> -#include <sys/types.h> -#include <utils/Mutex.h> - -#include <powermanager/IPowerManager.h> -#include <hardware/power.h> - -namespace android { -// --------------------------------------------------------------------------- - -class PowerHAL -{ -public: - status_t vsyncHint(bool enabled); - -private: - sp<IPowerManager> mPowerManager; - Mutex mlock; -}; - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_SF_POWER_HAL_H diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 1de5e48cb9..cde96e4162 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -176,12 +176,6 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { return NO_ERROR; } -#ifndef USE_HWC2 -status_t VirtualDisplaySurface::compositionComplete() { - return NO_ERROR; -} -#endif - status_t VirtualDisplaySurface::advanceFrame() { if (mDisplayId < 0) return NO_ERROR; @@ -221,7 +215,6 @@ status_t VirtualDisplaySurface::advanceFrame() { status_t result = NO_ERROR; if (fbBuffer != NULL) { -#ifdef USE_HWC2 uint32_t hwcSlot = 0; sp<GraphicBuffer> hwcBuffer; mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer, @@ -230,9 +223,6 @@ status_t VirtualDisplaySurface::advanceFrame() { // TODO: Correctly propagate the dataspace from GL composition result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFbFence, hwcBuffer, HAL_DATASPACE_UNKNOWN); -#else - result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer); -#endif } return result; @@ -246,32 +236,20 @@ void VirtualDisplaySurface::onFrameCommitted() { "Unexpected onFrameCommitted() in %s state", dbgStateStr()); mDbgState = DBG_STATE_IDLE; -#ifdef USE_HWC2 sp<Fence> retireFence = mHwc.getPresentFence(mDisplayId); -#else - sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId); -#endif if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) { // release the scratch buffer back to the pool Mutex::Autolock lock(mMutex); int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot); -#ifdef USE_HWC2 addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], retireFence); -#else - addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence); -#endif - releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot], - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot]); } if (mOutputProducerSlot >= 0) { int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot); QueueBufferOutput qbo; -#ifndef USE_HWC2 - sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId); -#endif VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); if (mMustRecompose) { status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, @@ -280,11 +258,7 @@ void VirtualDisplaySurface::onFrameCommitted() { HAL_DATASPACE_UNKNOWN, Rect(mSinkBufferWidth, mSinkBufferHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, -#ifdef USE_HWC2 retireFence), -#else - outFence), -#endif &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(std::move(qbo)); @@ -294,11 +268,7 @@ void VirtualDisplaySurface::onFrameCommitted() { // through the motions of updating the display to keep our state // machine happy. We cancel the buffer to avoid triggering another // re-composition and causing an infinite loop. -#ifdef USE_HWC2 mSource[SOURCE_SINK]->cancelBuffer(sslot, retireFence); -#else - mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence); -#endif } } diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 1671aba1d8..5c8aceae92 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -84,9 +84,6 @@ public: // virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); -#ifndef USE_HWC2 - virtual status_t compositionComplete(); -#endif virtual status_t advanceFrame(); virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; @@ -253,10 +250,7 @@ private: bool mMustRecompose; -#ifdef USE_HWC2 HWComposerBufferCache mHwcBufferCache; -#endif - bool mForceHwcCopy; }; diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp index 052a959724..02eea4769b 100644 --- a/services/surfaceflinger/EventControlThread.cpp +++ b/services/surfaceflinger/EventControlThread.cpp @@ -53,12 +53,7 @@ bool EventControlThread::threadLoop() { } bool enable = requestedVsyncState == VsyncState::On; -#ifdef USE_HWC2 mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable); -#else - mFlinger->eventControl(HWC_DISPLAY_PRIMARY, - SurfaceFlinger::EVENT_VSYNC, enable); -#endif currentVsyncState = requestedVsyncState; } diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index f647742e2c..a1a042039c 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -34,14 +34,6 @@ // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- -// time to wait between VSYNC requests before sending a VSYNC OFF power hint: 40msec. -const long vsyncHintOffDelay = 40000000; - -static void vsyncOffCallback(union sigval val) { - EventThread *ev = (EventThread *)val.sival_ptr; - ev->sendVsyncHintOff(); - return; -} EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs) : mVSyncSource(src), @@ -49,7 +41,6 @@ EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bo mUseSoftwareVSync(false), mVsyncEnabled(false), mDebugVsyncEnabled(false), - mVsyncHintSent(false), mInterceptVSyncs(interceptVSyncs) { for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { @@ -58,18 +49,6 @@ EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bo mVSyncEvent[i].header.timestamp = 0; mVSyncEvent[i].vsync.count = 0; } - struct sigevent se; - se.sigev_notify = SIGEV_THREAD; - se.sigev_value.sival_ptr = this; - se.sigev_notify_function = vsyncOffCallback; - se.sigev_notify_attributes = NULL; - timer_create(CLOCK_MONOTONIC, &se, &mTimerId); -} - -void EventThread::sendVsyncHintOff() { - Mutex::Autolock _l(mLock); - mPowerHAL.vsyncHint(false); - mVsyncHintSent = false; } void EventThread::setPhaseOffset(nsecs_t phaseOffset) { @@ -77,19 +56,6 @@ void EventThread::setPhaseOffset(nsecs_t phaseOffset) { mVSyncSource->setPhaseOffset(phaseOffset); } -void EventThread::sendVsyncHintOnLocked() { - struct itimerspec ts; - if(!mVsyncHintSent) { - mPowerHAL.vsyncHint(true); - mVsyncHintSent = true; - } - ts.it_value.tv_sec = 0; - ts.it_value.tv_nsec = vsyncHintOffDelay; - ts.it_interval.tv_sec = 0; - ts.it_interval.tv_nsec = 0; - timer_settime(mTimerId, 0, &ts, NULL); -} - void EventThread::onFirstRef() { run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); } @@ -357,7 +323,6 @@ void EventThread::enableVSyncLocked() { } } mDebugVsyncEnabled = true; - sendVsyncHintOnLocked(); } void EventThread::disableVSyncLocked() { diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h index 6a59fbbf42..0823839ee7 100644 --- a/services/surfaceflinger/EventThread.h +++ b/services/surfaceflinger/EventThread.h @@ -29,7 +29,6 @@ #include <utils/SortedVector.h> #include "DisplayDevice.h" -#include "DisplayHardware/PowerHAL.h" // --------------------------------------------------------------------------- namespace android { @@ -99,7 +98,6 @@ public: DisplayEventReceiver::Event* event); void dump(String8& result) const; - void sendVsyncHintOff(); void setPhaseOffset(nsecs_t phaseOffset); @@ -112,11 +110,9 @@ private: void removeDisplayEventConnection(const wp<Connection>& connection); void enableVSyncLocked(); void disableVSyncLocked(); - void sendVsyncHintOnLocked(); // constants sp<VSyncSource> mVSyncSource; - PowerHAL mPowerHAL; SurfaceFlinger& mFlinger; mutable Mutex mLock; @@ -132,9 +128,7 @@ private: // for debugging bool mDebugVsyncEnabled; - bool mVsyncHintSent; const bool mInterceptVSyncs; - timer_t mTimerId; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 70c702b6d3..cc675c491b 100755..100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -19,10 +19,10 @@ #define LOG_TAG "Layer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <stdlib.h> +#include <math.h> #include <stdint.h> +#include <stdlib.h> #include <sys/types.h> -#include <math.h> #include <cutils/compiler.h> #include <cutils/native_handle.h> @@ -39,41 +39,42 @@ #include <ui/PixelFormat.h> #include <gui/BufferItem.h> -#include <gui/BufferQueue.h> #include <gui/LayerDebugInfo.h> #include <gui/Surface.h> -#include "clz.h" #include "Colorizer.h" #include "DisplayDevice.h" #include "Layer.h" #include "LayerRejecter.h" #include "MonitoredProducer.h" #include "SurfaceFlinger.h" +#include "clz.h" #include "DisplayHardware/HWComposer.h" #include "RenderEngine/RenderEngine.h" #include <mutex> +#include "LayerProtoHelper.h" -#define DEBUG_RESIZE 0 +#define DEBUG_RESIZE 0 namespace android { -// --------------------------------------------------------------------------- +LayerBE::LayerBE() + : mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) { +} + int32_t Layer::sSequence = 1; -Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, - const String8& name, uint32_t w, uint32_t h, uint32_t flags) - : contentDirty(false), +Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, + uint32_t h, uint32_t flags) + : contentDirty(false), sequence(uint32_t(android_atomic_inc(&sSequence))), mFlinger(flinger), - mTextureName(UINT32_MAX), mPremultipliedAlpha(true), - mName("unnamed"), - mFormat(PIXEL_FORMAT_NONE), + mName(name), mTransactionFlags(0), mPendingStateMutex(), mPendingStates(), @@ -81,69 +82,43 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mSidebandStreamChanged(false), mActiveBufferSlot(BufferQueue::INVALID_BUFFER_SLOT), mCurrentTransform(0), - mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mOverrideScalingMode(-1), mCurrentOpacity(true), - mBufferLatched(false), mCurrentFrameNumber(0), - mPreviousFrameNumber(0), - mRefreshPending(false), mFrameLatencyNeeded(false), mFiltering(false), mNeedsFiltering(false), - mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2), -#ifndef USE_HWC2 - mIsGlesComposition(false), -#endif mProtectedByApp(false), - mHasSurface(false), mClientRef(client), mPotentialCursor(false), mQueueItemLock(), mQueueItemCondition(), mQueueItems(), mLastFrameNumberReceived(0), - mUpdateTexImageFailed(false), mAutoRefresh(false), - mFreezeGeometryUpdates(false) -{ -#ifdef USE_HWC2 - ALOGV("Creating Layer %s", name.string()); -#endif + mFreezeGeometryUpdates(false) { mCurrentCrop.makeInvalid(); - mFlinger->getRenderEngine().genTextures(1, &mTextureName); - mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName); uint32_t layerFlags = 0; - if (flags & ISurfaceComposerClient::eHidden) - layerFlags |= layer_state_t::eLayerHidden; - if (flags & ISurfaceComposerClient::eOpaque) - layerFlags |= layer_state_t::eLayerOpaque; - if (flags & ISurfaceComposerClient::eSecure) - layerFlags |= layer_state_t::eLayerSecure; - - if (flags & ISurfaceComposerClient::eNonPremultiplied) - mPremultipliedAlpha = false; + if (flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; + if (flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; + if (flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure; mName = name; mTransactionName = String8("TX - ") + mName; mCurrentState.active.w = w; mCurrentState.active.h = h; + mCurrentState.flags = layerFlags; mCurrentState.active.transform.set(0, 0); mCurrentState.crop.makeInvalid(); mCurrentState.finalCrop.makeInvalid(); mCurrentState.requestedFinalCrop = mCurrentState.finalCrop; mCurrentState.requestedCrop = mCurrentState.crop; mCurrentState.z = 0; -#ifdef USE_HWC2 - mCurrentState.alpha = 1.0f; -#else - mCurrentState.alpha = 0xFF; -#endif + mCurrentState.color.a = 1.0f; mCurrentState.layerStack = 0; - mCurrentState.flags = layerFlags; mCurrentState.sequence = 0; mCurrentState.requested = mCurrentState.active; mCurrentState.dataSpace = HAL_DATASPACE_UNKNOWN; @@ -153,42 +128,21 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, // drawing state & current state are identical mDrawingState = mCurrentState; -#ifdef USE_HWC2 const auto& hwc = flinger->getHwComposer(); const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY); nsecs_t displayPeriod = activeConfig->getVsyncPeriod(); -#else - nsecs_t displayPeriod = - flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); -#endif mFrameTracker.setDisplayRefreshPeriod(displayPeriod); CompositorTiming compositorTiming; flinger->getCompositorTiming(&compositorTiming); mFrameEventHistory.initializeCompositorTiming(compositorTiming); -} - -void Layer::onFirstRef() { - // Creates a custom BufferQueue for SurfaceFlingerConsumer to use - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer, true); - mProducer = new MonitoredProducer(producer, mFlinger, this); - mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this); - mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); - mSurfaceFlingerConsumer->setContentsChangedListener(this); - mSurfaceFlingerConsumer->setName(mName); - - if (mFlinger->isLayerTripleBufferingDisabled()) { - mProducer->setMaxDequeuedBufferCount(2); - } - const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice()); - updateTransformHint(hw); } +void Layer::onFirstRef() {} + Layer::~Layer() { - sp<Client> c(mClientRef.promote()); + sp<Client> c(mClientRef.promote()); if (c != 0) { c->detachLayer(this); } @@ -199,103 +153,25 @@ Layer::~Layer() { for (auto& point : mLocalSyncPoints) { point->setFrameAvailable(); } - mFlinger->deleteTextureAsync(mTextureName); mFrameTracker.logAndResetStats(mName); - -#ifdef USE_HWC2 - if (!mHwcLayers.empty()) { - ALOGE("Found stale hardware composer layers when destroying " - "surface flinger layer %s", mName.string()); - destroyAllHwcLayers(); - } -#endif } // --------------------------------------------------------------------------- // callbacks // --------------------------------------------------------------------------- -#ifdef USE_HWC2 -void Layer::onLayerDisplayed(const sp<Fence>& releaseFence) { - mSurfaceFlingerConsumer->setReleaseFence(releaseFence); -} -#else -void Layer::onLayerDisplayed(const sp<const DisplayDevice>& /* hw */, - HWComposer::HWCLayerInterface* layer) { - if (layer) { - layer->onDisplayed(); - mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence()); - } -} -#endif - -void Layer::onFrameAvailable(const BufferItem& item) { - // Add this buffer from our internal queue tracker - { // Autolock scope - Mutex::Autolock lock(mQueueItemLock); - mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(), - item.mGraphicBuffer->getHeight(), item.mFrameNumber); - // Reset the frame number tracker when we receive the first buffer after - // a frame number reset - if (item.mFrameNumber == 1) { - mLastFrameNumberReceived = 0; - } - - // Ensure that callbacks are handled in order - while (item.mFrameNumber != mLastFrameNumberReceived + 1) { - status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, - ms2ns(500)); - if (result != NO_ERROR) { - ALOGE("[%s] Timed out waiting on callback", mName.string()); - } - } - - mQueueItems.push_back(item); - android_atomic_inc(&mQueuedFrames); - - // Wake up any pending callbacks - mLastFrameNumberReceived = item.mFrameNumber; - mQueueItemCondition.broadcast(); - } - - mFlinger->signalLayerUpdate(); -} - -void Layer::onFrameReplaced(const BufferItem& item) { - { // Autolock scope - Mutex::Autolock lock(mQueueItemLock); - - // Ensure that callbacks are handled in order - while (item.mFrameNumber != mLastFrameNumberReceived + 1) { - status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, - ms2ns(500)); - if (result != NO_ERROR) { - ALOGE("[%s] Timed out waiting on callback", mName.string()); - } - } - - if (mQueueItems.empty()) { - ALOGE("Can't replace a frame on an empty queue"); - return; - } - mQueueItems.editItemAt(mQueueItems.size() - 1) = item; - - // Wake up any pending callbacks - mLastFrameNumberReceived = item.mFrameNumber; - mQueueItemCondition.broadcast(); - } -} - -void Layer::onSidebandStreamChanged() { - if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) { - // mSidebandStreamChanged was false - mFlinger->signalLayerUpdate(); - } -} +/* + * onLayerDisplayed is only meaningful for BufferLayer, but, is called through + * Layer. So, the implementation is done in BufferLayer. When called on a + * ColorLayer object, it's essentially a NOP. + */ +void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {} void Layer::onRemovedFromCurrentState() { // the layer is removed from SF mCurrentState to mLayersPendingRemoval + mPendingRemoval = true; + if (mCurrentState.zOrderRelativeOf != nullptr) { sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote(); if (strongRelative != nullptr) { @@ -312,11 +188,9 @@ void Layer::onRemovedFromCurrentState() { void Layer::onRemoved() { // the layer is removed from SF mLayersPendingRemoval + abandon(); - mSurfaceFlingerConsumer->abandon(); -#ifdef USE_HWC2 destroyAllHwcLayers(); -#endif for (const auto& child : mCurrentChildren) { child->onRemoved(); @@ -331,94 +205,58 @@ const String8& Layer::getName() const { return mName; } -status_t Layer::setBuffers( uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags) -{ - uint32_t const maxSurfaceDims = min( - mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims()); - - // never allow a surface larger than what our underlying GL implementation - // can handle. - if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) { - ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h)); - return BAD_VALUE; - } - - mFormat = format; - - mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false; - mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false; - mCurrentOpacity = getOpacityForFormat(format); - - mSurfaceFlingerConsumer->setDefaultBufferSize(w, h); - mSurfaceFlingerConsumer->setDefaultBufferFormat(format); - mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); - - return NO_ERROR; +bool Layer::getPremultipledAlpha() const { + return mPremultipliedAlpha; } sp<IBinder> Layer::getHandle() { Mutex::Autolock _l(mLock); - - LOG_ALWAYS_FATAL_IF(mHasSurface, - "Layer::getHandle() has already been called"); - - mHasSurface = true; - return new Handle(mFlinger, this); } -sp<IGraphicBufferProducer> Layer::getProducer() const { - return mProducer; -} - // --------------------------------------------------------------------------- // h/w composer set-up // --------------------------------------------------------------------------- -#ifdef USE_HWC2 bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) { - LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, - "Already have a layer for hwcId %d", hwcId); + LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(hwcId) != 0, + "Already have a layer for hwcId %d", hwcId); HWC2::Layer* layer = hwc->createLayer(hwcId); if (!layer) { return false; } - HWCInfo& hwcInfo = mHwcLayers[hwcId]; + LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers[hwcId]; hwcInfo.hwc = hwc; hwcInfo.layer = layer; layer->setLayerDestroyedListener( - [this, hwcId] (HWC2::Layer* /*layer*/){mHwcLayers.erase(hwcId);}); + [this, hwcId](HWC2::Layer* /*layer*/) { getBE().mHwcLayers.erase(hwcId); }); return true; } bool Layer::destroyHwcLayer(int32_t hwcId) { - if (mHwcLayers.count(hwcId) == 0) { + if (getBE().mHwcLayers.count(hwcId) == 0) { return false; } - auto& hwcInfo = mHwcLayers[hwcId]; - LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, - "Attempt to destroy null layer"); + auto& hwcInfo = getBE().mHwcLayers[hwcId]; + LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, "Attempt to destroy null layer"); LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer"); hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer); // The layer destroyed listener should have cleared the entry from // mHwcLayers. Verify that. - LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0, - "Stale layer entry in mHwcLayers"); - + LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(hwcId) != 0, + "Stale layer entry in getBE().mHwcLayers"); return true; } void Layer::destroyAllHwcLayers() { - size_t numLayers = mHwcLayers.size(); + size_t numLayers = getBE().mHwcLayers.size(); for (size_t i = 0; i < numLayers; ++i) { - LOG_ALWAYS_FATAL_IF(mHwcLayers.empty(), "destroyAllHwcLayers failed"); - destroyHwcLayer(mHwcLayers.begin()->first); + LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.empty(), "destroyAllHwcLayers failed"); + destroyHwcLayer(getBE().mHwcLayers.begin()->first); } - LOG_ALWAYS_FATAL_IF(!mHwcLayers.empty(), - "All hardware composer layers should have been destroyed"); + LOG_ALWAYS_FATAL_IF(!getBE().mHwcLayers.empty(), + "All hardware composer layers should have been destroyed"); } -#endif Rect Layer::getContentCrop() const { // this is the crop rectangle that applies to the buffer @@ -427,9 +265,9 @@ Rect Layer::getContentCrop() const { if (!mCurrentCrop.isEmpty()) { // if the buffer crop is defined, we use that crop = mCurrentCrop; - } else if (mActiveBuffer != NULL) { + } else if (getBE().compositionInfo.mBuffer != NULL) { // otherwise we use the whole buffer - crop = mActiveBuffer->getBounds(); + crop = getBE().compositionInfo.mBuffer->getBounds(); } else { // if we don't have a buffer yet, we use an empty/invalid crop crop.makeInvalid(); @@ -447,6 +285,14 @@ static Rect reduce(const Rect& win, const Region& exclude) { return Region(win).subtract(exclude).getBounds(); } +static FloatRect reduce(const FloatRect& win, const Region& exclude) { + if (CC_LIKELY(exclude.isEmpty())) { + return win; + } + // Convert through Rect (by rounding) for lack of FloatRegion + return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect(); +} + Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const { const Layer::State& s(getDrawingState()); Rect win(s.active.w, s.active.h); @@ -485,12 +331,12 @@ Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const { return win; } -Rect Layer::computeBounds() const { +FloatRect Layer::computeBounds() const { const Layer::State& s(getDrawingState()); return computeBounds(s.activeTransparentRegion); } -Rect Layer::computeBounds(const Region& activeTransparentRegion) const { +FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const { const Layer::State& s(getDrawingState()); Rect win(s.active.w, s.active.h); @@ -507,14 +353,16 @@ Rect Layer::computeBounds(const Region& activeTransparentRegion) const { } Transform t = getTransform(); + + FloatRect floatWin = win.toFloatRect(); if (p != nullptr) { - win = t.transform(win); - win.intersect(bounds, &win); - win = t.inverse().transform(win); + floatWin = t.transform(floatWin); + floatWin = floatWin.intersect(bounds.toFloatRect()); + floatWin = t.inverse().transform(floatWin); } // subtract the transparent region and snap to the bounds - return reduce(win, activeTransparentRegion); + return reduce(floatWin, activeTransparentRegion); } Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& hw) const { @@ -540,10 +388,17 @@ Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& hw) const { activeCrop.clear(); } if (!s.finalCrop.isEmpty()) { - if(!activeCrop.intersect(s.finalCrop, &activeCrop)) { + if (!activeCrop.intersect(s.finalCrop, &activeCrop)) { activeCrop.clear(); } } + + const auto& p = mDrawingParent.promote(); + if (p != nullptr) { + auto parentCrop = p->computeInitialCrop(hw); + activeCrop.intersect(parentCrop, &activeCrop); + } + return activeCrop; } @@ -557,11 +412,6 @@ FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { // Screen space to make reduction to parent crop clearer. Rect activeCrop = computeInitialCrop(hw); - const auto& p = mDrawingParent.promote(); - if (p != nullptr) { - auto parentCrop = p->computeInitialCrop(hw); - activeCrop.intersect(parentCrop, &activeCrop); - } Transform t = getTransform(); // Back to layer space to work with the content crop. activeCrop = t.inverse().transform(activeCrop); @@ -588,16 +438,13 @@ FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { * the code below applies the primary display's inverse transform to the * buffer */ - uint32_t invTransformOrient = - DisplayDevice::getPrimaryDisplayOrientationTransform(); + uint32_t invTransformOrient = DisplayDevice::getPrimaryDisplayOrientationTransform(); // calculate the inverse transform if (invTransformOrient & NATIVE_WINDOW_TRANSFORM_ROT_90) { - invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | - NATIVE_WINDOW_TRANSFORM_FLIP_H; + invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H; } // and apply to the current transform - invTransform = (Transform(invTransformOrient) * Transform(invTransform)) - .getOrientation(); + invTransform = (Transform(invTransformOrient) * Transform(invTransform)).getOrientation(); } int winWidth = s.active.w; @@ -611,49 +458,36 @@ FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0; bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0; if (is_h_flipped == is_v_flipped) { - invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | - NATIVE_WINDOW_TRANSFORM_FLIP_H; + invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H; } winWidth = s.active.h; winHeight = s.active.w; } - const Rect winCrop = activeCrop.transform( - invTransform, s.active.w, s.active.h); + const Rect winCrop = activeCrop.transform(invTransform, s.active.w, s.active.h); // below, crop is intersected with winCrop expressed in crop's coordinate space - float xScale = crop.getWidth() / float(winWidth); + float xScale = crop.getWidth() / float(winWidth); float yScale = crop.getHeight() / float(winHeight); - float insetL = winCrop.left * xScale; - float insetT = winCrop.top * yScale; - float insetR = (winWidth - winCrop.right ) * xScale; + float insetL = winCrop.left * xScale; + float insetT = winCrop.top * yScale; + float insetR = (winWidth - winCrop.right) * xScale; float insetB = (winHeight - winCrop.bottom) * yScale; - crop.left += insetL; - crop.top += insetT; - crop.right -= insetR; + crop.left += insetL; + crop.top += insetT; + crop.right -= insetR; crop.bottom -= insetB; return crop; } -#ifdef USE_HWC2 void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z) -#else -void Layer::setGeometry( - const sp<const DisplayDevice>& hw, - HWComposer::HWCLayerInterface& layer) -#endif { -#ifdef USE_HWC2 const auto hwcId = displayDevice->getHwcDisplayId(); - auto& hwcInfo = mHwcLayers[hwcId]; -#else - layer.setDefaultState(); -#endif + auto& hwcInfo = getBE().mHwcLayers[hwcId]; // enable this layer -#ifdef USE_HWC2 hwcInfo.forceClientComposition = false; if (isSecure() && !displayDevice->isSecure()) { @@ -661,33 +495,20 @@ void Layer::setGeometry( } auto& hwcLayer = hwcInfo.layer; -#else - layer.setSkip(false); - - if (isSecure() && !hw->isSecure()) { - layer.setSkip(true); - } -#endif // this gives us only the "orientation" component of the transform const State& s(getDrawingState()); -#ifdef USE_HWC2 auto blendMode = HWC2::BlendMode::None; if (!isOpaque(s) || getAlpha() != 1.0f) { - blendMode = mPremultipliedAlpha ? - HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage; + blendMode = + mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage; } auto error = hwcLayer->setBlendMode(blendMode); - ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set blend mode %s:" - " %s (%d)", mName.string(), to_string(blendMode).c_str(), - to_string(error).c_str(), static_cast<int32_t>(error)); -#else - if (!isOpaque(s) || getAlpha() != 0xFF) { - layer.setBlending(mPremultipliedAlpha ? - HWC_BLENDING_PREMULT : - HWC_BLENDING_COVERAGE); - } -#endif + ALOGE_IF(error != HWC2::Error::None, + "[%s] Failed to set blend mode %s:" + " %s (%d)", + mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(), + static_cast<int32_t>(error)); // apply the layer's transform, followed by the display's global transform // here we're guaranteed that the layer's transform preserves rects @@ -696,11 +517,7 @@ void Layer::setGeometry( if (!s.crop.isEmpty()) { Rect activeCrop(s.crop); activeCrop = t.transform(activeCrop); -#ifdef USE_HWC2 - if(!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) { -#else - if(!activeCrop.intersect(hw->getViewport(), &activeCrop)) { -#endif + if (!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) { activeCrop.clear(); } activeCrop = t.inverse().transform(activeCrop, true); @@ -710,26 +527,25 @@ void Layer::setGeometry( // transform.inverse().transform(transform.transform(Rect)) != Rect // in which case we need to make sure the final rect is clipped to the // display bounds. - if(!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) { + if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) { activeCrop.clear(); } // mark regions outside the crop as transparent activeTransparentRegion.orSelf(Rect(0, 0, s.active.w, activeCrop.top)); - activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom, - s.active.w, s.active.h)); - activeTransparentRegion.orSelf(Rect(0, activeCrop.top, - activeCrop.left, activeCrop.bottom)); - activeTransparentRegion.orSelf(Rect(activeCrop.right, activeCrop.top, - s.active.w, activeCrop.bottom)); + activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom, s.active.w, s.active.h)); + activeTransparentRegion.orSelf(Rect(0, activeCrop.top, activeCrop.left, activeCrop.bottom)); + activeTransparentRegion.orSelf( + Rect(activeCrop.right, activeCrop.top, s.active.w, activeCrop.bottom)); } - Rect frame(t.transform(computeBounds(activeTransparentRegion))); + // computeBounds returns a FloatRect to provide more accuracy during the + // transformation. We then round upon constructing 'frame'. + Rect frame{t.transform(computeBounds(activeTransparentRegion))}; if (!s.finalCrop.isEmpty()) { - if(!frame.intersect(s.finalCrop, &frame)) { + if (!frame.intersect(s.finalCrop, &frame)) { frame.clear(); } } -#ifdef USE_HWC2 if (!frame.intersect(displayDevice->getViewport(), &frame)) { frame.clear(); } @@ -737,10 +553,9 @@ void Layer::setGeometry( Rect transformedFrame = tr.transform(frame); error = hwcLayer->setDisplayFrame(transformedFrame); if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", - mName.string(), transformedFrame.left, transformedFrame.top, - transformedFrame.right, transformedFrame.bottom, - to_string(error).c_str(), static_cast<int32_t>(error)); + ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", mName.string(), + transformedFrame.left, transformedFrame.top, transformedFrame.right, + transformedFrame.bottom, to_string(error).c_str(), static_cast<int32_t>(error)); } else { hwcInfo.displayFrame = transformedFrame; } @@ -749,23 +564,23 @@ void Layer::setGeometry( error = hwcLayer->setSourceCrop(sourceCrop); if (error != HWC2::Error::None) { ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: " - "%s (%d)", mName.string(), sourceCrop.left, sourceCrop.top, - sourceCrop.right, sourceCrop.bottom, to_string(error).c_str(), - static_cast<int32_t>(error)); + "%s (%d)", + mName.string(), sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom, + to_string(error).c_str(), static_cast<int32_t>(error)); } else { hwcInfo.sourceCrop = sourceCrop; } - float alpha = getAlpha(); + float alpha = static_cast<float>(getAlpha()); error = hwcLayer->setPlaneAlpha(alpha); - ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: " - "%s (%d)", mName.string(), alpha, to_string(error).c_str(), - static_cast<int32_t>(error)); + ALOGE_IF(error != HWC2::Error::None, + "[%s] Failed to set plane alpha %.3f: " + "%s (%d)", + mName.string(), alpha, to_string(error).c_str(), static_cast<int32_t>(error)); error = hwcLayer->setZOrder(z); - ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", - mName.string(), z, to_string(error).c_str(), - static_cast<int32_t>(error)); + ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), z, + to_string(error).c_str(), static_cast<int32_t>(error)); int type = s.type; int appId = s.appId; @@ -777,17 +592,8 @@ void Layer::setGeometry( } error = hwcLayer->setInfo(type, appId); - ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", - mName.string(), static_cast<int32_t>(error)); -#else - if (!frame.intersect(hw->getViewport(), &frame)) { - frame.clear(); - } - const Transform& tr(hw->getTransform()); - layer.setFrame(tr.transform(frame)); - layer.setCrop(computeCrop(hw)); - layer.setPlaneAlpha(getAlpha()); -#endif + ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", mName.string(), + static_cast<int32_t>(error)); /* * Transformations are applied in this order: @@ -805,12 +611,10 @@ void Layer::setGeometry( * the code below applies the primary display's inverse transform to the * buffer */ - uint32_t invTransform = - DisplayDevice::getPrimaryDisplayOrientationTransform(); + uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform(); // calculate the inverse transform if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | - NATIVE_WINDOW_TRANSFORM_FLIP_H; + invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H; } /* @@ -824,163 +628,42 @@ void Layer::setGeometry( // this gives us only the "orientation" component of the transform const uint32_t orientation = transform.getOrientation(); -#ifdef USE_HWC2 if (orientation & Transform::ROT_INVALID) { // we can only handle simple transformation hwcInfo.forceClientComposition = true; } else { auto transform = static_cast<HWC2::Transform>(orientation); auto error = hwcLayer->setTransform(transform); - ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set transform %s: " - "%s (%d)", mName.string(), to_string(transform).c_str(), - to_string(error).c_str(), static_cast<int32_t>(error)); - } -#else - if (orientation & Transform::ROT_INVALID) { - // we can only handle simple transformation - layer.setSkip(true); - } else { - layer.setTransform(orientation); + ALOGE_IF(error != HWC2::Error::None, + "[%s] Failed to set transform %s: " + "%s (%d)", + mName.string(), to_string(transform).c_str(), to_string(error).c_str(), + static_cast<int32_t>(error)); } -#endif } -#ifdef USE_HWC2 void Layer::forceClientComposition(int32_t hwcId) { - if (mHwcLayers.count(hwcId) == 0) { + if (getBE().mHwcLayers.count(hwcId) == 0) { ALOGE("forceClientComposition: no HWC layer found (%d)", hwcId); return; } - mHwcLayers[hwcId].forceClientComposition = true; + getBE().mHwcLayers[hwcId].forceClientComposition = true; } -void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) { - // Apply this display's projection's viewport to the visible region - // before giving it to the HWC HAL. - const Transform& tr = displayDevice->getTransform(); - const auto& viewport = displayDevice->getViewport(); - Region visible = tr.transform(visibleRegion.intersect(viewport)); - auto hwcId = displayDevice->getHwcDisplayId(); - auto& hwcInfo = mHwcLayers[hwcId]; - auto& hwcLayer = hwcInfo.layer; - auto error = hwcLayer->setVisibleRegion(visible); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast<int32_t>(error)); - visible.dump(LOG_TAG); - } - - error = hwcLayer->setSurfaceDamage(surfaceDamageRegion); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast<int32_t>(error)); - surfaceDamageRegion.dump(LOG_TAG); - } - - // Sideband layers - if (mSidebandStream.get()) { - setCompositionType(hwcId, HWC2::Composition::Sideband); - ALOGV("[%s] Requesting Sideband composition", mName.string()); - error = hwcLayer->setSidebandStream(mSidebandStream->handle()); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", - mName.string(), mSidebandStream->handle(), - to_string(error).c_str(), static_cast<int32_t>(error)); - } - return; - } - - // Client layers - if (hwcInfo.forceClientComposition || - (mActiveBuffer != nullptr && mActiveBuffer->handle == nullptr)) { - ALOGV("[%s] Requesting Client composition", mName.string()); - setCompositionType(hwcId, HWC2::Composition::Client); - return; - } - - // SolidColor layers - if (mActiveBuffer == nullptr) { - setCompositionType(hwcId, HWC2::Composition::SolidColor); - - // For now, we only support black for DimLayer - error = hwcLayer->setColor({0, 0, 0, 255}); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast<int32_t>(error)); - } - - // Clear out the transform, because it doesn't make sense absent a - // source buffer - error = hwcLayer->setTransform(HWC2::Transform::None); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast<int32_t>(error)); - } - - return; - } - - // Device or Cursor layers - if (mPotentialCursor) { - ALOGV("[%s] Requesting Cursor composition", mName.string()); - setCompositionType(hwcId, HWC2::Composition::Cursor); - } else { - ALOGV("[%s] Requesting Device composition", mName.string()); - setCompositionType(hwcId, HWC2::Composition::Device); - } - - ALOGV("setPerFrameData: dataspace = %d", mCurrentState.dataSpace); - error = hwcLayer->setDataspace(mCurrentState.dataSpace); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), - mCurrentState.dataSpace, to_string(error).c_str(), - static_cast<int32_t>(error)); +bool Layer::getForceClientComposition(int32_t hwcId) { + if (getBE().mHwcLayers.count(hwcId) == 0) { + ALOGE("getForceClientComposition: no HWC layer found (%d)", hwcId); + return false; } - uint32_t hwcSlot = 0; - sp<GraphicBuffer> hwcBuffer; - hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, - &hwcSlot, &hwcBuffer); - - auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence(); - error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), - mActiveBuffer->handle, to_string(error).c_str(), - static_cast<int32_t>(error)); - } -} - -#else -void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, - HWComposer::HWCLayerInterface& layer) { - // we have to set the visible region on every frame because - // we currently free it during onLayerDisplayed(), which is called - // after HWComposer::commit() -- every frame. - // Apply this display's projection's viewport to the visible region - // before giving it to the HWC HAL. - const Transform& tr = hw->getTransform(); - Region visible = tr.transform(visibleRegion.intersect(hw->getViewport())); - layer.setVisibleRegionScreen(visible); - layer.setSurfaceDamage(surfaceDamageRegion); - mIsGlesComposition = (layer.getCompositionType() == HWC_FRAMEBUFFER); - - if (mSidebandStream.get()) { - layer.setSidebandStream(mSidebandStream); - } else { - // NOTE: buffer can be NULL if the client never drew into this - // layer yet, or if we ran out of memory - layer.setBuffer(mActiveBuffer); - } + return getBE().mHwcLayers[hwcId].forceClientComposition; } -#endif -#ifdef USE_HWC2 void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) { auto hwcId = displayDevice->getHwcDisplayId(); - if (mHwcLayers.count(hwcId) == 0 || - getCompositionType(hwcId) != HWC2::Composition::Cursor) { + if (getBE().mHwcLayers.count(hwcId) == 0 || + getCompositionType(hwcId) != HWC2::Composition::Cursor) { return; } @@ -1003,284 +686,62 @@ void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) { auto& displayTransform(displayDevice->getTransform()); auto position = displayTransform.transform(frame); - auto error = mHwcLayers[hwcId].layer->setCursorPosition(position.left, - position.top); - ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set cursor position " - "to (%d, %d): %s (%d)", mName.string(), position.left, - position.top, to_string(error).c_str(), - static_cast<int32_t>(error)); -} -#else -void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */, - HWComposer::HWCLayerInterface& layer) { - int fenceFd = -1; - - // TODO: there is a possible optimization here: we only need to set the - // acquire fence the first time a new buffer is acquired on EACH display. - - if (layer.getCompositionType() == HWC_OVERLAY || layer.getCompositionType() == HWC_CURSOR_OVERLAY) { - sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence(); - if (fence->isValid()) { - fenceFd = fence->dup(); - if (fenceFd == -1) { - ALOGW("failed to dup layer fence, skipping sync: %d", errno); - } - } - } - layer.setAcquireFenceFd(fenceFd); -} - -Rect Layer::getPosition( - const sp<const DisplayDevice>& hw) -{ - // this gives us only the "orientation" component of the transform - const State& s(getCurrentState()); - - // apply the layer's transform, followed by the display's global transform - // here we're guaranteed that the layer's transform preserves rects - Rect win(s.active.w, s.active.h); - if (!s.crop.isEmpty()) { - win.intersect(s.crop, &win); - } - // subtract the transparent region and snap to the bounds - Rect bounds = reduce(win, s.activeTransparentRegion); - Rect frame(getTransform().transform(bounds)); - frame.intersect(hw->getViewport(), &frame); - if (!s.finalCrop.isEmpty()) { - frame.intersect(s.finalCrop, &frame); - } - const Transform& tr(hw->getTransform()); - return Rect(tr.transform(frame)); + auto error = getBE().mHwcLayers[hwcId].layer->setCursorPosition(position.left, + position.top); + ALOGE_IF(error != HWC2::Error::None, + "[%s] Failed to set cursor position " + "to (%d, %d): %s (%d)", + mName.string(), position.left, position.top, to_string(error).c_str(), + static_cast<int32_t>(error)); } -#endif // --------------------------------------------------------------------------- // drawing... // --------------------------------------------------------------------------- -void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const { - onDraw(hw, clip, false); -} - -void Layer::draw(const sp<const DisplayDevice>& hw, - bool useIdentityTransform) const { - onDraw(hw, Region(hw->bounds()), useIdentityTransform); -} - -void Layer::draw(const sp<const DisplayDevice>& hw) const { - onDraw(hw, Region(hw->bounds()), false); +void Layer::draw(const RenderArea& renderArea, const Region& clip) const { + onDraw(renderArea, clip, false); } -static constexpr mat4 inverseOrientation(uint32_t transform) { - const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1); - const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1); - const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1); - mat4 tr; - - if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - tr = tr * rot90; - } - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - tr = tr * flipH; - } - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - tr = tr * flipV; - } - return inverse(tr); +void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) const { + onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform); } -/* - * onDraw will draw the current layer onto the presentable buffer - */ -void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip, - bool useIdentityTransform) const -{ - ATRACE_CALL(); - - if (CC_UNLIKELY(mActiveBuffer == 0)) { - // the texture has not been created yet, this Layer has - // in fact never been drawn into. This happens frequently with - // SurfaceView because the WindowManager can't know when the client - // has drawn the first time. - - // If there is nothing under us, we paint the screen in black, otherwise - // we just skip this update. - - // figure out if there is something below us - Region under; - bool finished = false; - mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) { - if (finished || layer == static_cast<Layer const*>(this)) { - finished = true; - return; - } - under.orSelf( hw->getTransform().transform(layer->visibleRegion) ); - }); - // if not everything below us is covered, we plug the holes! - Region holes(clip.subtract(under)); - if (!holes.isEmpty()) { - clearWithOpenGL(hw, 0, 0, 0, 1); - } - return; - } - - // Bind the current buffer to the GL texture, and wait for it to be - // ready for us to draw into. - status_t err = mSurfaceFlingerConsumer->bindTextureImage(); - if (err != NO_ERROR) { - ALOGW("onDraw: bindTextureImage failed (err=%d)", err); - // Go ahead and draw the buffer anyway; no matter what we do the screen - // is probably going to have something visibly wrong. - } - - bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure()); - - RenderEngine& engine(mFlinger->getRenderEngine()); - - if (!blackOutLayer) { - // TODO: we could be more subtle with isFixedSize() - const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize(); - - // Query the texture matrix given our current filtering mode. - float textureMatrix[16]; - mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering); - mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix); - - if (getTransformToDisplayInverse()) { - - /* - * the code below applies the primary display's inverse transform to - * the texture transform - */ - uint32_t transform = - DisplayDevice::getPrimaryDisplayOrientationTransform(); - mat4 tr = inverseOrientation(transform); - - /** - * TODO(b/36727915): This is basically a hack. - * - * Ensure that regardless of the parent transformation, - * this buffer is always transformed from native display - * orientation to display orientation. For example, in the case - * of a camera where the buffer remains in native orientation, - * we want the pixels to always be upright. - */ - sp<Layer> p = mDrawingParent.promote(); - if (p != nullptr) { - const auto parentTransform = p->getTransform(); - tr = tr * inverseOrientation(parentTransform.getOrientation()); - } - - // and finally apply it to the original texture matrix - const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr); - memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); - } - - // Set things up for texturing. - mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); - mTexture.setFiltering(useFiltering); - mTexture.setMatrix(textureMatrix); - - engine.setupLayerTexturing(mTexture); - } else { - engine.setupLayerBlackedOut(); - } - drawWithOpenGL(hw, useIdentityTransform); - engine.disableTexturing(); +void Layer::draw(const RenderArea& renderArea) const { + onDraw(renderArea, Region(renderArea.getBounds()), false); } - -void Layer::clearWithOpenGL(const sp<const DisplayDevice>& hw, - float red, float green, float blue, - float alpha) const -{ +void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue, + float alpha) const { RenderEngine& engine(mFlinger->getRenderEngine()); - computeGeometry(hw, mMesh, false); + computeGeometry(renderArea, getBE().mMesh, false); engine.setupFillWithColor(red, green, blue, alpha); - engine.drawMesh(mMesh); -} - -void Layer::clearWithOpenGL( - const sp<const DisplayDevice>& hw) const { - clearWithOpenGL(hw, 0,0,0,0); + engine.drawMesh(getBE().mMesh); } -void Layer::drawWithOpenGL(const sp<const DisplayDevice>& hw, - bool useIdentityTransform) const { - const State& s(getDrawingState()); - - computeGeometry(hw, mMesh, useIdentityTransform); - - /* - * NOTE: the way we compute the texture coordinates here produces - * different results than when we take the HWC path -- in the later case - * the "source crop" is rounded to texel boundaries. - * This can produce significantly different results when the texture - * is scaled by a large amount. - * - * The GL code below is more logical (imho), and the difference with - * HWC is due to a limitation of the HWC API to integers -- a question - * is suspend is whether we should ignore this problem or revert to - * GL composition when a buffer scaling is applied (maybe with some - * minimal value)? Or, we could make GL behave like HWC -- but this feel - * like more of a hack. - */ - Rect win(computeBounds()); - - Transform t = getTransform(); - if (!s.finalCrop.isEmpty()) { - win = t.transform(win); - if (!win.intersect(s.finalCrop, &win)) { - win.clear(); - } - win = t.inverse().transform(win); - if (!win.intersect(computeBounds(), &win)) { - win.clear(); - } - } - - float left = float(win.left) / float(s.active.w); - float top = float(win.top) / float(s.active.h); - float right = float(win.right) / float(s.active.w); - float bottom = float(win.bottom) / float(s.active.h); - - // TODO: we probably want to generate the texture coords with the mesh - // here we assume that we only have 4 vertices - Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>()); - texCoords[0] = vec2(left, 1.0f - top); - texCoords[1] = vec2(left, 1.0f - bottom); - texCoords[2] = vec2(right, 1.0f - bottom); - texCoords[3] = vec2(right, 1.0f - top); - - RenderEngine& engine(mFlinger->getRenderEngine()); - engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), getAlpha()); -#ifdef USE_HWC2 - engine.setSourceDataSpace(mCurrentState.dataSpace); -#endif - engine.drawMesh(mMesh); - engine.disableBlending(); +void Layer::clearWithOpenGL(const RenderArea& renderArea) const { + clearWithOpenGL(renderArea, 0, 0, 0, 0); } -#ifdef USE_HWC2 -void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type, - bool callIntoHwc) { - if (mHwcLayers.count(hwcId) == 0) { +void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc) { + if (getBE().mHwcLayers.count(hwcId) == 0) { ALOGE("setCompositionType called without a valid HWC layer"); return; } - auto& hwcInfo = mHwcLayers[hwcId]; + auto& hwcInfo = getBE().mHwcLayers[hwcId]; auto& hwcLayer = hwcInfo.layer; - ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(), - to_string(type).c_str(), static_cast<int>(callIntoHwc)); + ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(), to_string(type).c_str(), + static_cast<int>(callIntoHwc)); if (hwcInfo.compositionType != type) { ALOGV(" actually setting"); hwcInfo.compositionType = type; if (callIntoHwc) { auto error = hwcLayer->setCompositionType(type); - ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set " - "composition type %s: %s (%d)", mName.string(), - to_string(type).c_str(), to_string(error).c_str(), - static_cast<int32_t>(error)); + ALOGE_IF(error != HWC2::Error::None, + "[%s] Failed to set " + "composition type %s: %s (%d)", + mName.string(), to_string(type).c_str(), to_string(error).c_str(), + static_cast<int32_t>(error)); } } } @@ -1291,86 +752,27 @@ HWC2::Composition Layer::getCompositionType(int32_t hwcId) const { // have a HWC counterpart, then it will always be Client return HWC2::Composition::Client; } - if (mHwcLayers.count(hwcId) == 0) { + if (getBE().mHwcLayers.count(hwcId) == 0) { ALOGE("getCompositionType called with an invalid HWC layer"); return HWC2::Composition::Invalid; } - return mHwcLayers.at(hwcId).compositionType; + return getBE().mHwcLayers.at(hwcId).compositionType; } void Layer::setClearClientTarget(int32_t hwcId, bool clear) { - if (mHwcLayers.count(hwcId) == 0) { + if (getBE().mHwcLayers.count(hwcId) == 0) { ALOGE("setClearClientTarget called without a valid HWC layer"); return; } - mHwcLayers[hwcId].clearClientTarget = clear; + getBE().mHwcLayers[hwcId].clearClientTarget = clear; } bool Layer::getClearClientTarget(int32_t hwcId) const { - if (mHwcLayers.count(hwcId) == 0) { + if (getBE().mHwcLayers.count(hwcId) == 0) { ALOGE("getClearClientTarget called without a valid HWC layer"); return false; } - return mHwcLayers.at(hwcId).clearClientTarget; -} -#endif - -uint32_t Layer::getProducerStickyTransform() const { - int producerStickyTransform = 0; - int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform); - if (ret != OK) { - ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__, - strerror(-ret), ret); - return 0; - } - return static_cast<uint32_t>(producerStickyTransform); -} - -bool Layer::latchUnsignaledBuffers() { - static bool propertyLoaded = false; - static bool latch = false; - static std::mutex mutex; - std::lock_guard<std::mutex> lock(mutex); - if (!propertyLoaded) { - char value[PROPERTY_VALUE_MAX] = {}; - property_get("debug.sf.latch_unsignaled", value, "0"); - latch = atoi(value); - propertyLoaded = true; - } - return latch; -} - -uint64_t Layer::getHeadFrameNumber() const { - Mutex::Autolock lock(mQueueItemLock); - if (!mQueueItems.empty()) { - return mQueueItems[0].mFrameNumber; - } else { - return mCurrentFrameNumber; - } -} - -bool Layer::headFenceHasSignaled() const { -#ifdef USE_HWC2 - if (latchUnsignaledBuffers()) { - return true; - } - - Mutex::Autolock lock(mQueueItemLock); - if (mQueueItems.empty()) { - return true; - } - if (mQueueItems[0].mIsDroppable) { - // Even though this buffer's fence may not have signaled yet, it could - // be replaced by another buffer before it has a chance to, which means - // that it's possible to get into a situation where a buffer is never - // able to be latched. To avoid this, grab this buffer anyway. - return true; - } - return mQueueItems[0].mFenceTime->getSignalTime() != - Fence::SIGNAL_TIME_PENDING; -#else - return true; -#endif + return getBE().mHwcLayers.at(hwcId).clearClientTarget; } bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) { @@ -1393,28 +795,6 @@ bool Layer::getFiltering() const { return mFiltering; } -// As documented in libhardware header, formats in the range -// 0x100 - 0x1FF are specific to the HAL implementation, and -// are known to have no alpha channel -// TODO: move definition for device-specific range into -// hardware.h, instead of using hard-coded values here. -#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF) - -bool Layer::getOpacityForFormat(uint32_t format) { - if (HARDWARE_IS_DEVICE_FORMAT(format)) { - return true; - } - switch (format) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_BGRA_8888: - case HAL_PIXEL_FORMAT_RGBA_FP16: - case HAL_PIXEL_FORMAT_RGBA_1010102: - return false; - } - // in all other case, we have no blending (also for unknown formats) - return true; -} - // ---------------------------------------------------------------------------- // local state // ---------------------------------------------------------------------------- @@ -1434,13 +814,12 @@ static void boundPoint(vec2* point, const Rect& crop) { } } -void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, - bool useIdentityTransform) const -{ +void Layer::computeGeometry(const RenderArea& renderArea, Mesh& mesh, + bool useIdentityTransform) const { const Layer::State& s(getDrawingState()); - const Transform hwTransform(hw->getTransform()); - const uint32_t hw_h = hw->getHeight(); - Rect win = computeBounds(); + const Transform renderAreaTransform(renderArea.getTransform()); + const uint32_t height = renderArea.getHeight(); + FloatRect win = computeBounds(); vec2 lt = vec2(win.left, win.top); vec2 lb = vec2(win.left, win.bottom); @@ -1463,53 +842,20 @@ void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, } Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - position[0] = hwTransform.transform(lt); - position[1] = hwTransform.transform(lb); - position[2] = hwTransform.transform(rb); - position[3] = hwTransform.transform(rt); - for (size_t i=0 ; i<4 ; i++) { - position[i].y = hw_h - position[i].y; + position[0] = renderAreaTransform.transform(lt); + position[1] = renderAreaTransform.transform(lb); + position[2] = renderAreaTransform.transform(rb); + position[3] = renderAreaTransform.transform(rt); + for (size_t i = 0; i < 4; i++) { + position[i].y = height - position[i].y; } } -bool Layer::isOpaque(const Layer::State& s) const -{ - // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the - // layer's opaque flag. - if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) { - return false; - } - - // if the layer has the opaque flag, then we're always opaque, - // otherwise we use the current buffer's format. - return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity; -} - -bool Layer::isSecure() const -{ +bool Layer::isSecure() const { const Layer::State& s(mDrawingState); return (s.flags & layer_state_t::eLayerSecure); } -bool Layer::isProtected() const -{ - const sp<GraphicBuffer>& activeBuffer(mActiveBuffer); - return (activeBuffer != 0) && - (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED); -} - -bool Layer::isFixedSize() const { - return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE; -} - -bool Layer::isCropped() const { - return !mCurrentCrop.isEmpty(); -} - -bool Layer::needsFiltering(const sp<const DisplayDevice>& hw) const { - return mNeedsFiltering || hw->needsFiltering(); -} - void Layer::setVisibleRegion(const Region& visibleRegion) { // always called from main thread this->visibleRegion = visibleRegion; @@ -1520,8 +866,7 @@ void Layer::setCoveredRegion(const Region& coveredRegion) { this->coveredRegion = coveredRegion; } -void Layer::setVisibleNonTransparentRegion(const Region& - setVisibleNonTransparentRegion) { +void Layer::setVisibleNonTransparentRegion(const Region& setVisibleNonTransparentRegion) { // always called from main thread this->visibleNonTransparentRegion = setVisibleNonTransparentRegion; } @@ -1546,8 +891,7 @@ void Layer::pushPendingState() { // to be applied as per normal (no synchronization). mCurrentState.barrierLayer = nullptr; } else { - auto syncPoint = std::make_shared<SyncPoint>( - mCurrentState.frameNumber); + auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber); if (barrierLayer->addSyncPoint(syncPoint)) { mRemoteSyncPoints.push_back(std::move(syncPoint)); } else { @@ -1568,8 +912,8 @@ void Layer::pushPendingState() { void Layer::popPendingState(State* stateToCommit) { auto oldFlags = stateToCommit->flags; *stateToCommit = mPendingStates[0]; - stateToCommit->flags = (oldFlags & ~stateToCommit->mask) | - (stateToCommit->flags & stateToCommit->mask); + stateToCommit->flags = + (oldFlags & ~stateToCommit->mask) | (stateToCommit->flags & stateToCommit->mask); mPendingStates.removeAt(0); ATRACE_INT(mTransactionName.string(), mPendingStates.size()); @@ -1589,10 +933,8 @@ bool Layer::applyPendingStates(State* stateToCommit) { continue; } - if (mRemoteSyncPoints.front()->getFrameNumber() != - mPendingStates[0].frameNumber) { - ALOGE("[%s] Unexpected sync point frame number found", - mName.string()); + if (mRemoteSyncPoints.front()->getFrameNumber() != mPendingStates[0].frameNumber) { + ALOGE("[%s] Unexpected sync point frame number found", mName.string()); // Signal our end of the sync point and then dispose of it mRemoteSyncPoints.front()->setTransactionApplied(); @@ -1628,17 +970,6 @@ bool Layer::applyPendingStates(State* stateToCommit) { return stateUpdateAvailable; } -void Layer::notifyAvailableFrames() { - auto headFrameNumber = getHeadFrameNumber(); - bool headFenceSignaled = headFenceHasSignaled(); - Mutex::Autolock lock(mLocalSyncPointMutex); - for (auto& point : mLocalSyncPoints) { - if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) { - point->setFrameAvailable(); - } - } -} - uint32_t Layer::doTransaction(uint32_t flags) { ATRACE_CALL(); @@ -1650,59 +981,50 @@ uint32_t Layer::doTransaction(uint32_t flags) { const Layer::State& s(getDrawingState()); - const bool sizeChanged = (c.requested.w != s.requested.w) || - (c.requested.h != s.requested.h); + const bool sizeChanged = (c.requested.w != s.requested.w) || (c.requested.h != s.requested.h); if (sizeChanged) { // the size changed, we need to ask our client to request a new buffer ALOGD_IF(DEBUG_RESIZE, - "doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n" - " current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" - " requested={ wh={%4u,%4u} }}\n" - " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" - " requested={ wh={%4u,%4u} }}\n", - this, getName().string(), mCurrentTransform, - getEffectiveScalingMode(), - c.active.w, c.active.h, - c.crop.left, - c.crop.top, - c.crop.right, - c.crop.bottom, - c.crop.getWidth(), - c.crop.getHeight(), - c.requested.w, c.requested.h, - s.active.w, s.active.h, - s.crop.left, - s.crop.top, - s.crop.right, - s.crop.bottom, - s.crop.getWidth(), - s.crop.getHeight(), - s.requested.w, s.requested.h); + "doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n" + " current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" + " requested={ wh={%4u,%4u} }}\n" + " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" + " requested={ wh={%4u,%4u} }}\n", + this, getName().string(), mCurrentTransform, + getEffectiveScalingMode(), c.active.w, c.active.h, c.crop.left, c.crop.top, + c.crop.right, c.crop.bottom, c.crop.getWidth(), c.crop.getHeight(), c.requested.w, + c.requested.h, s.active.w, s.active.h, s.crop.left, s.crop.top, s.crop.right, + s.crop.bottom, s.crop.getWidth(), s.crop.getHeight(), s.requested.w, + s.requested.h); // record the new size, form this point on, when the client request // a buffer, it'll get the new size. - mSurfaceFlingerConsumer->setDefaultBufferSize( - c.requested.w, c.requested.h); - } - - const bool resizePending = (c.requested.w != c.active.w) || - (c.requested.h != c.active.h); + setDefaultBufferSize(c.requested.w, c.requested.h); + } + + // Don't let Layer::doTransaction update the drawing state + // if we have a pending resize, unless we are in fixed-size mode. + // the drawing state will be updated only once we receive a buffer + // with the correct size. + // + // In particular, we want to make sure the clip (which is part + // of the geometry state) is latched together with the size but is + // latched immediately when no resizing is involved. + // + // If a sideband stream is attached, however, we want to skip this + // optimization so that transactions aren't missed when a buffer + // never arrives + // + // In the case that we don't have a buffer we ignore other factors + // and avoid entering the resizePending state. At a high level the + // resizePending state is to avoid applying the state of the new buffer + // to the old buffer. However in the state where we don't have an old buffer + // there is no such concern but we may still be being used as a parent layer. + const bool resizePending = ((c.requested.w != c.active.w) || (c.requested.h != c.active.h)) && + (getBE().compositionInfo.mBuffer != nullptr); if (!isFixedSize()) { - if (resizePending && mSidebandStream == NULL) { - // don't let Layer::doTransaction update the drawing state - // if we have a pending resize, unless we are in fixed-size mode. - // the drawing state will be updated only once we receive a buffer - // with the correct size. - // - // in particular, we want to make sure the clip (which is part - // of the geometry state) is latched together with the size but is - // latched immediately when no resizing is involved. - // - // If a sideband stream is attached, however, we want to skip this - // optimization so that transactions aren't missed when a buffer - // never arrives - + if (resizePending && getBE().compositionInfo.hwc.sidebandStream == nullptr) { flags |= eDontUpdateGeometryState; } } @@ -1749,8 +1071,7 @@ uint32_t Layer::doTransaction(uint32_t flags) { // we may use linear filtering, if the matrix scales us const uint8_t type = c.active.transform.getType(); - mNeedsFiltering = (!c.active.transform.preserveRects() || - (type >= Transform::SCALE)); + mNeedsFiltering = (!c.active.transform.preserveRects() || (type >= Transform::SCALE)); } // If the layer is hidden, signal and clear out all local sync points so @@ -1808,13 +1129,27 @@ bool Layer::setChildLayer(const sp<Layer>& childLayer, int32_t z) { if (childLayer->setLayer(z)) { mCurrentChildren.removeAt(idx); mCurrentChildren.add(childLayer); + return true; } - return true; + return false; } -bool Layer::setLayer(int32_t z) { - if (mCurrentState.z == z) +bool Layer::setChildRelativeLayer(const sp<Layer>& childLayer, + const sp<IBinder>& relativeToHandle, int32_t relativeZ) { + ssize_t idx = mCurrentChildren.indexOf(childLayer); + if (idx < 0) { return false; + } + if (childLayer->setRelativeLayer(relativeToHandle, relativeZ)) { + mCurrentChildren.removeAt(idx); + mCurrentChildren.add(childLayer); + return true; + } + return false; +} + +bool Layer::setLayer(int32_t z) { + if (mCurrentState.z == z && !usingRelativeZ(LayerVector::StateSet::Current)) return false; mCurrentState.sequence++; mCurrentState.z = z; mCurrentState.modified = true; @@ -1845,7 +1180,7 @@ void Layer::addZOrderRelative(const wp<Layer>& relative) { setTransactionFlags(eTransactionNeeded); } -bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t z) { +bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) { sp<Handle> handle = static_cast<Handle*>(relativeToHandle.get()); if (handle == nullptr) { return false; @@ -1855,10 +1190,19 @@ bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t z) { return false; } + if (mCurrentState.z == relativeZ && usingRelativeZ(LayerVector::StateSet::Current) && + mCurrentState.zOrderRelativeOf == relative) { + return false; + } + mCurrentState.sequence++; mCurrentState.modified = true; - mCurrentState.z = z; + mCurrentState.z = relativeZ; + auto oldZOrderRelativeOf = mCurrentState.zOrderRelativeOf.promote(); + if (oldZOrderRelativeOf != nullptr) { + oldZOrderRelativeOf->removeZOrderRelative(this); + } mCurrentState.zOrderRelativeOf = relative; relative->addZOrderRelative(this); @@ -1868,31 +1212,39 @@ bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t z) { } bool Layer::setSize(uint32_t w, uint32_t h) { - if (mCurrentState.requested.w == w && mCurrentState.requested.h == h) - return false; + if (mCurrentState.requested.w == w && mCurrentState.requested.h == h) return false; mCurrentState.requested.w = w; mCurrentState.requested.h = h; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } -#ifdef USE_HWC2 bool Layer::setAlpha(float alpha) { -#else -bool Layer::setAlpha(uint8_t alpha) { -#endif - if (mCurrentState.alpha == alpha) + if (mCurrentState.color.a == alpha) return false; + mCurrentState.sequence++; + mCurrentState.color.a = alpha; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setColor(const half3& color) { + if (color.r == mCurrentState.color.r && color.g == mCurrentState.color.g && + color.b == mCurrentState.color.b) return false; + mCurrentState.sequence++; - mCurrentState.alpha = alpha; + mCurrentState.color.r = color.r; + mCurrentState.color.g = color.g; + mCurrentState.color.b = color.b; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } + bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) { mCurrentState.sequence++; - mCurrentState.requested.transform.set( - matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); + mCurrentState.requested.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; @@ -1905,8 +1257,7 @@ bool Layer::setTransparentRegionHint(const Region& transparent) { } bool Layer::setFlags(uint8_t flags, uint8_t mask) { const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask); - if (mCurrentState.flags == newFlags) - return false; + if (mCurrentState.flags == newFlags) return false; mCurrentState.sequence++; mCurrentState.flags = newFlags; mCurrentState.mask = mask; @@ -1916,8 +1267,7 @@ bool Layer::setFlags(uint8_t flags, uint8_t mask) { } bool Layer::setCrop(const Rect& crop, bool immediate) { - if (mCurrentState.requestedCrop == crop) - return false; + if (mCurrentState.requestedCrop == crop) return false; mCurrentState.sequence++; mCurrentState.requestedCrop = crop; if (immediate && !mFreezeGeometryUpdates) { @@ -1931,8 +1281,7 @@ bool Layer::setCrop(const Rect& crop, bool immediate) { } bool Layer::setFinalCrop(const Rect& crop, bool immediate) { - if (mCurrentState.requestedFinalCrop == crop) - return false; + if (mCurrentState.requestedFinalCrop == crop) return false; mCurrentState.sequence++; mCurrentState.requestedFinalCrop = crop; if (immediate && !mFreezeGeometryUpdates) { @@ -1946,30 +1295,21 @@ bool Layer::setFinalCrop(const Rect& crop, bool immediate) { } bool Layer::setOverrideScalingMode(int32_t scalingMode) { - if (scalingMode == mOverrideScalingMode) - return false; + if (scalingMode == mOverrideScalingMode) return false; mOverrideScalingMode = scalingMode; setTransactionFlags(eTransactionNeeded); return true; } void Layer::setInfo(uint32_t type, uint32_t appId) { - mCurrentState.appId = appId; - mCurrentState.type = type; - mCurrentState.modified = true; - setTransactionFlags(eTransactionNeeded); -} - -uint32_t Layer::getEffectiveScalingMode() const { - if (mOverrideScalingMode >= 0) { - return mOverrideScalingMode; - } - return mCurrentScalingMode; + mCurrentState.appId = appId; + mCurrentState.type = type; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); } bool Layer::setLayerStack(uint32_t layerStack) { - if (mCurrentState.layerStack == layerStack) - return false; + if (mCurrentState.layerStack == layerStack) return false; mCurrentState.sequence++; mCurrentState.layerStack = layerStack; mCurrentState.modified = true; @@ -1978,8 +1318,7 @@ bool Layer::setLayerStack(uint32_t layerStack) { } bool Layer::setDataSpace(android_dataspace dataSpace) { - if (mCurrentState.dataSpace == dataSpace) - return false; + if (mCurrentState.dataSpace == dataSpace) return false; mCurrentState.sequence++; mCurrentState.dataSpace = dataSpace; mCurrentState.modified = true; @@ -1999,8 +1338,7 @@ uint32_t Layer::getLayerStack() const { return p->getLayerStack(); } -void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer, - uint64_t frameNumber) { +void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber) { mCurrentState.barrierLayer = barrierLayer; mCurrentState.frameNumber = frameNumber; // We don't set eTransactionNeeded, because just receiving a deferral @@ -2012,124 +1350,16 @@ void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer, mCurrentState.modified = false; } -void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle, - uint64_t frameNumber) { +void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber) { sp<Handle> handle = static_cast<Handle*>(barrierHandle.get()); deferTransactionUntil(handle->owner.promote(), frameNumber); } -void Layer::useSurfaceDamage() { - if (mFlinger->mForceFullDamage) { - surfaceDamageRegion = Region::INVALID_REGION; - } else { - surfaceDamageRegion = mSurfaceFlingerConsumer->getSurfaceDamage(); - } -} - -void Layer::useEmptyDamage() { - surfaceDamageRegion.clear(); -} // ---------------------------------------------------------------------------- // pageflip handling... // ---------------------------------------------------------------------------- -bool Layer::shouldPresentNow(const DispSync& dispSync) const { - if (mSidebandStreamChanged || mAutoRefresh) { - return true; - } - - Mutex::Autolock lock(mQueueItemLock); - if (mQueueItems.empty()) { - return false; - } - auto timestamp = mQueueItems[0].mTimestamp; - nsecs_t expectedPresent = - mSurfaceFlingerConsumer->computeExpectedPresent(dispSync); - - // Ignore timestamps more than a second in the future - bool isPlausible = timestamp < (expectedPresent + s2ns(1)); - ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible " - "relative to expectedPresent %" PRId64, mName.string(), timestamp, - expectedPresent); - - bool isDue = timestamp < expectedPresent; - return isDue || !isPlausible; -} - -bool Layer::onPreComposition(nsecs_t refreshStartTime) { - if (mBufferLatched) { - Mutex::Autolock lock(mFrameEventHistoryMutex); - mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime); - } - mRefreshPending = false; - return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh; -} - -bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence, - const std::shared_ptr<FenceTime>& presentFence, - const CompositorTiming& compositorTiming) { - // mFrameLatencyNeeded is true when a new frame was latched for the - // composition. - if (!mFrameLatencyNeeded) - return false; - - // Update mFrameEventHistory. - { - Mutex::Autolock lock(mFrameEventHistoryMutex); - mFrameEventHistory.addPostComposition(mCurrentFrameNumber, - glDoneFence, presentFence, compositorTiming); - } - - // Update mFrameTracker. - nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp(); - mFrameTracker.setDesiredPresentTime(desiredPresentTime); - - std::shared_ptr<FenceTime> frameReadyFence = - mSurfaceFlingerConsumer->getCurrentFenceTime(); - if (frameReadyFence->isValid()) { - mFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); - } else { - // There was no fence for this frame, so assume that it was ready - // to be presented at the desired present time. - mFrameTracker.setFrameReadyTime(desiredPresentTime); - } - - if (presentFence->isValid()) { - mFrameTracker.setActualPresentFence( - std::shared_ptr<FenceTime>(presentFence)); - } else { - // The HWC doesn't support present fences, so use the refresh - // timestamp instead. - mFrameTracker.setActualPresentTime( - mFlinger->getHwComposer().getRefreshTimestamp( - HWC_DISPLAY_PRIMARY)); - } - - mFrameTracker.advanceFrame(); - mFrameLatencyNeeded = false; - return true; -} - -#ifdef USE_HWC2 -void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { - if (!mSurfaceFlingerConsumer->releasePendingBuffer()) { - return; - } - - auto releaseFenceTime = std::make_shared<FenceTime>( - mSurfaceFlingerConsumer->getPrevFinalReleaseFence()); - mReleaseTimeline.updateSignalTimes(); - mReleaseTimeline.push(releaseFenceTime); - - Mutex::Autolock lock(mFrameEventHistoryMutex); - if (mPreviousFrameNumber != 0) { - mFrameEventHistory.addRelease(mPreviousFrameNumber, - dequeueReadyTime, std::move(releaseFenceTime)); - } -} -#endif - bool Layer::isHiddenByPolicy() const { const Layer::State& s(mDrawingState); const auto& parent = mDrawingParent.promote(); @@ -2139,256 +1369,7 @@ bool Layer::isHiddenByPolicy() const { return s.flags & layer_state_t::eLayerHidden; } -bool Layer::isVisible() const { -#ifdef USE_HWC2 - return !(isHiddenByPolicy()) && getAlpha() > 0.0f - && (mActiveBuffer != NULL || mSidebandStream != NULL); -#else - return !(isHiddenByPolicy()) && getAlpha() - && (mActiveBuffer != NULL || mSidebandStream != NULL); -#endif -} - -bool Layer::allTransactionsSignaled() { - auto headFrameNumber = getHeadFrameNumber(); - bool matchingFramesFound = false; - bool allTransactionsApplied = true; - Mutex::Autolock lock(mLocalSyncPointMutex); - - for (auto& point : mLocalSyncPoints) { - if (point->getFrameNumber() > headFrameNumber) { - break; - } - matchingFramesFound = true; - - if (!point->frameIsAvailable()) { - // We haven't notified the remote layer that the frame for - // this point is available yet. Notify it now, and then - // abort this attempt to latch. - point->setFrameAvailable(); - allTransactionsApplied = false; - break; - } - - allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied(); - } - return !matchingFramesFound || allTransactionsApplied; -} - -Region Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) -{ - ATRACE_CALL(); - - if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) { - // mSidebandStreamChanged was true - mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream(); - if (mSidebandStream != NULL) { - setTransactionFlags(eTransactionNeeded); - mFlinger->setTransactionFlags(eTraversalNeeded); - } - recomputeVisibleRegions = true; - - const State& s(getDrawingState()); - return getTransform().transform(Region(Rect(s.active.w, s.active.h))); - } - - Region outDirtyRegion; - if (mQueuedFrames <= 0 && !mAutoRefresh) { - return outDirtyRegion; - } - - // if we've already called updateTexImage() without going through - // a composition step, we have to skip this layer at this point - // because we cannot call updateTeximage() without a corresponding - // compositionComplete() call. - // we'll trigger an update in onPreComposition(). - if (mRefreshPending) { - return outDirtyRegion; - } - - // If the head buffer's acquire fence hasn't signaled yet, return and - // try again later - if (!headFenceHasSignaled()) { - mFlinger->signalLayerUpdate(); - return outDirtyRegion; - } - - // Capture the old state of the layer for comparisons later - const State& s(getDrawingState()); - const bool oldOpacity = isOpaque(s); - sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer; - - if (!allTransactionsSignaled()) { - mFlinger->signalLayerUpdate(); - return outDirtyRegion; - } - - // This boolean is used to make sure that SurfaceFlinger's shadow copy - // of the buffer queue isn't modified when the buffer queue is returning - // BufferItem's that weren't actually queued. This can happen in shared - // buffer mode. - bool queuedBuffer = false; - LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions, - getProducerStickyTransform() != 0, mName.string(), - mOverrideScalingMode, mFreezeGeometryUpdates); - status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r, - mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer, - mLastFrameNumberReceived); - if (updateResult == BufferQueue::PRESENT_LATER) { - // Producer doesn't want buffer to be displayed yet. Signal a - // layer update so we check again at the next opportunity. - mFlinger->signalLayerUpdate(); - return outDirtyRegion; - } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) { - // If the buffer has been rejected, remove it from the shadow queue - // and return early - if (queuedBuffer) { - Mutex::Autolock lock(mQueueItemLock); - mQueueItems.removeAt(0); - android_atomic_dec(&mQueuedFrames); - } - return outDirtyRegion; - } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) { - // This can occur if something goes wrong when trying to create the - // EGLImage for this buffer. If this happens, the buffer has already - // been released, so we need to clean up the queue and bug out - // early. - if (queuedBuffer) { - Mutex::Autolock lock(mQueueItemLock); - mQueueItems.clear(); - android_atomic_and(0, &mQueuedFrames); - } - - // Once we have hit this state, the shadow queue may no longer - // correctly reflect the incoming BufferQueue's contents, so even if - // updateTexImage starts working, the only safe course of action is - // to continue to ignore updates. - mUpdateTexImageFailed = true; - - return outDirtyRegion; - } - - if (queuedBuffer) { - // Autolock scope - auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber(); - - Mutex::Autolock lock(mQueueItemLock); - - // Remove any stale buffers that have been dropped during - // updateTexImage - while (mQueueItems[0].mFrameNumber != currentFrameNumber) { - mQueueItems.removeAt(0); - android_atomic_dec(&mQueuedFrames); - } - - mQueueItems.removeAt(0); - } - - - // Decrement the queued-frames count. Signal another event if we - // have more frames pending. - if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) - || mAutoRefresh) { - mFlinger->signalLayerUpdate(); - } - - // update the active buffer - mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer( - &mActiveBufferSlot); - if (mActiveBuffer == NULL) { - // this can only happen if the very first buffer was rejected. - return outDirtyRegion; - } - - mBufferLatched = true; - mPreviousFrameNumber = mCurrentFrameNumber; - mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber(); - - { - Mutex::Autolock lock(mFrameEventHistoryMutex); - mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime); -#ifndef USE_HWC2 - auto releaseFenceTime = std::make_shared<FenceTime>( - mSurfaceFlingerConsumer->getPrevFinalReleaseFence()); - mReleaseTimeline.updateSignalTimes(); - mReleaseTimeline.push(releaseFenceTime); - if (mPreviousFrameNumber != 0) { - mFrameEventHistory.addRelease(mPreviousFrameNumber, - latchTime, std::move(releaseFenceTime)); - } -#endif - } - - mRefreshPending = true; - mFrameLatencyNeeded = true; - if (oldActiveBuffer == NULL) { - // the first time we receive a buffer, we need to trigger a - // geometry invalidation. - recomputeVisibleRegions = true; - } - - setDataSpace(mSurfaceFlingerConsumer->getCurrentDataSpace()); - - Rect crop(mSurfaceFlingerConsumer->getCurrentCrop()); - const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform()); - const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode()); - if ((crop != mCurrentCrop) || - (transform != mCurrentTransform) || - (scalingMode != mCurrentScalingMode)) - { - mCurrentCrop = crop; - mCurrentTransform = transform; - mCurrentScalingMode = scalingMode; - recomputeVisibleRegions = true; - } - - if (oldActiveBuffer != NULL) { - uint32_t bufWidth = mActiveBuffer->getWidth(); - uint32_t bufHeight = mActiveBuffer->getHeight(); - if (bufWidth != uint32_t(oldActiveBuffer->width) || - bufHeight != uint32_t(oldActiveBuffer->height)) { - recomputeVisibleRegions = true; - } - } - - mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format); - if (oldOpacity != isOpaque(s)) { - recomputeVisibleRegions = true; - } - - // Remove any sync points corresponding to the buffer which was just - // latched - { - Mutex::Autolock lock(mLocalSyncPointMutex); - auto point = mLocalSyncPoints.begin(); - while (point != mLocalSyncPoints.end()) { - if (!(*point)->frameIsAvailable() || - !(*point)->transactionIsApplied()) { - // This sync point must have been added since we started - // latching. Don't drop it yet. - ++point; - continue; - } - - if ((*point)->getFrameNumber() <= mCurrentFrameNumber) { - point = mLocalSyncPoints.erase(point); - } else { - ++point; - } - } - } - - // FIXME: postedRegion should be dirty & bounds - Region dirtyRegion(Rect(s.active.w, s.active.h)); - - // transform the dirty region to window-manager space - outDirtyRegion = (getTransform().transform(dirtyRegion)); - - return outDirtyRegion; -} - -uint32_t Layer::getEffectiveUsage(uint32_t usage) const -{ +uint32_t Layer::getEffectiveUsage(uint32_t usage) const { // TODO: should we do something special if mSecure is set? if (mProtectedByApp) { // need a hardware-protected path to external video sink @@ -2413,7 +1394,7 @@ void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { orientation = 0; } } - mSurfaceFlingerConsumer->setTransformHint(orientation); + setTransformHint(orientation); } // ---------------------------------------------------------------------------- @@ -2438,7 +1419,7 @@ LayerDebugInfo Layer::getLayerDebugInfo() const { info.mHeight = ds.active.h; info.mCrop = ds.crop; info.mFinalCrop = ds.finalCrop; - info.mAlpha = ds.alpha; + info.mColor = ds.color; info.mFlags = ds.flags; info.mPixelFormat = getPixelFormat(); info.mDataSpace = getDataSpace(); @@ -2447,12 +1428,12 @@ LayerDebugInfo Layer::getLayerDebugInfo() const { info.mMatrix[1][0] = ds.active.transform[1][0]; info.mMatrix[1][1] = ds.active.transform[1][1]; { - sp<const GraphicBuffer> activeBuffer = getActiveBuffer(); - if (activeBuffer != 0) { - info.mActiveBufferWidth = activeBuffer->getWidth(); - info.mActiveBufferHeight = activeBuffer->getHeight(); - info.mActiveBufferStride = activeBuffer->getStride(); - info.mActiveBufferFormat = activeBuffer->format; + sp<const GraphicBuffer> buffer = getBE().compositionInfo.mBuffer; + if (buffer != 0) { + info.mActiveBufferWidth = buffer->getWidth(); + info.mActiveBufferHeight = buffer->getHeight(); + info.mActiveBufferStride = buffer->getStride(); + info.mActiveBufferFormat = buffer->format; } else { info.mActiveBufferWidth = 0; info.mActiveBufferHeight = 0; @@ -2467,7 +1448,6 @@ LayerDebugInfo Layer::getLayerDebugInfo() const { return info; } -#ifdef USE_HWC2 void Layer::miniDumpHeader(String8& result) { result.append("----------------------------------------"); result.append("---------------------------------------\n"); @@ -2481,7 +1461,7 @@ void Layer::miniDumpHeader(String8& result) { } void Layer::miniDump(String8& result, int32_t hwcId) const { - if (mHwcLayers.count(hwcId) == 0) { + if (getBE().mHwcLayers.count(hwcId) == 0) { return; } @@ -2499,21 +1479,17 @@ void Layer::miniDump(String8& result, int32_t hwcId) const { result.appendFormat(" %s\n", name.string()); const Layer::State& layerState(getDrawingState()); - const HWCInfo& hwcInfo = mHwcLayers.at(hwcId); - result.appendFormat(" %10u | ", layerState.z); - result.appendFormat("%10s | ", - to_string(getCompositionType(hwcId)).c_str()); + const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(hwcId); + result.appendFormat(" %10d | ", layerState.z); + result.appendFormat("%10s | ", to_string(getCompositionType(hwcId)).c_str()); const Rect& frame = hwcInfo.displayFrame; - result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, - frame.right, frame.bottom); + result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom); const FloatRect& crop = hwcInfo.sourceCrop; - result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, - crop.right, crop.bottom); + result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right, crop.bottom); result.append("- - - - - - - - - - - - - - - - - - - - "); result.append("- - - - - - - - - - - - - - - - - - - -\n"); } -#endif void Layer::dumpFrameStats(String8& result) const { mFrameTracker.dumpStats(result); @@ -2532,8 +1508,7 @@ void Layer::getFrameStats(FrameStats* outStats) const { } void Layer::dumpFrameEvents(String8& result) { - result.appendFormat("- Layer %s (%s, %p)\n", - getName().string(), getTypeId(), this); + result.appendFormat("- Layer %s (%s, %p)\n", getName().string(), getTypeId(), this); Mutex::Autolock lock(mFrameEventHistoryMutex); mFrameEventHistory.checkFencesForCompletion(); mFrameEventHistory.dump(result); @@ -2545,7 +1520,7 @@ void Layer::onDisconnect() { } void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, - FrameEventHistoryDelta *outDelta) { + FrameEventHistoryDelta* outDelta) { Mutex::Autolock lock(mFrameEventHistoryMutex); if (newTimestamps) { // If there are any unsignaled fences in the aquire timeline at this @@ -2563,23 +1538,6 @@ void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, } } -std::vector<OccupancyTracker::Segment> Layer::getOccupancyHistory( - bool forceFlush) { - std::vector<OccupancyTracker::Segment> history; - status_t result = mSurfaceFlingerConsumer->getOccupancyHistory(forceFlush, - &history); - if (result != NO_ERROR) { - ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), - result); - return {}; - } - return history; -} - -bool Layer::getTransformToDisplayInverse() const { - return mSurfaceFlingerConsumer->getTransformToDisplayInverse(); -} - size_t Layer::getChildrenCount() const { size_t count = 0; for (const sp<Layer>& child : mCurrentChildren) { @@ -2624,17 +1582,43 @@ bool Layer::reparentChildren(const sp<IBinder>& newParentHandle) { return true; } -bool Layer::detachChildren() { - traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* child) { - if (child == this) { - return; - } +bool Layer::reparent(const sp<IBinder>& newParentHandle) { + if (newParentHandle == nullptr) { + return false; + } + + auto handle = static_cast<Handle*>(newParentHandle.get()); + sp<Layer> newParent = handle->owner.promote(); + if (newParent == nullptr) { + ALOGE("Unable to promote Layer handle"); + return false; + } + + sp<Layer> parent = getParent(); + if (parent != nullptr) { + parent->removeChild(this); + } + newParent->addChild(this); + + sp<Client> client(mClientRef.promote()); + sp<Client> newParentClient(newParent->mClientRef.promote()); + + if (client != newParentClient) { + client->setParentLayer(newParent); + } + return true; +} + +bool Layer::detachChildren() { + for (const sp<Layer>& child : mCurrentChildren) { + sp<Client> parentClient = mClientRef.promote(); sp<Client> client(child->mClientRef.promote()); - if (client != nullptr) { - client->detachLayer(child); + if (client != nullptr && parentClient != client) { + client->detachLayer(child.get()); + child->detachChildren(); } - }); + } return true; } @@ -2659,8 +1643,14 @@ int32_t Layer::getZ() const { return mDrawingState.z; } -__attribute__((no_sanitize("unsigned-integer-overflow"))) -LayerVector Layer::makeTraversalList(LayerVector::StateSet stateSet) { +bool Layer::usingRelativeZ(LayerVector::StateSet stateSet) { + const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; + const State& state = useDrawing ? mDrawingState : mCurrentState; + return state.zOrderRelativeOf != nullptr; +} + +__attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::makeTraversalList( + LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers) { LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid, "makeTraversalList received invalid stateSet"); const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; @@ -2668,10 +1658,11 @@ LayerVector Layer::makeTraversalList(LayerVector::StateSet stateSet) { const State& state = useDrawing ? mDrawingState : mCurrentState; if (state.zOrderRelatives.size() == 0) { + *outSkipRelativeZUsers = true; return children; } - LayerVector traverse; + LayerVector traverse; for (const wp<Layer>& weakRelative : state.zOrderRelatives) { sp<Layer> strongRelative = weakRelative.promote(); if (strongRelative != nullptr) { @@ -2680,6 +1671,10 @@ LayerVector Layer::makeTraversalList(LayerVector::StateSet stateSet) { } for (const sp<Layer>& child : children) { + const State& childState = useDrawing ? child->mDrawingState : child->mCurrentState; + if (childState.zOrderRelativeOf != nullptr) { + continue; + } traverse.add(child); } @@ -2690,19 +1685,35 @@ LayerVector Layer::makeTraversalList(LayerVector::StateSet stateSet) { * Negatively signed relatives are before 'this' in Z-order. */ void Layer::traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor) { - LayerVector list = makeTraversalList(stateSet); + // In the case we have other layers who are using a relative Z to us, makeTraversalList will + // produce a new list for traversing, including our relatives, and not including our children + // who are relatives of another surface. In the case that there are no relative Z, + // makeTraversalList returns our children directly to avoid significant overhead. + // However in this case we need to take the responsibility for filtering children which + // are relatives of another surface here. + bool skipRelativeZUsers = false; + const LayerVector list = makeTraversalList(stateSet, &skipRelativeZUsers); size_t i = 0; for (; i < list.size(); i++) { const auto& relative = list[i]; + if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) { + continue; + } + if (relative->getZ() >= 0) { break; } relative->traverseInZOrder(stateSet, visitor); } + visitor(this); for (; i < list.size(); i++) { const auto& relative = list[i]; + + if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) { + continue; + } relative->traverseInZOrder(stateSet, visitor); } } @@ -2712,23 +1723,58 @@ void Layer::traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector:: */ void Layer::traverseInReverseZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor) { - LayerVector list = makeTraversalList(stateSet); + // See traverseInZOrder for documentation. + bool skipRelativeZUsers = false; + LayerVector list = makeTraversalList(stateSet, &skipRelativeZUsers); int32_t i = 0; for (i = int32_t(list.size()) - 1; i >= 0; i--) { const auto& relative = list[i]; + + if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) { + continue; + } + if (relative->getZ() < 0) { break; } relative->traverseInReverseZOrder(stateSet, visitor); } visitor(this); - for (; i>=0; i--) { + for (; i >= 0; i--) { const auto& relative = list[i]; + + if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) { + continue; + } + relative->traverseInReverseZOrder(stateSet, visitor); } } +/** + * Traverse only children in z order, ignoring relative layers. + */ +void Layer::traverseChildrenInZOrder(LayerVector::StateSet stateSet, + const LayerVector::Visitor& visitor) { + const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; + const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren; + + size_t i = 0; + for (; i < children.size(); i++) { + const auto& relative = children[i]; + if (relative->getZ() >= 0) { + break; + } + relative->traverseChildrenInZOrder(stateSet, visitor); + } + visitor(this); + for (; i < children.size(); i++) { + const auto& relative = children[i]; + relative->traverseChildrenInZOrder(stateSet, visitor); + } +} + Transform Layer::getTransform() const { Transform t; const auto& p = mDrawingParent.promote(); @@ -2740,20 +1786,18 @@ Transform Layer::getTransform() const { // for in the transform. We need to mirror this scaling in child surfaces // or we will break the contract where WM can treat child surfaces as // pixels in the parent surface. - if (p->isFixedSize() && p->mActiveBuffer != nullptr) { + if (p->isFixedSize() && p->getBE().compositionInfo.mBuffer != nullptr) { int bufferWidth; int bufferHeight; if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) { - bufferWidth = p->mActiveBuffer->getWidth(); - bufferHeight = p->mActiveBuffer->getHeight(); + bufferWidth = p->getBE().compositionInfo.mBuffer->getWidth(); + bufferHeight = p->getBE().compositionInfo.mBuffer->getHeight(); } else { - bufferHeight = p->mActiveBuffer->getWidth(); - bufferWidth = p->mActiveBuffer->getHeight(); + bufferHeight = p->getBE().compositionInfo.mBuffer->getWidth(); + bufferWidth = p->getBE().compositionInfo.mBuffer->getHeight(); } - float sx = p->getDrawingState().active.w / - static_cast<float>(bufferWidth); - float sy = p->getDrawingState().active.h / - static_cast<float>(bufferHeight); + float sx = p->getDrawingState().active.w / static_cast<float>(bufferWidth); + float sy = p->getDrawingState().active.h / static_cast<float>(bufferHeight); Transform extraParentScaling; extraParentScaling.set(sx, 0, 0, sy); t = t * extraParentScaling; @@ -2762,23 +1806,17 @@ Transform Layer::getTransform() const { return t * getDrawingState().active.transform; } -#ifdef USE_HWC2 -float Layer::getAlpha() const { +half Layer::getAlpha() const { const auto& p = mDrawingParent.promote(); - float parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0; - return parentAlpha * getDrawingState().alpha; + half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; + return parentAlpha * getDrawingState().color.a; } -#else -uint8_t Layer::getAlpha() const { - const auto& p = mDrawingParent.promote(); - float parentAlpha = (p != nullptr) ? (p->getAlpha() / 255.0f) : 1.0; - float drawingAlpha = getDrawingState().alpha / 255.0f; - drawingAlpha = drawingAlpha * parentAlpha; - return static_cast<uint8_t>(std::round(drawingAlpha * 255)); +half4 Layer::getColor() const { + const half4 color(getDrawingState().color); + return half4(color.r, color.g, color.b, getAlpha()); } -#endif void Layer::commitChildList() { for (size_t i = 0; i < mCurrentChildren.size(); i++) { @@ -2789,6 +1827,82 @@ void Layer::commitChildList() { mDrawingParent = mCurrentParent; } +void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) { + const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; + const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren; + const State& state = useDrawing ? mDrawingState : mCurrentState; + + Transform requestedTransform = state.active.transform; + Transform transform = getTransform(); + + layerInfo->set_id(sequence); + layerInfo->set_name(getName().c_str()); + layerInfo->set_type(String8(getTypeId())); + + for (const auto& child : children) { + layerInfo->add_children(child->sequence); + } + + for (const wp<Layer>& weakRelative : state.zOrderRelatives) { + sp<Layer> strongRelative = weakRelative.promote(); + if (strongRelative != nullptr) { + layerInfo->add_relatives(strongRelative->sequence); + } + } + + LayerProtoHelper::writeToProto(state.activeTransparentRegion, + layerInfo->mutable_transparent_region()); + LayerProtoHelper::writeToProto(visibleRegion, layerInfo->mutable_visible_region()); + LayerProtoHelper::writeToProto(surfaceDamageRegion, layerInfo->mutable_damage_region()); + + layerInfo->set_layer_stack(getLayerStack()); + layerInfo->set_z(state.z); + + PositionProto* position = layerInfo->mutable_position(); + position->set_x(transform.tx()); + position->set_y(transform.ty()); + + PositionProto* requestedPosition = layerInfo->mutable_requested_position(); + requestedPosition->set_x(requestedTransform.tx()); + requestedPosition->set_y(requestedTransform.ty()); + + SizeProto* size = layerInfo->mutable_size(); + size->set_w(state.active.w); + size->set_h(state.active.h); + + LayerProtoHelper::writeToProto(state.crop, layerInfo->mutable_crop()); + LayerProtoHelper::writeToProto(state.finalCrop, layerInfo->mutable_final_crop()); + + layerInfo->set_is_opaque(isOpaque(state)); + layerInfo->set_invalidate(contentDirty); + layerInfo->set_dataspace(dataspaceDetails(getDataSpace())); + layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat())); + LayerProtoHelper::writeToProto(getColor(), layerInfo->mutable_color()); + LayerProtoHelper::writeToProto(state.color, layerInfo->mutable_requested_color()); + layerInfo->set_flags(state.flags); + + LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform()); + LayerProtoHelper::writeToProto(requestedTransform, layerInfo->mutable_requested_transform()); + + auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); + if (parent != nullptr) { + layerInfo->set_parent(parent->sequence); + } + + auto zOrderRelativeOf = state.zOrderRelativeOf.promote(); + if (zOrderRelativeOf != nullptr) { + layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence); + } + + auto buffer = getBE().compositionInfo.mBuffer; + if (buffer != nullptr) { + LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer()); + } + + layerInfo->set_queued_frames(getQueuedFrameCount()); + layerInfo->set_refresh_pending(isBufferLatched()); +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f7501a3d48..e44ccf8d57 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -20,37 +20,40 @@ #include <stdint.h> #include <sys/types.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - #include <utils/RefBase.h> #include <utils/String8.h> #include <utils/Timers.h> +#include <ui/FloatRect.h> #include <ui/FrameStats.h> #include <ui/GraphicBuffer.h> #include <ui/PixelFormat.h> #include <ui/Region.h> #include <gui/ISurfaceComposerClient.h> - -#include <private/gui/LayerState.h> +#include <gui/LayerState.h> +#include <gui/BufferQueue.h> #include <list> -#include "FrameTracker.h" #include "Client.h" +#include "FrameTracker.h" #include "LayerVector.h" #include "MonitoredProducer.h" #include "SurfaceFlinger.h" -#include "SurfaceFlingerConsumer.h" #include "Transform.h" +#include <layerproto/LayerProtoHeader.h> #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/HWComposerBufferCache.h" +#include "RenderArea.h" #include "RenderEngine/Mesh.h" #include "RenderEngine/Texture.h" +#include <math/vec4.h> + +using namespace android::surfaceflinger; + namespace android { // --------------------------------------------------------------------------- @@ -61,20 +64,78 @@ class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; class LayerDebugInfo; +class LayerBE; // --------------------------------------------------------------------------- -/* - * A new BufferQueue and a new SurfaceFlingerConsumer are created when the - * Layer is first referenced. - * - * This also implements onFrameAvailable(), which notifies SurfaceFlinger - * that new data has arrived. - */ -class Layer : public SurfaceFlingerConsumer::ContentsChangedListener { +struct CompositionInfo { + HWC2::Composition compositionType; + sp<GraphicBuffer> mBuffer = nullptr; + int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT; + struct { + HWComposer* hwc; + sp<Fence> fence; + HWC2::BlendMode blendMode; + Rect displayFrame; + float alpha; + FloatRect sourceCrop; + HWC2::Transform transform; + int z; + int type; + int appId; + Region visibleRegion; + Region surfaceDamage; + sp<NativeHandle> sidebandStream; + android_dataspace dataspace; + hwc_color_t color; + } hwc; + struct { + RenderEngine* renderEngine; + Mesh* mesh; + } renderEngine; +}; + +class LayerBE { +public: + LayerBE(); + + // The mesh used to draw the layer in GLES composition mode + Mesh mMesh; + + // HWC items, accessed from the main thread + struct HWCInfo { + HWCInfo() + : hwc(nullptr), + layer(nullptr), + forceClientComposition(false), + compositionType(HWC2::Composition::Invalid), + clearClientTarget(false) {} + + HWComposer* hwc; + HWC2::Layer* layer; + bool forceClientComposition; + HWC2::Composition compositionType; + bool clearClientTarget; + Rect displayFrame; + FloatRect sourceCrop; + HWComposerBufferCache bufferCache; + }; + + // A layer can be attached to multiple displays when operating in mirror mode + // (a.k.a: when several displays are attached with equal layerStack). In this + // case we need to keep track. In non-mirror mode, a layer will have only one + // HWCInfo. This map key is a display layerStack. + std::unordered_map<int32_t, HWCInfo> mHwcLayers; + + CompositionInfo compositionInfo; +}; + +class Layer : public virtual RefBase { static int32_t sSequence; public: + LayerBE& getBE() { return mBE; } + LayerBE& getBE() const { return mBE; } mutable bool contentDirty; // regions below are in window-manager space Region visibleRegion; @@ -97,14 +158,11 @@ public: uint32_t h; Transform transform; - inline bool operator ==(const Geometry& rhs) const { - return (w == rhs.w && h == rhs.h) && - (transform.tx() == rhs.transform.tx()) && + inline bool operator==(const Geometry& rhs) const { + return (w == rhs.w && h == rhs.h) && (transform.tx() == rhs.transform.tx()) && (transform.ty() == rhs.transform.ty()); } - inline bool operator !=(const Geometry& rhs) const { - return !operator ==(rhs); - } + inline bool operator!=(const Geometry& rhs) const { return !operator==(rhs); } }; struct State { @@ -119,11 +177,6 @@ public: // to achieve mirroring. uint32_t layerStack; -#ifdef USE_HWC2 - float alpha; -#else - uint8_t alpha; -#endif uint8_t flags; uint8_t mask; uint8_t reserved[2]; @@ -158,20 +211,16 @@ public: // A list of surfaces whose Z-order is interpreted relative to ours. SortedVector<wp<Layer>> zOrderRelatives; - }; - - // ----------------------------------------------------------------------- - Layer(SurfaceFlinger* flinger, const sp<Client>& client, - const String8& name, uint32_t w, uint32_t h, uint32_t flags); + half4 color; + }; + Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, + uint32_t h, uint32_t flags); virtual ~Layer(); void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; } - // the this layer's size and format - status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); - // ------------------------------------------------------------------------ // Geometry setting functions. // @@ -225,11 +274,8 @@ public: bool setLayer(int32_t z); bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ); -#ifdef USE_HWC2 bool setAlpha(float alpha); -#else - bool setAlpha(uint8_t alpha); -#endif + bool setColor(const half3& color); bool setTransparentRegionHint(const Region& transparent); bool setFlags(uint8_t flags, uint8_t mask); bool setLayerStack(uint32_t layerStack); @@ -241,13 +287,14 @@ public: bool setOverrideScalingMode(int32_t overrideScalingMode); void setInfo(uint32_t type, uint32_t appId); bool reparentChildren(const sp<IBinder>& layer); + bool reparent(const sp<IBinder>& newParentHandle); bool detachChildren(); // If we have received a new buffer this frame, we will pass its surface // damage down to hardware composer. Otherwise, we must send a region with // one empty rect. - void useSurfaceDamage(); - void useEmptyDamage(); + virtual void useSurfaceDamage() = 0; + virtual void useEmptyDamage() = 0; uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); @@ -256,17 +303,15 @@ public: return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay); } - void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, - bool useIdentityTransform) const; - Rect computeBounds(const Region& activeTransparentRegion) const; - Rect computeBounds() const; + void computeGeometry(const RenderArea& renderArea, Mesh& mesh, bool useIdentityTransform) const; + FloatRect computeBounds(const Region& activeTransparentRegion) const; + FloatRect computeBounds() const; int32_t getSequence() const { return sequence; } // ----------------------------------------------------------------------- // Virtuals - - virtual const char* getTypeId() const { return "Layer"; } + virtual const char* getTypeId() const = 0; /* * isOpaque - true if this surface is opaque @@ -275,24 +320,18 @@ public: * pixel format includes an alpha channel) and the "opaque" flag set * on the layer. It does not examine the current plane alpha value. */ - virtual bool isOpaque(const Layer::State& s) const; + virtual bool isOpaque(const Layer::State& s) const = 0; /* * isSecure - true if this surface is secure, that is if it prevents * screenshots or VNC servers. */ - virtual bool isSecure() const; - - /* - * isProtected - true if the layer may contain protected content in the - * GRALLOC_USAGE_PROTECTED sense. - */ - virtual bool isProtected() const; + bool isSecure() const; /* * isVisible - true if this layer is visible, false otherwise */ - virtual bool isVisible() const; + virtual bool isVisible() const = 0; /* * isHiddenByPolicy - true if this layer has been forced invisible. @@ -300,87 +339,75 @@ public: * For example if this layer has no active buffer, it may not be hidden by * policy, but it still can not be visible. */ - virtual bool isHiddenByPolicy() const; + bool isHiddenByPolicy() const; /* * isFixedSize - true if content has a fixed size */ - virtual bool isFixedSize() const; + virtual bool isFixedSize() const = 0; + + bool isPendingRemoval() const { return mPendingRemoval; } + + void writeToProto(LayerProto* layerInfo, + LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing); protected: /* * onDraw - draws the surface. */ - virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip, - bool useIdentityTransform) const; + virtual void onDraw(const RenderArea& renderArea, const Region& clip, + bool useIdentityTransform) const = 0; public: - // ----------------------------------------------------------------------- + virtual void setDefaultBufferSize(uint32_t w, uint32_t h) = 0; -#ifdef USE_HWC2 void setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z); void forceClientComposition(int32_t hwcId); - void setPerFrameData(const sp<const DisplayDevice>& displayDevice); + bool getForceClientComposition(int32_t hwcId); + virtual void setPerFrameData(const sp<const DisplayDevice>& displayDevice) = 0; // callIntoHwc exists so we can update our local state and call // acceptDisplayChanges without unnecessarily updating the device's state - void setCompositionType(int32_t hwcId, HWC2::Composition type, - bool callIntoHwc = true); + void setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc = true); HWC2::Composition getCompositionType(int32_t hwcId) const; - void setClearClientTarget(int32_t hwcId, bool clear); bool getClearClientTarget(int32_t hwcId) const; - void updateCursorPosition(const sp<const DisplayDevice>& hw); -#else - void setGeometry(const sp<const DisplayDevice>& hw, - HWComposer::HWCLayerInterface& layer); - void setPerFrameData(const sp<const DisplayDevice>& hw, - HWComposer::HWCLayerInterface& layer); - void setAcquireFence(const sp<const DisplayDevice>& hw, - HWComposer::HWCLayerInterface& layer); - - Rect getPosition(const sp<const DisplayDevice>& hw); -#endif /* * called after page-flip */ -#ifdef USE_HWC2 - void onLayerDisplayed(const sp<Fence>& releaseFence); -#else - void onLayerDisplayed(const sp<const DisplayDevice>& hw, - HWComposer::HWCLayerInterface* layer); -#endif + virtual void onLayerDisplayed(const sp<Fence>& releaseFence); - bool shouldPresentNow(const DispSync& dispSync) const; + virtual void abandon() = 0; + + virtual bool shouldPresentNow(const DispSync& dispSync) const = 0; + virtual void setTransformHint(uint32_t orientation) const = 0; /* * called before composition. * returns true if the layer has pending updates. */ - bool onPreComposition(nsecs_t refreshStartTime); + virtual bool onPreComposition(nsecs_t refreshStartTime) = 0; /* * called after composition. * returns true if the layer latched a new buffer this frame. */ - bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence, - const std::shared_ptr<FenceTime>& presentFence, - const CompositorTiming& compositorTiming); + virtual bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence, + const std::shared_ptr<FenceTime>& presentFence, + const CompositorTiming& compositorTiming) = 0; -#ifdef USE_HWC2 // If a buffer was replaced this frame, release the former buffer - void releasePendingBuffer(nsecs_t dequeueReadyTime); -#endif + virtual void releasePendingBuffer(nsecs_t dequeueReadyTime) = 0; /* * draw - performs some global clipping optimizations * and calls onDraw(). */ - void draw(const sp<const DisplayDevice>& hw, const Region& clip) const; - void draw(const sp<const DisplayDevice>& hw, bool useIdentityTransform) const; - void draw(const sp<const DisplayDevice>& hw) const; + void draw(const RenderArea& renderArea, const Region& clip) const; + void draw(const RenderArea& renderArea, bool useIdentityTransform) const; + void draw(const RenderArea& renderArea) const; /* * doTransaction - process the transaction. This is a good place to figure @@ -405,8 +432,7 @@ public: * setVisibleNonTransparentRegion - called when the visible and * non-transparent region changes. */ - void setVisibleNonTransparentRegion(const Region& - visibleNonTransparentRegion); + void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion); /* * latchBuffer - called each time the screen is redrawn and returns whether @@ -414,11 +440,10 @@ public: * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ - Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime); - bool isBufferLatched() const { return mRefreshPending; } - - bool isPotentialCursor() const { return mPotentialCursor;} + virtual Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0; + virtual bool isBufferLatched() const = 0; + bool isPotentialCursor() const { return mPotentialCursor; } /* * called with the state lock from a binder thread when the layer is * removed from the current list to the pending removal list @@ -431,7 +456,6 @@ public: */ void onRemoved(); - // Updates the transform hint in our SurfaceFlingerConsumer to match // the current orientation of the display device. void updateTransformHint(const sp<const DisplayDevice>& hw) const; @@ -445,12 +469,12 @@ public: /* * Returns if a frame is queued. */ - bool hasQueuedFrame() const { return mQueuedFrames > 0 || - mSidebandStreamChanged || mAutoRefresh; } + bool hasQueuedFrame() const { + return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh; + } int32_t getQueuedFrameCount() const { return mQueuedFrames; } -#ifdef USE_HWC2 // ----------------------------------------------------------------------- bool createHwcLayer(HWComposer* hwc, int32_t hwcId); @@ -458,66 +482,61 @@ public: void destroyAllHwcLayers(); bool hasHwcLayer(int32_t hwcId) { - return mHwcLayers.count(hwcId) > 0; + return getBE().mHwcLayers.count(hwcId) > 0; } HWC2::Layer* getHwcLayer(int32_t hwcId) { - if (mHwcLayers.count(hwcId) == 0) { + if (getBE().mHwcLayers.count(hwcId) == 0) { return nullptr; } - return mHwcLayers[hwcId].layer; + return getBE().mHwcLayers[hwcId].layer; } -#endif // ----------------------------------------------------------------------- - void clearWithOpenGL(const sp<const DisplayDevice>& hw) const; + void clearWithOpenGL(const RenderArea& renderArea) const; void setFiltering(bool filtering); bool getFiltering() const; - // only for debugging - inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; } - inline const State& getDrawingState() const { return mDrawingState; } - inline const State& getCurrentState() const { return mCurrentState; } - inline State& getCurrentState() { return mCurrentState; } + inline const State& getDrawingState() const { return mDrawingState; } + inline const State& getCurrentState() const { return mCurrentState; } + inline State& getCurrentState() { return mCurrentState; } LayerDebugInfo getLayerDebugInfo() const; /* always call base class first */ -#ifdef USE_HWC2 static void miniDumpHeader(String8& result); void miniDump(String8& result, int32_t hwcId) const; -#endif void dumpFrameStats(String8& result) const; void dumpFrameEvents(String8& result); void clearFrameStats(); void logFrameStats(); void getFrameStats(FrameStats* outStats) const; - std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush); + virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) = 0; void onDisconnect(); void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry, - FrameEventHistoryDelta* outDelta); + FrameEventHistoryDelta* outDelta); - bool getTransformToDisplayInverse() const; + virtual bool getTransformToDisplayInverse() const = 0; Transform getTransform() const; // Returns the Alpha of the Surface, accounting for the Alpha // of parent Surfaces in the hierarchy (alpha's will be multiplied // down the hierarchy). -#ifdef USE_HWC2 - float getAlpha() const; -#else - uint8_t getAlpha() const; -#endif + half getAlpha() const; + half4 getColor() const; void traverseInReverseZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor); void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor); + void traverseChildrenInZOrder(LayerVector::StateSet stateSet, + const LayerVector::Visitor& visitor); + size_t getChildrenCount() const; void addChild(const sp<Layer>& layer); // Returns index if removed, or negative value otherwise @@ -525,15 +544,16 @@ public: ssize_t removeChild(const sp<Layer>& layer); sp<Layer> getParent() const { return mCurrentParent.promote(); } bool hasParent() const { return getParent() != nullptr; } - Rect computeScreenBounds(bool reduceTransparentRegion = true) const; bool setChildLayer(const sp<Layer>& childLayer, int32_t z); + bool setChildRelativeLayer(const sp<Layer>& childLayer, + const sp<IBinder>& relativeToHandle, int32_t relativeZ); // Copy the current list of children to the drawing state. Called by // SurfaceFlinger to complete a transaction. void commitChildList(); - int32_t getZ() const; + protected: // constant sp<SurfaceFlinger> mFlinger; @@ -544,90 +564,57 @@ protected: class LayerCleaner { sp<SurfaceFlinger> mFlinger; wp<Layer> mLayer; + protected: ~LayerCleaner() { // destroy client resources mFlinger->onLayerDestroyed(mLayer); } + public: - LayerCleaner(const sp<SurfaceFlinger>& flinger, - const sp<Layer>& layer) - : mFlinger(flinger), mLayer(layer) { - } + LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer) + : mFlinger(flinger), mLayer(layer) {} }; - virtual void onFirstRef(); - - -private: friend class SurfaceInterceptor; - // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener - virtual void onFrameAvailable(const BufferItem& item) override; - virtual void onFrameReplaced(const BufferItem& item) override; - virtual void onSidebandStreamChanged() override; void commitTransaction(const State& stateToCommit); - // needsLinearFiltering - true if this surface's state requires filtering - bool needsFiltering(const sp<const DisplayDevice>& hw) const; - uint32_t getEffectiveUsage(uint32_t usage) const; FloatRect computeCrop(const sp<const DisplayDevice>& hw) const; - // Compute the initial crop as specified by parent layers and the SurfaceControl - // for this layer. Does not include buffer crop from the IGraphicBufferProducer - // client, as that should not affect child clipping. Returns in screen space. + // Compute the initial crop as specified by parent layers and the + // SurfaceControl for this layer. Does not include buffer crop from the + // IGraphicBufferProducer client, as that should not affect child clipping. + // Returns in screen space. Rect computeInitialCrop(const sp<const DisplayDevice>& hw) const; - bool isCropped() const; - static bool getOpacityForFormat(uint32_t format); // drawing - void clearWithOpenGL(const sp<const DisplayDevice>& hw, - float r, float g, float b, float alpha) const; - void drawWithOpenGL(const sp<const DisplayDevice>& hw, - bool useIdentityTransform) const; - - // Temporary - Used only for LEGACY camera mode. - uint32_t getProducerStickyTransform() const; - - // Loads the corresponding system property once per process - static bool latchUnsignaledBuffers(); + void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b, + float alpha) const; void setParent(const sp<Layer>& layer); - LayerVector makeTraversalList(LayerVector::StateSet stateSet); + LayerVector makeTraversalList(LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers); void addZOrderRelative(const wp<Layer>& relative); void removeZOrderRelative(const wp<Layer>& relative); - // ----------------------------------------------------------------------- - - class SyncPoint - { + class SyncPoint { public: - explicit SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber), - mFrameIsAvailable(false), mTransactionIsApplied(false) {} + explicit SyncPoint(uint64_t frameNumber) + : mFrameNumber(frameNumber), mFrameIsAvailable(false), mTransactionIsApplied(false) {} - uint64_t getFrameNumber() const { - return mFrameNumber; - } + uint64_t getFrameNumber() const { return mFrameNumber; } - bool frameIsAvailable() const { - return mFrameIsAvailable; - } + bool frameIsAvailable() const { return mFrameIsAvailable; } - void setFrameAvailable() { - mFrameIsAvailable = true; - } + void setFrameAvailable() { mFrameIsAvailable = true; } - bool transactionIsApplied() const { - return mTransactionIsApplied; - } + bool transactionIsApplied() const { return mTransactionIsApplied; } - void setTransactionApplied() { - mTransactionIsApplied = true; - } + void setTransactionApplied() { mTransactionIsApplied = true; } private: const uint64_t mFrameNumber; @@ -645,9 +632,6 @@ private: // is applied std::list<std::shared_ptr<SyncPoint>> mRemoteSyncPoints; - uint64_t getHeadFrameNumber() const; - bool headFenceHasSignaled() const; - // Returns false if the relevant frame has already been latched bool addSyncPoint(const std::shared_ptr<SyncPoint>& point); @@ -660,7 +644,8 @@ private: // Returns mCurrentScaling mode (originating from the // Client) or mOverrideScalingMode mode (originating from // the Surface Controller) if set. - uint32_t getEffectiveScalingMode() const; + virtual uint32_t getEffectiveScalingMode() const = 0; + public: /* * The layer handle is just a BBinder object passed to the client @@ -671,37 +656,26 @@ public: * this layer when the handle is destroyed. */ class Handle : public BBinder, public LayerCleaner { - public: - Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer) - : LayerCleaner(flinger, layer), owner(layer) {} + public: + Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer) + : LayerCleaner(flinger, layer), owner(layer) {} - wp<Layer> owner; + wp<Layer> owner; }; sp<IBinder> getHandle(); - sp<IGraphicBufferProducer> getProducer() const; const String8& getName() const; - void notifyAvailableFrames(); - - PixelFormat getPixelFormat() const { return mFormat; } - -private: + virtual void notifyAvailableFrames() = 0; + virtual PixelFormat getPixelFormat() const = 0; + bool getPremultipledAlpha() const; +protected: // ----------------------------------------------------------------------- + bool usingRelativeZ(LayerVector::StateSet stateSet); - // Check all of the local sync points to ensure that all transactions - // which need to have been applied prior to the frame which is about to - // be latched have signaled - bool allTransactionsSignaled(); - - // constants - sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer; - sp<IGraphicBufferProducer> mProducer; - uint32_t mTextureName; // from GLES bool mPremultipliedAlpha; String8 mName; String8 mTransactionName; // A cached version of "TX - " + mName for systraces - PixelFormat mFormat; bool mPrimaryDisplayOnly = false; @@ -734,60 +708,24 @@ private: sp<NativeHandle> mSidebandStream; Rect mCurrentCrop; uint32_t mCurrentTransform; - uint32_t mCurrentScalingMode; // We encode unset as -1. int32_t mOverrideScalingMode; bool mCurrentOpacity; - bool mBufferLatched = false; // TODO: Use mActiveBuffer? std::atomic<uint64_t> mCurrentFrameNumber; - uint64_t mPreviousFrameNumber; // Only accessed on the main thread. - bool mRefreshPending; bool mFrameLatencyNeeded; // Whether filtering is forced on or not bool mFiltering; // Whether filtering is needed b/c of the drawingstate bool mNeedsFiltering; - // The mesh used to draw the layer in GLES composition mode - mutable Mesh mMesh; - // The texture used to draw the layer in GLES composition mode - mutable Texture mTexture; - -#ifdef USE_HWC2 - // HWC items, accessed from the main thread - struct HWCInfo { - HWCInfo() - : hwc(nullptr), - layer(nullptr), - forceClientComposition(false), - compositionType(HWC2::Composition::Invalid), - clearClientTarget(false) {} - - HWComposer* hwc; - HWC2::Layer* layer; - bool forceClientComposition; - HWC2::Composition compositionType; - bool clearClientTarget; - Rect displayFrame; - FloatRect sourceCrop; - HWComposerBufferCache bufferCache; - }; - // A layer can be attached to multiple displays when operating in mirror mode - // (a.k.a: when several displays are attached with equal layerStack). In this - // case we need to keep track. In non-mirror mode, a layer will have only one - // HWCInfo. This map key is a display layerStack. - std::unordered_map<int32_t, HWCInfo> mHwcLayers; -#else - bool mIsGlesComposition; -#endif + bool mPendingRemoval = false; // page-flip thread (currently main thread) bool mProtectedByApp; // application requires protected path to external sink // protected by mLock mutable Mutex mLock; - // Set to true once we've returned this surface's handle - mutable bool mHasSurface; + const wp<Client> mClientRef; // This layer can be a cursor on some displays. @@ -798,8 +736,6 @@ private: Condition mQueueItemCondition; Vector<BufferItem> mQueueItems; std::atomic<uint64_t> mLastFrameNumberReceived; - bool mUpdateTexImageFailed; // This is only accessed on the main thread. - bool mAutoRefresh; bool mFreezeGeometryUpdates; @@ -810,6 +746,8 @@ private: wp<Layer> mCurrentParent; wp<Layer> mDrawingParent; + + mutable LayerBE mBE; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp deleted file mode 100644 index daebf8abcd..0000000000 --- a/services/surfaceflinger/LayerDim.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// #define LOG_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "LayerDim" - -#include <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/Log.h> - -#include <ui/GraphicBuffer.h> - -#include "LayerDim.h" -#include "SurfaceFlinger.h" -#include "DisplayDevice.h" -#include "RenderEngine/RenderEngine.h" - -namespace android { -// --------------------------------------------------------------------------- - -LayerDim::LayerDim(SurfaceFlinger* flinger, const sp<Client>& client, - const String8& name, uint32_t w, uint32_t h, uint32_t flags) - : Layer(flinger, client, name, w, h, flags) { -} - -LayerDim::~LayerDim() { -} - -void LayerDim::onDraw(const sp<const DisplayDevice>& hw, - const Region& /* clip */, bool useIdentityTransform) const -{ - const State& s(getDrawingState()); - if (s.alpha>0) { - Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2); - computeGeometry(hw, mesh, useIdentityTransform); - RenderEngine& engine(mFlinger->getRenderEngine()); - engine.setupDimLayerBlending(s.alpha); - engine.drawMesh(mesh); - engine.disableBlending(); - } -} - -bool LayerDim::isVisible() const { - const Layer::State& s(getDrawingState()); - return !isHiddenByPolicy() && s.alpha; -} - - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h deleted file mode 100644 index a0cfca98cf..0000000000 --- a/services/surfaceflinger/LayerDim.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_LAYER_DIM_H -#define ANDROID_LAYER_DIM_H - -#include <stdint.h> -#include <sys/types.h> - -#include "Layer.h" - -// --------------------------------------------------------------------------- - -namespace android { - -class LayerDim : public Layer -{ -public: - LayerDim(SurfaceFlinger* flinger, const sp<Client>& client, - const String8& name, uint32_t w, uint32_t h, uint32_t flags); - virtual ~LayerDim(); - - virtual const char* getTypeId() const { return "LayerDim"; } - virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip, - bool useIdentityTransform) const; - virtual bool isOpaque(const Layer::State&) const { return false; } - virtual bool isSecure() const { return false; } - virtual bool isFixedSize() const { return true; } - virtual bool isVisible() const; -}; - -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_LAYER_DIM_H diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp new file mode 100644 index 0000000000..6a33148d27 --- /dev/null +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LayerProtoHelper.h" + +namespace android { +namespace surfaceflinger { +void LayerProtoHelper::writeToProto(const Region& region, RegionProto* regionProto) { + Region::const_iterator head = region.begin(); + Region::const_iterator const tail = region.end(); + uint64_t address = reinterpret_cast<uint64_t>(®ion); + regionProto->set_id(address); + while (head != tail) { + RectProto* rectProto = regionProto->add_rect(); + writeToProto(*head, rectProto); + head++; + } +} + +void LayerProtoHelper::writeToProto(const Rect& rect, RectProto* rectProto) { + rectProto->set_left(rect.left); + rectProto->set_top(rect.top); + rectProto->set_bottom(rect.bottom); + rectProto->set_right(rect.right); +} + +void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) { + colorProto->set_r(color.r); + colorProto->set_g(color.g); + colorProto->set_b(color.b); + colorProto->set_a(color.a); +} + +void LayerProtoHelper::writeToProto(const Transform& transform, TransformProto* transformProto) { + transformProto->set_dsdx(transform[0][0]); + transformProto->set_dtdx(transform[0][1]); + transformProto->set_dsdy(transform[1][0]); + transformProto->set_dtdy(transform[1][1]); +} + +void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer, + ActiveBufferProto* activeBufferProto) { + activeBufferProto->set_width(buffer->getWidth()); + activeBufferProto->set_height(buffer->getHeight()); + activeBufferProto->set_stride(buffer->getStride()); + activeBufferProto->set_format(buffer->format); +} + +} // namespace surfaceflinger +} // namespace android diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h new file mode 100644 index 0000000000..45a0b5d173 --- /dev/null +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <layerproto/LayerProtoHeader.h> + +#include <ui/GraphicBuffer.h> +#include <ui/Rect.h> +#include <ui/Region.h> + +#include <Transform.h> + +#include <math/vec4.h> + +namespace android { +namespace surfaceflinger { +class LayerProtoHelper { +public: + static void writeToProto(const Rect& rect, RectProto* rectProto); + static void writeToProto(const Region& region, RegionProto* regionProto); + static void writeToProto(const half4 color, ColorProto* colorProto); + static void writeToProto(const Transform& transform, TransformProto* transformProto); + static void writeToProto(const sp<GraphicBuffer>& buffer, ActiveBufferProto* activeBufferProto); +}; + +} // namespace surfaceflinger +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h index 828cd8b96e..40972aac87 100644 --- a/services/surfaceflinger/LayerRejecter.h +++ b/services/surfaceflinger/LayerRejecter.h @@ -18,10 +18,10 @@ #define ANDROID_LAYER_REJECTER_H #include "Layer.h" -#include "SurfaceFlingerConsumer.h" +#include "BufferLayerConsumer.h" namespace android { - class LayerRejecter : public SurfaceFlingerConsumer::BufferRejecter { + class LayerRejecter : public BufferLayerConsumer::BufferRejecter { public: LayerRejecter(Layer::State &front, Layer::State ¤t, diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp index d0f8fbea22..47156c19d2 100644 --- a/services/surfaceflinger/LayerVector.cpp +++ b/services/surfaceflinger/LayerVector.cpp @@ -37,8 +37,8 @@ int LayerVector::do_compare(const void* lhs, const void* rhs) const if (ls != rs) return (ls > rs) ? 1 : -1; - uint32_t lz = l->getCurrentState().z; - uint32_t rz = r->getCurrentState().z; + int32_t lz = l->getCurrentState().z; + int32_t rz = r->getCurrentState().z; if (lz != rz) return (lz > rz) ? 1 : -1; diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp new file mode 100644 index 0000000000..6225df134d --- /dev/null +++ b/services/surfaceflinger/RenderArea.cpp @@ -0,0 +1,34 @@ +#include "RenderArea.h" + +namespace android { + +/* + * Checks that the requested width and height are valid and updates them to the render area + * dimensions if they are set to 0 + */ +status_t RenderArea::updateDimensions() { + // get screen geometry + + uint32_t width = getWidth(); + uint32_t height = getHeight(); + + if (mRotationFlags & Transform::ROT_90) { + std::swap(width, height); + } + + if ((mReqWidth > width) || (mReqHeight > height)) { + ALOGE("size mismatch (%d, %d) > (%d, %d)", mReqWidth, mReqHeight, width, height); + return BAD_VALUE; + } + + if (mReqWidth == 0) { + mReqWidth = width; + } + if (mReqHeight == 0) { + mReqHeight = height; + } + + return NO_ERROR; +} + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h new file mode 100644 index 0000000000..fa4df8360f --- /dev/null +++ b/services/surfaceflinger/RenderArea.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Transform.h" + +namespace android { + +class RenderArea { +public: + RenderArea(uint32_t reqHeight, uint32_t reqWidth, + ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone) + : mReqHeight(reqHeight), mReqWidth(reqWidth) { + mRotationFlags = Transform::fromRotation(rotation); + } + + virtual ~RenderArea() = default; + + virtual const Transform& getTransform() const = 0; + virtual Rect getBounds() const = 0; + virtual int getHeight() const = 0; + virtual int getWidth() const = 0; + virtual bool isSecure() const = 0; + virtual bool needsFiltering() const = 0; + virtual Rect getSourceCrop() const = 0; + + int getReqHeight() const { return mReqHeight; }; + int getReqWidth() const { return mReqWidth; }; + Transform::orientation_flags getRotationFlags() const { return mRotationFlags; }; + virtual bool getWideColorSupport() const = 0; + virtual android_color_mode_t getActiveColorMode() const = 0; + + status_t updateDimensions(); + +private: + uint32_t mReqHeight; + uint32_t mReqWidth; + Transform::orientation_flags mRotationFlags; +}; + +} // namespace android diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp index effd3191c8..e0144063f3 100644 --- a/services/surfaceflinger/RenderEngine/Description.cpp +++ b/services/surfaceflinger/RenderEngine/Description.cpp @@ -27,21 +27,13 @@ namespace android { Description::Description() { - mPlaneAlpha = 1.0f; mPremultipliedAlpha = false; mOpaque = true; mTextureEnabled = false; mColorMatrixEnabled = false; - - memset(mColor, 0, sizeof(mColor)); -} - -Description::~Description() { } -void Description::setPlaneAlpha(GLclampf planeAlpha) { - mPlaneAlpha = planeAlpha; -} +Description::~Description() {} void Description::setPremultipliedAlpha(bool premultipliedAlpha) { mPremultipliedAlpha = premultipliedAlpha; @@ -60,11 +52,8 @@ void Description::disableTexture() { mTextureEnabled = false; } -void Description::setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - mColor[0] = red; - mColor[1] = green; - mColor[2] = blue; - mColor[3] = alpha; +void Description::setColor(const half4& color) { + mColor = color; } void Description::setProjectionMatrix(const mat4& mtx) { diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h index 3beffdf9e1..cbac855ff3 100644 --- a/services/surfaceflinger/RenderEngine/Description.h +++ b/services/surfaceflinger/RenderEngine/Description.h @@ -35,8 +35,6 @@ class Description { friend class Program; friend class ProgramCache; - // value of the plane-alpha, between 0 and 1 - GLclampf mPlaneAlpha; // whether textures are premultiplied bool mPremultipliedAlpha; // whether this layer is marked as opaque @@ -46,8 +44,8 @@ class Description { Texture mTexture; bool mTextureEnabled; - // color used when texturing is disabled - GLclampf mColor[4]; + // color used when texturing is disabled or when setting alpha. + half4 mColor; // projection matrix mat4 mProjectionMatrix; @@ -60,12 +58,11 @@ public: Description(); ~Description(); - void setPlaneAlpha(GLclampf planeAlpha); void setPremultipliedAlpha(bool premultipliedAlpha); void setOpaque(bool opaque); void setTexture(const Texture& texture); void disableTexture(); - void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void setColor(const half4& color); void setProjectionMatrix(const mat4& mtx); void setColorMatrix(const mat4& mtx); const mat4& getColorMatrix() const; diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 9c0af8b2ed..d1ee6f8c9c 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -33,18 +33,17 @@ #include <gui/ISurfaceComposer.h> #include <math.h> +#include "Description.h" #include "GLES20RenderEngine.h" +#include "Mesh.h" #include "Program.h" #include "ProgramCache.h" -#include "Description.h" -#include "Mesh.h" #include "Texture.h" -#include <sstream> #include <fstream> +#include <sstream> // --------------------------------------------------------------------------- -#ifdef USE_HWC2 bool checkGlError(const char* op, int lineNumber) { bool errorFound = false; GLint error = glGetError(); @@ -103,41 +102,36 @@ void writePPM(const char* basename, GLuint width, GLuint height) { } file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size()); } -#endif // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- -GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) : - mVpWidth(0), - mVpHeight(0), - mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) { - +GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) + : mVpWidth(0), mVpHeight(0), mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4); - const uint16_t protTexData[] = { 0 }; + const uint16_t protTexData[] = {0}; glGenTextures(1, &mProtectedTexName); glBindTexture(GL_TEXTURE_2D, mProtectedTexName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); - //mColorBlindnessCorrection = M; + // mColorBlindnessCorrection = M; -#ifdef USE_HWC2 if (mPlatformHasWideColor) { // Compute sRGB to DisplayP3 color transform // NOTE: For now, we are limiting wide-color support to // Display-P3 only. - mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform(); + mat3 srgbToP3 = + ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform(); // color transform needs to be expanded to 4x4 to be what the shader wants // mat has an initializer that expands mat3 to mat4, but @@ -145,27 +139,21 @@ GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) : mat4 gamutTransform(srgbToP3); mSrgbToDisplayP3 = gamutTransform; } -#endif -} - -GLES20RenderEngine::~GLES20RenderEngine() { } +GLES20RenderEngine::~GLES20RenderEngine() {} size_t GLES20RenderEngine::getMaxTextureSize() const { return mMaxTextureSize; } size_t GLES20RenderEngine::getMaxViewportDims() const { - return - mMaxViewportDims[0] < mMaxViewportDims[1] ? - mMaxViewportDims[0] : mMaxViewportDims[1]; + return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1]; } -void GLES20RenderEngine::setViewportAndProjection( - size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, - Transform::orientation_flags rotation) { - +void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, + size_t hwh, bool yswap, + Transform::orientation_flags rotation) { int32_t l = sourceCrop.left; int32_t r = sourceCrop.right; @@ -186,13 +174,13 @@ void GLES20RenderEngine::setViewportAndProjection( case Transform::ROT_0: break; case Transform::ROT_90: - m = mat4::rotate(rot90InRadians, vec3(0,0,1)) * m; + m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m; break; case Transform::ROT_180: - m = mat4::rotate(rot90InRadians * 2.0f, vec3(0,0,1)) * m; + m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m; break; case Transform::ROT_270: - m = mat4::rotate(rot90InRadians * 3.0f, vec3(0,0,1)) * m; + m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m; break; default: break; @@ -204,25 +192,17 @@ void GLES20RenderEngine::setViewportAndProjection( mVpHeight = vph; } -#ifdef USE_HWC2 -void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, - bool opaque, float alpha) { -#else -void GLES20RenderEngine::setupLayerBlending( - bool premultipliedAlpha, bool opaque, int alpha) { -#endif - +void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, + bool disableTexture, const half4& color) { mState.setPremultipliedAlpha(premultipliedAlpha); mState.setOpaque(opaque); -#ifdef USE_HWC2 - mState.setPlaneAlpha(alpha); + mState.setColor(color); - if (alpha < 1.0f || !opaque) { -#else - mState.setPlaneAlpha(alpha / 255.0f); + if (disableTexture) { + mState.disableTexture(); + } - if (alpha < 0xFF || !opaque) { -#endif + if (color.a < 1.0f || !opaque) { glEnable(GL_BLEND); glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { @@ -230,34 +210,6 @@ void GLES20RenderEngine::setupLayerBlending( } } -#ifdef USE_HWC2 -void GLES20RenderEngine::setupDimLayerBlending(float alpha) { -#else -void GLES20RenderEngine::setupDimLayerBlending(int alpha) { -#endif - mState.setPlaneAlpha(1.0f); - mState.setPremultipliedAlpha(true); - mState.setOpaque(false); -#ifdef USE_HWC2 - mState.setColor(0, 0, 0, alpha); -#else - mState.setColor(0, 0, 0, alpha/255.0f); -#endif - mState.disableTexture(); - -#ifdef USE_HWC2 - if (alpha == 1.0f) { -#else - if (alpha == 0xFF) { -#endif - glDisable(GL_BLEND); - } else { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } -} - -#ifdef USE_HWC2 void GLES20RenderEngine::setColorMode(android_color_mode mode) { ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode); @@ -291,7 +243,6 @@ void GLES20RenderEngine::setWideColor(bool hasWideColor) { bool GLES20RenderEngine::usesWideColor() { return mUseWideColor; } -#endif void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) { GLuint target = texture.getTextureTarget(); @@ -329,9 +280,8 @@ void GLES20RenderEngine::disableBlending() { glDisable(GL_BLEND); } - -void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, - uint32_t* texName, uint32_t* fbName, uint32_t* status) { +void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, + uint32_t* fbName, uint32_t* status) { GLuint tname, name; // turn our EGLImage into a texture glGenTextures(1, &tname); @@ -355,32 +305,23 @@ void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) { } void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) { - mState.setPlaneAlpha(1.0f); mState.setPremultipliedAlpha(true); mState.setOpaque(false); - mState.setColor(r, g, b, a); + mState.setColor(half4(r, g, b, a)); mState.disableTexture(); glDisable(GL_BLEND); } void GLES20RenderEngine::drawMesh(const Mesh& mesh) { - if (mesh.getTexCoordsSize()) { glEnableVertexAttribArray(Program::texCoords); - glVertexAttribPointer(Program::texCoords, - mesh.getTexCoordsSize(), - GL_FLOAT, GL_FALSE, - mesh.getByteStride(), - mesh.getTexCoords()); + glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE, + mesh.getByteStride(), mesh.getTexCoords()); } - glVertexAttribPointer(Program::position, - mesh.getVertexSize(), - GL_FLOAT, GL_FALSE, - mesh.getByteStride(), - mesh.getPositions()); + glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE, + mesh.getByteStride(), mesh.getPositions()); -#ifdef USE_HWC2 if (usesWideColor()) { Description wideColorState = mState; if (mDataSpace != HAL_DATASPACE_DISPLAY_P3) { @@ -402,11 +343,6 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); } -#else - ProgramCache::getInstance().useProgram(mState); - - glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); -#endif if (mesh.getTexCoordsSize()) { glDisableVertexAttribArray(Program::texCoords); @@ -415,13 +351,11 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { void GLES20RenderEngine::dump(String8& result) { RenderEngine::dump(result); -#ifdef USE_HWC2 if (usesWideColor()) { result.append("Wide-color: On\n"); } else { result.append("Wide-color: Off\n"); } -#endif } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index eaf94af54c..5ee9326c21 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -14,7 +14,6 @@ * limitations under the License. */ - #ifndef SF_GLES20RENDERENGINE_H_ #define SF_GLES20RENDERENGINE_H_ @@ -24,9 +23,9 @@ #include <GLES2/gl2.h> #include <Transform.h> -#include "RenderEngine.h" -#include "ProgramCache.h" #include "Description.h" +#include "ProgramCache.h" +#include "RenderEngine.h" // --------------------------------------------------------------------------- namespace android { @@ -54,24 +53,20 @@ class GLES20RenderEngine : public RenderEngine { Description mState; Vector<Group> mGroupStack; - virtual void bindImageAsFramebuffer(EGLImageKHR image, - uint32_t* texName, uint32_t* fbName, uint32_t* status); + virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, + uint32_t* status); virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName); public: GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag - -protected: virtual ~GLES20RenderEngine(); +protected: virtual void dump(String8& result); - virtual void setViewportAndProjection(size_t vpw, size_t vph, - Rect sourceCrop, size_t hwh, bool yswap, - Transform::orientation_flags rotation); -#ifdef USE_HWC2 - virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, - float alpha) override; - virtual void setupDimLayerBlending(float alpha) override; + virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, + bool yswap, Transform::orientation_flags rotation); + virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, + const half4& color) override; // Color management related functions and state void setColorMode(android_color_mode mode); @@ -92,11 +87,6 @@ protected: // Currently only supporting sRGB and DisplayP3 color spaces mat4 mSrgbToDisplayP3; -#else - virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, - int alpha); - virtual void setupDimLayerBlending(int alpha); -#endif bool mPlatformHasWideColor = false; virtual void setupLayerTexturing(const Texture& texture); diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp index 76bbcc1bfe..e6e4df1a6f 100644 --- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp +++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp @@ -14,51 +14,44 @@ * limitations under the License. */ -#include <stdlib.h> -#include <stdio.h> #include <stdint.h> +#include <stdio.h> +#include <stdlib.h> #include "GLExtensions.h" namespace android { // --------------------------------------------------------------------------- -ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions ) +ANDROID_SINGLETON_STATIC_INSTANCE(GLExtensions) -GLExtensions::GLExtensions() - : mHaveFramebufferObject(false) -{ -} - -void GLExtensions::initWithGLStrings( - GLubyte const* vendor, - GLubyte const* renderer, - GLubyte const* version, - GLubyte const* extensions) -{ - mVendor = (char const*)vendor; - mRenderer = (char const*)renderer; - mVersion = (char const*)version; - mExtensions = (char const*)extensions; +SortedVector<String8> GLExtensions::parseExtensionString(char const* extensions) { + SortedVector<String8> list; - char const* curr = (char const*)extensions; + char const* curr = extensions; char const* head = curr; do { head = strchr(curr, ' '); - String8 s(curr, head ? head-curr : strlen(curr)); + String8 s(curr, head ? head - curr : strlen(curr)); if (s.length()) { - mExtensionList.add(s); + list.add(s); } - curr = head+1; + curr = head + 1; } while (head); - if (hasExtension("GL_OES_framebuffer_object")) { - mHaveFramebufferObject = true; - } + return list; } -bool GLExtensions::hasExtension(char const* extension) const -{ +void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, + GLubyte const* version, GLubyte const* extensions) { + mVendor = (char const*)vendor; + mRenderer = (char const*)renderer; + mVersion = (char const*)version; + mExtensions = (char const*)extensions; + mExtensionList = parseExtensionString(mExtensions); +} + +bool GLExtensions::hasExtension(char const* extension) const { const String8 s(extension); return mExtensionList.indexOf(s) >= 0; } @@ -75,9 +68,58 @@ char const* GLExtensions::getVersion() const { return mVersion.string(); } -char const* GLExtensions::getExtension() const { +char const* GLExtensions::getExtensions() const { return mExtensions.string(); } +void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) { + mEGLVersion = eglVersion; + mEGLExtensions = eglExtensions; + mEGLExtensionList = parseExtensionString(mEGLExtensions); + + // EGL_ANDROIDX_no_config_context is an experimental extension with no + // written specification. It will be replaced by something more formal. + // SurfaceFlinger is using it to allow a single EGLContext to render to + // both a 16-bit primary display framebuffer and a 32-bit virtual display + // framebuffer. + // + // EGL_KHR_no_config_context is official extension to allow creating a + // context that works with any surface of a display. + if (hasEGLExtension("EGL_ANDROIDX_no_config_context") || + hasEGLExtension("EGL_KHR_no_config_context")) { + mHasNoConfigContext = true; + } + + if (hasEGLExtension("EGL_ANDROID_native_fence_sync")) { + mHasNativeFenceSync = true; + } + if (hasEGLExtension("EGL_KHR_fence_sync")) { + mHasFenceSync = true; + } + if (hasEGLExtension("EGL_KHR_wait_sync")) { + mHasWaitSync = true; + } + + if (hasEGLExtension("EGL_ANDROID_image_crop")) { + mHasImageCrop = true; + } + if (hasEGLExtension("EGL_EXT_protected_content")) { + mHasProtectedContent = true; + } +} + +char const* GLExtensions::getEGLVersion() const { + return mEGLVersion.string(); +} + +char const* GLExtensions::getEGLExtensions() const { + return mEGLExtensions.string(); +} + +bool GLExtensions::hasEGLExtension(char const* extension) const { + const String8 s(extension); + return mEGLExtensionList.indexOf(s) >= 0; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h index d81ed2a7bc..81078e0455 100644 --- a/services/surfaceflinger/RenderEngine/GLExtensions.h +++ b/services/surfaceflinger/RenderEngine/GLExtensions.h @@ -20,9 +20,9 @@ #include <stdint.h> #include <sys/types.h> -#include <utils/String8.h> -#include <utils/SortedVector.h> #include <utils/Singleton.h> +#include <utils/SortedVector.h> +#include <utils/String8.h> #include <EGL/egl.h> #include <EGL/eglext.h> @@ -32,11 +32,15 @@ namespace android { // --------------------------------------------------------------------------- -class GLExtensions : public Singleton<GLExtensions> -{ +class GLExtensions : public Singleton<GLExtensions> { friend class Singleton<GLExtensions>; - bool mHaveFramebufferObject : 1; + bool mHasNoConfigContext = false; + bool mHasNativeFenceSync = false; + bool mHasFenceSync = false; + bool mHasWaitSync = false; + bool mHasImageCrop = false; + bool mHasProtectedContent = false; String8 mVendor; String8 mRenderer; @@ -44,32 +48,39 @@ class GLExtensions : public Singleton<GLExtensions> String8 mExtensions; SortedVector<String8> mExtensionList; + String8 mEGLVersion; + String8 mEGLExtensions; + SortedVector<String8> mEGLExtensionList; + + static SortedVector<String8> parseExtensionString(char const* extensions); + GLExtensions(const GLExtensions&); - GLExtensions& operator = (const GLExtensions&); + GLExtensions& operator=(const GLExtensions&); protected: - GLExtensions(); + GLExtensions() = default; public: - - inline bool haveFramebufferObject() const { - return mHaveFramebufferObject; - } - - void initWithGLStrings( - GLubyte const* vendor, - GLubyte const* renderer, - GLubyte const* version, - GLubyte const* extensions); - + bool hasNoConfigContext() const { return mHasNoConfigContext; } + bool hasNativeFenceSync() const { return mHasNativeFenceSync; } + bool hasFenceSync() const { return mHasFenceSync; } + bool hasWaitSync() const { return mHasWaitSync; } + bool hasImageCrop() const { return mHasImageCrop; } + bool hasProtectedContent() const { return mHasProtectedContent; } + + void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version, + GLubyte const* extensions); char const* getVendor() const; char const* getRenderer() const; char const* getVersion() const; - char const* getExtension() const; - + char const* getExtensions() const; bool hasExtension(char const* extension) const; -}; + void initWithEGLStrings(char const* eglVersion, char const* eglExtensions); + char const* getEGLVersion() const; + char const* getEGLExtensions() const; + bool hasEGLExtension(char const* extension) const; +}; // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/RenderEngine/Image.cpp b/services/surfaceflinger/RenderEngine/Image.cpp new file mode 100644 index 0000000000..1f8e75a0ae --- /dev/null +++ b/services/surfaceflinger/RenderEngine/Image.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Image.h" + +#include <vector> + +#include <log/log.h> + +#include "GLExtensions.h" +#include "RenderEngine.h" + +namespace android { +namespace RE { + +Image::Image(const RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {} + +Image::~Image() { + setNativeWindowBuffer(nullptr, false, 0, 0); +} + +static std::vector<EGLint> buildAttributeList(bool isProtected, int32_t cropWidth, + int32_t cropHeight) { + std::vector<EGLint> attrs; + attrs.reserve(16); + + attrs.push_back(EGL_IMAGE_PRESERVED_KHR); + attrs.push_back(EGL_TRUE); + + if (isProtected && GLExtensions::getInstance().hasProtectedContent()) { + attrs.push_back(EGL_PROTECTED_CONTENT_EXT); + attrs.push_back(EGL_TRUE); + } + + if (cropWidth > 0 && cropHeight > 0) { + attrs.push_back(EGL_IMAGE_CROP_LEFT_ANDROID); + attrs.push_back(0); + attrs.push_back(EGL_IMAGE_CROP_TOP_ANDROID); + attrs.push_back(0); + attrs.push_back(EGL_IMAGE_CROP_RIGHT_ANDROID); + attrs.push_back(cropWidth); + attrs.push_back(EGL_IMAGE_CROP_BOTTOM_ANDROID); + attrs.push_back(cropHeight); + } + + attrs.push_back(EGL_NONE); + + return attrs; +} + +bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth, + int32_t cropHeight) { + if (mEGLImage != EGL_NO_IMAGE_KHR) { + if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) { + ALOGE("failed to destroy image: %#x", eglGetError()); + } + mEGLImage = EGL_NO_IMAGE_KHR; + } + + if (buffer) { + std::vector<EGLint> attrs = buildAttributeList(isProtected, cropWidth, cropHeight); + mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, + static_cast<EGLClientBuffer>(buffer), attrs.data()); + if (mEGLImage == EGL_NO_IMAGE_KHR) { + ALOGE("failed to create EGLImage: %#x", eglGetError()); + return false; + } + } + + return true; +} + +} // namespace RE +} // namespace android diff --git a/services/surfaceflinger/RenderEngine/Image.h b/services/surfaceflinger/RenderEngine/Image.h new file mode 100644 index 0000000000..f55aa59a8a --- /dev/null +++ b/services/surfaceflinger/RenderEngine/Image.h @@ -0,0 +1,53 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +struct ANativeWindowBuffer; + +namespace android { + +class RenderEngine; + +namespace RE { + +class Image { +public: + Image(const RenderEngine& engine); + ~Image(); + + Image(const Image&) = delete; + Image& operator=(const Image&) = delete; + + bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth, + int32_t cropHeight); + +private: + // methods internal to RenderEngine + friend class android::RenderEngine; + EGLSurface getEGLImage() const { return mEGLImage; } + + EGLDisplay mEGLDisplay; + EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR; +}; + +} // namespace RE +} // namespace android diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp index ffd9be2a8a..6a62b1d7dd 100644 --- a/services/surfaceflinger/RenderEngine/Mesh.cpp +++ b/services/surfaceflinger/RenderEngine/Mesh.cpp @@ -21,9 +21,10 @@ namespace android { Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize) - : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize), - mPrimitive(primitive) -{ + : mVertexCount(vertexCount), + mVertexSize(vertexSize), + mTexCoordsSize(texCoordSize), + mPrimitive(primitive) { if (vertexCount == 0) { mVertices = new float[1]; mVertices[0] = 0.0f; @@ -37,8 +38,7 @@ Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t te // either vertexSize or texCoordSize, it must have overflowed. remainder // will be equal to stride as long as stride * vertexCount doesn't overflow. if ((stride < vertexSize) || (remainder != stride)) { - ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, - texCoordSize); + ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize); mVertices = new float[1]; mVertices[0] = 0.0f; mVertexCount = 0; @@ -53,14 +53,13 @@ Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t te } Mesh::~Mesh() { - delete [] mVertices; + delete[] mVertices; } Mesh::Primitive Mesh::getPrimitive() const { return mPrimitive; } - float const* Mesh::getPositions() const { return mVertices; } @@ -75,7 +74,6 @@ float* Mesh::getTexCoords() { return mVertices + mVertexSize; } - size_t Mesh::getVertexCount() const { return mVertexCount; } @@ -89,7 +87,7 @@ size_t Mesh::getTexCoordsSize() const { } size_t Mesh::getByteStride() const { - return mStride*sizeof(float); + return mStride * sizeof(float); } size_t Mesh::getStride() const { diff --git a/services/surfaceflinger/RenderEngine/Mesh.h b/services/surfaceflinger/RenderEngine/Mesh.h index b6d42b0975..d0a9ac0c65 100644 --- a/services/surfaceflinger/RenderEngine/Mesh.h +++ b/services/surfaceflinger/RenderEngine/Mesh.h @@ -24,9 +24,9 @@ namespace android { class Mesh { public: enum Primitive { - TRIANGLES = 0x0004, // GL_TRIANGLES - TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP - TRIANGLE_FAN = 0x0006 // GL_TRIANGLE_FAN + TRIANGLES = 0x0004, // GL_TRIANGLES + TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP + TRIANGLE_FAN = 0x0006 // GL_TRIANGLE_FAN }; Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordsSize = 0); @@ -40,21 +40,24 @@ public: friend class Mesh; float* mData; size_t mStride; - VertexArray(float* data, size_t stride) : mData(data), mStride(stride) { } + VertexArray(float* data, size_t stride) : mData(data), mStride(stride) {} + public: - TYPE& operator[](size_t index) { - return *reinterpret_cast<TYPE*>(&mData[index*mStride]); - } + TYPE& operator[](size_t index) { return *reinterpret_cast<TYPE*>(&mData[index * mStride]); } TYPE const& operator[](size_t index) const { - return *reinterpret_cast<TYPE const*>(&mData[index*mStride]); + return *reinterpret_cast<TYPE const*>(&mData[index * mStride]); } }; template <typename TYPE> - VertexArray<TYPE> getPositionArray() { return VertexArray<TYPE>(getPositions(), mStride); } + VertexArray<TYPE> getPositionArray() { + return VertexArray<TYPE>(getPositions(), mStride); + } template <typename TYPE> - VertexArray<TYPE> getTexCoordArray() { return VertexArray<TYPE>(getTexCoords(), mStride); } + VertexArray<TYPE> getTexCoordArray() { + return VertexArray<TYPE>(getTexCoords(), mStride); + } Primitive getPrimitive() const; @@ -81,8 +84,8 @@ public: private: Mesh(const Mesh&); - Mesh& operator = (const Mesh&); - Mesh const& operator = (const Mesh&) const; + Mesh& operator=(const Mesh&); + Mesh const& operator=(const Mesh&) const; float* getPositions(); float* getTexCoords(); @@ -94,6 +97,5 @@ private: Primitive mPrimitive; }; - } /* namespace android */ #endif /* SF_RENDER_ENGINE_MESH_H */ diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp index 48a8da5e8e..baf92ebf60 100644 --- a/services/surfaceflinger/RenderEngine/Program.cpp +++ b/services/surfaceflinger/RenderEngine/Program.cpp @@ -19,14 +19,15 @@ #include <log/log.h> #include <utils/String8.h> +#include <math/mat4.h> +#include "Description.h" #include "Program.h" #include "ProgramCache.h" -#include "Description.h" namespace android { Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment) - : mInitialized(false) { + : mInitialized(false) { GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER); GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER); GLuint programId = glCreateProgram(); @@ -63,18 +64,15 @@ Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const c mTextureMatrixLoc = glGetUniformLocation(programId, "texture"); mSamplerLoc = glGetUniformLocation(programId, "sampler"); mColorLoc = glGetUniformLocation(programId, "color"); - mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane"); // set-up the default values for our uniforms glUseProgram(programId); - const GLfloat m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; - glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, m); + glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, mat4().asArray()); glEnableVertexAttribArray(0); } } -Program::~Program() { -} +Program::~Program() {} bool Program::isValid() const { return mInitialized; @@ -119,12 +117,11 @@ String8& Program::dumpShader(String8& result, GLenum /*type*/) { char* src = new char[l]; glGetShaderSource(shader, l, NULL, src); result.append(src); - delete [] src; + delete[] src; return result; } void Program::setUniforms(const Description& desc) { - // TODO: we should have a mechanism here to not always reset uniforms that // didn't change for this program. @@ -132,11 +129,9 @@ void Program::setUniforms(const Description& desc) { glUniform1i(mSamplerLoc, 0); glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.mTexture.getMatrix().asArray()); } - if (mAlphaPlaneLoc >= 0) { - glUniform1f(mAlphaPlaneLoc, desc.mPlaneAlpha); - } if (mColorLoc >= 0) { - glUniform4fv(mColorLoc, 1, desc.mColor); + const float color[4] = {desc.mColor.r, desc.mColor.g, desc.mColor.b, desc.mColor.a}; + glUniform4fv(mColorLoc, 1, color); } if (mColorMatrixLoc >= 0) { glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray()); diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h index 36bd120e39..6e57fdd56f 100644 --- a/services/surfaceflinger/RenderEngine/Program.h +++ b/services/surfaceflinger/RenderEngine/Program.h @@ -34,7 +34,7 @@ class String8; class Program { public: // known locations for position and texture coordinates - enum { position=0, texCoords=1 }; + enum { position = 0, texCoords = 1 }; Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment); ~Program(); @@ -54,7 +54,6 @@ public: /* set-up uniforms from the description */ void setUniforms(const Description& desc); - private: GLuint buildShader(const char* source, GLenum type); String8& dumpShader(String8& result, GLenum type); @@ -79,14 +78,10 @@ private: /* location of the sampler uniform */ GLint mSamplerLoc; - /* location of the alpha plane uniform */ - GLint mAlphaPlaneLoc; - /* location of the color uniform */ GLint mColorLoc; }; - } /* namespace android */ #endif /* SF_RENDER_ENGINE_PROGRAM_H */ diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index 06b225299c..4f138dc14c 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -19,14 +19,13 @@ #include <utils/String8.h> -#include "ProgramCache.h" -#include "Program.h" #include "Description.h" +#include "Program.h" +#include "ProgramCache.h" namespace android { // ----------------------------------------------------------------------------------------------- - /* * A simple formatter class to automatically add the endl and * manage the indentation. @@ -42,23 +41,22 @@ class Formatter { typedef Formatter& (*FormaterManipFunc)(Formatter&); friend Formatter& indent(Formatter& f); friend Formatter& dedent(Formatter& f); + public: Formatter() : mIndent(0) {} - String8 getString() const { - return mString; - } + String8 getString() const { return mString; } - friend Formatter& operator << (Formatter& out, const char* in) { - for (int i=0 ; i<out.mIndent ; i++) { + friend Formatter& operator<<(Formatter& out, const char* in) { + for (int i = 0; i < out.mIndent; i++) { out.mString.append(" "); } out.mString.append(in); out.mString.append("\n"); return out; } - friend inline Formatter& operator << (Formatter& out, const String8& in) { - return operator << (out, in.string()); + friend inline Formatter& operator<<(Formatter& out, const String8& in) { + return operator<<(out, in.string()); } friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) { return (*func)(to); @@ -83,13 +81,11 @@ ProgramCache::ProgramCache() { primeCache(); } -ProgramCache::~ProgramCache() { -} +ProgramCache::~ProgramCache() {} void ProgramCache::primeCache() { uint32_t shaderCount = 0; - uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | - Key::PLANE_ALPHA_MASK | Key::TEXTURE_MASK; + uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK; // Prime the cache for all combinations of the above masks, // leaving off the experimental color matrix mask options. @@ -98,9 +94,7 @@ void ProgramCache::primeCache() { Key shaderKey; shaderKey.set(keyMask, keyVal); uint32_t tex = shaderKey.getTextureTarget(); - if (tex != Key::TEXTURE_OFF && - tex != Key::TEXTURE_EXT && - tex != Key::TEXTURE_2D) { + if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) { continue; } Program* program = mCache.valueFor(shaderKey); @@ -118,34 +112,36 @@ void ProgramCache::primeCache() { ProgramCache::Key ProgramCache::computeKey(const Description& description) { Key needs; needs.set(Key::TEXTURE_MASK, - !description.mTextureEnabled ? Key::TEXTURE_OFF : - description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT : - description.mTexture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_2D : - Key::TEXTURE_OFF) - .set(Key::PLANE_ALPHA_MASK, - (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE) - .set(Key::BLEND_MASK, - description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) - .set(Key::OPACITY_MASK, - description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT) - .set(Key::COLOR_MATRIX_MASK, - description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF) - .set(Key::WIDE_GAMUT_MASK, - description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF); + !description.mTextureEnabled + ? Key::TEXTURE_OFF + : description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES + ? Key::TEXTURE_EXT + : description.mTexture.getTextureTarget() == GL_TEXTURE_2D + ? Key::TEXTURE_2D + : Key::TEXTURE_OFF) + .set(Key::ALPHA_MASK, + (description.mColor.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE) + .set(Key::BLEND_MASK, + description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) + .set(Key::OPACITY_MASK, + description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT) + .set(Key::COLOR_MATRIX_MASK, + description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF) + .set(Key::WIDE_GAMUT_MASK, + description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF); return needs; } String8 ProgramCache::generateVertexShader(const Key& needs) { Formatter vs; if (needs.isTexturing()) { - vs << "attribute vec4 texCoords;" - << "varying vec2 outTexCoords;"; + vs << "attribute vec4 texCoords;" + << "varying vec2 outTexCoords;"; } vs << "attribute vec4 position;" << "uniform mat4 projection;" << "uniform mat4 texture;" - << "void main(void) {" << indent - << "gl_Position = projection * position;"; + << "void main(void) {" << indent << "gl_Position = projection * position;"; if (needs.isTexturing()) { vs << "outTexCoords = (texture * texCoords).st;"; } @@ -168,12 +164,12 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { } else if (needs.getTextureTarget() == Key::TEXTURE_2D) { fs << "uniform sampler2D sampler;" << "varying vec2 outTexCoords;"; - } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) { - fs << "uniform vec4 color;"; } - if (needs.hasPlaneAlpha()) { - fs << "uniform float alphaPlane;"; + + if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) { + fs << "uniform vec4 color;"; } + if (needs.hasColorMatrix()) { fs << "uniform mat4 colorMatrix;"; } @@ -225,18 +221,19 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { if (needs.isTexturing()) { fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; } else { - fs << "gl_FragColor = color;"; + fs << "gl_FragColor.rgb = color.rgb;"; + fs << "gl_FragColor.a = 1.0;"; } if (needs.isOpaque()) { fs << "gl_FragColor.a = 1.0;"; } - if (needs.hasPlaneAlpha()) { - // modulate the alpha value with planeAlpha + if (needs.hasAlpha()) { + // modulate the current alpha value with alpha set if (needs.isPremultiplied()) { // ... and the color too if we're premultiplied - fs << "gl_FragColor *= alphaPlane;"; + fs << "gl_FragColor *= color.a;"; } else { - fs << "gl_FragColor.a *= alphaPlane;"; + fs << "gl_FragColor.a *= color.a;"; } } @@ -271,11 +268,10 @@ Program* ProgramCache::generateProgram(const Key& needs) { } void ProgramCache::useProgram(const Description& description) { - // generate the key for the shader based on the description Key needs(computeKey(description)); - // look-up the program in the cache + // look-up the program in the cache Program* program = mCache.valueFor(needs); if (program == NULL) { // we didn't find our program, so generate one... @@ -284,7 +280,7 @@ void ProgramCache::useProgram(const Description& description) { mCache.add(needs, program); time += systemTime(); - //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)", + // ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)", // needs.mNeeds, uint32_t(ns2ms(time)), mCache.size()); } @@ -295,5 +291,4 @@ void ProgramCache::useProgram(const Description& description) { } } - } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h index 5b0fbcd153..54d3722df3 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.h +++ b/services/surfaceflinger/RenderEngine/ProgramCache.h @@ -19,8 +19,8 @@ #include <GLES2/gl2.h> -#include <utils/Singleton.h> #include <utils/KeyedVector.h> +#include <utils/Singleton.h> #include <utils/TypeHelpers.h> #include "Description.h" @@ -47,63 +47,50 @@ public: friend class ProgramCache; typedef uint32_t key_t; key_t mKey; + public: enum { - BLEND_PREMULT = 0x00000001, - BLEND_NORMAL = 0x00000000, - BLEND_MASK = 0x00000001, - - OPACITY_OPAQUE = 0x00000002, - OPACITY_TRANSLUCENT = 0x00000000, - OPACITY_MASK = 0x00000002, - - PLANE_ALPHA_LT_ONE = 0x00000004, - PLANE_ALPHA_EQ_ONE = 0x00000000, - PLANE_ALPHA_MASK = 0x00000004, - - TEXTURE_OFF = 0x00000000, - TEXTURE_EXT = 0x00000008, - TEXTURE_2D = 0x00000010, - TEXTURE_MASK = 0x00000018, - - COLOR_MATRIX_OFF = 0x00000000, - COLOR_MATRIX_ON = 0x00000020, - COLOR_MATRIX_MASK = 0x00000020, - - WIDE_GAMUT_OFF = 0x00000000, - WIDE_GAMUT_ON = 0x00000040, - WIDE_GAMUT_MASK = 0x00000040, + BLEND_PREMULT = 0x00000001, + BLEND_NORMAL = 0x00000000, + BLEND_MASK = 0x00000001, + + OPACITY_OPAQUE = 0x00000002, + OPACITY_TRANSLUCENT = 0x00000000, + OPACITY_MASK = 0x00000002, + + ALPHA_LT_ONE = 0x00000004, + ALPHA_EQ_ONE = 0x00000000, + ALPHA_MASK = 0x00000004, + + TEXTURE_OFF = 0x00000000, + TEXTURE_EXT = 0x00000008, + TEXTURE_2D = 0x00000010, + TEXTURE_MASK = 0x00000018, + + COLOR_MATRIX_OFF = 0x00000000, + COLOR_MATRIX_ON = 0x00000020, + COLOR_MATRIX_MASK = 0x00000020, + + WIDE_GAMUT_OFF = 0x00000000, + WIDE_GAMUT_ON = 0x00000040, + WIDE_GAMUT_MASK = 0x00000040, }; - inline Key() : mKey(0) { } - inline Key(const Key& rhs) : mKey(rhs.mKey) { } + inline Key() : mKey(0) {} + inline Key(const Key& rhs) : mKey(rhs.mKey) {} inline Key& set(key_t mask, key_t value) { mKey = (mKey & ~mask) | value; return *this; } - inline bool isTexturing() const { - return (mKey & TEXTURE_MASK) != TEXTURE_OFF; - } - inline int getTextureTarget() const { - return (mKey & TEXTURE_MASK); - } - inline bool isPremultiplied() const { - return (mKey & BLEND_MASK) == BLEND_PREMULT; - } - inline bool isOpaque() const { - return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; - } - inline bool hasPlaneAlpha() const { - return (mKey & PLANE_ALPHA_MASK) == PLANE_ALPHA_LT_ONE; - } - inline bool hasColorMatrix() const { - return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; - } - inline bool isWideGamut() const { - return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON; - } + inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; } + inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); } + inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; } + inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; } + inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; } + inline bool hasColorMatrix() const { return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; } + inline bool isWideGamut() const { return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON; } // this is the definition of a friend function -- not a method of class Needs friend inline int strictly_order_type(const Key& lhs, const Key& rhs) { @@ -135,7 +122,6 @@ private: DefaultKeyedVector<Key, Program*> mCache; }; - ANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key) } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index 56e9ac07ad..314333f044 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -18,13 +18,14 @@ #include <ui/Rect.h> #include <ui/Region.h> -#include "RenderEngine.h" #include "GLES20RenderEngine.h" #include "GLExtensions.h" +#include "Image.h" #include "Mesh.h" +#include "RenderEngine.h" -#include <vector> #include <SurfaceFlinger.h> +#include <vector> extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); @@ -32,46 +33,28 @@ extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy namespace android { // --------------------------------------------------------------------------- -static bool findExtension(const char* exts, const char* name) { - if (!exts) - return false; - size_t len = strlen(name); - - const char* pos = exts; - while ((pos = strstr(pos, name)) != NULL) { - if (pos[len] == '\0' || pos[len] == ' ') - return true; - pos += len; +std::unique_ptr<RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) { + // initialize EGL for the default display + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (!eglInitialize(display, NULL, NULL)) { + LOG_ALWAYS_FATAL("failed to initialize EGL"); } - return false; -} + GLExtensions& extensions(GLExtensions::getInstance()); + extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION), + eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS)); -RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t featureFlags) { - // EGL_ANDROIDX_no_config_context is an experimental extension with no - // written specification. It will be replaced by something more formal. - // SurfaceFlinger is using it to allow a single EGLContext to render to - // both a 16-bit primary display framebuffer and a 32-bit virtual display - // framebuffer. - // - // EGL_KHR_no_config_context is official extension to allow creating a - // context that works with any surface of a display. - // // The code assumes that ES2 or later is available if this extension is // supported. EGLConfig config = EGL_NO_CONFIG; - if (!findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), - "EGL_ANDROIDX_no_config_context") && - !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), - "EGL_KHR_no_config_context")) { + if (!extensions.hasNoConfigContext()) { config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } EGLint renderableType = 0; if (config == EGL_NO_CONFIG) { renderableType = EGL_OPENGL_ES2_BIT; - } else if (!eglGetConfigAttrib(display, config, - EGL_RENDERABLE_TYPE, &renderableType)) { + } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) { LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE"); } EGLint contextClientVersion = 0; @@ -96,12 +79,10 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f contextAttributes.push_back(EGL_NONE); contextAttributes.push_back(EGL_NONE); - EGLContext ctxt = eglCreateContext(display, config, NULL, - contextAttributes.data()); + EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes.data()); // if can't create a GL context, we can only abort. - LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed"); - + LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed"); // now figure out what version of GL did we actually get // NOTE: a dummy surface is not needed if KHR_create_context is supported @@ -110,41 +91,37 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f if (dummyConfig == EGL_NO_CONFIG) { dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } - EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE }; + EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE}; EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs); - LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer"); + LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer"); EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt); LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current"); - GLExtensions& extensions(GLExtensions::getInstance()); - extensions.initWithGLStrings( - glGetString(GL_VENDOR), - glGetString(GL_RENDERER), - glGetString(GL_VERSION), - glGetString(GL_EXTENSIONS)); + extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER), + glGetString(GL_VERSION), glGetString(GL_EXTENSIONS)); - GlesVersion version = parseGlesVersion( extensions.getVersion() ); + GlesVersion version = parseGlesVersion(extensions.getVersion()); // initialize the renderer while GL is current - RenderEngine* engine = NULL; + std::unique_ptr<RenderEngine> engine; switch (version) { - case GLES_VERSION_1_0: - case GLES_VERSION_1_1: - LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run."); - break; - case GLES_VERSION_2_0: - case GLES_VERSION_3_0: - engine = new GLES20RenderEngine(featureFlags); - break; + case GLES_VERSION_1_0: + case GLES_VERSION_1_1: + LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run."); + break; + case GLES_VERSION_2_0: + case GLES_VERSION_3_0: + engine = std::make_unique<GLES20RenderEngine>(featureFlags); + break; } - engine->setEGLHandles(config, ctxt); + engine->setEGLHandles(display, config, ctxt); ALOGI("OpenGL ES informations:"); ALOGI("vendor : %s", extensions.getVendor()); ALOGI("renderer : %s", extensions.getRenderer()); ALOGI("version : %s", extensions.getVersion()); - ALOGI("extensions: %s", extensions.getExtension()); + ALOGI("extensions: %s", extensions.getExtensions()); ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize()); ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims()); @@ -154,31 +131,140 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t f return engine; } -RenderEngine::RenderEngine() : mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) { -} +RenderEngine::RenderEngine() + : mEGLDisplay(EGL_NO_DISPLAY), mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) {} RenderEngine::~RenderEngine() { + eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglTerminate(mEGLDisplay); } -void RenderEngine::setEGLHandles(EGLConfig config, EGLContext ctxt) { +void RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) { + mEGLDisplay = display; mEGLConfig = config; mEGLContext = ctxt; } -EGLContext RenderEngine::getEGLConfig() const { +EGLDisplay RenderEngine::getEGLDisplay() const { + return mEGLDisplay; +} + +EGLConfig RenderEngine::getEGLConfig() const { return mEGLConfig; } -EGLContext RenderEngine::getEGLContext() const { - return mEGLContext; +bool RenderEngine::supportsImageCrop() const { + return GLExtensions::getInstance().hasImageCrop(); +} + +bool RenderEngine::isCurrent() const { + return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext(); +} + +bool RenderEngine::setCurrentSurface(const RE::Surface& surface) { + bool success = true; + EGLSurface eglSurface = surface.getEGLSurface(); + if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) { + success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE; + if (success && surface.getAsync()) { + eglSwapInterval(mEGLDisplay, 0); + } + } + + return success; +} + +void RenderEngine::resetCurrentSurface() { + eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +} + +base::unique_fd RenderEngine::flush() { + if (!GLExtensions::getInstance().hasNativeFenceSync()) { + return base::unique_fd(); + } + + EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); + if (sync == EGL_NO_SYNC_KHR) { + ALOGW("failed to create EGL native fence sync: %#x", eglGetError()); + return base::unique_fd(); + } + + // native fence fd will not be populated until flush() is done. + glFlush(); + + // get the fence fd + base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync)); + eglDestroySyncKHR(mEGLDisplay, sync); + if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + ALOGW("failed to dup EGL native fence sync: %#x", eglGetError()); + } + + return fenceFd; +} + +bool RenderEngine::finish() { + if (!GLExtensions::getInstance().hasFenceSync()) { + ALOGW("no synchronization support"); + return false; + } + + EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL); + if (sync == EGL_NO_SYNC_KHR) { + ALOGW("failed to create EGL fence sync: %#x", eglGetError()); + return false; + } + + EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, + 2000000000 /*2 sec*/); + EGLint error = eglGetError(); + eglDestroySyncKHR(mEGLDisplay, sync); + if (result != EGL_CONDITION_SATISFIED_KHR) { + if (result == EGL_TIMEOUT_EXPIRED_KHR) { + ALOGW("fence wait timed out"); + } else { + ALOGW("error waiting on EGL fence: %#x", error); + } + return false; + } + + return true; +} + +bool RenderEngine::waitFence(base::unique_fd fenceFd) { + if (!GLExtensions::getInstance().hasNativeFenceSync() || + !GLExtensions::getInstance().hasWaitSync()) { + return false; + } + + EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE}; + EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + if (sync == EGL_NO_SYNC_KHR) { + ALOGE("failed to create EGL native fence sync: %#x", eglGetError()); + return false; + } + + // fenceFd is now owned by EGLSync + (void)fenceFd.release(); + + // XXX: The spec draft is inconsistent as to whether this should return an + // EGLint or void. Ignore the return value for now, as it's not strictly + // needed. + eglWaitSyncKHR(mEGLDisplay, sync, 0); + EGLint error = eglGetError(); + eglDestroySyncKHR(mEGLDisplay, sync); + if (error != EGL_SUCCESS) { + ALOGE("failed to wait for EGL native fence sync: %#x", error); + return false; + } + + return true; } void RenderEngine::checkErrors() const { do { // there could be more than one error flag GLenum error = glGetError(); - if (error == GL_NO_ERROR) - break; + if (error == GL_NO_ERROR) break; ALOGE("GL error 0x%04x", int(error)); } while (true); } @@ -201,41 +287,36 @@ RenderEngine::GlesVersion RenderEngine::parseGlesVersion(const char* str) { return GLES_VERSION_1_0; } -void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, - float red, float green, float blue, float alpha) { +void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red, + float green, float blue, float alpha) { size_t c; Rect const* r = region.getArray(&c); - Mesh mesh(Mesh::TRIANGLES, c*6, 2); + Mesh mesh(Mesh::TRIANGLES, c * 6, 2); Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - for (size_t i=0 ; i<c ; i++, r++) { - position[i*6 + 0].x = r->left; - position[i*6 + 0].y = height - r->top; - position[i*6 + 1].x = r->left; - position[i*6 + 1].y = height - r->bottom; - position[i*6 + 2].x = r->right; - position[i*6 + 2].y = height - r->bottom; - position[i*6 + 3].x = r->left; - position[i*6 + 3].y = height - r->top; - position[i*6 + 4].x = r->right; - position[i*6 + 4].y = height - r->bottom; - position[i*6 + 5].x = r->right; - position[i*6 + 5].y = height - r->top; + for (size_t i = 0; i < c; i++, r++) { + position[i * 6 + 0].x = r->left; + position[i * 6 + 0].y = height - r->top; + position[i * 6 + 1].x = r->left; + position[i * 6 + 1].y = height - r->bottom; + position[i * 6 + 2].x = r->right; + position[i * 6 + 2].y = height - r->bottom; + position[i * 6 + 3].x = r->left; + position[i * 6 + 3].y = height - r->top; + position[i * 6 + 4].x = r->right; + position[i * 6 + 4].y = height - r->bottom; + position[i * 6 + 5].x = r->right; + position[i * 6 + 5].y = height - r->top; } setupFillWithColor(red, green, blue, alpha); drawMesh(mesh); } -void RenderEngine::flush() { - glFlush(); -} - void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) { glClearColor(red, green, blue, alpha); glClear(GL_COLOR_BUFFER_BIT); } -void RenderEngine::setScissor( - uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) { +void RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) { glScissor(left, bottom, right, top); glEnable(GL_SCISSOR_TEST); } @@ -252,43 +333,66 @@ void RenderEngine::deleteTextures(size_t count, uint32_t const* names) { glDeleteTextures(count, names); } +void RenderEngine::bindExternalTextureImage(uint32_t texName, const RE::Image& image) { + const GLenum target = GL_TEXTURE_EXTERNAL_OES; + + glBindTexture(target, texName); + if (image.getEGLImage() != EGL_NO_IMAGE_KHR) { + glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image.getEGLImage())); + } +} + void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) { glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } void RenderEngine::dump(String8& result) { const GLExtensions& extensions(GLExtensions::getInstance()); - result.appendFormat("GLES: %s, %s, %s\n", - extensions.getVendor(), - extensions.getRenderer(), - extensions.getVersion()); - result.appendFormat("%s\n", extensions.getExtension()); + + result.appendFormat("EGL implementation : %s\n", extensions.getEGLVersion()); + result.appendFormat("%s\n", extensions.getEGLExtensions()); + + result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(), + extensions.getVersion()); + result.appendFormat("%s\n", extensions.getExtensions()); } // --------------------------------------------------------------------------- -RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer( - RenderEngine& engine, EGLImageKHR image) : mEngine(engine) -{ - mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus); +RenderEngine::BindNativeBufferAsFramebuffer::BindNativeBufferAsFramebuffer( + RenderEngine& engine, ANativeWindowBuffer* buffer) + : mEngine(engine) { + mImage = eglCreateImageKHR(mEngine.mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, + buffer, NULL); + if (mImage == EGL_NO_IMAGE_KHR) { + mStatus = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + return; + } + + mEngine.bindImageAsFramebuffer(mImage, &mTexName, &mFbName, &mStatus); - ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES, - "glCheckFramebufferStatusOES error %d", mStatus); + ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d", + mStatus); } -RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() { +RenderEngine::BindNativeBufferAsFramebuffer::~BindNativeBufferAsFramebuffer() { + if (mImage == EGL_NO_IMAGE_KHR) { + return; + } + // back to main framebuffer mEngine.unbindFramebuffer(mTexName, mFbName); + eglDestroyImageKHR(mEngine.mEGLDisplay, mImage); } -status_t RenderEngine::BindImageAsFramebuffer::getStatus() const { +status_t RenderEngine::BindNativeBufferAsFramebuffer::getStatus() const { return mStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE; } // --------------------------------------------------------------------------- -static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, - EGLint attribute, EGLint wanted, EGLConfig* outConfig) { +static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, + EGLint wanted, EGLConfig* outConfig) { EGLint numConfigs = -1, n = 0; eglGetConfigs(dpy, NULL, 0, &numConfigs); EGLConfig* const configs = new EGLConfig[numConfigs]; @@ -296,23 +400,23 @@ static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, if (n) { if (attribute != EGL_NONE) { - for (int i=0 ; i<n ; i++) { + for (int i = 0; i < n; i++) { EGLint value = 0; eglGetConfigAttrib(dpy, configs[i], attribute, &value); if (wanted == value) { *outConfig = configs[i]; - delete [] configs; + delete[] configs; return NO_ERROR; } } } else { // just pick the first one *outConfig = configs[0]; - delete [] configs; + delete[] configs; return NO_ERROR; } } - delete [] configs; + delete[] configs; return NAME_NOT_FOUND; } @@ -322,10 +426,10 @@ class EGLAttributeVector { friend class Adder; KeyedVector<Attribute, EGLint> mList; struct Attribute { - Attribute() : v(0) {}; - explicit Attribute(EGLint v) : v(v) { } + Attribute() : v(0){}; + explicit Attribute(EGLint v) : v(v) {} EGLint v; - bool operator < (const Attribute& other) const { + bool operator<(const Attribute& other) const { // this places EGL_NONE at the end EGLint lhs(v); EGLint rhs(other.v); @@ -338,39 +442,32 @@ class EGLAttributeVector { friend class EGLAttributeVector; EGLAttributeVector& v; EGLint attribute; - Adder(EGLAttributeVector& v, EGLint attribute) - : v(v), attribute(attribute) { - } + Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {} + public: - void operator = (EGLint value) { + void operator=(EGLint value) { if (attribute != EGL_NONE) { v.mList.add(Attribute(attribute), value); } } - operator EGLint () const { return v.mList[attribute]; } + operator EGLint() const { return v.mList[attribute]; } }; + public: - EGLAttributeVector() { - mList.add(Attribute(EGL_NONE), EGL_NONE); - } + EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); } void remove(EGLint attribute) { if (attribute != EGL_NONE) { mList.removeItem(Attribute(attribute)); } } - Adder operator [] (EGLint attribute) { - return Adder(*this, attribute); - } - EGLint operator [] (EGLint attribute) const { - return mList[attribute]; - } + Adder operator[](EGLint attribute) { return Adder(*this, attribute); } + EGLint operator[](EGLint attribute) const { return mList[attribute]; } // cast-operator to (EGLint const*) - operator EGLint const* () const { return &mList.keyAt(0).v; } + operator EGLint const*() const { return &mList.keyAt(0).v; } }; - -static status_t selectEGLConfig(EGLDisplay display, EGLint format, - EGLint renderableType, EGLConfig* config) { +static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType, + EGLConfig* config) { // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if // it is to be used with WIFI displays status_t err; @@ -379,24 +476,23 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLAttributeVector attribs; if (renderableType) { - attribs[EGL_RENDERABLE_TYPE] = renderableType; - attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE; - attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT|EGL_PBUFFER_BIT; + attribs[EGL_RENDERABLE_TYPE] = renderableType; + attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE; + attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE; - attribs[EGL_RED_SIZE] = 8; - attribs[EGL_GREEN_SIZE] = 8; - attribs[EGL_BLUE_SIZE] = 8; - attribs[EGL_ALPHA_SIZE] = 8; - wantedAttribute = EGL_NONE; - wantedAttributeValue = EGL_NONE; + attribs[EGL_RED_SIZE] = 8; + attribs[EGL_GREEN_SIZE] = 8; + attribs[EGL_BLUE_SIZE] = 8; + attribs[EGL_ALPHA_SIZE] = 8; + wantedAttribute = EGL_NONE; + wantedAttributeValue = EGL_NONE; } else { // if no renderable type specified, fallback to a simplified query - wantedAttribute = EGL_NATIVE_VISUAL_ID; - wantedAttributeValue = format; + wantedAttribute = EGL_NATIVE_VISUAL_ID; + wantedAttributeValue = format; } - err = selectConfigForAttribute(display, attribs, - wantedAttribute, wantedAttributeValue, config); + err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config); if (err == NO_ERROR) { EGLint caveat; if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat)) @@ -406,8 +502,7 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, return err; } -EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, - bool logConfig) { +EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) { status_t err; EGLConfig config; @@ -430,23 +525,22 @@ EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, if (logConfig) { // print some debugging info - EGLint r,g,b,a; - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); + EGLint r, g, b, a; + eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); ALOGI("EGL information:"); ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); - ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported"); ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); } return config; } - void RenderEngine::primeCache() const { // Getting the ProgramCache instance causes it to prime its shader cache, // which is performed in its constructor diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 954457946e..f8869197b1 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -14,20 +14,25 @@ * limitations under the License. */ - #ifndef SF_RENDERENGINE_H_ #define SF_RENDERENGINE_H_ +#include <memory> + #include <stdint.h> #include <sys/types.h> #include <EGL/egl.h> #include <EGL/eglext.h> -#include <math/mat4.h> #include <Transform.h> +#include <android-base/unique_fd.h> +#include <gui/SurfaceControl.h> +#include <math/mat4.h> #define EGL_NO_CONFIG ((EGLConfig)0) +struct ANativeWindowBuffer; + // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- @@ -38,31 +43,39 @@ class Region; class Mesh; class Texture; +namespace RE { +class Image; +class Surface; +} // namespace RE + class RenderEngine { enum GlesVersion { - GLES_VERSION_1_0 = 0x10000, - GLES_VERSION_1_1 = 0x10001, - GLES_VERSION_2_0 = 0x20000, - GLES_VERSION_3_0 = 0x30000, + GLES_VERSION_1_0 = 0x10000, + GLES_VERSION_1_1 = 0x10001, + GLES_VERSION_2_0 = 0x20000, + GLES_VERSION_3_0 = 0x30000, }; static GlesVersion parseGlesVersion(const char* str); + EGLDisplay mEGLDisplay; EGLConfig mEGLConfig; EGLContext mEGLContext; - void setEGLHandles(EGLConfig config, EGLContext ctxt); + void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt); - virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) = 0; + virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, + uint32_t* status) = 0; virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0; protected: RenderEngine(); - virtual ~RenderEngine() = 0; public: + virtual ~RenderEngine() = 0; + enum FeatureFlag { WIDE_COLOR_SUPPORT = 1 << 0 // Platform has a wide color display }; - static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags); + static std::unique_ptr<RenderEngine> create(int hwcFormat, uint32_t featureFlags); static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); @@ -71,51 +84,65 @@ public: // dump the extension strings. always call the base class. virtual void dump(String8& result); + bool supportsImageCrop() const; + + bool isCurrent() const; + bool setCurrentSurface(const RE::Surface& surface); + void resetCurrentSurface(); + + // synchronization + + // flush submits RenderEngine command stream for execution and returns a + // native fence fd that is signaled when the execution has completed. It + // returns -1 on errors. + base::unique_fd flush(); + // finish waits until RenderEngine command stream has been executed. It + // returns false on errors. + bool finish(); + // waitFence inserts a wait on an external fence fd to RenderEngine + // command stream. It returns false on errors. + bool waitFence(base::unique_fd fenceFd); + // helpers - void flush(); void clearWithColor(float red, float green, float blue, float alpha); - void fillRegionWithColor(const Region& region, uint32_t height, - float red, float green, float blue, float alpha); + void fillRegionWithColor(const Region& region, uint32_t height, float red, float green, + float blue, float alpha); // common to all GL versions void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top); void disableScissor(); void genTextures(size_t count, uint32_t* names); void deleteTextures(size_t count, uint32_t const* names); + void bindExternalTextureImage(uint32_t texName, const RE::Image& image); void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels); - class BindImageAsFramebuffer { + class BindNativeBufferAsFramebuffer { RenderEngine& mEngine; + EGLImageKHR mImage; uint32_t mTexName, mFbName; uint32_t mStatus; + public: - BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image); - ~BindImageAsFramebuffer(); + BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer); + ~BindNativeBufferAsFramebuffer(); int getStatus() const; }; // set-up virtual void checkErrors() const; - virtual void setViewportAndProjection(size_t vpw, size_t vph, - Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) = 0; -#ifdef USE_HWC2 - virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) = 0; - virtual void setupDimLayerBlending(float alpha) = 0; + virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, + bool yswap, Transform::orientation_flags rotation) = 0; + virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, + const half4& color) = 0; virtual void setColorMode(android_color_mode mode) = 0; virtual void setSourceDataSpace(android_dataspace source) = 0; virtual void setWideColor(bool hasWideColor) = 0; virtual bool usesWideColor() = 0; -#else - virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0; - virtual void setupDimLayerBlending(int alpha) = 0; -#endif virtual void setupLayerTexturing(const Texture& texture) = 0; virtual void setupLayerBlackedOut() = 0; virtual void setupFillWithColor(float r, float g, float b, float a) = 0; - virtual mat4 setupColorTransform(const mat4& /* colorTransform */) { - return mat4(); - } + virtual mat4 setupColorTransform(const mat4& /* colorTransform */) { return mat4(); } virtual void disableTexturing() = 0; virtual void disableBlending() = 0; @@ -127,8 +154,9 @@ public: virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; + // internal to RenderEngine + EGLDisplay getEGLDisplay() const; EGLConfig getEGLConfig() const; - EGLContext getEGLContext() const; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/Surface.cpp b/services/surfaceflinger/RenderEngine/Surface.cpp new file mode 100644 index 0000000000..a23d9fbb4e --- /dev/null +++ b/services/surfaceflinger/RenderEngine/Surface.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Surface.h" + +#include "RenderEngine.h" + +#include <log/log.h> + +namespace android { +namespace RE { + +Surface::Surface(const RenderEngine& engine) + : mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) { + // RE does not assume any config when EGL_KHR_no_config_context is supported + if (mEGLConfig == EGL_NO_CONFIG_KHR) { + mEGLConfig = RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false); + } +} + +Surface::~Surface() { + setNativeWindow(nullptr); +} + +void Surface::setNativeWindow(ANativeWindow* window) { + if (mEGLSurface != EGL_NO_SURFACE) { + eglDestroySurface(mEGLDisplay, mEGLSurface); + mEGLSurface = EGL_NO_SURFACE; + } + + mWindow = window; + if (mWindow) { + mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mWindow, nullptr); + } +} + +void Surface::swapBuffers() const { + if (!eglSwapBuffers(mEGLDisplay, mEGLSurface)) { + EGLint error = eglGetError(); + + const char format[] = "eglSwapBuffers(%p, %p) failed with 0x%08x"; + if (mCritical || error == EGL_CONTEXT_LOST) { + LOG_ALWAYS_FATAL(format, mEGLDisplay, mEGLSurface, error); + } else { + ALOGE(format, mEGLDisplay, mEGLSurface, error); + } + } +} + +EGLint Surface::queryConfig(EGLint attrib) const { + EGLint value; + if (!eglGetConfigAttrib(mEGLConfig, mEGLConfig, attrib, &value)) { + value = 0; + } + + return value; +} + +EGLint Surface::querySurface(EGLint attrib) const { + EGLint value; + if (!eglQuerySurface(mEGLDisplay, mEGLSurface, attrib, &value)) { + value = 0; + } + + return value; +} + +int32_t Surface::queryRedSize() const { + return queryConfig(EGL_RED_SIZE); +} + +int32_t Surface::queryGreenSize() const { + return queryConfig(EGL_GREEN_SIZE); +} + +int32_t Surface::queryBlueSize() const { + return queryConfig(EGL_BLUE_SIZE); +} + +int32_t Surface::queryAlphaSize() const { + return queryConfig(EGL_ALPHA_SIZE); +} + +int32_t Surface::queryWidth() const { + return querySurface(EGL_WIDTH); +} + +int32_t Surface::queryHeight() const { + return querySurface(EGL_HEIGHT); +} + +} // namespace RE +} // namespace android diff --git a/services/surfaceflinger/RenderEngine/Surface.h b/services/surfaceflinger/RenderEngine/Surface.h new file mode 100644 index 0000000000..8b10be9303 --- /dev/null +++ b/services/surfaceflinger/RenderEngine/Surface.h @@ -0,0 +1,73 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include <EGL/egl.h> + +struct ANativeWindow; + +namespace android { + +class RenderEngine; + +namespace RE { + +class Surface { +public: + Surface(const RenderEngine& engine); + ~Surface(); + + Surface(const Surface&) = delete; + Surface& operator=(const Surface&) = delete; + + void setCritical(bool enable) { mCritical = enable; } + void setAsync(bool enable) { mAsync = enable; } + + void setNativeWindow(ANativeWindow* window); + void swapBuffers() const; + + int32_t queryRedSize() const; + int32_t queryGreenSize() const; + int32_t queryBlueSize() const; + int32_t queryAlphaSize() const; + + int32_t queryWidth() const; + int32_t queryHeight() const; + +private: + EGLint queryConfig(EGLint attrib) const; + EGLint querySurface(EGLint attrib) const; + + // methods internal to RenderEngine + friend class android::RenderEngine; + bool getAsync() const { return mAsync; } + EGLSurface getEGLSurface() const { return mEGLSurface; } + + EGLDisplay mEGLDisplay; + EGLConfig mEGLConfig; + + bool mCritical = false; + bool mAsync = false; + + ANativeWindow* mWindow = nullptr; + EGLSurface mEGLSurface = EGL_NO_SURFACE; +}; + +} // namespace RE +} // namespace android diff --git a/services/surfaceflinger/RenderEngine/Texture.cpp b/services/surfaceflinger/RenderEngine/Texture.cpp index 8875b6d85b..351430fa06 100644 --- a/services/surfaceflinger/RenderEngine/Texture.cpp +++ b/services/surfaceflinger/RenderEngine/Texture.cpp @@ -20,24 +20,22 @@ namespace android { -Texture::Texture() : - mTextureName(0), mTextureTarget(TEXTURE_2D), - mWidth(0), mHeight(0), mFiltering(false) { -} +Texture::Texture() + : mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) {} -Texture::Texture(Target textureTarget, uint32_t textureName) : - mTextureName(textureName), mTextureTarget(textureTarget), - mWidth(0), mHeight(0), mFiltering(false) { -} +Texture::Texture(Target textureTarget, uint32_t textureName) + : mTextureName(textureName), + mTextureTarget(textureTarget), + mWidth(0), + mHeight(0), + mFiltering(false) {} void Texture::init(Target textureTarget, uint32_t textureName) { mTextureName = textureName; mTextureTarget = textureTarget; } -Texture::~Texture() { -} - +Texture::~Texture() {} void Texture::setMatrix(float const* matrix) { mTextureMatrix = mat4(matrix); diff --git a/services/surfaceflinger/RenderEngine/Texture.h b/services/surfaceflinger/RenderEngine/Texture.h index a07e0c3c37..56b6b31573 100644 --- a/services/surfaceflinger/RenderEngine/Texture.h +++ b/services/surfaceflinger/RenderEngine/Texture.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#include <stdint.h> #include <math/mat4.h> +#include <stdint.h> #ifndef SF_RENDER_ENGINE_TEXTURE_H #define SF_RENDER_ENGINE_TEXTURE_H diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ee85e387b5..7e308e811e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -28,8 +28,6 @@ #include <stdatomic.h> #include <optional> -#include <EGL/egl.h> - #include <cutils/properties.h> #include <log/log.h> @@ -72,8 +70,9 @@ #include "EventControlThread.h" #include "EventThread.h" #include "Layer.h" +#include "BufferLayer.h" #include "LayerVector.h" -#include "LayerDim.h" +#include "ColorLayer.h" #include "MonitoredProducer.h" #include "SurfaceFlinger.h" @@ -90,6 +89,8 @@ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <configstore/Utils.h> +#include <layerproto/LayerProtoParser.h> + #define DISPLAY_COUNT 1 /* @@ -98,8 +99,6 @@ */ #define DEBUG_SCREENSHOTS false -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); - namespace android { using namespace android::hardware::configstore; @@ -154,6 +153,15 @@ bool useTrebleTestingOverride() { return std::string(value) == "true"; } +SurfaceFlingerBE::SurfaceFlingerBE() + : mHwcServiceName(getHwcServiceName()), + mRenderEngine(nullptr), + mFrameBuckets(), + mTotalTime(0), + mLastSwapTime(0), + mComposerSequenceId(0) { +} + SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), mTransactionFlags(0), @@ -162,8 +170,6 @@ SurfaceFlinger::SurfaceFlinger() mLayersRemoved(false), mLayersAdded(false), mRepaintEverything(0), - mHwcServiceName(getHwcServiceName()), - mRenderEngine(nullptr), mBootTime(systemTime()), mBuiltinDisplays(), mVisibleRegionsDirty(false), @@ -185,13 +191,9 @@ SurfaceFlinger::SurfaceFlinger() mHWVsyncAvailable(false), mHasColorMatrix(false), mHasPoweredOff(false), - mFrameBuckets(), - mTotalTime(0), - mLastSwapTime(0), mNumLayers(0), mVrFlingerRequestsDisplay(false), - mMainThreadId(std::this_thread::get_id()), - mComposerSequenceId(0) + mMainThreadId(std::this_thread::get_id()) { ALOGI("SurfaceFlinger is starting"); @@ -226,7 +228,7 @@ SurfaceFlinger::SurfaceFlinger() hasWideColorDisplay = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); - mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset); + mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset); // debugging stuff... char value[PROPERTY_VALUE_MAX]; @@ -282,9 +284,6 @@ void SurfaceFlinger::onFirstRef() SurfaceFlinger::~SurfaceFlinger() { - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(display); } void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */) @@ -568,7 +567,7 @@ public: virtual void onInjectSyncEvent(nsecs_t when) { std::lock_guard<std::mutex> lock(mCallbackMutex); - if (mCallback != nullptr) { + if (mCallback) { mCallback->onVSyncEvent(when); } } @@ -591,16 +590,12 @@ void SurfaceFlinger::init() { Mutex::Autolock _l(mStateLock); - // initialize EGL for the default display - mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(mEGLDisplay, NULL, NULL); - // start the EventThread - sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, - vsyncPhaseOffsetNs, true, "app"); + sp<VSyncSource> vsyncSrc = + new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true, "app"); mEventThread = new EventThread(vsyncSrc, *this, false); - sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, - sfVsyncPhaseOffsetNs, true, "sf"); + sp<VSyncSource> sfVsyncSrc = + new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf"); mSFEventThread = new EventThread(sfVsyncSrc, *this, true); mEventQueue.setEventThread(mSFEventThread); @@ -615,20 +610,14 @@ void SurfaceFlinger::init() { } // Get a RenderEngine for the given display / config (can't fail) - mRenderEngine = RenderEngine::create(mEGLDisplay, - HAL_PIXEL_FORMAT_RGBA_8888, + getBE().mRenderEngine = RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888, hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); - - // retrieve the EGL context that was selected/created - mEGLContext = mRenderEngine->getEGLContext(); - - LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, - "couldn't create EGLContext"); + LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine"); LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, "Starting with vr flinger active is not currently supported."); - mHwc.reset(new HWComposer(mHwcServiceName)); - mHwc->registerCallback(this, mComposerSequenceId); + getBE().mHwc.reset(new HWComposer(getBE().mHwcServiceName)); + getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId); if (useVrFlinger) { auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) { @@ -645,8 +634,9 @@ void SurfaceFlinger::init() { }); postMessageAsync(message); }; - mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(), - vrFlingerRequestDisplayCallback); + mVrFlinger = dvr::VrFlinger::Create(getBE().mHwc->getComposer(), + getBE().mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0), + vrFlingerRequestDisplayCallback); if (!mVrFlinger) { ALOGE("Failed to start vrflinger"); } @@ -661,7 +651,7 @@ void SurfaceFlinger::init() { // set initial conditions (e.g. unblank default device) initializeDisplays(); - mRenderEngine->primeCache(); + getBE().mRenderEngine->primeCache(); // Inform native graphics APIs whether the present timestamp is supported: if (getHwComposer().hasCapability( @@ -703,11 +693,11 @@ void SurfaceFlinger::startBootAnim() { } size_t SurfaceFlinger::getMaxTextureSize() const { - return mRenderEngine->getMaxTextureSize(); + return getBE().mRenderEngine->getMaxTextureSize(); } size_t SurfaceFlinger::getMaxViewportDims() const { - return mRenderEngine->getMaxViewportDims(); + return getBE().mRenderEngine->getMaxViewportDims(); } // ---------------------------------------------------------------------------- @@ -1055,7 +1045,7 @@ status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display, } std::unique_ptr<HdrCapabilities> capabilities = - mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId()); + getBE().mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId()); if (capabilities) { std::swap(*outCapabilities, *capabilities); } else { @@ -1065,42 +1055,29 @@ status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display, return NO_ERROR; } -void SurfaceFlinger::enableVSyncInjectionsInternal(bool enable) { - Mutex::Autolock _l(mStateLock); - - if (mInjectVSyncs == enable) { - return; - } +status_t SurfaceFlinger::enableVSyncInjections(bool enable) { + sp<LambdaMessage> enableVSyncInjections = new LambdaMessage([&]() { + Mutex::Autolock _l(mStateLock); - if (enable) { - ALOGV("VSync Injections enabled"); - if (mVSyncInjector.get() == nullptr) { - mVSyncInjector = new InjectVSyncSource(); - mInjectorEventThread = new EventThread(mVSyncInjector, *this, false); + if (mInjectVSyncs == enable) { + return; } - mEventQueue.setEventThread(mInjectorEventThread); - } else { - ALOGV("VSync Injections disabled"); - mEventQueue.setEventThread(mSFEventThread); - } - - mInjectVSyncs = enable; -} -status_t SurfaceFlinger::enableVSyncInjections(bool enable) { - class MessageEnableVSyncInjections : public MessageBase { - SurfaceFlinger* mFlinger; - bool mEnable; - public: - MessageEnableVSyncInjections(SurfaceFlinger* flinger, bool enable) - : mFlinger(flinger), mEnable(enable) { } - virtual bool handler() { - mFlinger->enableVSyncInjectionsInternal(mEnable); - return true; + if (enable) { + ALOGV("VSync Injections enabled"); + if (mVSyncInjector.get() == nullptr) { + mVSyncInjector = new InjectVSyncSource(); + mInjectorEventThread = new EventThread(mVSyncInjector, *this, false); + } + mEventQueue.setEventThread(mInjectorEventThread); + } else { + ALOGV("VSync Injections disabled"); + mEventQueue.setEventThread(mSFEventThread); } - }; - sp<MessageBase> msg = new MessageEnableVSyncInjections(this, enable); - postMessageSync(msg); + + mInjectVSyncs = enable; + }); + postMessageSync(enableVSyncInjections); return NO_ERROR; } @@ -1216,7 +1193,7 @@ void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) { return; } - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); mPrimaryDispSync.reset(); @@ -1259,12 +1236,12 @@ void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t displayId, int64_t timestamp) { Mutex::Autolock lock(mStateLock); // Ignore any vsyncs from a previous hardware composer. - if (sequenceId != mComposerSequenceId) { + if (sequenceId != getBE().mComposerSequenceId) { return; } int32_t type; - if (!mHwc->onVsync(displayId, timestamp, &type)) { + if (!getBE().mHwc->onVsync(displayId, timestamp, &type)) { return; } @@ -1285,8 +1262,8 @@ void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, } void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { - std::lock_guard<std::mutex> lock(mCompositorTimingLock); - *compositorTiming = mCompositorTiming; + std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); + *compositorTiming = getBE().mCompositorTiming; } void SurfaceFlinger::createDefaultDisplayDevice() { @@ -1300,7 +1277,7 @@ void SurfaceFlinger::createDefaultDisplayDevice() { sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); - sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, type, consumer); + sp<FramebufferSurface> fbs = new FramebufferSurface(*getBE().mHwc, type, consumer); bool hasWideColorModes = false; std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type); @@ -1317,8 +1294,7 @@ void SurfaceFlinger::createDefaultDisplayDevice() { } bool useWideColorMode = hasWideColorModes && hasWideColorDisplay && !mForceNativeColorMode; sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure, - token, fbs, producer, mRenderEngine->getEGLConfig(), - useWideColorMode); + token, fbs, producer, useWideColorMode); mDisplays.add(token, hw); android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE; if (useWideColorMode) { @@ -1333,7 +1309,7 @@ void SurfaceFlinger::createDefaultDisplayDevice() { // make the GLContext current so that we can create textures when creating // Layers (which may happens before we render something) - hw->makeCurrent(mEGLDisplay, mEGLContext); + hw->makeCurrent(); } void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, @@ -1353,20 +1329,20 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, std::this_thread::get_id() != mMainThreadId); if (primaryDisplay) { - mHwc->onHotplug(display, connection); + getBE().mHwc->onHotplug(display, connection); if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) { createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); } createDefaultDisplayDevice(); } else { - if (sequenceId != mComposerSequenceId) { + if (sequenceId != getBE().mComposerSequenceId) { return; } - if (mHwc->isUsingVrComposer()) { + if (getBE().mHwc->isUsingVrComposer()) { ALOGE("External displays are not supported by the vr hardware composer."); return; } - mHwc->onHotplug(display, connection); + getBE().mHwc->onHotplug(display, connection); auto type = DisplayDevice::DISPLAY_EXTERNAL; if (connection == HWC2::Connection::Connected) { createBuiltinDisplayLocked(type); @@ -1383,7 +1359,7 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*display*/) { Mutex::Autolock lock(mStateLock); - if (sequenceId != mComposerSequenceId) { + if (sequenceId != getBE().mComposerSequenceId) { return; } repaintEverythingLocked(); @@ -1404,7 +1380,7 @@ void SurfaceFlinger::resetDisplayState() { // mCurrentState and mDrawingState and re-apply all changes when we make the // transition. mDrawingState.displays.clear(); - eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + getRenderEngine().resetCurrentSurface(); mDisplays.clear(); } @@ -1412,11 +1388,11 @@ void SurfaceFlinger::updateVrFlinger() { if (!mVrFlinger) return; bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay; - if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) { + if (vrFlingerRequestsDisplay == getBE().mHwc->isUsingVrComposer()) { return; } - if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) { + if (vrFlingerRequestsDisplay && !getBE().mHwc->getComposer()->isRemote()) { ALOGE("Vr flinger is only supported for remote hardware composer" " service connections. Ignoring request to transition to vr" " flinger."); @@ -1434,13 +1410,12 @@ void SurfaceFlinger::updateVrFlinger() { } resetDisplayState(); - mHwc.reset(); // Delete the current instance before creating the new one - mHwc.reset(new HWComposer( - vrFlingerRequestsDisplay ? "vr" : mHwcServiceName)); - mHwc->registerCallback(this, ++mComposerSequenceId); + getBE().mHwc.reset(); // Delete the current instance before creating the new one + getBE().mHwc.reset(new HWComposer(vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName)); + getBE().mHwc->registerCallback(this, ++getBE().mComposerSequenceId); - LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(), - "Switched to non-remote hardware composer"); + LOG_ALWAYS_FATAL_IF(!getBE().mHwc->getComposer()->isRemote(), + "Switched to non-remote hardware composer"); if (vrFlingerRequestsDisplay) { mVrFlinger->GrantDisplayOwnership(); @@ -1457,7 +1432,7 @@ void SurfaceFlinger::updateVrFlinger() { setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true); // Reset the timing values to account for the period of the swapped in HWC - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); mAnimFrameTracker.setDisplayRefreshPeriod(period); @@ -1531,16 +1506,17 @@ void SurfaceFlinger::handleMessageRefresh() { rebuildLayerStacks(); setUpHWComposer(); doDebugFlashRegions(); + doTracing("handleRefresh"); doComposition(); postComposition(refreshStartTime); - mPreviousPresentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY); + mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY); mHadClientComposition = false; for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { const sp<DisplayDevice>& displayDevice = mDisplays[displayId]; mHadClientComposition = mHadClientComposition || - mHwc->hasClientComposition(displayDevice->getHwcDisplayId()); + getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId()); } mLayersWithQueuedFrames.clear(); @@ -1560,7 +1536,7 @@ void SurfaceFlinger::doDebugFlashRegions() const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); if (!dirtyRegion.isEmpty()) { // redraw the whole screen - doComposeSurfaces(hw, Region(hw->bounds())); + doComposeSurfaces(hw); // and draw the dirty region const int32_t height = hw->getHeight(); @@ -1584,9 +1560,19 @@ void SurfaceFlinger::doDebugFlashRegions() continue; } - status_t result = displayDevice->prepareFrame(*mHwc); - ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:" - " %d (%s)", displayId, result, strerror(-result)); + status_t result = displayDevice->prepareFrame(*getBE().mHwc); + ALOGE_IF(result != NO_ERROR, + "prepareFrame for display %zd failed:" + " %d (%s)", + displayId, result, strerror(-result)); + } +} + +void SurfaceFlinger::doTracing(const char* where) { + ATRACE_CALL(); + ATRACE_NAME(where); + if (CC_UNLIKELY(mTracing.isEnabled())) { + mTracing.traceLayers(where, dumpProtoInfo(LayerVector::StateSet::Drawing)); } } @@ -1612,10 +1598,10 @@ void SurfaceFlinger::updateCompositorTiming( std::shared_ptr<FenceTime>& presentFenceTime) { // Update queue of past composite+present times and determine the // most recently known composite to present latency. - mCompositePresentTimes.push({compositeTime, presentFenceTime}); + getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime}); nsecs_t compositeToPresentLatency = -1; - while (!mCompositePresentTimes.empty()) { - CompositePresentTime& cpt = mCompositePresentTimes.front(); + while (!getBE().mCompositePresentTimes.empty()) { + SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front(); // Cached values should have been updated before calling this method, // which helps avoid duplicate syscalls. nsecs_t displayTime = cpt.display->getCachedSignalTime(); @@ -1623,12 +1609,12 @@ void SurfaceFlinger::updateCompositorTiming( break; } compositeToPresentLatency = displayTime - cpt.composite; - mCompositePresentTimes.pop(); + getBE().mCompositePresentTimes.pop(); } // Don't let mCompositePresentTimes grow unbounded, just in case. - while (mCompositePresentTimes.size() > 16) { - mCompositePresentTimes.pop(); + while (getBE().mCompositePresentTimes.size() > 16) { + getBE().mCompositePresentTimes.pop(); } setCompositorTimingSnapped( @@ -1660,10 +1646,10 @@ void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase, nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ? idealLatency + (extraVsyncs * vsyncInterval) : idealLatency; - std::lock_guard<std::mutex> lock(mCompositorTimingLock); - mCompositorTiming.deadline = vsyncPhase - idealLatency; - mCompositorTiming.interval = vsyncInterval; - mCompositorTiming.presentLatency = snappedCompositeToPresentLatency; + std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); + getBE().mCompositorTiming.deadline = vsyncPhase - idealLatency; + getBE().mCompositorTiming.interval = vsyncInterval; + getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency; } void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) @@ -1680,20 +1666,20 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) // |mStateLock| not needed as we are on the main thread const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked()); - mGlCompositionDoneTimeline.updateSignalTimes(); + getBE().mGlCompositionDoneTimeline.updateSignalTimes(); std::shared_ptr<FenceTime> glCompositionDoneFenceTime; - if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) { + if (getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) { glCompositionDoneFenceTime = std::make_shared<FenceTime>(hw->getClientTargetAcquireFence()); - mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime); + getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime); } else { glCompositionDoneFenceTime = FenceTime::NO_FENCE; } - mDisplayTimeline.updateSignalTimes(); - sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY); + getBE().mDisplayTimeline.updateSignalTimes(); + sp<Fence> presentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY); auto presentFenceTime = std::make_shared<FenceTime>(presentFence); - mDisplayTimeline.push(presentFenceTime); + getBE().mDisplayTimeline.push(presentFenceTime); nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0); nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod(); @@ -1705,8 +1691,8 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) vsyncPhase, vsyncInterval, refreshStartTime, presentFenceTime); CompositorTiming compositorTiming; { - std::lock_guard<std::mutex> lock(mCompositorTimingLock); - compositorTiming = mCompositorTiming; + std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); + compositorTiming = getBE().mCompositorTiming; } mDrawingState.traverseInZOrder([&](Layer* layer) { @@ -1742,7 +1728,7 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) // The HWC doesn't support present fences, so use the refresh // timestamp instead. nsecs_t presentTime = - mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY); + getBE().mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY); mAnimFrameTracker.setActualPresentTime(presentTime); } mAnimFrameTracker.advanceFrame(); @@ -1756,16 +1742,16 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) if (mHasPoweredOff) { mHasPoweredOff = false; } else { - nsecs_t elapsedTime = currentTime - mLastSwapTime; + nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime; size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval); - if (numPeriods < NUM_BUCKETS - 1) { - mFrameBuckets[numPeriods] += elapsedTime; + if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) { + getBE().mFrameBuckets[numPeriods] += elapsedTime; } else { - mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime; + getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime; } - mTotalTime += elapsedTime; + getBE().mTotalTime += elapsedTime; } - mLastSwapTime = currentTime; + getBE().mLastSwapTime = currentTime; } void SurfaceFlinger::rebuildLayerStacks() { @@ -1774,7 +1760,7 @@ void SurfaceFlinger::rebuildLayerStacks() { // rebuild the visible layer list per screen if (CC_UNLIKELY(mVisibleRegionsDirty)) { - ATRACE_CALL(); + ATRACE_NAME("rebuildLayerStacks VR Dirty"); mVisibleRegionsDirty = false; invalidateHwcGeometry(); @@ -1941,7 +1927,7 @@ void SurfaceFlinger::setUpHWComposer() { for (size_t i = 0; i < currentLayers.size(); i++) { const auto& layer = currentLayers[i]; if (!layer->hasHwcLayer(hwcId)) { - if (!layer->createHwcLayer(mHwc.get(), hwcId)) { + if (!layer->createHwcLayer(getBE().mHwc.get(), hwcId)) { layer->forceClientComposition(hwcId); continue; } @@ -1968,11 +1954,17 @@ void SurfaceFlinger::setUpHWComposer() { continue; } if (colorMatrix != mPreviousColorMatrix) { - status_t result = mHwc->setColorTransform(hwcId, colorMatrix); + status_t result = getBE().mHwc->setColorTransform(hwcId, colorMatrix); ALOGE_IF(result != NO_ERROR, "Failed to set color transform on " "display %zd: %d", displayId, result); } for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { + if (layer->getForceClientComposition(hwcId)) { + ALOGV("[%s] Requesting Client composition", layer->getName().string()); + layer->setCompositionType(hwcId, HWC2::Composition::Client); + continue; + } + layer->setPerFrameData(displayDevice); } @@ -2000,7 +1992,7 @@ void SurfaceFlinger::setUpHWComposer() { continue; } - status_t result = displayDevice->prepareFrame(*mHwc); + status_t result = displayDevice->prepareFrame(*getBE().mHwc); ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:" " %d (%s)", displayId, result, strerror(-result)); } @@ -2021,8 +2013,7 @@ void SurfaceFlinger::doComposition() { doDisplayComposition(hw, dirtyRegion); hw->dirtyRegion.clear(); - hw->flip(hw->swapRegion); - hw->swapRegion.clear(); + hw->flip(); } } postFramebuffer(); @@ -2043,16 +2034,16 @@ void SurfaceFlinger::postFramebuffer() } const auto hwcId = displayDevice->getHwcDisplayId(); if (hwcId >= 0) { - mHwc->presentAndGetReleaseFences(hwcId); + getBE().mHwc->presentAndGetReleaseFences(hwcId); } displayDevice->onSwapBuffersCompleted(); - displayDevice->makeCurrent(mEGLDisplay, mEGLContext); + displayDevice->makeCurrent(); for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { // The layer buffer from the previous frame (if any) is released // by HWC only when the release fence from this frame (if any) is // signaled. Always get the release fence from HWC first. auto hwcLayer = layer->getHwcLayer(hwcId); - sp<Fence> releaseFence = mHwc->getLayerReleaseFence(hwcId, hwcLayer); + sp<Fence> releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer); // If the layer was client composited in the previous frame, we // need to merge with the previous client target acquire fence. @@ -2071,14 +2062,14 @@ void SurfaceFlinger::postFramebuffer() // displayDevice->getVisibleLayersSortedByZ. The best we can do is to // supply them with the present fence. if (!displayDevice->getLayersNeedingFences().isEmpty()) { - sp<Fence> presentFence = mHwc->getPresentFence(hwcId); + sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId); for (auto& layer : displayDevice->getLayersNeedingFences()) { layer->onLayerDisplayed(presentFence); } } if (hwcId >= 0) { - mHwc->clearReleaseFences(hwcId); + getBE().mHwc->clearReleaseFences(hwcId); } } @@ -2172,7 +2163,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // be sure that nothing associated with this display // is current. const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked()); - defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); + defaultDisplay->makeCurrent(); sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i))); if (hw != NULL) hw->disconnect(getHwComposer()); @@ -2243,7 +2234,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (state.surface != NULL) { // Allow VR composer to use virtual displays. - if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) { + if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) { int width = 0; int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); @@ -2262,14 +2253,14 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) auto format = static_cast<android_pixel_format_t>( intFormat); - mHwc->allocateVirtualDisplay(width, height, &format, + getBE().mHwc->allocateVirtualDisplay(width, height, &format, &hwcId); } // TODO: Plumb requested format back up to consumer sp<VirtualDisplaySurface> vds = - new VirtualDisplaySurface(*mHwc, + new VirtualDisplaySurface(*getBE().mHwc, hwcId, state.surface, bqProducer, bqConsumer, state.displayName); @@ -2283,7 +2274,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) state.surface.get()); hwcId = state.type; - dispSurface = new FramebufferSurface(*mHwc, hwcId, bqConsumer); + dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer); producer = bqProducer; } @@ -2291,9 +2282,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (dispSurface != NULL) { sp<DisplayDevice> hw = new DisplayDevice(this, state.type, hwcId, state.isSecure, display, - dispSurface, producer, - mRenderEngine->getEGLConfig(), - hasWideColorDisplay); + dispSurface, producer, hasWideColorDisplay); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); @@ -2354,16 +2343,19 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) } } } - if (disp == NULL) { - // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to - // redraw after transform hint changes. See bug 8508397. - - // could be null when this layer is using a layerStack - // that is not visible on any display. Also can occur at - // screen off/on times. - disp = getDefaultDisplayDeviceLocked(); + + if (transactionFlags & eDisplayTransactionNeeded) { + if (disp == NULL) { + // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to + // redraw after transform hint changes. See bug 8508397. + + // could be null when this layer is using a layerStack + // that is not visible on any display. Also can occur at + // screen off/on times. + disp = getDefaultDisplayDeviceLocked(); + } + layer->updateTransformHint(disp); } - layer->updateTransformHint(disp); first = false; }); @@ -2513,7 +2505,7 @@ void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displa // compute the opaque region const int32_t layerOrientation = tr.getOrientation(); - if (s.alpha == 1.0f && !translucent && + if (layer->getAlpha() == 1.0f && !translucent && ((layerOrientation & Transform::ROT_INVALID) == false)) { // the opaque region is the layer's footprint opaqueRegion = visibleRegion; @@ -2658,92 +2650,59 @@ void SurfaceFlinger::doDisplayComposition( } ALOGV("doDisplayComposition"); - - Region dirtyRegion(inDirtyRegion); - - // compute the invalid region - displayDevice->swapRegion.orSelf(dirtyRegion); - - uint32_t flags = displayDevice->getFlags(); - if (flags & DisplayDevice::SWAP_RECTANGLE) { - // we can redraw only what's dirty, but since SWAP_RECTANGLE only - // takes a rectangle, we must make sure to update that whole - // rectangle in that case - dirtyRegion.set(displayDevice->swapRegion.bounds()); - } else { - if (flags & DisplayDevice::PARTIAL_UPDATES) { - // We need to redraw the rectangle that will be updated - // (pushed to the framebuffer). - // This is needed because PARTIAL_UPDATES only takes one - // rectangle instead of a region (see DisplayDevice::flip()) - dirtyRegion.set(displayDevice->swapRegion.bounds()); - } else { - // we need to redraw everything (the whole screen) - dirtyRegion.set(displayDevice->bounds()); - displayDevice->swapRegion = dirtyRegion; - } - } - - if (!doComposeSurfaces(displayDevice, dirtyRegion)) return; - - // update the swap region and clear the dirty region - displayDevice->swapRegion.orSelf(dirtyRegion); + if (!doComposeSurfaces(displayDevice)) return; // swap buffers (presentation) displayDevice->swapBuffers(getHwComposer()); } -bool SurfaceFlinger::doComposeSurfaces( - const sp<const DisplayDevice>& displayDevice, const Region& dirty) +bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDevice) { ALOGV("doComposeSurfaces"); + const Region bounds(displayDevice->bounds()); + const DisplayRenderArea renderArea(displayDevice); const auto hwcId = displayDevice->getHwcDisplayId(); mat4 oldColorMatrix; - const bool applyColorMatrix = !mHwc->hasDeviceComposition(hwcId) && - !mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform); + const bool applyColorMatrix = !getBE().mHwc->hasDeviceComposition(hwcId) && + !getBE().mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform); if (applyColorMatrix) { mat4 colorMatrix = mColorMatrix * mDaltonizer(); oldColorMatrix = getRenderEngine().setupColorTransform(colorMatrix); } - bool hasClientComposition = mHwc->hasClientComposition(hwcId); + bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId); if (hasClientComposition) { ALOGV("hasClientComposition"); -#ifdef USE_HWC2 - mRenderEngine->setWideColor( + getBE().mRenderEngine->setWideColor( displayDevice->getWideColorSupport() && !mForceNativeColorMode); - mRenderEngine->setColorMode(mForceNativeColorMode ? + getBE().mRenderEngine->setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode()); -#endif - if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) { + if (!displayDevice->makeCurrent()) { ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", displayDevice->getDisplayName().string()); - eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + getRenderEngine().resetCurrentSurface(); // |mStateLock| not needed as we are on the main thread - if(!getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext)) { + if(!getDefaultDisplayDeviceLocked()->makeCurrent()) { ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting."); } return false; } // Never touch the framebuffer if we don't have any framebuffer layers - const bool hasDeviceComposition = mHwc->hasDeviceComposition(hwcId); + const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId); if (hasDeviceComposition) { // when using overlays, we assume a fully transparent framebuffer // NOTE: we could reduce how much we need to clear, for instance // remove where there are opaque FB layers. however, on some // GPUs doing a "clean slate" clear might be more efficient. // We'll revisit later if needed. - mRenderEngine->clearWithColor(0, 0, 0, 0); + getBE().mRenderEngine->clearWithColor(0, 0, 0, 0); } else { - // we start with the whole screen area - const Region bounds(displayDevice->getBounds()); - - // we remove the scissor part + // we start with the whole screen area and remove the scissor part // we're left with the letterbox region // (common case is that letterbox ends-up being empty) const Region letterbox(bounds.subtract(displayDevice->getScissor())); @@ -2751,9 +2710,6 @@ bool SurfaceFlinger::doComposeSurfaces( // compute the area to clear Region region(displayDevice->undefinedRegion.merge(letterbox)); - // but limit it to the dirty region - region.andSelf(dirty); - // screen is already cleared here if (!region.isEmpty()) { // can happen with SurfaceView @@ -2774,7 +2730,7 @@ bool SurfaceFlinger::doComposeSurfaces( // enable scissor for this frame const uint32_t height = displayDevice->getHeight(); - mRenderEngine->setScissor(scissor.left, height - scissor.bottom, + getBE().mRenderEngine->setScissor(scissor.left, height - scissor.bottom, scissor.getWidth(), scissor.getHeight()); } } @@ -2790,7 +2746,7 @@ bool SurfaceFlinger::doComposeSurfaces( // we're using h/w composer bool firstLayer = true; for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - const Region clip(dirty.intersect( + const Region clip(bounds.intersect( displayTransform.transform(layer->visibleRegion))); ALOGV("Layer: %s", layer->getName().string()); ALOGV(" Composition type: %s", @@ -2803,16 +2759,16 @@ bool SurfaceFlinger::doComposeSurfaces( case HWC2::Composition::SolidColor: { const Layer::State& state(layer->getDrawingState()); if (layer->getClearClientTarget(hwcId) && !firstLayer && - layer->isOpaque(state) && (state.alpha == 1.0f) + layer->isOpaque(state) && (state.color.a == 1.0f) && hasClientComposition) { // never clear the very first layer since we're // guaranteed the FB is already cleared - layer->clearWithOpenGL(displayDevice); + layer->clearWithOpenGL(renderArea); } break; } case HWC2::Composition::Client: { - layer->draw(displayDevice, clip); + layer->draw(renderArea, clip); break; } default: @@ -2826,10 +2782,10 @@ bool SurfaceFlinger::doComposeSurfaces( } else { // we're not using h/w composer for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - const Region clip(dirty.intersect( + const Region clip(bounds.intersect( displayTransform.transform(layer->visibleRegion))); if (!clip.isEmpty()) { - layer->draw(displayDevice, clip); + layer->draw(renderArea, clip); } } } @@ -2839,7 +2795,7 @@ bool SurfaceFlinger::doComposeSurfaces( } // disable scissor at the end of the frame - mRenderEngine->disableScissor(); + getBE().mRenderEngine->disableScissor(); return true; } @@ -2866,7 +2822,7 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, if (parent == nullptr) { mCurrentState.layersSortedByZ.add(lbc); } else { - if (mCurrentState.layersSortedByZ.indexOf(parent) < 0) { + if (parent->isPendingRemoval()) { ALOGE("addClientLayer called with a removed parent"); return NAME_NOT_FOUND; } @@ -2887,6 +2843,10 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) { Mutex::Autolock _l(mStateLock); + if (layer->isPendingRemoval()) { + return NO_ERROR; + } + const auto& p = layer->getParent(); ssize_t index; if (p != nullptr) { @@ -3090,122 +3050,153 @@ uint32_t SurfaceFlinger::setClientStateLocked( const sp<Client>& client, const layer_state_t& s) { - uint32_t flags = 0; sp<Layer> layer(client->getLayerUser(s.surface)); - if (layer != 0) { - const uint32_t what = s.what; - bool geometryAppliesWithResize = - what & layer_state_t::eGeometryAppliesWithResize; - if (what & layer_state_t::ePositionChanged) { - if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) { - flags |= eTraversalNeeded; - } - } - if (what & layer_state_t::eLayerChanged) { - // NOTE: index needs to be calculated before we update the state - const auto& p = layer->getParent(); - if (p == nullptr) { - ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - if (layer->setLayer(s.z) && idx >= 0) { - mCurrentState.layersSortedByZ.removeAt(idx); - mCurrentState.layersSortedByZ.add(layer); - // we need traversal (state changed) - // AND transaction (list changed) - flags |= eTransactionNeeded|eTraversalNeeded; - } - } else { - if (p->setChildLayer(layer, s.z)) { - flags |= eTransactionNeeded|eTraversalNeeded; - } - } + if (layer == nullptr) { + return 0; + } + + if (layer->isPendingRemoval()) { + ALOGW("Attempting to set client state on removed layer: %s", layer->getName().string()); + return 0; + } + + uint32_t flags = 0; + + const uint32_t what = s.what; + bool geometryAppliesWithResize = + what & layer_state_t::eGeometryAppliesWithResize; + if (what & layer_state_t::ePositionChanged) { + if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) { + flags |= eTraversalNeeded; } - if (what & layer_state_t::eRelativeLayerChanged) { + } + if (what & layer_state_t::eLayerChanged) { + // NOTE: index needs to be calculated before we update the state + const auto& p = layer->getParent(); + if (p == nullptr) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) { + if (layer->setLayer(s.z) && idx >= 0) { mCurrentState.layersSortedByZ.removeAt(idx); mCurrentState.layersSortedByZ.add(layer); + // we need traversal (state changed) + // AND transaction (list changed) flags |= eTransactionNeeded|eTraversalNeeded; } - } - if (what & layer_state_t::eSizeChanged) { - if (layer->setSize(s.w, s.h)) { - flags |= eTraversalNeeded; + } else { + if (p->setChildLayer(layer, s.z)) { + flags |= eTransactionNeeded|eTraversalNeeded; } } - if (what & layer_state_t::eAlphaChanged) { - if (layer->setAlpha(s.alpha)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eMatrixChanged) { - if (layer->setMatrix(s.matrix)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eTransparentRegionChanged) { - if (layer->setTransparentRegionHint(s.transparentRegion)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eFlagsChanged) { - if (layer->setFlags(s.flags, s.mask)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eCropChanged) { - if (layer->setCrop(s.crop, !geometryAppliesWithResize)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eFinalCropChanged) { - if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eLayerStackChanged) { + } + if (what & layer_state_t::eRelativeLayerChanged) { + // NOTE: index needs to be calculated before we update the state + const auto& p = layer->getParent(); + if (p == nullptr) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - // We only allow setting layer stacks for top level layers, - // everything else inherits layer stack from its parent. - if (layer->hasParent()) { - ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid", - layer->getName().string()); - } else if (idx < 0) { - ALOGE("Attempt to set layer stack on layer without parent (%s) that " - "that also does not appear in the top level layer list. Something" - " has gone wrong.", layer->getName().string()); - } else if (layer->setLayerStack(s.layerStack)) { + if (layer->setRelativeLayer(s.relativeLayerHandle, s.z) && idx >= 0) { mCurrentState.layersSortedByZ.removeAt(idx); mCurrentState.layersSortedByZ.add(layer); // we need traversal (state changed) // AND transaction (list changed) flags |= eTransactionNeeded|eTraversalNeeded; } - } - if (what & layer_state_t::eDeferTransaction) { - if (s.barrierHandle != nullptr) { - layer->deferTransactionUntil(s.barrierHandle, s.frameNumber); - } else if (s.barrierGbp != nullptr) { - const sp<IGraphicBufferProducer>& gbp = s.barrierGbp; - if (authenticateSurfaceTextureLocked(gbp)) { - const auto& otherLayer = - (static_cast<MonitoredProducer*>(gbp.get()))->getLayer(); - layer->deferTransactionUntil(otherLayer, s.frameNumber); - } else { - ALOGE("Attempt to defer transaction to to an" - " unrecognized GraphicBufferProducer"); - } + } else { + if (p->setChildRelativeLayer(layer, s.relativeLayerHandle, s.z)) { + flags |= eTransactionNeeded|eTraversalNeeded; } - // We don't trigger a traversal here because if no other state is - // changed, we don't want this to cause any more work } - if (what & layer_state_t::eReparentChildren) { - if (layer->reparentChildren(s.reparentHandle)) { - flags |= eTransactionNeeded|eTraversalNeeded; + } + if (what & layer_state_t::eSizeChanged) { + if (layer->setSize(s.w, s.h)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eAlphaChanged) { + if (layer->setAlpha(s.alpha)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eColorChanged) { + if (layer->setColor(s.color)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eMatrixChanged) { + if (layer->setMatrix(s.matrix)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eTransparentRegionChanged) { + if (layer->setTransparentRegionHint(s.transparentRegion)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eFlagsChanged) { + if (layer->setFlags(s.flags, s.mask)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eCropChanged) { + if (layer->setCrop(s.crop, !geometryAppliesWithResize)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eFinalCropChanged) { + if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eLayerStackChanged) { + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + // We only allow setting layer stacks for top level layers, + // everything else inherits layer stack from its parent. + if (layer->hasParent()) { + ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid", + layer->getName().string()); + } else if (idx < 0) { + ALOGE("Attempt to set layer stack on layer without parent (%s) that " + "that also does not appear in the top level layer list. Something" + " has gone wrong.", layer->getName().string()); + } else if (layer->setLayerStack(s.layerStack)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + // we need traversal (state changed) + // AND transaction (list changed) + flags |= eTransactionNeeded|eTraversalNeeded; + } + } + if (what & layer_state_t::eDeferTransaction) { + if (s.barrierHandle != nullptr) { + layer->deferTransactionUntil(s.barrierHandle, s.frameNumber); + } else if (s.barrierGbp != nullptr) { + const sp<IGraphicBufferProducer>& gbp = s.barrierGbp; + if (authenticateSurfaceTextureLocked(gbp)) { + const auto& otherLayer = + (static_cast<MonitoredProducer*>(gbp.get()))->getLayer(); + layer->deferTransactionUntil(otherLayer, s.frameNumber); + } else { + ALOGE("Attempt to defer transaction to to an" + " unrecognized GraphicBufferProducer"); } } - if (what & layer_state_t::eDetachChildren) { - layer->detachChildren(); + // We don't trigger a traversal here because if no other state is + // changed, we don't want this to cause any more work + } + if (what & layer_state_t::eReparent) { + bool hadParent = layer->hasParent(); + if (layer->reparent(s.parentHandleForChild)) { + if (!hadParent) { + mCurrentState.layersSortedByZ.remove(layer); + } + flags |= eTransactionNeeded|eTraversalNeeded; } - if (what & layer_state_t::eOverrideScalingModeChanged) { - layer->setOverrideScalingMode(s.overrideScalingMode); - // We don't trigger a traversal here because if no other state is - // changed, we don't want this to cause any more work + } + if (what & layer_state_t::eReparentChildren) { + if (layer->reparentChildren(s.reparentHandle)) { + flags |= eTransactionNeeded|eTraversalNeeded; } } + if (what & layer_state_t::eDetachChildren) { + layer->detachChildren(); + } + if (what & layer_state_t::eOverrideScalingModeChanged) { + layer->setOverrideScalingMode(s.overrideScalingMode); + // We don't trigger a traversal here because if no other state is + // changed, we don't want this to cause any more work + } return flags; } @@ -3230,14 +3221,15 @@ status_t SurfaceFlinger::createLayer( switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceNormal: - result = createNormalLayer(client, + result = createBufferLayer(client, uniqueName, w, h, flags, format, handle, gbp, &layer); + break; - case ISurfaceComposerClient::eFXSurfaceDim: - result = createDimLayer(client, + case ISurfaceComposerClient::eFXSurfaceColor: + result = createColorLayer(client, uniqueName, w, h, flags, - handle, gbp, &layer); + handle, &layer); break; default: result = BAD_VALUE; @@ -3291,7 +3283,7 @@ String8 SurfaceFlinger::getUniqueLayerName(const String8& name) return uniqueName; } -status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, +status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) { @@ -3306,24 +3298,24 @@ status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, break; } - *outLayer = new Layer(this, client, name, w, h, flags); - status_t err = (*outLayer)->setBuffers(w, h, format, flags); + sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags); + status_t err = layer->setBuffers(w, h, format, flags); if (err == NO_ERROR) { - *handle = (*outLayer)->getHandle(); - *gbp = (*outLayer)->getProducer(); + *handle = layer->getHandle(); + *gbp = layer->getProducer(); + *outLayer = layer; } - ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err)); + ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err)); return err; } -status_t SurfaceFlinger::createDimLayer(const sp<Client>& client, +status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, - sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) + sp<IBinder>* handle, sp<Layer>* outLayer) { - *outLayer = new LayerDim(this, client, name, w, h, flags); + *outLayer = new ColorLayer(this, client, name, w, h, flags); *handle = (*outLayer)->getHandle(); - *gbp = (*outLayer)->getProducer(); return NO_ERROR; } @@ -3375,7 +3367,7 @@ void SurfaceFlinger::onInitializeDisplays() { setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL, /*stateLockHeld*/ false); - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); mAnimFrameTracker.setDisplayRefreshPeriod(period); @@ -3451,7 +3443,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, ALOGW("Couldn't set SCHED_OTHER on display off"); } - if (type == DisplayDevice::DISPLAY_PRIMARY) { + if (type == DisplayDevice::DISPLAY_PRIMARY && + currentMode != HWC_POWER_MODE_DOZE_SUSPEND) { disableHardwareVsync(true); // also cancels any in-progress resync // FIXME: eventthread only knows about the main display right now @@ -3465,7 +3458,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, mode == HWC_POWER_MODE_NORMAL) { // Update display while dozing getHwComposer().setPowerMode(type, mode); - if (type == DisplayDevice::DISPLAY_PRIMARY) { + if (type == DisplayDevice::DISPLAY_PRIMARY && + currentMode == HWC_POWER_MODE_DOZE_SUSPEND) { // FIXME: eventthread only knows about the main display right now mEventThread->onScreenAcquired(); resyncToHardwareVsync(true); @@ -3514,13 +3508,13 @@ void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) { // --------------------------------------------------------------------------- -status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) -{ +status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) { String8 result; IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { result.appendFormat("Permission Denial: " @@ -3540,6 +3534,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) bool dumpAll = true; size_t index = 0; size_t numArgs = args.size(); + + if (asProto) { + LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current); + result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize()); + dumpAll = false; + } + if (numArgs) { if ((index < numArgs) && (args[index] == String16("--list"))) { @@ -3619,7 +3620,7 @@ void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index index++; } - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); result.appendFormat("%" PRId64 "\n", period); @@ -3682,24 +3683,24 @@ void SurfaceFlinger::appendSfConfigString(String8& result) const void SurfaceFlinger::dumpStaticScreenStats(String8& result) const { result.appendFormat("Static screen stats:\n"); - for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) { - float bucketTimeSec = mFrameBuckets[b] / 1e9; + for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) { + float bucketTimeSec = getBE().mFrameBuckets[b] / 1e9; float percent = 100.0f * - static_cast<float>(mFrameBuckets[b]) / mTotalTime; + static_cast<float>(getBE().mFrameBuckets[b]) / getBE().mTotalTime; result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n", b + 1, bucketTimeSec, percent); } - float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9; + float bucketTimeSec = getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] / 1e9; float percent = 100.0f * - static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime; + static_cast<float>(getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1]) / getBE().mTotalTime; result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n", - NUM_BUCKETS - 1, bucketTimeSec, percent); + SurfaceFlingerBE::NUM_BUCKETS - 1, bucketTimeSec, percent); } void SurfaceFlinger::recordBufferingStats(const char* layerName, std::vector<OccupancyTracker::Segment>&& history) { - Mutex::Autolock lock(mBufferingStatsMutex); - auto& stats = mBufferingStats[layerName]; + Mutex::Autolock lock(getBE().mBufferingStatsMutex); + auto& stats = getBE().mBufferingStats[layerName]; for (const auto& segment : history) { if (!segment.usedThirdBuffer) { stats.twoBufferTime += segment.totalTime; @@ -3728,12 +3729,12 @@ void SurfaceFlinger::dumpBufferingStats(String8& result) const { result.append("Buffering stats:\n"); result.append(" [Layer name] <Active time> <Two buffer> " "<Double buffered> <Triple buffered>\n"); - Mutex::Autolock lock(mBufferingStatsMutex); + Mutex::Autolock lock(getBE().mBufferingStatsMutex); typedef std::tuple<std::string, float, float, float> BufferTuple; std::map<float, BufferTuple, std::greater<float>> sorted; - for (const auto& statsPair : mBufferingStats) { + for (const auto& statsPair : getBE().mBufferingStats) { const char* name = statsPair.first.c_str(); - const BufferingStats& stats = statsPair.second; + const SurfaceFlingerBE::BufferingStats& stats = statsPair.second; if (stats.numSegments == 0) { continue; } @@ -3784,6 +3785,18 @@ void SurfaceFlinger::dumpWideColorInfo(String8& result) const { result.append("\n"); } +LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const { + LayersProto layersProto; + const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; + const State& state = useDrawing ? mDrawingState : mCurrentState; + state.traverseInZOrder([&](Layer* layer) { + LayerProto* layerProto = layersProto.add_layers(); + layer->writeToProto(layerProto, stateSet); + }); + + return layersProto; +} + void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, String8& result) const { @@ -3824,7 +3837,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, result.append(SyncFeatures::getInstance().toString()); result.append("\n"); - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); colorizer.bold(result); result.append("DispSync configuration: "); @@ -3848,9 +3861,10 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, colorizer.bold(result); result.appendFormat("Visible layers (count = %zu)\n", mNumLayers); colorizer.reset(result); - mCurrentState.traverseInZOrder([&](Layer* layer) { - result.append(to_string(layer->getLayerDebugInfo()).c_str()); - }); + + LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current); + auto layerTree = LayerProtoParser::generateLayerTree(layersProto); + result.append(LayerProtoParser::layersToString(layerTree).c_str()); /* * Dump Display state @@ -3875,14 +3889,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, HWComposer& hwc(getHwComposer()); sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked()); - colorizer.bold(result); - result.appendFormat("EGL implementation : %s\n", - eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION)); - colorizer.reset(result); - result.appendFormat("%s\n", - eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS)); - - mRenderEngine->dump(result); + getBE().mRenderEngine->dump(result); hw->undefinedRegion.dump(result, "undefinedRegion"); result.appendFormat(" orientation=%d, isDisplayOn=%d\n", @@ -4044,6 +4051,17 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } break; } + case CAPTURE_LAYERS: { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + break; + } } return OK; } @@ -4227,6 +4245,20 @@ status_t SurfaceFlinger::onTransact( reply->writeBool(hasWideColorDisplay); return NO_ERROR; } + case 1025: { // tracing + n = data.readInt32(); + if (n) { + ALOGV("LayerTracing enabled"); + mTracing.enable(); + doTracing("tracing.enable"); + reply->writeInt32(NO_ERROR); + } else { + ALOGV("LayerTracing disabled"); + status_t err = mTracing.disable(); + reply->writeInt32(err); + } + return NO_ERROR; + } } } return err; @@ -4243,35 +4275,6 @@ void SurfaceFlinger::repaintEverything() { repaintEverythingLocked(); } -// Checks that the requested width and height are valid and updates them to the display dimensions -// if they are set to 0 -static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice, - Transform::orientation_flags rotation, - uint32_t* requestedWidth, uint32_t* requestedHeight) { - // get screen geometry - uint32_t displayWidth = displayDevice->getWidth(); - uint32_t displayHeight = displayDevice->getHeight(); - - if (rotation & Transform::ROT_90) { - std::swap(displayWidth, displayHeight); - } - - if ((*requestedWidth > displayWidth) || (*requestedHeight > displayHeight)) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", - *requestedWidth, *requestedHeight, displayWidth, displayHeight); - return BAD_VALUE; - } - - if (*requestedWidth == 0) { - *requestedWidth = displayWidth; - } - if (*requestedHeight == 0) { - *requestedHeight = displayHeight; - } - - return NO_ERROR; -} - // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope class WindowDisconnector { public: @@ -4285,111 +4288,109 @@ private: const int mApi; }; -static status_t getWindowBuffer(ANativeWindow* window, uint32_t requestedWidth, - uint32_t requestedHeight, bool hasWideColorDisplay, - bool renderEngineUsesWideColor, ANativeWindowBuffer** outBuffer) { - const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; +status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, + ISurfaceComposer::Rotation rotation) { + ATRACE_CALL(); - int err = 0; - err = native_window_set_buffers_dimensions(window, requestedWidth, requestedHeight); - err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); - err |= native_window_set_usage(window, usage); + if (CC_UNLIKELY(display == 0)) return BAD_VALUE; - if (hasWideColorDisplay) { - err |= native_window_set_buffers_data_space(window, - renderEngineUsesWideColor - ? HAL_DATASPACE_DISPLAY_P3 - : HAL_DATASPACE_V0_SRGB); - } + const sp<const DisplayDevice> device(getDisplayDeviceLocked(display)); + DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation); - if (err != NO_ERROR) { - return BAD_VALUE; - } - - /* TODO: Once we have the sync framework everywhere this can use - * server-side waits on the fence that dequeueBuffer returns. - */ - err = native_window_dequeue_buffer_and_wait(window, outBuffer); - if (err != NO_ERROR) { - return err; - } - - return NO_ERROR; + auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this, + device, minLayerZ, maxLayerZ, std::placeholders::_1); + return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform); } -status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { +status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder, + sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop, + float frameScale) { ATRACE_CALL(); - if (CC_UNLIKELY(display == 0)) - return BAD_VALUE; + class LayerRenderArea : public RenderArea { + public: + LayerRenderArea(const sp<Layer>& layer, const Rect crop, int32_t reqWidth, + int32_t reqHeight) + : RenderArea(reqHeight, reqWidth), mLayer(layer), mCrop(crop) {} + const Transform& getTransform() const override { + // Make the top level transform the inverse the transform and it's parent so it sets + // the whole capture back to 0,0 + return *new Transform(mLayer->getTransform().inverse()); + } + Rect getBounds() const override { + const Layer::State& layerState(mLayer->getDrawingState()); + return Rect(layerState.active.w, layerState.active.h); + } + int getHeight() const override { return mLayer->getDrawingState().active.h; } + int getWidth() const override { return mLayer->getDrawingState().active.w; } + bool isSecure() const override { return false; } + bool needsFiltering() const override { return false; } + + Rect getSourceCrop() const override { + if (mCrop.isEmpty()) { + return getBounds(); + } else { + return mCrop; + } + } + bool getWideColorSupport() const override { return false; } + android_color_mode_t getActiveColorMode() const override { return HAL_COLOR_MODE_NATIVE; } - if (CC_UNLIKELY(producer == 0)) - return BAD_VALUE; + private: + const sp<Layer> mLayer; + const Rect mCrop; + }; - // 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). - bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder(); + auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get()); + auto parent = layerHandle->owner.promote(); - // Convert to surfaceflinger's internal rotation type. - Transform::orientation_flags rotationFlags; - switch (rotation) { - case ISurfaceComposer::eRotateNone: - rotationFlags = Transform::ROT_0; - break; - case ISurfaceComposer::eRotate90: - rotationFlags = Transform::ROT_90; - break; - case ISurfaceComposer::eRotate180: - rotationFlags = Transform::ROT_180; - break; - case ISurfaceComposer::eRotate270: - rotationFlags = Transform::ROT_270; - break; - default: - rotationFlags = Transform::ROT_0; - ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation); - break; + if (parent == nullptr || parent->isPendingRemoval()) { + ALOGE("captureLayers called with a removed parent"); + return NAME_NOT_FOUND; } - { // Autolock scope - Mutex::Autolock lock(mStateLock); - sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display)); - updateDimensionsLocked(displayDevice, rotationFlags, &reqWidth, &reqHeight); + Rect crop(sourceCrop); + if (sourceCrop.width() <= 0) { + crop.left = 0; + crop.right = parent->getCurrentState().active.w; } - // create a surface (because we're a producer, and we need to - // dequeue/queue a buffer) - sp<Surface> surface = new Surface(producer, false); + if (sourceCrop.height() <= 0) { + crop.top = 0; + crop.bottom = parent->getCurrentState().active.h; + } - // Put the screenshot Surface into async mode so that - // Layer::headFenceHasSignaled will always return true and we'll latch the - // first buffer regardless of whether or not its acquire fence has - // signaled. This is needed to avoid a race condition in the rotation - // animation. See b/30209608 - surface->setAsyncMode(true); + int32_t reqWidth = crop.width() * frameScale; + int32_t reqHeight = crop.height() * frameScale; - ANativeWindow* window = surface.get(); + LayerRenderArea renderArea(parent, crop, reqWidth, reqHeight); - status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); - if (result != NO_ERROR) { - return result; - } - WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL); + auto traverseLayers = [parent](const LayerVector::Visitor& visitor) { + parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { + if (!layer->isVisible()) { + return; + } + visitor(layer); + }); + }; + return captureScreenCommon(renderArea, traverseLayers, outBuffer, false); +} - ANativeWindowBuffer* buffer = nullptr; - result = getWindowBuffer(window, reqWidth, reqHeight, - hasWideColorDisplay && !mForceNativeColorMode, - getRenderEngine().usesWideColor(), &buffer); - if (result != NO_ERROR) { - return result; - } +status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + sp<GraphicBuffer>* outBuffer, + bool useIdentityTransform) { + ATRACE_CALL(); + + renderArea.updateDimensions(); + + const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; + *outBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(), + HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot"); // This mutex protects syncFd and captureResult for communication of the return values from the // main thread back to this Binder thread @@ -4414,10 +4415,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, int fd = -1; { Mutex::Autolock _l(mStateLock); - sp<const DisplayDevice> device(getDisplayDeviceLocked(display)); - result = captureScreenImplLocked(device, buffer, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, - rotationFlags, isLocalScreenshot, &fd); + result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(), + useIdentityTransform, &fd); } { @@ -4428,7 +4427,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, } }); - result = postMessageAsync(message); + status_t result = postMessageAsync(message); if (result == NO_ERROR) { captureCondition.wait(captureLock, [&]() { return captureResult; }); while (*captureResult == EAGAIN) { @@ -4443,153 +4442,96 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, } if (result == NO_ERROR) { - // queueBuffer takes ownership of syncFd - result = window->queueBuffer(window, buffer, syncFd); + sync_wait(syncFd, -1); + close(syncFd); } return result; } - -void SurfaceFlinger::renderScreenImplLocked( - const sp<const DisplayDevice>& hw, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation) -{ +void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, bool yswap, + bool useIdentityTransform) { ATRACE_CALL(); + RenderEngine& engine(getRenderEngine()); // get screen geometry - const int32_t hw_w = hw->getWidth(); - const int32_t hw_h = hw->getHeight(); - const bool filtering = static_cast<int32_t>(reqWidth) != hw_w || - static_cast<int32_t>(reqHeight) != hw_h; + const auto raWidth = renderArea.getWidth(); + const auto raHeight = renderArea.getHeight(); + + const auto reqWidth = renderArea.getReqWidth(); + const auto reqHeight = renderArea.getReqHeight(); + Rect sourceCrop = renderArea.getSourceCrop(); + + const bool filtering = static_cast<int32_t>(reqWidth) != raWidth || + static_cast<int32_t>(reqHeight) != raHeight; // if a default or invalid sourceCrop is passed in, set reasonable values - if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || - !sourceCrop.isValid()) { + if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) { sourceCrop.setLeftTop(Point(0, 0)); - sourceCrop.setRightBottom(Point(hw_w, hw_h)); + sourceCrop.setRightBottom(Point(raWidth, raHeight)); } // ensure that sourceCrop is inside screen if (sourceCrop.left < 0) { ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left); } - if (sourceCrop.right > hw_w) { - ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w); + if (sourceCrop.right > raWidth) { + ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth); } if (sourceCrop.top < 0) { ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top); } - if (sourceCrop.bottom > hw_h) { - ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h); + if (sourceCrop.bottom > raHeight) { + ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight); } -#ifdef USE_HWC2 - engine.setWideColor(hw->getWideColorSupport() && !mForceNativeColorMode); - engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : hw->getActiveColorMode()); -#endif + engine.setWideColor(renderArea.getWideColorSupport() && !mForceNativeColorMode); + engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE + : renderArea.getActiveColorMode()); // make sure to clear all GL error flags engine.checkErrors(); // set-up our viewport - engine.setViewportAndProjection( - reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation); + engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, raHeight, yswap, + renderArea.getRotationFlags()); engine.disableTexturing(); // redraw the screen entirely... engine.clearWithColor(0, 0, 0, 1); - // We loop through the first level of layers without traversing, - // as we need to interpret min/max layer Z in the top level Z space. - for (const auto& layer : mDrawingState.layersSortedByZ) { - if (!layer->belongsToDisplay(hw->getLayerStack(), false)) { - continue; - } - const Layer::State& state(layer->getDrawingState()); - if (state.z < minLayerZ || state.z > maxLayerZ) { - continue; - } - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (!layer->isVisible()) { - return; - } - if (filtering) layer->setFiltering(true); - layer->draw(hw, useIdentityTransform); - if (filtering) layer->setFiltering(false); - }); - } - - hw->setViewportAndProjection(); + traverseLayers([&](Layer* layer) { + if (filtering) layer->setFiltering(true); + layer->draw(renderArea, useIdentityTransform); + if (filtering) layer->setFiltering(false); + }); } -// A simple RAII class that holds an EGLImage and destroys it either: -// a) When the destroy() method is called -// b) When the object goes out of scope -class ImageHolder { -public: - ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {} - ~ImageHolder() { destroy(); } - - void destroy() { - if (mImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mDisplay, mImage); - mImage = EGL_NO_IMAGE_KHR; - } - } - -private: - const EGLDisplay mDisplay; - EGLImageKHR mImage; -}; - -status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& hw, - ANativeWindowBuffer* buffer, Rect sourceCrop, - uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, +status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + ANativeWindowBuffer* buffer, bool useIdentityTransform, - Transform::orientation_flags rotation, - bool isLocalScreenshot, int* outSyncFd) { + int* outSyncFd) { ATRACE_CALL(); bool secureLayerIsVisible = false; - for (const auto& layer : mDrawingState.layersSortedByZ) { - const Layer::State& state(layer->getDrawingState()); - if (!layer->belongsToDisplay(hw->getLayerStack(), false) || - (state.z < minLayerZ || state.z > maxLayerZ)) { - continue; - } - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) { - secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && - layer->isSecure()); - }); - } - if (!isLocalScreenshot && secureLayerIsVisible) { + traverseLayers([&](Layer* layer) { + secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure()); + }); + + if (secureLayerIsVisible) { ALOGW("FB is protected: PERMISSION_DENIED"); return PERMISSION_DENIED; } - int syncFd = -1; - // create an EGLImage from the buffer so we can later - // turn it into a texture - EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, - EGL_NATIVE_BUFFER_ANDROID, buffer, NULL); - if (image == EGL_NO_IMAGE_KHR) { - return BAD_VALUE; - } - - // This will automatically destroy the image if we return before calling its destroy method - ImageHolder imageHolder(mEGLDisplay, image); - // this binds the given EGLImage as a framebuffer for the // duration of this scope. - RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image); - if (imageBond.getStatus() != NO_ERROR) { - ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot"); + RenderEngine::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer); + if (bufferBond.getStatus() != NO_ERROR) { + ALOGE("got ANWB binding error while taking screenshot"); return INVALID_OPERATION; } @@ -4597,89 +4539,50 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& // via an FBO, which means we didn't have to create // an EGLSurface and therefore we're not // dependent on the context's EGLConfig. - renderScreenImplLocked( - hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true, - useIdentityTransform, rotation); - - // Attempt to create a sync khr object that can produce a sync point. If that - // isn't available, create a non-dupable sync object in the fallback path and - // wait on it directly. - EGLSyncKHR sync = EGL_NO_SYNC_KHR; - if (!DEBUG_SCREENSHOTS) { - sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); - // native fence fd will not be populated until flush() is done. - getRenderEngine().flush(); - } - - if (sync != EGL_NO_SYNC_KHR) { - // get the sync fd - syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync); - if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - ALOGW("captureScreen: failed to dup sync khr object"); - syncFd = -1; - } - eglDestroySyncKHR(mEGLDisplay, sync); - } else { - // fallback path - sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL); - if (sync != EGL_NO_SYNC_KHR) { - EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, - EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/); - EGLint eglErr = eglGetError(); - if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ALOGW("captureScreen: fence wait timed out"); - } else { - ALOGW_IF(eglErr != EGL_SUCCESS, - "captureScreen: error waiting on EGL fence: %#x", eglErr); - } - eglDestroySyncKHR(mEGLDisplay, sync); - } else { - ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); - } - } - *outSyncFd = syncFd; + renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform); if (DEBUG_SCREENSHOTS) { + getRenderEngine().finish(); + *outSyncFd = -1; + + const auto reqWidth = renderArea.getReqWidth(); + const auto reqHeight = renderArea.getReqHeight(); + uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); - checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, - hw, minLayerZ, maxLayerZ); + checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, traverseLayers); delete [] pixels; + } else { + base::unique_fd syncFd = getRenderEngine().flush(); + if (syncFd < 0) { + getRenderEngine().finish(); + } + *outSyncFd = syncFd.release(); } - // destroy our image - imageHolder.destroy(); - return NO_ERROR; } void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, - const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) { + TraverseLayersFunction traverseLayers) { if (DEBUG_SCREENSHOTS) { - for (size_t y=0 ; y<h ; y++) { - uint32_t const * p = (uint32_t const *)vaddr + y*s; - for (size_t x=0 ; x<w ; x++) { + for (size_t y = 0; y < h; y++) { + uint32_t const* p = (uint32_t const*)vaddr + y * s; + for (size_t x = 0; x < w; x++) { if (p[x] != 0xFF000000) return; } } - ALOGE("*** we just took a black screenshot ***\n" - "requested minz=%d, maxz=%d, layerStack=%d", - minLayerZ, maxLayerZ, hw->getLayerStack()); + ALOGE("*** we just took a black screenshot ***"); size_t i = 0; - for (const auto& layer : mDrawingState.layersSortedByZ) { + traverseLayers([&](Layer* layer) { const Layer::State& state(layer->getDrawingState()); - if (layer->belongsToDisplay(hw->getLayerStack(), false) && state.z >= minLayerZ && - state.z <= maxLayerZ) { - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f", - layer->isVisible() ? '+' : '-', - i, layer->getName().string(), layer->getLayerStack(), state.z, - layer->isVisible(), state.flags, state.alpha); - i++; - }); - } - } + ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f", + layer->isVisible() ? '+' : '-', i, layer->getName().string(), + layer->getLayerStack(), state.z, layer->isVisible(), state.flags, + static_cast<float>(state.color.a)); + i++; + }); } } @@ -4693,6 +4596,29 @@ void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& layersSortedByZ.traverseInReverseZOrder(stateSet, visitor); } +void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw, int32_t minLayerZ, + int32_t maxLayerZ, + const LayerVector::Visitor& visitor) { + // We loop through the first level of layers without traversing, + // as we need to interpret min/max layer Z in the top level Z space. + for (const auto& layer : mDrawingState.layersSortedByZ) { + if (!layer->belongsToDisplay(hw->getLayerStack(), false)) { + continue; + } + const Layer::State& state(layer->getDrawingState()); + // relative layers are traversed in Layer::traverseInZOrder + if (state.zOrderRelativeOf != nullptr || state.z < minLayerZ || state.z > maxLayerZ) { + continue; + } + layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { + if (!layer->isVisible()) { + return; + } + visitor(layer); + }); + } +} + }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 231709d408..2477bdcfa1 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -21,8 +21,6 @@ #include <stdint.h> #include <sys/types.h> -#include <EGL/egl.h> - /* * NOTE: Make sure this file doesn't include anything from <gl/ > or <gl2/ > */ @@ -43,13 +41,15 @@ #include <gui/FrameTimestamps.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> +#include <gui/LayerState.h> + #include <gui/OccupancyTracker.h> #include <hardware/hwcomposer_defs.h> -#include <system/graphics.h> +#include <serviceutils/PriorityDumper.h> -#include <private/gui/LayerState.h> +#include <system/graphics.h> #include "Barrier.h" #include "DisplayDevice.h" @@ -58,14 +58,11 @@ #include "LayerVector.h" #include "MessageQueue.h" #include "SurfaceInterceptor.h" +#include "SurfaceTracing.h" #include "StartPropertySetThread.h" -#ifdef USE_HWC2 #include "DisplayHardware/HWC2.h" #include "DisplayHardware/HWComposer.h" -#else -#include "DisplayHardware/HWComposer_hwc1.h" -#endif #include "Effects/Daltonizer.h" @@ -75,6 +72,11 @@ #include <string> #include <thread> #include <utility> +#include "RenderArea.h" + +#include <layerproto/LayerProtoHeader.h> + +using namespace android::surfaceflinger; namespace android { @@ -84,12 +86,15 @@ class Client; class DisplayEventConnection; class EventThread; class Layer; -class LayerDim; +class ColorLayer; class Surface; class RenderEngine; class EventControlThread; class VSyncSource; class InjectVSyncSource; +class SurfaceFlingerBE; + +typedef std::function<void(const LayerVector::Visitor&)> TraverseLayersFunction; namespace dvr { class VrFlinger; @@ -104,15 +109,97 @@ enum { eTransactionMask = 0x07 }; +class SurfaceFlingerBE +{ +public: + SurfaceFlingerBE(); + + // The current hardware composer interface. + // + // The following thread safety rules apply when accessing mHwc, either + // directly or via getHwComposer(): + // + // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc + // only when switching into and out of vr. Recreating mHwc must only be + // done on the main thread. + // + // 2. When accessing mHwc on the main thread, it's not necessary to acquire + // mStateLock. + // + // 3. When accessing mHwc on a thread other than the main thread, we always + // need to acquire mStateLock. This is because the main thread could be + // in the process of destroying the current mHwc instance. + // + // The above thread safety rules only apply to SurfaceFlinger.cpp. In + // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never + // destroy it, so it's always safe to access mHwc from any thread without + // acquiring mStateLock. + std::unique_ptr<HWComposer> mHwc; + + const std::string mHwcServiceName; // "default" for real use, something else for testing. + + // constant members (no synchronization needed for access) + std::unique_ptr<RenderEngine> mRenderEngine; + EGLContext mEGLContext; + EGLDisplay mEGLDisplay; + + FenceTimeline mGlCompositionDoneTimeline; + FenceTimeline mDisplayTimeline; + + // protected by mCompositorTimingLock; + mutable std::mutex mCompositorTimingLock; + CompositorTiming mCompositorTiming; + + // Only accessed from the main thread. + struct CompositePresentTime { + nsecs_t composite { -1 }; + std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE }; + }; + std::queue<CompositePresentTime> mCompositePresentTimes; + + static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ + nsecs_t mFrameBuckets[NUM_BUCKETS]; + nsecs_t mTotalTime; + std::atomic<nsecs_t> mLastSwapTime; + + // Double- vs. triple-buffering stats + struct BufferingStats { + BufferingStats() + : numSegments(0), + totalTime(0), + twoBufferTime(0), + doubleBufferedTime(0), + tripleBufferedTime(0) {} + + size_t numSegments; + nsecs_t totalTime; + + // "Two buffer" means that a third buffer was never used, whereas + // "double-buffered" means that on average the segment only used two + // buffers (though it may have used a third for some part of the + // segment) + nsecs_t twoBufferTime; + nsecs_t doubleBufferedTime; + nsecs_t tripleBufferedTime; + }; + mutable Mutex mBufferingStatsMutex; + std::unordered_map<std::string, BufferingStats> mBufferingStats; + + // The composer sequence id is a monotonically increasing integer that we + // use to differentiate callbacks from different hardware composer + // instances. Each hardware composer instance gets a different sequence id. + int32_t mComposerSequenceId; +}; + + class SurfaceFlinger : public BnSurfaceComposer, + public PriorityDumper, private IBinder::DeathRecipient, -#ifdef USE_HWC2 private HWC2::ComposerCallback -#else - private HWComposer::EventHandler -#endif { public: + SurfaceFlingerBE& getBE() { return mBE; } + const SurfaceFlingerBE& getBE() const { return mBE; } // This is the phase offset in nanoseconds of the software vsync event // relative to the vsync event reported by HWComposer. The software vsync @@ -206,11 +293,7 @@ public: // enable/disable h/w composer event // TODO: this should be made accessible only to EventThread -#ifdef USE_HWC2 void setVsyncEnabled(int disp, int enabled); -#else - void eventControl(int disp, int event, int enabled); -#endif // called on the main thread by MessageQueue when an internal message // is received @@ -222,7 +305,7 @@ public: const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id); RenderEngine& getRenderEngine() const { - return *mRenderEngine; + return *getBE().mRenderEngine; } bool authenticateSurfaceTextureLocked( @@ -233,6 +316,7 @@ private: friend class DisplayEventConnection; friend class EventThread; friend class Layer; + friend class BufferLayer; friend class MonitoredProducer; // This value is specified in number of frames. Log frame stats at most @@ -272,7 +356,7 @@ private: */ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - virtual status_t dump(int fd, const Vector<String16>& args); + virtual status_t dump(int fd, const Vector<String16>& args) { return priorityDump(fd, args); } /* ------------------------------------------------------------------------ * ISurfaceComposer interface @@ -291,11 +375,12 @@ private: std::vector<FrameEvent>* outSupported) const; virtual sp<IDisplayEventConnection> createDisplayEventConnection( ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp); - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, ISurfaceComposer::Rotation rotation); + virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, + ISurfaceComposer::Rotation rotation); + virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer, + const Rect& sourceCrop, float frameScale); virtual status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats); virtual status_t getDisplayConfigs(const sp<IBinder>& display, @@ -329,18 +414,12 @@ private: /* ------------------------------------------------------------------------ * HWC2::ComposerCallback / HWComposer::EventHandler interface */ -#ifdef USE_HWC2 void onVsyncReceived(int32_t sequenceId, hwc2_display_t display, int64_t timestamp) override; void onHotplugReceived(int32_t sequenceId, hwc2_display_t display, HWC2::Connection connection, bool primaryDisplay) override; void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override; -#else - void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp) override; - void onHotplugReceived(HWComposer* composer, int disp, bool connected) override; - void onInvalidateReceived(HWComposer* composer) override; -#endif /* ------------------------------------------------------------------------ * Message handling @@ -357,19 +436,12 @@ private: // called on the main thread in response to setActiveConfig() void setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode); // called on the main thread in response to setPowerMode() -#ifdef USE_HWC2 void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode, bool stateLockHeld); -#else - void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode); -#endif // Called on the main thread in response to setActiveColorMode() void setActiveColorModeInternal(const sp<DisplayDevice>& hw, android_color_mode_t colorMode); - // Called on the main thread in response to enableVSyncInjections() - void enableVSyncInjectionsInternal(bool enable); - // Returns whether the transaction actually modified any state bool handleMessageTransaction(); @@ -408,14 +480,14 @@ private: uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent); - status_t createNormalLayer(const sp<Client>& client, const String8& name, + status_t createBufferLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer); - status_t createDimLayer(const sp<Client>& client, const String8& name, + status_t createColorLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle, - sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer); + sp<Layer>* outLayer); String8 getUniqueLayerName(const String8& name); @@ -444,28 +516,17 @@ private: void startBootAnim(); - void renderScreenImplLocked( - const sp<const DisplayDevice>& hw, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation); - -#ifdef USE_HWC2 - status_t captureScreenImplLocked(const sp<const DisplayDevice>& device, - ANativeWindowBuffer* buffer, Rect sourceCrop, - uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ, - int32_t maxLayerZ, bool useIdentityTransform, - Transform::orientation_flags rotation, bool isLocalScreenshot, + void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, + bool yswap, bool useIdentityTransform); + status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, + sp<GraphicBuffer>* outBuffer, + bool useIdentityTransform); + status_t captureScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + ANativeWindowBuffer* buffer, bool useIdentityTransform, int* outSyncFd); -#else - status_t captureScreenImplLocked( - const sp<const DisplayDevice>& hw, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, Transform::orientation_flags rotation, - bool isLocalScreenshot); -#endif + void traverseLayersInDisplay(const sp<const DisplayDevice>& display, int32_t minLayerZ, + int32_t maxLayerZ, const LayerVector::Visitor& visitor); sp<StartPropertySetThread> mStartPropertySetThread = nullptr; @@ -530,15 +591,11 @@ private: // region of all screens presenting this layer stack. void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty); -#ifndef USE_HWC2 - int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type); -#endif - /* ------------------------------------------------------------------------ * H/W composer */ - HWComposer& getHwComposer() const { return *mHwc; } + HWComposer& getHwComposer() const { return *getBE().mHwc; } /* ------------------------------------------------------------------------ * Compositing @@ -567,11 +624,12 @@ private: void setUpHWComposer(); void doComposition(); void doDebugFlashRegions(); + void doTracing(const char* where); void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion); // compose surfaces for display hw. this fails if using GL and the surface // has been destroyed and is no longer valid. - bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice, const Region& dirty); + bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice); void postFramebuffer(); void drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const; @@ -595,6 +653,16 @@ private: /* ------------------------------------------------------------------------ * Debugging & dumpsys */ +public: + status_t dumpCritical(int fd, const Vector<String16>& /*args*/, bool asProto) { + return doDump(fd, Vector<String16>(), asProto); + } + + status_t dumpAll(int fd, const Vector<String16>& args, bool asProto) { + return doDump(fd, args, asProto); + } + +private: void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const; void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const; void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result); @@ -602,8 +670,7 @@ private: bool startDdmConnection(); void appendSfConfigString(String8& result) const; void checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, - const sp<const DisplayDevice>& hw, - int32_t minLayerZ, int32_t maxLayerZ); + TraverseLayersFunction traverseLayers); void logFrameStats(); @@ -615,12 +682,13 @@ private: std::vector<OccupancyTracker::Segment>&& history); void dumpBufferingStats(String8& result) const; void dumpWideColorInfo(String8& result) const; + LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const; bool isLayerTripleBufferingDisabled() const { return this->mLayerTripleBufferingDisabled; } + status_t doDump(int fd, const Vector<String16>& args, bool asProto); -#ifdef USE_HWC2 /* ------------------------------------------------------------------------ * VrFlinger */ @@ -628,7 +696,6 @@ private: // Check to see if we should handoff to vr flinger. void updateVrFlinger(); -#endif /* ------------------------------------------------------------------------ * Attributes @@ -651,34 +718,7 @@ private: // access must be protected by mInvalidateLock volatile int32_t mRepaintEverything; - // The current hardware composer interface. - // - // The following thread safety rules apply when accessing mHwc, either - // directly or via getHwComposer(): - // - // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc - // only when switching into and out of vr. Recreating mHwc must only be - // done on the main thread. - // - // 2. When accessing mHwc on the main thread, it's not necessary to acquire - // mStateLock. - // - // 3. When accessing mHwc on a thread other than the main thread, we always - // need to acquire mStateLock. This is because the main thread could be - // in the process of destroying the current mHwc instance. - // - // The above thread safety rules only apply to SurfaceFlinger.cpp. In - // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never - // destroy it, so it's always safe to access mHwc from any thread without - // acquiring mStateLock. - std::unique_ptr<HWComposer> mHwc; - -#ifdef USE_HWC2 - const std::string mHwcServiceName; // "default" for real use, something else for testing. -#endif - // constant members (no synchronization needed for access) - RenderEngine* mRenderEngine; nsecs_t mBootTime; bool mGpuToCpuSupported; sp<EventThread> mEventThread; @@ -686,27 +726,17 @@ private: sp<EventThread> mInjectorEventThread; sp<InjectVSyncSource> mVSyncInjector; sp<EventControlThread> mEventControlThread; - EGLContext mEGLContext; - EGLDisplay mEGLDisplay; sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES]; // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState{LayerVector::StateSet::Drawing}; bool mVisibleRegionsDirty; -#ifndef USE_HWC2 - bool mHwWorkListDirty; -#else bool mGeometryInvalid; -#endif bool mAnimCompositionPending; -#ifdef USE_HWC2 std::vector<sp<Layer>> mLayersWithQueuedFrames; sp<Fence> mPreviousPresentFence = Fence::NO_FENCE; bool mHadClientComposition = false; -#endif - FenceTimeline mGlCompositionDoneTimeline; - FenceTimeline mDisplayTimeline; // this may only be written from the main thread with mStateLock held // it may be read from other threads with mStateLock held @@ -723,10 +753,9 @@ private: nsecs_t mLastTransactionTime; bool mBootFinished; bool mForceFullDamage; -#ifdef USE_HWC2 bool mPropagateBackpressure = true; -#endif SurfaceInterceptor mInterceptor; + SurfaceTracing mTracing; bool mUseHwcVirtualDisplays = false; // Restrict layers to use two buffers in their bufferqueues. @@ -746,17 +775,6 @@ private: bool mPrimaryHWVsyncEnabled; bool mHWVsyncAvailable; - // protected by mCompositorTimingLock; - mutable std::mutex mCompositorTimingLock; - CompositorTiming mCompositorTiming; - - // Only accessed from the main thread. - struct CompositePresentTime { - nsecs_t composite { -1 }; - std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE }; - }; - std::queue<CompositePresentTime> mCompositePresentTimes; - std::atomic<bool> mRefreshPending{false}; /* ------------------------------------------------------------------------ @@ -766,9 +784,6 @@ private: bool mInjectVSyncs; Daltonizer mDaltonizer; -#ifndef USE_HWC2 - bool mDaltonize; -#endif mat4 mPreviousColorMatrix; mat4 mColorMatrix; @@ -776,53 +791,23 @@ private: // Static screen stats bool mHasPoweredOff; - static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ - nsecs_t mFrameBuckets[NUM_BUCKETS]; - nsecs_t mTotalTime; - std::atomic<nsecs_t> mLastSwapTime; size_t mNumLayers; - // Double- vs. triple-buffering stats - struct BufferingStats { - BufferingStats() - : numSegments(0), - totalTime(0), - twoBufferTime(0), - doubleBufferedTime(0), - tripleBufferedTime(0) {} - - size_t numSegments; - nsecs_t totalTime; - - // "Two buffer" means that a third buffer was never used, whereas - // "double-buffered" means that on average the segment only used two - // buffers (though it may have used a third for some part of the - // segment) - nsecs_t twoBufferTime; - nsecs_t doubleBufferedTime; - nsecs_t tripleBufferedTime; - }; - mutable Mutex mBufferingStatsMutex; - std::unordered_map<std::string, BufferingStats> mBufferingStats; // Verify that transaction is being called by an approved process: // either AID_GRAPHICS or AID_SYSTEM. status_t CheckTransactCodeCredentials(uint32_t code); -#ifdef USE_HWC2 std::unique_ptr<dvr::VrFlinger> mVrFlinger; std::atomic<bool> mVrFlingerRequestsDisplay; static bool useVrFlinger; std::thread::id mMainThreadId; - // The composer sequence id is a monotonically increasing integer that we - // use to differentiate callbacks from different hardware composer - // instances. Each hardware composer instance gets a different sequence id. - int32_t mComposerSequenceId; -#endif float mSaturation = 1.0f; bool mForceNativeColorMode = false; + + SurfaceFlingerBE mBE; }; }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp deleted file mode 100644 index abc8fde26b..0000000000 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include "SurfaceFlingerConsumer.h" -#include "Layer.h" - -#include <private/gui/SyncFeatures.h> - -#include <gui/BufferItem.h> -#include <gui/BufferQueue.h> - -#include <utils/Errors.h> -#include <utils/NativeHandle.h> -#include <utils/Trace.h> - -namespace android { - -// --------------------------------------------------------------------------- - -status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, - const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer, - uint64_t maxFrameNumber) -{ - ATRACE_CALL(); - ALOGV("updateTexImage"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("updateTexImage: GLConsumer is abandoned!"); - return NO_INIT; - } - - // Make sure the EGL state is the same as in previous calls. - status_t err = checkAndUpdateEglStateLocked(); - if (err != NO_ERROR) { - return err; - } - - BufferItem item; - - // Acquire the next buffer. - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), - maxFrameNumber); - if (err != NO_ERROR) { - if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - err = NO_ERROR; - } else if (err == BufferQueue::PRESENT_LATER) { - // return the error, without logging - } else { - ALOGE("updateTexImage: acquire failed: %s (%d)", - strerror(-err), err); - } - return err; - } - - if (autoRefresh) { - *autoRefresh = item.mAutoRefresh; - } - - if (queuedBuffer) { - *queuedBuffer = item.mQueuedBuffer; - } - - // We call the rejecter here, in case the caller has a reason to - // not accept this buffer. This is used by SurfaceFlinger to - // reject buffers which have the wrong size - int slot = item.mSlot; - if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) { - releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR); - return BUFFER_REJECTED; - } - - // Release the previous buffer. -#ifdef USE_HWC2 - err = updateAndReleaseLocked(item, &mPendingRelease); -#else - err = updateAndReleaseLocked(item); -#endif - if (err != NO_ERROR) { - return err; - } - - if (!SyncFeatures::getInstance().useNativeFenceSync()) { - // Bind the new buffer to the GL texture. - // - // Older devices require the "implicit" synchronization provided - // by glEGLImageTargetTexture2DOES, which this method calls. Newer - // devices will either call this in Layer::onDraw, or (if it's not - // a GL-composited layer) not at all. - err = bindTextureImageLocked(); - } - - return err; -} - -status_t SurfaceFlingerConsumer::bindTextureImage() -{ - Mutex::Autolock lock(mMutex); - - return bindTextureImageLocked(); -} - -status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item, - nsecs_t presentWhen, uint64_t maxFrameNumber) { - status_t result = GLConsumer::acquireBufferLocked(item, presentWhen, - maxFrameNumber); - if (result == NO_ERROR) { - mTransformToDisplayInverse = item->mTransformToDisplayInverse; - mSurfaceDamage = item->mSurfaceDamage; - } - return result; -} - -bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const { - Mutex::Autolock lock(mMutex); - return mTransformToDisplayInverse; -} - -const Region& SurfaceFlingerConsumer::getSurfaceDamage() const { - return mSurfaceDamage; -} - -sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const { - sp<NativeHandle> stream; - mConsumer->getSidebandStream(&stream); - return stream; -} - -// We need to determine the time when a buffer acquired now will be -// displayed. This can be calculated: -// time when previous buffer's actual-present fence was signaled -// + current display refresh rate * HWC latency -// + a little extra padding -// -// Buffer producers are expected to set their desired presentation time -// based on choreographer time stamps, which (coming from vsync events) -// will be slightly later then the actual-present timing. If we get a -// desired-present time that is unintentionally a hair after the next -// vsync, we'll hold the frame when we really want to display it. We -// need to take the offset between actual-present and reported-vsync -// into account. -// -// If the system is configured without a DispSync phase offset for the app, -// we also want to throw in a bit of padding to avoid edge cases where we -// just barely miss. We want to do it here, not in every app. A major -// source of trouble is the app's use of the display's ideal refresh time -// (via Display.getRefreshRate()), which could be off of the actual refresh -// by a few percent, with the error multiplied by the number of frames -// between now and when the buffer should be displayed. -// -// If the refresh reported to the app has a phase offset, we shouldn't need -// to tweak anything here. -nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync) -{ - // The HWC doesn't currently have a way to report additional latency. - // Assume that whatever we submit now will appear right after the flip. - // For a smart panel this might be 1. This is expressed in frames, - // rather than time, because we expect to have a constant frame delay - // regardless of the refresh rate. - const uint32_t hwcLatency = 0; - - // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC). - const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency); - - // The DispSync time is already adjusted for the difference between - // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so - // we don't need to factor that in here. Pad a little to avoid - // weird effects if apps might be requesting times right on the edge. - nsecs_t extraPadding = 0; - if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) { - extraPadding = 1000000; // 1ms (6% of 60Hz) - } - - return nextRefresh + extraPadding; -} - -sp<Fence> SurfaceFlingerConsumer::getPrevFinalReleaseFence() const { - Mutex::Autolock lock(mMutex); - return ConsumerBase::mPrevFinalReleaseFence; -} - -#ifdef USE_HWC2 -void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence) -{ - if (!mPendingRelease.isPending) { - GLConsumer::setReleaseFence(fence); - return; - } - auto currentTexture = mPendingRelease.currentTexture; - if (fence->isValid() && - currentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - status_t result = addReleaseFence(currentTexture, - mPendingRelease.graphicBuffer, fence); - ALOGE_IF(result != NO_ERROR, "setReleaseFence: failed to add the" - " fence: %s (%d)", strerror(-result), result); - } -} - -bool SurfaceFlingerConsumer::releasePendingBuffer() -{ - if (!mPendingRelease.isPending) { - ALOGV("Pending buffer already released"); - return false; - } - ALOGV("Releasing pending buffer"); - Mutex::Autolock lock(mMutex); - status_t result = releaseBufferLocked(mPendingRelease.currentTexture, - mPendingRelease.graphicBuffer, mPendingRelease.display, - mPendingRelease.fence); - ALOGE_IF(result < NO_ERROR, "releasePendingBuffer failed: %s (%d)", - strerror(-result), result); - mPendingRelease = PendingRelease(); - return true; -} -#endif - -void SurfaceFlingerConsumer::setContentsChangedListener( - const wp<ContentsChangedListener>& listener) { - setFrameAvailableListener(listener); - Mutex::Autolock lock(mMutex); - mContentsChangedListener = listener; -} - -void SurfaceFlingerConsumer::onSidebandStreamChanged() { - FrameAvailableListener* unsafeFrameAvailableListener = nullptr; - { - Mutex::Autolock lock(mFrameAvailableMutex); - unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get(); - } - sp<ContentsChangedListener> listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); - ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get()); - listener = mContentsChangedListener.promote(); - } - - if (listener != NULL) { - listener->onSidebandStreamChanged(); - } -} - -void SurfaceFlingerConsumer::onDisconnect() { - sp<Layer> l = mLayer.promote(); - if (l.get()) { - l->onDisconnect(); - } -} - -void SurfaceFlingerConsumer::addAndGetFrameTimestamps( - const NewFrameEventsEntry* newTimestamps, - FrameEventHistoryDelta *outDelta) { - sp<Layer> l = mLayer.promote(); - if (l.get()) { - l->addAndGetFrameTimestamps(newTimestamps, outDelta); - } -} - -// --------------------------------------------------------------------------- -}; // namespace android - diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h deleted file mode 100644 index 1126233d60..0000000000 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_SURFACEFLINGERCONSUMER_H -#define ANDROID_SURFACEFLINGERCONSUMER_H - -#include "DispSync.h" - -#include <ui/Region.h> -#include <gui/GLConsumer.h> - -namespace android { -// ---------------------------------------------------------------------------- - -class Layer; - -/* - * This is a thin wrapper around GLConsumer. - */ -class SurfaceFlingerConsumer : public GLConsumer { -public: - static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; - - struct ContentsChangedListener: public FrameAvailableListener { - virtual void onSidebandStreamChanged() = 0; - }; - - SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer, - uint32_t tex, Layer* layer) - : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false), - mTransformToDisplayInverse(false), mSurfaceDamage(), mLayer(layer) - {} - - class BufferRejecter { - friend class SurfaceFlingerConsumer; - virtual bool reject(const sp<GraphicBuffer>& buf, - const BufferItem& item) = 0; - - protected: - virtual ~BufferRejecter() { } - }; - - virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, - uint64_t maxFrameNumber = 0) override; - - // This version of updateTexImage() takes a functor that may be used to - // reject the newly acquired buffer. Unlike the GLConsumer version, - // this does not guarantee that the buffer has been bound to the GL - // texture. - status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, - bool* autoRefresh, bool* queuedBuffer, - uint64_t maxFrameNumber); - - // See GLConsumer::bindTextureImageLocked(). - status_t bindTextureImage(); - - bool getTransformToDisplayInverse() const; - - // must be called from SF main thread - const Region& getSurfaceDamage() const; - - // Sets the contents changed listener. This should be used instead of - // ConsumerBase::setFrameAvailableListener(). - void setContentsChangedListener(const wp<ContentsChangedListener>& listener); - - sp<NativeHandle> getSidebandStream() const; - - nsecs_t computeExpectedPresent(const DispSync& dispSync); - - sp<Fence> getPrevFinalReleaseFence() const; -#ifdef USE_HWC2 - virtual void setReleaseFence(const sp<Fence>& fence) override; - bool releasePendingBuffer(); -#endif - - void onDisconnect() override; - void addAndGetFrameTimestamps( - const NewFrameEventsEntry* newTimestamps, - FrameEventHistoryDelta* outDelta) override; - -private: - virtual void onSidebandStreamChanged(); - - wp<ContentsChangedListener> mContentsChangedListener; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after GLConsumer::mCurrentTransform. - // This must be set/read from SurfaceFlinger's main thread. - bool mTransformToDisplayInverse; - - // The portion of this surface that has changed since the previous frame - Region mSurfaceDamage; - -#ifdef USE_HWC2 - // A release that is pending on the receipt of a new release fence from - // presentDisplay - PendingRelease mPendingRelease; -#endif - - // The layer for this SurfaceFlingerConsumer - const wp<Layer> mLayer; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_SURFACEFLINGERCONSUMER_H diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp deleted file mode 100644 index 1d6fbaf19b..0000000000 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ /dev/null @@ -1,4117 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include <dlfcn.h> -#include <errno.h> -#include <inttypes.h> -#include <math.h> -#include <stdatomic.h> -#include <stdint.h> -#include <sys/types.h> - -#include <mutex> - -#include <EGL/egl.h> - -#include <cutils/properties.h> -#include <log/log.h> - -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/PermissionCache.h> - -#include <ui/DisplayInfo.h> -#include <ui/DisplayStatInfo.h> - -#include <gui/BufferQueue.h> -#include <gui/GuiConfig.h> -#include <gui/IDisplayEventConnection.h> -#include <gui/LayerDebugInfo.h> -#include <gui/Surface.h> - -#include <ui/GraphicBufferAllocator.h> -#include <ui/HdrCapabilities.h> -#include <ui/PixelFormat.h> -#include <ui/UiConfig.h> - -#include <utils/misc.h> -#include <utils/String8.h> -#include <utils/String16.h> -#include <utils/StopWatch.h> -#include <utils/Timers.h> -#include <utils/Trace.h> - -#include <private/android_filesystem_config.h> -#include <private/gui/SyncFeatures.h> - -#include <set> - -#include "Client.h" -#include "clz.h" -#include "Colorizer.h" -#include "DdmConnection.h" -#include "DisplayDevice.h" -#include "DispSync.h" -#include "EventControlThread.h" -#include "EventThread.h" -#include "Layer.h" -#include "LayerVector.h" -#include "LayerDim.h" -#include "MonitoredProducer.h" -#include "SurfaceFlinger.h" - -#include "DisplayHardware/FramebufferSurface.h" -#include "DisplayHardware/HWComposer.h" -#include "DisplayHardware/VirtualDisplaySurface.h" - -#include "Effects/Daltonizer.h" - -#include "RenderEngine/RenderEngine.h" -#include <cutils/compiler.h> - -#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> -#include <configstore/Utils.h> - -#define DISPLAY_COUNT 1 - -/* - * DEBUG_SCREENSHOTS: set to true to check that screenshots are not all - * black pixels. - */ -#define DEBUG_SCREENSHOTS false - -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); - -namespace android { -// --------------------------------------------------------------------------- - -using namespace android::hardware::configstore; -using namespace android::hardware::configstore::V1_0; - -const String16 sHardwareTest("android.permission.HARDWARE_TEST"); -const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); -const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); -const String16 sDump("android.permission.DUMP"); - -// --------------------------------------------------------------------------- -int64_t SurfaceFlinger::vsyncPhaseOffsetNs; -int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs; -bool SurfaceFlinger::useContextPriority; -int64_t SurfaceFlinger::dispSyncPresentTimeOffset; -bool SurfaceFlinger::useHwcForRgbToYuv; -uint64_t SurfaceFlinger::maxVirtualDisplaySize; -bool SurfaceFlinger::hasSyncFramework; -int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; - -SurfaceFlinger::SurfaceFlinger() - : BnSurfaceComposer(), - mTransactionFlags(0), - mTransactionPending(false), - mAnimTransactionPending(false), - mLayersRemoved(false), - mLayersAdded(false), - mRepaintEverything(0), - mRenderEngine(NULL), - mBootTime(systemTime()), - mVisibleRegionsDirty(false), - mHwWorkListDirty(false), - mAnimCompositionPending(false), - mDebugRegion(0), - mDebugDDMS(0), - mDebugDisableHWC(0), - mDebugDisableTransformHint(0), - mDebugInSwapBuffers(0), - mLastSwapBufferTime(0), - mDebugInTransaction(0), - mLastTransactionTime(0), - mBootFinished(false), - mForceFullDamage(false), - mInterceptor(this), - mPrimaryDispSync("PrimaryDispSync"), - mPrimaryHWVsyncEnabled(false), - mHWVsyncAvailable(false), - mDaltonize(false), - mHasColorMatrix(false), - mHasPoweredOff(false), - mFrameBuckets(), - mTotalTime(0), - mLastSwapTime(0), - mNumLayers(0) -{ - ALOGI("SurfaceFlinger is starting"); - - vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000); - - sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000); - - maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(0); - - hasSyncFramework = getBool< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::hasSyncFramework>(true); - - useContextPriority = getBool< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::useContextPriority>(false); - - dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0); - - useHwcForRgbToYuv = getBool< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::useHwcForRGBtoYUV>(false); - - maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2); - - mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset); - - char value[PROPERTY_VALUE_MAX]; - - property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); - mGpuToCpuSupported = !atoi(value); - - property_get("debug.sf.showupdates", value, "0"); - mDebugRegion = atoi(value); - - property_get("debug.sf.ddms", value, "0"); - mDebugDDMS = atoi(value); - if (mDebugDDMS) { - if (!startDdmConnection()) { - // start failed, and DDMS debugging not enabled - mDebugDDMS = 0; - } - } - ALOGI_IF(mDebugRegion, "showupdates enabled"); - ALOGI_IF(mDebugDDMS, "DDMS debugging enabled"); - - property_get("debug.sf.enable_hwc_vds", value, "0"); - mUseHwcVirtualDisplays = atoi(value); - ALOGI_IF(!mUseHwcVirtualDisplays, "Enabling HWC virtual displays"); - - property_get("ro.sf.disable_triple_buffer", value, "1"); - mLayerTripleBufferingDisabled = atoi(value); - ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering"); -} - -void SurfaceFlinger::onFirstRef() -{ - mEventQueue.init(this); -} - -SurfaceFlinger::~SurfaceFlinger() -{ - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(display); -} - -void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */) -{ - // the window manager died on us. prepare its eulogy. - - // restore initial conditions (default device unblank, etc) - initializeDisplays(); - - // restart the boot-animation - startBootAnim(); -} - -static sp<ISurfaceComposerClient> initClient(const sp<Client>& client) { - status_t err = client->initCheck(); - if (err == NO_ERROR) { - return client; - } - return nullptr; -} - -sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() { - return initClient(new Client(this)); -} - -sp<ISurfaceComposerClient> SurfaceFlinger::createScopedConnection( - const sp<IGraphicBufferProducer>& gbp) { - if (authenticateSurfaceTexture(gbp) == false) { - return nullptr; - } - const auto& layer = (static_cast<MonitoredProducer*>(gbp.get()))->getLayer(); - if (layer == nullptr) { - return nullptr; - } - - return initClient(new Client(this, layer)); -} - -sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, - bool secure) -{ - class DisplayToken : public BBinder { - sp<SurfaceFlinger> flinger; - virtual ~DisplayToken() { - // no more references, this display must be terminated - Mutex::Autolock _l(flinger->mStateLock); - flinger->mCurrentState.displays.removeItem(this); - flinger->setTransactionFlags(eDisplayTransactionNeeded); - } - public: - explicit DisplayToken(const sp<SurfaceFlinger>& flinger) - : flinger(flinger) { - } - }; - - sp<BBinder> token = new DisplayToken(this); - - Mutex::Autolock _l(mStateLock); - DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure); - info.displayName = displayName; - mCurrentState.displays.add(token, info); - mInterceptor.saveDisplayCreation(info); - return token; -} - -void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) { - Mutex::Autolock _l(mStateLock); - - ssize_t idx = mCurrentState.displays.indexOfKey(display); - if (idx < 0) { - ALOGW("destroyDisplay: invalid display token"); - return; - } - - const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx)); - if (!info.isVirtualDisplay()) { - ALOGE("destroyDisplay called for non-virtual display"); - return; - } - mInterceptor.saveDisplayDeletion(info.displayId); - mCurrentState.displays.removeItemsAt(idx); - setTransactionFlags(eDisplayTransactionNeeded); -} - -void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) { - ALOGW_IF(mBuiltinDisplays[type], - "Overwriting display token for display type %d", type); - mBuiltinDisplays[type] = new BBinder(); - // All non-virtual displays are currently considered secure. - DisplayDeviceState info(type, true); - mCurrentState.displays.add(mBuiltinDisplays[type], info); - mInterceptor.saveDisplayCreation(info); -} - -sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) { - if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { - ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id); - return NULL; - } - return mBuiltinDisplays[id]; -} - -void SurfaceFlinger::bootFinished() -{ - if (mStartPropertySetThread->join() != NO_ERROR) { - ALOGE("Join StartPropertySetThread failed!"); - } - const nsecs_t now = systemTime(); - const nsecs_t duration = now - mBootTime; - ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); - mBootFinished = true; - - // wait patiently for the window manager death - const String16 name("window"); - sp<IBinder> window(defaultServiceManager()->getService(name)); - if (window != 0) { - window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); - } - - // stop boot animation - // formerly we would just kill the process, but we now ask it to exit so it - // can choose where to stop the animation. - property_set("service.bootanim.exit", "1"); - - const int LOGTAG_SF_STOP_BOOTANIM = 60110; - LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, - ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); -} - -void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { - class MessageDestroyGLTexture : public MessageBase { - RenderEngine& engine; - uint32_t texture; - public: - MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture) - : engine(engine), texture(texture) { - } - virtual bool handler() { - engine.deleteTextures(1, &texture); - return true; - } - }; - postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture)); -} - -class DispSyncSource : public VSyncSource, private DispSync::Callback { -public: - DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, - const char* name) : - mName(name), - mValue(0), - mTraceVsync(traceVsync), - mVsyncOnLabel(String8::format("VsyncOn-%s", name)), - mVsyncEventLabel(String8::format("VSYNC-%s", name)), - mDispSync(dispSync), - mCallbackMutex(), - mCallback(), - mVsyncMutex(), - mPhaseOffset(phaseOffset), - mEnabled(false) {} - - virtual ~DispSyncSource() {} - - virtual void setVSyncEnabled(bool enable) { - Mutex::Autolock lock(mVsyncMutex); - if (enable) { - status_t err = mDispSync->addEventListener(mName, mPhaseOffset, - static_cast<DispSync::Callback*>(this)); - if (err != NO_ERROR) { - ALOGE("error registering vsync callback: %s (%d)", - strerror(-err), err); - } - //ATRACE_INT(mVsyncOnLabel.string(), 1); - } else { - status_t err = mDispSync->removeEventListener( - static_cast<DispSync::Callback*>(this)); - if (err != NO_ERROR) { - ALOGE("error unregistering vsync callback: %s (%d)", - strerror(-err), err); - } - //ATRACE_INT(mVsyncOnLabel.string(), 0); - } - mEnabled = enable; - } - - virtual void setCallback(const sp<VSyncSource::Callback>& callback) { - Mutex::Autolock lock(mCallbackMutex); - mCallback = callback; - } - - virtual void setPhaseOffset(nsecs_t phaseOffset) { - Mutex::Autolock lock(mVsyncMutex); - - // Normalize phaseOffset to [0, period) - auto period = mDispSync->getPeriod(); - phaseOffset %= period; - if (phaseOffset < 0) { - // If we're here, then phaseOffset is in (-period, 0). After this - // operation, it will be in (0, period) - phaseOffset += period; - } - mPhaseOffset = phaseOffset; - - // If we're not enabled, we don't need to mess with the listeners - if (!mEnabled) { - return; - } - - // Remove the listener with the old offset - status_t err = mDispSync->removeEventListener( - static_cast<DispSync::Callback*>(this)); - if (err != NO_ERROR) { - ALOGE("error unregistering vsync callback: %s (%d)", - strerror(-err), err); - } - - // Add a listener with the new offset - err = mDispSync->addEventListener(mName, mPhaseOffset, - static_cast<DispSync::Callback*>(this)); - if (err != NO_ERROR) { - ALOGE("error registering vsync callback: %s (%d)", - strerror(-err), err); - } - } - -private: - virtual void onDispSyncEvent(nsecs_t when) { - sp<VSyncSource::Callback> callback; - { - Mutex::Autolock lock(mCallbackMutex); - callback = mCallback; - - if (mTraceVsync) { - mValue = (mValue + 1) % 2; - ATRACE_INT(mVsyncEventLabel.string(), mValue); - } - } - - if (callback != NULL) { - callback->onVSyncEvent(when); - } - } - - const char* const mName; - - int mValue; - - const bool mTraceVsync; - const String8 mVsyncOnLabel; - const String8 mVsyncEventLabel; - - DispSync* mDispSync; - - Mutex mCallbackMutex; // Protects the following - sp<VSyncSource::Callback> mCallback; - - Mutex mVsyncMutex; // Protects the following - nsecs_t mPhaseOffset; - bool mEnabled; -}; - -class InjectVSyncSource : public VSyncSource { -public: - InjectVSyncSource() {} - - virtual ~InjectVSyncSource() {} - - virtual void setCallback(const sp<VSyncSource::Callback>& callback) { - std::lock_guard<std::mutex> lock(mCallbackMutex); - mCallback = callback; - } - - virtual void onInjectSyncEvent(nsecs_t when) { - std::lock_guard<std::mutex> lock(mCallbackMutex); - mCallback->onVSyncEvent(when); - } - - virtual void setVSyncEnabled(bool) {} - virtual void setPhaseOffset(nsecs_t) {} - -private: - std::mutex mCallbackMutex; // Protects the following - sp<VSyncSource::Callback> mCallback; -}; - -// Do not call property_set on main thread which will be blocked by init -// Use StartPropertySetThread instead. -void SurfaceFlinger::init() { - ALOGI( "SurfaceFlinger's main thread ready to run. " - "Initializing graphics H/W..."); - - Mutex::Autolock _l(mStateLock); - - // initialize EGL for the default display - mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(mEGLDisplay, NULL, NULL); - - // start the EventThread - sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, - vsyncPhaseOffsetNs, true, "app"); - mEventThread = new EventThread(vsyncSrc, *this, false); - sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, - sfVsyncPhaseOffsetNs, true, "sf"); - mSFEventThread = new EventThread(sfVsyncSrc, *this, true); - mEventQueue.setEventThread(mSFEventThread); - - // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter - struct sched_param param = {0}; - param.sched_priority = 2; - if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); - } - if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for EventThread"); - } - - // Initialize the H/W composer object. There may or may not be an - // actual hardware composer underneath. - mHwc.reset(new HWComposer(this, - *static_cast<HWComposer::EventHandler *>(this))); - - // get a RenderEngine for the given display / config (can't fail) - mRenderEngine = RenderEngine::create(mEGLDisplay, - mHwc->getVisualID(), 0); - - // retrieve the EGL context that was selected/created - mEGLContext = mRenderEngine->getEGLContext(); - - LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, - "couldn't create EGLContext"); - - // initialize our non-virtual displays - for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { - DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i); - // set-up the displays that are already connected - if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) { - // All non-virtual displays are currently considered secure. - bool isSecure = true; - createBuiltinDisplayLocked(type); - wp<IBinder> token = mBuiltinDisplays[i]; - - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - - sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, - consumer); - int32_t hwcId = allocateHwcDisplayId(type); - sp<DisplayDevice> hw = new DisplayDevice(this, - type, hwcId, mHwc->getFormat(hwcId), isSecure, token, - fbs, producer, - mRenderEngine->getEGLConfig(), false); - if (i > DisplayDevice::DISPLAY_PRIMARY) { - // FIXME: currently we don't get blank/unblank requests - // for displays other than the main display, so we always - // assume a connected display is unblanked. - ALOGD("marking display %zu as acquired/unblanked", i); - hw->setPowerMode(HWC_POWER_MODE_NORMAL); - } - mDisplays.add(token, hw); - } - } - - // make the GLContext current so that we can create textures when creating Layers - // (which may happens before we render something) - getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext); - - mEventControlThread = new EventControlThread(this); - mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); - - // set a fake vsync period if there is no HWComposer - if (mHwc->initCheck() != NO_ERROR) { - mPrimaryDispSync.setPeriod(16666667); - } - - // initialize our drawing state - mDrawingState = mCurrentState; - - // set initial conditions (e.g. unblank default device) - initializeDisplays(); - - mRenderEngine->primeCache(); - - // Inform native graphics APIs that the present timestamp is NOT supported: - mStartPropertySetThread = new StartPropertySetThread(false); - if (mStartPropertySetThread->Start() != NO_ERROR) { - ALOGE("Run StartPropertySetThread failed!"); - } - - ALOGV("Done initializing"); -} - -int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) { - return (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) ? - type : mHwc->allocateDisplayId(); -} - -void SurfaceFlinger::startBootAnim() { - // Start boot animation service by setting a property mailbox - // if property setting thread is already running, Start() will be just a NOP - mStartPropertySetThread->Start(); - // Wait until property was set - if (mStartPropertySetThread->join() != NO_ERROR) { - ALOGE("Join StartPropertySetThread failed!"); - } -} - -size_t SurfaceFlinger::getMaxTextureSize() const { - return mRenderEngine->getMaxTextureSize(); -} - -size_t SurfaceFlinger::getMaxViewportDims() const { - return mRenderEngine->getMaxViewportDims(); -} - -// ---------------------------------------------------------------------------- - -bool SurfaceFlinger::authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& bufferProducer) const { - Mutex::Autolock _l(mStateLock); - return authenticateSurfaceTextureLocked(bufferProducer); -} - -bool SurfaceFlinger::authenticateSurfaceTextureLocked( - const sp<IGraphicBufferProducer>& bufferProducer) const { - sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer)); - return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0; -} - -status_t SurfaceFlinger::getSupportedFrameTimestamps( - std::vector<FrameEvent>* outSupported) const { - *outSupported = { - FrameEvent::REQUESTED_PRESENT, - FrameEvent::ACQUIRE, - FrameEvent::LATCH, - FrameEvent::FIRST_REFRESH_START, - FrameEvent::LAST_REFRESH_START, - FrameEvent::GPU_COMPOSITION_DONE, - FrameEvent::DEQUEUE_READY, - FrameEvent::RELEASE, - }; - return NO_ERROR; -} - -status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, - Vector<DisplayInfo>* configs) { - if ((configs == NULL) || (display.get() == NULL)) { - return BAD_VALUE; - } - - int32_t type = getDisplayType(display); - if (type < 0) return type; - - // TODO: Not sure if display density should handled by SF any longer - class Density { - static int getDensityFromProperty(char const* propName) { - char property[PROPERTY_VALUE_MAX]; - int density = 0; - if (property_get(propName, property, NULL) > 0) { - density = atoi(property); - } - return density; - } - public: - static int getEmuDensity() { - return getDensityFromProperty("qemu.sf.lcd_density"); } - static int getBuildDensity() { - return getDensityFromProperty("ro.sf.lcd_density"); } - }; - - configs->clear(); - - const Vector<HWComposer::DisplayConfig>& hwConfigs = - getHwComposer().getConfigs(type); - for (size_t c = 0; c < hwConfigs.size(); ++c) { - const HWComposer::DisplayConfig& hwConfig = hwConfigs[c]; - DisplayInfo info = DisplayInfo(); - - float xdpi = hwConfig.xdpi; - float ydpi = hwConfig.ydpi; - - if (type == DisplayDevice::DISPLAY_PRIMARY) { - // The density of the device is provided by a build property - float density = Density::getBuildDensity() / 160.0f; - if (density == 0) { - // the build doesn't provide a density -- this is wrong! - // use xdpi instead - ALOGE("ro.sf.lcd_density must be defined as a build property"); - density = xdpi / 160.0f; - } - if (Density::getEmuDensity()) { - // if "qemu.sf.lcd_density" is specified, it overrides everything - xdpi = ydpi = density = Density::getEmuDensity(); - density /= 160.0f; - } - info.density = density; - - // TODO: this needs to go away (currently needed only by webkit) - sp<const DisplayDevice> hw(getDefaultDisplayDevice()); - info.orientation = hw->getOrientation(); - } else { - // TODO: where should this value come from? - static const int TV_DENSITY = 213; - info.density = TV_DENSITY / 160.0f; - info.orientation = 0; - } - - info.w = hwConfig.width; - info.h = hwConfig.height; - info.xdpi = xdpi; - info.ydpi = ydpi; - info.fps = float(1e9 / hwConfig.refresh); - info.appVsyncOffset = vsyncPhaseOffsetNs; - - // This is how far in advance a buffer must be queued for - // presentation at a given time. If you want a buffer to appear - // on the screen at time N, you must submit the buffer before - // (N - presentationDeadline). - // - // Normally it's one full refresh period (to give SF a chance to - // latch the buffer), but this can be reduced by configuring a - // DispSync offset. Any additional delays introduced by the hardware - // composer or panel must be accounted for here. - // - // We add an additional 1ms to allow for processing time and - // differences between the ideal and actual refresh rate. - info.presentationDeadline = - hwConfig.refresh - sfVsyncPhaseOffsetNs + 1000000; - - // All non-virtual displays are currently considered secure. - info.secure = true; - - configs->push_back(info); - } - - return NO_ERROR; -} - -status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */, - DisplayStatInfo* stats) { - if (stats == NULL) { - return BAD_VALUE; - } - - // FIXME for now we always return stats for the primary display - memset(stats, 0, sizeof(*stats)); - stats->vsyncTime = mPrimaryDispSync.computeNextRefresh(0); - stats->vsyncPeriod = mPrimaryDispSync.getPeriod(); - return NO_ERROR; -} - -int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) { - sp<const DisplayDevice> device(getDisplayDevice(display)); - if (device != NULL) { - return device->getActiveConfig(); - } - return BAD_VALUE; -} - -void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) { - ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), - this); - int32_t type = hw->getDisplayType(); - int currentMode = hw->getActiveConfig(); - - if (mode == currentMode) { - ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode); - return; - } - - if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { - ALOGW("Trying to set config for virtual display"); - return; - } - - hw->setActiveConfig(mode); - getHwComposer().setActiveConfig(type, mode); -} - -status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) { - class MessageSetActiveConfig: public MessageBase { - SurfaceFlinger& mFlinger; - sp<IBinder> mDisplay; - int mMode; - public: - MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp, - int mode) : - mFlinger(flinger), mDisplay(disp) { mMode = mode; } - virtual bool handler() { - Vector<DisplayInfo> configs; - mFlinger.getDisplayConfigs(mDisplay, &configs); - if (mMode < 0 || mMode >= static_cast<int>(configs.size())) { - ALOGE("Attempt to set active config = %d for display with %zu configs", - mMode, configs.size()); - } - sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay)); - if (hw == NULL) { - ALOGE("Attempt to set active config = %d for null display %p", - mMode, mDisplay.get()); - } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) { - ALOGW("Attempt to set active config = %d for virtual display", - mMode); - } else { - mFlinger.setActiveConfigInternal(hw, mMode); - } - return true; - } - }; - sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode); - postMessageSync(msg); - return NO_ERROR; -} - -status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display, - Vector<android_color_mode_t>* outColorModes) { - if (outColorModes == nullptr || display.get() == nullptr) { - return BAD_VALUE; - } - - int32_t type = getDisplayType(display); - if (type < 0) return type; - - std::set<android_color_mode_t> colorModes; - for (const HWComposer::DisplayConfig& hwConfig : getHwComposer().getConfigs(type)) { - colorModes.insert(hwConfig.colorMode); - } - - outColorModes->clear(); - std::copy(colorModes.cbegin(), colorModes.cend(), std::back_inserter(*outColorModes)); - - return NO_ERROR; -} - -android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) { - if (display.get() == nullptr) return static_cast<android_color_mode_t>(BAD_VALUE); - - int32_t type = getDisplayType(display); - if (type < 0) return static_cast<android_color_mode_t>(type); - - return getHwComposer().getColorMode(type); -} - -status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display, - android_color_mode_t colorMode) { - if (display.get() == nullptr || colorMode < 0) { - return BAD_VALUE; - } - - int32_t type = getDisplayType(display); - if (type < 0) return type; - const Vector<HWComposer::DisplayConfig>& hwConfigs = getHwComposer().getConfigs(type); - HWComposer::DisplayConfig desiredConfig = hwConfigs[getHwComposer().getCurrentConfig(type)]; - desiredConfig.colorMode = colorMode; - for (size_t c = 0; c < hwConfigs.size(); ++c) { - const HWComposer::DisplayConfig config = hwConfigs[c]; - if (config == desiredConfig) { - return setActiveConfig(display, c); - } - } - return BAD_VALUE; -} - -status_t SurfaceFlinger::clearAnimationFrameStats() { - Mutex::Autolock _l(mStateLock); - mAnimFrameTracker.clearStats(); - return NO_ERROR; -} - -status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const { - Mutex::Autolock _l(mStateLock); - mAnimFrameTracker.getStats(outStats); - return NO_ERROR; -} - -status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& /*display*/, - HdrCapabilities* outCapabilities) const { - // HWC1 does not provide HDR capabilities - *outCapabilities = HdrCapabilities(); - return NO_ERROR; -} - -status_t SurfaceFlinger::enableVSyncInjections(bool enable) { - if (enable == mInjectVSyncs) { - return NO_ERROR; - } - - if (enable) { - mInjectVSyncs = enable; - ALOGV("VSync Injections enabled"); - if (mVSyncInjector.get() == nullptr) { - mVSyncInjector = new InjectVSyncSource(); - mInjectorEventThread = new EventThread(mVSyncInjector, *this, false); - } - mEventQueue.setEventThread(mInjectorEventThread); - } else { - mInjectVSyncs = enable; - ALOGV("VSync Injections disabled"); - mEventQueue.setEventThread(mSFEventThread); - mVSyncInjector.clear(); - } - return NO_ERROR; -} - -status_t SurfaceFlinger::injectVSync(nsecs_t when) { - if (!mInjectVSyncs) { - ALOGE("VSync Injections not enabled"); - return BAD_VALUE; - } - if (mInjectVSyncs && mInjectorEventThread.get() != nullptr) { - ALOGV("Injecting VSync inside SurfaceFlinger"); - mVSyncInjector->onInjectSyncEvent(when); - } - return NO_ERROR; -} - -status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const { - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_SHELL) && - !PermissionCache::checkPermission(sDump, pid, uid)) { - ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - - // Try to acquire a lock for 1s, fail gracefully - status_t err = mStateLock.timedLock(s2ns(1)); - bool locked = (err == NO_ERROR); - if (!locked) { - ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err); - return TIMED_OUT; - } - - outLayers->clear(); - mCurrentState.traverseInZOrder([&](Layer* layer) { - outLayers->push_back(layer->getLayerDebugInfo()); - }); - - mStateLock.unlock(); - - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- - -sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource) { - if (vsyncSource == eVsyncSourceSurfaceFlinger) { - return mSFEventThread->createEventConnection(); - } else { - return mEventThread->createEventConnection(); - } -} - -// ---------------------------------------------------------------------------- - -void SurfaceFlinger::waitForEvent() { - mEventQueue.waitMessage(); -} - -void SurfaceFlinger::signalTransaction() { - mEventQueue.invalidate(); -} - -void SurfaceFlinger::signalLayerUpdate() { - mEventQueue.invalidate(); -} - -void SurfaceFlinger::signalRefresh() { - mEventQueue.refresh(); -} - -status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg, - nsecs_t reltime, uint32_t /* flags */) { - return mEventQueue.postMessage(msg, reltime); -} - -status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, - nsecs_t reltime, uint32_t /* flags */) { - status_t res = mEventQueue.postMessage(msg, reltime); - if (res == NO_ERROR) { - msg->wait(); - } - return res; -} - -void SurfaceFlinger::run() { - do { - waitForEvent(); - } while (true); -} - -void SurfaceFlinger::enableHardwareVsync() { - Mutex::Autolock _l(mHWVsyncLock); - if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { - mPrimaryDispSync.beginResync(); - //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); - mEventControlThread->setVsyncEnabled(true); - mPrimaryHWVsyncEnabled = true; - } -} - -void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) { - Mutex::Autolock _l(mHWVsyncLock); - - if (makeAvailable) { - mHWVsyncAvailable = true; - } else if (!mHWVsyncAvailable) { - // Hardware vsync is not currently available, so abort the resync - // attempt for now - return; - } - - const nsecs_t period = - getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); - - mPrimaryDispSync.reset(); - mPrimaryDispSync.setPeriod(period); - - if (!mPrimaryHWVsyncEnabled) { - mPrimaryDispSync.beginResync(); - //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); - mEventControlThread->setVsyncEnabled(true); - mPrimaryHWVsyncEnabled = true; - } -} - -void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) { - Mutex::Autolock _l(mHWVsyncLock); - if (mPrimaryHWVsyncEnabled) { - //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false); - mEventControlThread->setVsyncEnabled(false); - mPrimaryDispSync.endResync(); - mPrimaryHWVsyncEnabled = false; - } - if (makeUnavailable) { - mHWVsyncAvailable = false; - } -} - -void SurfaceFlinger::resyncWithRateLimit() { - static constexpr nsecs_t kIgnoreDelay = ms2ns(500); - if (systemTime() - mLastSwapTime > kIgnoreDelay) { - resyncToHardwareVsync(false); - } -} - -void SurfaceFlinger::onVSyncReceived(HWComposer* /*composer*/, int type, - nsecs_t timestamp) { - bool needsHwVsync = false; - - { // Scope for the lock - Mutex::Autolock _l(mHWVsyncLock); - if (type == 0 && mPrimaryHWVsyncEnabled) { - needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); - } - } - - if (needsHwVsync) { - enableHardwareVsync(); - } else { - disableHardwareVsync(false); - } -} - -void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { - std::lock_guard<std::mutex> lock(mCompositorTimingLock); - *compositorTiming = mCompositorTiming; -} - -void SurfaceFlinger::onHotplugReceived(HWComposer* /*composer*/, int type, bool connected) { - if (mEventThread == NULL) { - // This is a temporary workaround for b/7145521. A non-null pointer - // does not mean EventThread has finished initializing, so this - // is not a correct fix. - ALOGW("WARNING: EventThread not started, ignoring hotplug"); - return; - } - - if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { - Mutex::Autolock _l(mStateLock); - if (connected) { - createBuiltinDisplayLocked((DisplayDevice::DisplayType)type); - } else { - mCurrentState.displays.removeItem(mBuiltinDisplays[type]); - mBuiltinDisplays[type].clear(); - } - setTransactionFlags(eDisplayTransactionNeeded); - - // Defer EventThread notification until SF has updated mDisplays. - } -} - -void SurfaceFlinger::onInvalidateReceived(HWComposer* /*composer*/) { - repaintEverything(); -} - -void SurfaceFlinger::eventControl(int disp, int event, int enabled) { - ATRACE_CALL(); - getHwComposer().eventControl(disp, event, enabled); -} - -void SurfaceFlinger::onMessageReceived(int32_t what) { - ATRACE_CALL(); - switch (what) { - case MessageQueue::INVALIDATE: { - bool refreshNeeded = handleMessageTransaction(); - refreshNeeded |= handleMessageInvalidate(); - refreshNeeded |= mRepaintEverything; - if (refreshNeeded) { - // Signal a refresh if a transaction modified the window state, - // a new buffer was latched, or if HWC has requested a full - // repaint - signalRefresh(); - } - break; - } - case MessageQueue::REFRESH: { - handleMessageRefresh(); - break; - } - } -} - -bool SurfaceFlinger::handleMessageTransaction() { - uint32_t transactionFlags = peekTransactionFlags(); - if (transactionFlags) { - handleTransaction(transactionFlags); - return true; - } - return false; -} - -bool SurfaceFlinger::handleMessageInvalidate() { - ATRACE_CALL(); - return handlePageFlip(); -} - -void SurfaceFlinger::handleMessageRefresh() { - ATRACE_CALL(); - - nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC); - - preComposition(refreshStartTime); - rebuildLayerStacks(); - setUpHWComposer(); - doDebugFlashRegions(); - doComposition(); - postComposition(refreshStartTime); -} - -void SurfaceFlinger::doDebugFlashRegions() -{ - // is debugging enabled - if (CC_LIKELY(!mDebugRegion)) - return; - - const bool repaintEverything = mRepaintEverything; - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - const sp<DisplayDevice>& hw(mDisplays[dpy]); - if (hw->isDisplayOn()) { - // transform the dirty region into this screen's coordinate space - const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); - if (!dirtyRegion.isEmpty()) { - // redraw the whole screen - doComposeSurfaces(hw, Region(hw->bounds())); - - // and draw the dirty region - const int32_t height = hw->getHeight(); - RenderEngine& engine(getRenderEngine()); - engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1); - - hw->compositionComplete(); - hw->swapBuffers(getHwComposer()); - } - } - } - - postFramebuffer(); - - if (mDebugRegion > 1) { - usleep(mDebugRegion * 1000); - } - - HWComposer& hwc(getHwComposer()); - if (hwc.initCheck() == NO_ERROR) { - status_t err = hwc.prepare(); - ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); - } -} - -void SurfaceFlinger::preComposition(nsecs_t refreshStartTime) -{ - bool needExtraInvalidate = false; - mDrawingState.traverseInZOrder([&](Layer* layer) { - if (layer->onPreComposition(refreshStartTime)) { - needExtraInvalidate = true; - } - }); - - if (needExtraInvalidate) { - signalLayerUpdate(); - } -} - -void SurfaceFlinger::updateCompositorTiming( - nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime, - std::shared_ptr<FenceTime>& presentFenceTime) { - // Update queue of past composite+present times and determine the - // most recently known composite to present latency. - mCompositePresentTimes.push({compositeTime, presentFenceTime}); - nsecs_t compositeToPresentLatency = -1; - while (!mCompositePresentTimes.empty()) { - CompositePresentTime& cpt = mCompositePresentTimes.front(); - // Cached values should have been updated before calling this method, - // which helps avoid duplicate syscalls. - nsecs_t displayTime = cpt.display->getCachedSignalTime(); - if (displayTime == Fence::SIGNAL_TIME_PENDING) { - break; - } - compositeToPresentLatency = displayTime - cpt.composite; - mCompositePresentTimes.pop(); - } - - // Don't let mCompositePresentTimes grow unbounded, just in case. - while (mCompositePresentTimes.size() > 16) { - mCompositePresentTimes.pop(); - } - - setCompositorTimingSnapped( - vsyncPhase, vsyncInterval, compositeToPresentLatency); -} - -void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase, - nsecs_t vsyncInterval, nsecs_t compositeToPresentLatency) { - // Integer division and modulo round toward 0 not -inf, so we need to - // treat negative and positive offsets differently. - nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0) ? - (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) : - ((-sfVsyncPhaseOffsetNs) % vsyncInterval); - - // Just in case sfVsyncPhaseOffsetNs == -vsyncInterval. - if (idealLatency <= 0) { - idealLatency = vsyncInterval; - } - - // Snap the latency to a value that removes scheduling jitter from the - // composition and present times, which often have >1ms of jitter. - // Reducing jitter is important if an app attempts to extrapolate - // something (such as user input) to an accurate diasplay time. - // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs - // with (presentLatency % interval). - nsecs_t bias = vsyncInterval / 2; - int64_t extraVsyncs = - (compositeToPresentLatency - idealLatency + bias) / vsyncInterval; - nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ? - idealLatency + (extraVsyncs * vsyncInterval) : idealLatency; - - std::lock_guard<std::mutex> lock(mCompositorTimingLock); - mCompositorTiming.deadline = vsyncPhase - idealLatency; - mCompositorTiming.interval = vsyncInterval; - mCompositorTiming.presentLatency = snappedCompositeToPresentLatency; -} - -void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) -{ - const HWComposer& hwc = getHwComposer(); - const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); - - mGlCompositionDoneTimeline.updateSignalTimes(); - std::shared_ptr<FenceTime> glCompositionDoneFenceTime; - if (getHwComposer().hasGlesComposition(hw->getHwcDisplayId())) { - glCompositionDoneFenceTime = - std::make_shared<FenceTime>(hw->getClientTargetAcquireFence()); - mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime); - } else { - glCompositionDoneFenceTime = FenceTime::NO_FENCE; - } - - mDisplayTimeline.updateSignalTimes(); - sp<Fence> retireFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY); - auto retireFenceTime = std::make_shared<FenceTime>(retireFence); - mDisplayTimeline.push(retireFenceTime); - - nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0); - nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod(); - - // We use the refreshStartTime which might be sampled a little later than - // when we started doing work for this frame, but that should be okay - // since updateCompositorTiming has snapping logic. - updateCompositorTiming( - vsyncPhase, vsyncInterval, refreshStartTime, retireFenceTime); - CompositorTiming compositorTiming; - { - std::lock_guard<std::mutex> lock(mCompositorTimingLock); - compositorTiming = mCompositorTiming; - } - - mDrawingState.traverseInZOrder([&](Layer* layer) { - // TODO(brianderson): The retire fence is incorrectly passed in as the - // present fence. Fix this if this file lives on. - bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime, - retireFenceTime, compositorTiming); - if (frameLatched) { - recordBufferingStats(layer->getName().string(), - layer->getOccupancyHistory(false)); - } - }); - - if (retireFence->isValid()) { - if (mPrimaryDispSync.addPresentFence(retireFenceTime)) { - enableHardwareVsync(); - } else { - disableHardwareVsync(false); - } - } - - if (!hasSyncFramework) { - if (hw->isDisplayOn()) { - enableHardwareVsync(); - } - } - - if (mAnimCompositionPending) { - mAnimCompositionPending = false; - - if (retireFenceTime->isValid()) { - mAnimFrameTracker.setActualPresentFence(std::move(retireFenceTime)); - } else { - // The HWC doesn't support present fences, so use the refresh - // timestamp instead. - nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY); - mAnimFrameTracker.setActualPresentTime(presentTime); - } - mAnimFrameTracker.advanceFrame(); - } - - if (hw->getPowerMode() == HWC_POWER_MODE_OFF) { - return; - } - - nsecs_t currentTime = systemTime(); - if (mHasPoweredOff) { - mHasPoweredOff = false; - } else { - nsecs_t period = mPrimaryDispSync.getPeriod(); - nsecs_t elapsedTime = currentTime - mLastSwapTime; - size_t numPeriods = static_cast<size_t>(elapsedTime / period); - if (numPeriods < NUM_BUCKETS - 1) { - mFrameBuckets[numPeriods] += elapsedTime; - } else { - mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime; - } - mTotalTime += elapsedTime; - } - mLastSwapTime = currentTime; -} - -void SurfaceFlinger::rebuildLayerStacks() { - // rebuild the visible layer list per screen - if (CC_UNLIKELY(mVisibleRegionsDirty)) { - ATRACE_CALL(); - mVisibleRegionsDirty = false; - invalidateHwcGeometry(); - - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - Region opaqueRegion; - Region dirtyRegion; - Vector< sp<Layer> > layersSortedByZ; - const sp<DisplayDevice>& hw(mDisplays[dpy]); - const Transform& tr(hw->getTransform()); - const Rect bounds(hw->getBounds()); - if (hw->isDisplayOn()) { - computeVisibleRegions(hw, dirtyRegion, opaqueRegion); - - mDrawingState.traverseInZOrder([&](Layer* layer) { - if (layer->getLayerStack() == hw->getLayerStack()) { - Region drawRegion(tr.transform( - layer->visibleNonTransparentRegion)); - drawRegion.andSelf(bounds); - if (!drawRegion.isEmpty()) { - layersSortedByZ.add(layer); - } - } - }); - } - hw->setVisibleLayersSortedByZ(layersSortedByZ); - hw->undefinedRegion.set(bounds); - hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion)); - hw->dirtyRegion.orSelf(dirtyRegion); - } - } -} - -void SurfaceFlinger::setUpHWComposer() { - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty(); - bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0; - bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers; - - // If nothing has changed (!dirty), don't recompose. - // If something changed, but we don't currently have any visible layers, - // and didn't when we last did a composition, then skip it this time. - // The second rule does two things: - // - When all layers are removed from a display, we'll emit one black - // frame, then nothing more until we get new layers. - // - When a display is created with a private layer stack, we won't - // emit any black frames until a layer is added to the layer stack. - bool mustRecompose = dirty && !(empty && wasEmpty); - - ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL, - "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy, - mustRecompose ? "doing" : "skipping", - dirty ? "+" : "-", - empty ? "+" : "-", - wasEmpty ? "+" : "-"); - - mDisplays[dpy]->beginFrame(mustRecompose); - - if (mustRecompose) { - mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty; - } - } - - HWComposer& hwc(getHwComposer()); - if (hwc.initCheck() == NO_ERROR) { - // build the h/w work list - if (CC_UNLIKELY(mHwWorkListDirty)) { - mHwWorkListDirty = false; - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - sp<const DisplayDevice> hw(mDisplays[dpy]); - const int32_t id = hw->getHwcDisplayId(); - if (id >= 0) { - const Vector< sp<Layer> >& currentLayers( - hw->getVisibleLayersSortedByZ()); - const size_t count = currentLayers.size(); - if (hwc.createWorkList(id, count) == NO_ERROR) { - HWComposer::LayerListIterator cur = hwc.begin(id); - const HWComposer::LayerListIterator end = hwc.end(id); - for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { - const sp<Layer>& layer(currentLayers[i]); - layer->setGeometry(hw, *cur); - if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) { - cur->setSkip(true); - } - } - } - } - } - } - - // set the per-frame data - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - sp<const DisplayDevice> hw(mDisplays[dpy]); - const int32_t id = hw->getHwcDisplayId(); - if (id >= 0) { - const Vector< sp<Layer> >& currentLayers( - hw->getVisibleLayersSortedByZ()); - const size_t count = currentLayers.size(); - HWComposer::LayerListIterator cur = hwc.begin(id); - const HWComposer::LayerListIterator end = hwc.end(id); - for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { - /* - * update the per-frame h/w composer data for each layer - * and build the transparent region of the FB - */ - const sp<Layer>& layer(currentLayers[i]); - layer->setPerFrameData(hw, *cur); - } - } - } - - // If possible, attempt to use the cursor overlay on each display. - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - sp<const DisplayDevice> hw(mDisplays[dpy]); - const int32_t id = hw->getHwcDisplayId(); - if (id >= 0) { - const Vector< sp<Layer> >& currentLayers( - hw->getVisibleLayersSortedByZ()); - const size_t count = currentLayers.size(); - HWComposer::LayerListIterator cur = hwc.begin(id); - const HWComposer::LayerListIterator end = hwc.end(id); - for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { - const sp<Layer>& layer(currentLayers[i]); - if (layer->isPotentialCursor()) { - cur->setIsCursorLayerHint(); - break; - } - } - } - } - - status_t err = hwc.prepare(); - ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); - - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - sp<const DisplayDevice> hw(mDisplays[dpy]); - hw->prepareFrame(hwc); - } - } -} - -void SurfaceFlinger::doComposition() { - ATRACE_CALL(); - const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - const sp<DisplayDevice>& hw(mDisplays[dpy]); - if (hw->isDisplayOn()) { - // transform the dirty region into this screen's coordinate space - const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); - - // repaint the framebuffer (if needed) - doDisplayComposition(hw, dirtyRegion); - - hw->dirtyRegion.clear(); - hw->flip(hw->swapRegion); - hw->swapRegion.clear(); - } - // inform the h/w that we're done compositing - hw->compositionComplete(); - } - postFramebuffer(); -} - -void SurfaceFlinger::postFramebuffer() -{ - ATRACE_CALL(); - - const nsecs_t now = systemTime(); - mDebugInSwapBuffers = now; - - HWComposer& hwc(getHwComposer()); - if (hwc.initCheck() == NO_ERROR) { - if (!hwc.supportsFramebufferTarget()) { - // EGL spec says: - // "surface must be bound to the calling thread's current context, - // for the current rendering API." - getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); - } - hwc.commit(); - } - - // make the default display current because the VirtualDisplayDevice code cannot - // deal with dequeueBuffer() being called outside of the composition loop; however - // the code below can call glFlush() which is allowed (and does in some case) call - // dequeueBuffer(). - getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); - - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - sp<const DisplayDevice> hw(mDisplays[dpy]); - const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ()); - hw->onSwapBuffersCompleted(hwc); - const size_t count = currentLayers.size(); - int32_t id = hw->getHwcDisplayId(); - if (id >=0 && hwc.initCheck() == NO_ERROR) { - HWComposer::LayerListIterator cur = hwc.begin(id); - const HWComposer::LayerListIterator end = hwc.end(id); - for (size_t i = 0; cur != end && i < count; ++i, ++cur) { - currentLayers[i]->onLayerDisplayed(hw, &*cur); - } - } else { - for (size_t i = 0; i < count; i++) { - currentLayers[i]->onLayerDisplayed(hw, NULL); - } - } - } - - mLastSwapBufferTime = systemTime() - now; - mDebugInSwapBuffers = 0; - - uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount(); - if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { - logFrameStats(); - } -} - -void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) -{ - ATRACE_CALL(); - - // here we keep a copy of the drawing state (that is the state that's - // going to be overwritten by handleTransactionLocked()) outside of - // mStateLock so that the side-effects of the State assignment - // don't happen with mStateLock held (which can cause deadlocks). - State drawingState(mDrawingState); - - Mutex::Autolock _l(mStateLock); - const nsecs_t now = systemTime(); - mDebugInTransaction = now; - - // Here we're guaranteed that some transaction flags are set - // so we can call handleTransactionLocked() unconditionally. - // We call getTransactionFlags(), which will also clear the flags, - // with mStateLock held to guarantee that mCurrentState won't change - // until the transaction is committed. - - transactionFlags = getTransactionFlags(eTransactionMask); - handleTransactionLocked(transactionFlags); - - mLastTransactionTime = systemTime() - now; - mDebugInTransaction = 0; - invalidateHwcGeometry(); - // here the transaction has been committed -} - -void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) -{ - // Notify all layers of available frames - mCurrentState.traverseInZOrder([](Layer* layer) { - layer->notifyAvailableFrames(); - }); - - /* - * Traversal of the children - * (perform the transaction for each of them if needed) - */ - - if (transactionFlags & eTraversalNeeded) { - mCurrentState.traverseInZOrder([&](Layer* layer) { - uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); - if (!trFlags) return; - - const uint32_t flags = layer->doTransaction(0); - if (flags & Layer::eVisibleRegion) - mVisibleRegionsDirty = true; - }); - } - - /* - * Perform display own transactions if needed - */ - - if (transactionFlags & eDisplayTransactionNeeded) { - // here we take advantage of Vector's copy-on-write semantics to - // improve performance by skipping the transaction entirely when - // know that the lists are identical - const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays); - const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); - if (!curr.isIdenticalTo(draw)) { - mVisibleRegionsDirty = true; - const size_t cc = curr.size(); - size_t dc = draw.size(); - - // find the displays that were removed - // (ie: in drawing state but not in current state) - // also handle displays that changed - // (ie: displays that are in both lists) - for (size_t i=0 ; i<dc ; i++) { - const ssize_t j = curr.indexOfKey(draw.keyAt(i)); - if (j < 0) { - // in drawing state but not in current state - if (!draw[i].isMainDisplay()) { - // Call makeCurrent() on the primary display so we can - // be sure that nothing associated with this display - // is current. - const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked()); - defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); - sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i))); - if (hw != NULL) - hw->disconnect(getHwComposer()); - if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) - mEventThread->onHotplugReceived(draw[i].type, false); - mDisplays.removeItem(draw.keyAt(i)); - } else { - ALOGW("trying to remove the main display"); - } - } else { - // this display is in both lists. see if something changed. - const DisplayDeviceState& state(curr[j]); - const wp<IBinder>& display(curr.keyAt(j)); - const sp<IBinder> state_binder = IInterface::asBinder(state.surface); - const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface); - if (state_binder != draw_binder) { - // changing the surface is like destroying and - // recreating the DisplayDevice, so we just remove it - // from the drawing state, so that it get re-added - // below. - sp<DisplayDevice> hw(getDisplayDeviceLocked(display)); - if (hw != NULL) - hw->disconnect(getHwComposer()); - mDisplays.removeItem(display); - mDrawingState.displays.removeItemsAt(i); - dc--; i--; - // at this point we must loop to the next item - continue; - } - - const sp<DisplayDevice> disp(getDisplayDeviceLocked(display)); - if (disp != NULL) { - if (state.layerStack != draw[i].layerStack) { - disp->setLayerStack(state.layerStack); - } - if ((state.orientation != draw[i].orientation) - || (state.viewport != draw[i].viewport) - || (state.frame != draw[i].frame)) - { - disp->setProjection(state.orientation, - state.viewport, state.frame); - } - if (state.width != draw[i].width || state.height != draw[i].height) { - disp->setDisplaySize(state.width, state.height); - } - } - } - } - - // find displays that were added - // (ie: in current state but not in drawing state) - for (size_t i=0 ; i<cc ; i++) { - if (draw.indexOfKey(curr.keyAt(i)) < 0) { - const DisplayDeviceState& state(curr[i]); - - sp<DisplaySurface> dispSurface; - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferProducer> bqProducer; - sp<IGraphicBufferConsumer> bqConsumer; - BufferQueue::createBufferQueue(&bqProducer, &bqConsumer); - - int32_t hwcDisplayId = -1; - if (state.isVirtualDisplay()) { - // Virtual displays without a surface are dormant: - // they have external state (layer stack, projection, - // etc.) but no internal state (i.e. a DisplayDevice). - if (state.surface != NULL) { - - int width = 0; - int status = state.surface->query( - NATIVE_WINDOW_WIDTH, &width); - ALOGE_IF(status != NO_ERROR, - "Unable to query width (%d)", status); - int height = 0; - status = state.surface->query( - NATIVE_WINDOW_HEIGHT, &height); - ALOGE_IF(status != NO_ERROR, - "Unable to query height (%d)", status); - if (mUseHwcVirtualDisplays && - (SurfaceFlinger::maxVirtualDisplaySize == 0 || - (width <= static_cast<int>(SurfaceFlinger::maxVirtualDisplaySize) && - height <= static_cast<int>(SurfaceFlinger::maxVirtualDisplaySize)))) { - hwcDisplayId = allocateHwcDisplayId(state.type); - } - - sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface( - *mHwc, hwcDisplayId, state.surface, - bqProducer, bqConsumer, state.displayName); - - dispSurface = vds; - producer = vds; - } - } else { - ALOGE_IF(state.surface!=NULL, - "adding a supported display, but rendering " - "surface is provided (%p), ignoring it", - state.surface.get()); - hwcDisplayId = allocateHwcDisplayId(state.type); - // for supported (by hwc) displays we provide our - // own rendering surface - dispSurface = new FramebufferSurface(*mHwc, state.type, - bqConsumer); - producer = bqProducer; - } - - const wp<IBinder>& display(curr.keyAt(i)); - if (dispSurface != NULL) { - sp<DisplayDevice> hw = new DisplayDevice(this, - state.type, hwcDisplayId, - mHwc->getFormat(hwcDisplayId), state.isSecure, - display, dispSurface, producer, - mRenderEngine->getEGLConfig(), false); - hw->setLayerStack(state.layerStack); - hw->setProjection(state.orientation, - state.viewport, state.frame); - hw->setDisplayName(state.displayName); - mDisplays.add(display, hw); - if (state.isVirtualDisplay()) { - if (hwcDisplayId >= 0) { - mHwc->setVirtualDisplayProperties(hwcDisplayId, - hw->getWidth(), hw->getHeight(), - hw->getFormat()); - } - } else { - mEventThread->onHotplugReceived(state.type, true); - } - } - } - } - } - } - - if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) { - // The transform hint might have changed for some layers - // (either because a display has changed, or because a layer - // as changed). - // - // Walk through all the layers in currentLayers, - // and update their transform hint. - // - // If a layer is visible only on a single display, then that - // display is used to calculate the hint, otherwise we use the - // default display. - // - // NOTE: we do this here, rather than in rebuildLayerStacks() so that - // the hint is set before we acquire a buffer from the surface texture. - // - // NOTE: layer transactions have taken place already, so we use their - // drawing state. However, SurfaceFlinger's own transaction has not - // happened yet, so we must use the current state layer list - // (soon to become the drawing state list). - // - sp<const DisplayDevice> disp; - uint32_t currentlayerStack = 0; - bool first = true; - mCurrentState.traverseInZOrder([&](Layer* layer) { - // NOTE: we rely on the fact that layers are sorted by - // layerStack first (so we don't have to traverse the list - // of displays for every layer). - uint32_t layerStack = layer->getLayerStack(); - if (first || currentlayerStack != layerStack) { - currentlayerStack = layerStack; - // figure out if this layerstack is mirrored - // (more than one display) if so, pick the default display, - // if not, pick the only display it's on. - disp.clear(); - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - sp<const DisplayDevice> hw(mDisplays[dpy]); - if (hw->getLayerStack() == currentlayerStack) { - if (disp == NULL) { - disp = hw; - } else { - disp = NULL; - break; - } - } - } - } - if (disp == NULL) { - // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to - // redraw after transform hint changes. See bug 8508397. - - // could be null when this layer is using a layerStack - // that is not visible on any display. Also can occur at - // screen off/on times. - disp = getDefaultDisplayDeviceLocked(); - } - layer->updateTransformHint(disp); - - first = false; - }); - } - - - /* - * Perform our own transaction if needed - */ - - if (mLayersAdded) { - mLayersAdded = false; - // Layers have been added. - mVisibleRegionsDirty = true; - } - - // some layers might have been removed, so - // we need to update the regions they're exposing. - if (mLayersRemoved) { - mLayersRemoved = false; - mVisibleRegionsDirty = true; - mDrawingState.traverseInZOrder([&](Layer* layer) { - if (mLayersPendingRemoval.indexOf(layer) >= 0) { - // this layer is not visible anymore - // TODO: we could traverse the tree from front to back and - // compute the actual visible region - // TODO: we could cache the transformed region - Region visibleReg; - visibleReg.set(layer->computeScreenBounds()); - invalidateLayerStack(layer, visibleReg); - } - }); - } - - commitTransaction(); - - updateCursorAsync(); -} - -void SurfaceFlinger::updateCursorAsync() -{ - HWComposer& hwc(getHwComposer()); - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - sp<const DisplayDevice> hw(mDisplays[dpy]); - const int32_t id = hw->getHwcDisplayId(); - if (id < 0) { - continue; - } - const Vector< sp<Layer> >& currentLayers( - hw->getVisibleLayersSortedByZ()); - const size_t count = currentLayers.size(); - HWComposer::LayerListIterator cur = hwc.begin(id); - const HWComposer::LayerListIterator end = hwc.end(id); - for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { - if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) { - continue; - } - const sp<Layer>& layer(currentLayers[i]); - Rect cursorPos = layer->getPosition(hw); - hwc.setCursorPositionAsync(id, cursorPos); - break; - } - } -} - -void SurfaceFlinger::commitTransaction() -{ - if (!mLayersPendingRemoval.isEmpty()) { - // Notify removed layers now that they can't be drawn from - for (const auto& l : mLayersPendingRemoval) { - recordBufferingStats(l->getName().string(), - l->getOccupancyHistory(true)); - l->onRemoved(); - } - mLayersPendingRemoval.clear(); - } - - // If this transaction is part of a window animation then the next frame - // we composite should be considered an animation as well. - mAnimCompositionPending = mAnimTransactionPending; - - mDrawingState = mCurrentState; - mDrawingState.traverseInZOrder([](Layer* layer) { - layer->commitChildList(); - }); - mTransactionPending = false; - mAnimTransactionPending = false; - mTransactionCV.broadcast(); -} - -void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice, - Region& outDirtyRegion, Region& outOpaqueRegion) -{ - ATRACE_CALL(); - - Region aboveOpaqueLayers; - Region aboveCoveredLayers; - Region dirty; - - outDirtyRegion.clear(); - - mDrawingState.traverseInReverseZOrder([&](Layer* layer) { - // start with the whole surface at its current location - const Layer::State& s(layer->getDrawingState()); - - // only consider the layers on the given layer stack - if (layer->getLayerStack() != displayDevice->getLayerStack()) - return; - - /* - * opaqueRegion: area of a surface that is fully opaque. - */ - Region opaqueRegion; - - /* - * visibleRegion: area of a surface that is visible on screen - * and not fully transparent. This is essentially the layer's - * footprint minus the opaque regions above it. - * Areas covered by a translucent surface are considered visible. - */ - Region visibleRegion; - - /* - * coveredRegion: area of a surface that is covered by all - * visible regions above it (which includes the translucent areas). - */ - Region coveredRegion; - - /* - * transparentRegion: area of a surface that is hinted to be completely - * transparent. This is only used to tell when the layer has no visible - * non-transparent regions and can be removed from the layer list. It - * does not affect the visibleRegion of this layer or any layers - * beneath it. The hint may not be correct if apps don't respect the - * SurfaceView restrictions (which, sadly, some don't). - */ - Region transparentRegion; - - - // handle hidden surfaces by setting the visible region to empty - if (CC_LIKELY(layer->isVisible())) { - const bool translucent = !layer->isOpaque(s); - Rect bounds(layer->computeScreenBounds()); - visibleRegion.set(bounds); - Transform tr = layer->getTransform(); - if (!visibleRegion.isEmpty()) { - // Remove the transparent area from the visible region - if (translucent) { - if (tr.preserveRects()) { - // transform the transparent region - transparentRegion = tr.transform(s.activeTransparentRegion); - } else { - // transformation too complex, can't do the - // transparent region optimization. - transparentRegion.clear(); - } - } - - // compute the opaque region - const int32_t layerOrientation = tr.getOrientation(); - if (s.alpha==255 && !translucent && - ((layerOrientation & Transform::ROT_INVALID) == false)) { - // the opaque region is the layer's footprint - opaqueRegion = visibleRegion; - } - } - } - - // Clip the covered region to the visible region - coveredRegion = aboveCoveredLayers.intersect(visibleRegion); - - // Update aboveCoveredLayers for next (lower) layer - aboveCoveredLayers.orSelf(visibleRegion); - - // subtract the opaque region covered by the layers above us - visibleRegion.subtractSelf(aboveOpaqueLayers); - - // compute this layer's dirty region - if (layer->contentDirty) { - // we need to invalidate the whole region - dirty = visibleRegion; - // as well, as the old visible region - dirty.orSelf(layer->visibleRegion); - layer->contentDirty = false; - } else { - /* compute the exposed region: - * the exposed region consists of two components: - * 1) what's VISIBLE now and was COVERED before - * 2) what's EXPOSED now less what was EXPOSED before - * - * note that (1) is conservative, we start with the whole - * visible region but only keep what used to be covered by - * something -- which mean it may have been exposed. - * - * (2) handles areas that were not covered by anything but got - * exposed because of a resize. - */ - const Region newExposed = visibleRegion - coveredRegion; - const Region oldVisibleRegion = layer->visibleRegion; - const Region oldCoveredRegion = layer->coveredRegion; - const Region oldExposed = oldVisibleRegion - oldCoveredRegion; - dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); - } - dirty.subtractSelf(aboveOpaqueLayers); - - // accumulate to the screen dirty region - outDirtyRegion.orSelf(dirty); - - // Update aboveOpaqueLayers for next (lower) layer - aboveOpaqueLayers.orSelf(opaqueRegion); - - // Store the visible region in screen space - layer->setVisibleRegion(visibleRegion); - layer->setCoveredRegion(coveredRegion); - layer->setVisibleNonTransparentRegion( - visibleRegion.subtract(transparentRegion)); - }); - - outOpaqueRegion = aboveOpaqueLayers; -} - -void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) { - uint32_t layerStack = layer->getLayerStack(); - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - const sp<DisplayDevice>& hw(mDisplays[dpy]); - if (hw->getLayerStack() == layerStack) { - hw->dirtyRegion.orSelf(dirty); - } - } -} - -bool SurfaceFlinger::handlePageFlip() -{ - nsecs_t latchTime = systemTime(); - Region dirtyRegion; - - bool visibleRegions = false; - bool frameQueued = false; - - // Store the set of layers that need updates. This set must not change as - // buffers are being latched, as this could result in a deadlock. - // Example: Two producers share the same command stream and: - // 1.) Layer 0 is latched - // 2.) Layer 0 gets a new frame - // 2.) Layer 1 gets a new frame - // 3.) Layer 1 is latched. - // Display is now waiting on Layer 1's frame, which is behind layer 0's - // second frame. But layer 0's second frame could be waiting on display. - Vector<Layer*> layersWithQueuedFrames; - mDrawingState.traverseInZOrder([&](Layer* layer) { - if (layer->hasQueuedFrame()) { - frameQueued = true; - if (layer->shouldPresentNow(mPrimaryDispSync)) { - layersWithQueuedFrames.push_back(layer); - } else { - layer->useEmptyDamage(); - } - } else { - layer->useEmptyDamage(); - } - }); - for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) { - Layer* layer = layersWithQueuedFrames[i]; - const Region dirty(layer->latchBuffer(visibleRegions, latchTime)); - layer->useSurfaceDamage(); - invalidateLayerStack(layer, dirty); - } - - mVisibleRegionsDirty |= visibleRegions; - - // If we will need to wake up at some time in the future to deal with a - // queued frame that shouldn't be displayed during this vsync period, wake - // up during the next vsync period to check again. - if (frameQueued && layersWithQueuedFrames.empty()) { - signalLayerUpdate(); - } - - // Only continue with the refresh if there is actually new work to do - return !layersWithQueuedFrames.empty(); -} - -void SurfaceFlinger::invalidateHwcGeometry() -{ - mHwWorkListDirty = true; -} - - -void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, - const Region& inDirtyRegion) -{ - // We only need to actually compose the display if: - // 1) It is being handled by hardware composer, which may need this to - // keep its virtual display state machine in sync, or - // 2) There is work to be done (the dirty region isn't empty) - bool isHwcDisplay = hw->getHwcDisplayId() >= 0; - if (!isHwcDisplay && inDirtyRegion.isEmpty()) { - return; - } - - Region dirtyRegion(inDirtyRegion); - - // compute the invalid region - hw->swapRegion.orSelf(dirtyRegion); - - uint32_t flags = hw->getFlags(); - if (flags & DisplayDevice::SWAP_RECTANGLE) { - // we can redraw only what's dirty, but since SWAP_RECTANGLE only - // takes a rectangle, we must make sure to update that whole - // rectangle in that case - dirtyRegion.set(hw->swapRegion.bounds()); - } else { - if (flags & DisplayDevice::PARTIAL_UPDATES) { - // We need to redraw the rectangle that will be updated - // (pushed to the framebuffer). - // This is needed because PARTIAL_UPDATES only takes one - // rectangle instead of a region (see DisplayDevice::flip()) - dirtyRegion.set(hw->swapRegion.bounds()); - } else { - // we need to redraw everything (the whole screen) - dirtyRegion.set(hw->bounds()); - hw->swapRegion = dirtyRegion; - } - } - - if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) { - if (!doComposeSurfaces(hw, dirtyRegion)) return; - } else { - RenderEngine& engine(getRenderEngine()); - mat4 colorMatrix = mColorMatrix; - if (mDaltonize) { - colorMatrix = colorMatrix * mDaltonizer(); - } - mat4 oldMatrix = engine.setupColorTransform(colorMatrix); - doComposeSurfaces(hw, dirtyRegion); - engine.setupColorTransform(oldMatrix); - } - - // update the swap region and clear the dirty region - hw->swapRegion.orSelf(dirtyRegion); - - // swap buffers (presentation) - hw->swapBuffers(getHwComposer()); -} - -bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty) -{ - RenderEngine& engine(getRenderEngine()); - const int32_t id = hw->getHwcDisplayId(); - HWComposer& hwc(getHwComposer()); - HWComposer::LayerListIterator cur = hwc.begin(id); - const HWComposer::LayerListIterator end = hwc.end(id); - - bool hasGlesComposition = hwc.hasGlesComposition(id); - if (hasGlesComposition) { - if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) { - ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", - hw->getDisplayName().string()); - eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) { - ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting."); - } - return false; - } - - // Never touch the framebuffer if we don't have any framebuffer layers - const bool hasHwcComposition = hwc.hasHwcComposition(id); - if (hasHwcComposition) { - // when using overlays, we assume a fully transparent framebuffer - // NOTE: we could reduce how much we need to clear, for instance - // remove where there are opaque FB layers. however, on some - // GPUs doing a "clean slate" clear might be more efficient. - // We'll revisit later if needed. - engine.clearWithColor(0, 0, 0, 0); - } else { - // we start with the whole screen area - const Region bounds(hw->getBounds()); - - // we remove the scissor part - // we're left with the letterbox region - // (common case is that letterbox ends-up being empty) - const Region letterbox(bounds.subtract(hw->getScissor())); - - // compute the area to clear - Region region(hw->undefinedRegion.merge(letterbox)); - - // but limit it to the dirty region - region.andSelf(dirty); - - // screen is already cleared here - if (!region.isEmpty()) { - // can happen with SurfaceView - drawWormhole(hw, region); - } - } - - if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) { - // just to be on the safe side, we don't set the - // scissor on the main display. It should never be needed - // anyways (though in theory it could since the API allows it). - const Rect& bounds(hw->getBounds()); - const Rect& scissor(hw->getScissor()); - if (scissor != bounds) { - // scissor doesn't match the screen's dimensions, so we - // need to clear everything outside of it and enable - // the GL scissor so we don't draw anything where we shouldn't - - // enable scissor for this frame - const uint32_t height = hw->getHeight(); - engine.setScissor(scissor.left, height - scissor.bottom, - scissor.getWidth(), scissor.getHeight()); - } - } - } - - /* - * and then, render the layers targeted at the framebuffer - */ - - const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ()); - const size_t count = layers.size(); - const Transform& tr = hw->getTransform(); - if (cur != end) { - // we're using h/w composer - for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) { - const sp<Layer>& layer(layers[i]); - const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); - if (!clip.isEmpty()) { - switch (cur->getCompositionType()) { - case HWC_CURSOR_OVERLAY: - case HWC_OVERLAY: { - const Layer::State& state(layer->getDrawingState()); - if ((cur->getHints() & HWC_HINT_CLEAR_FB) - && i - && layer->isOpaque(state) && (state.alpha == 0xFF) - && hasGlesComposition) { - // never clear the very first layer since we're - // guaranteed the FB is already cleared - layer->clearWithOpenGL(hw); - } - break; - } - case HWC_FRAMEBUFFER: { - layer->draw(hw, clip); - break; - } - case HWC_FRAMEBUFFER_TARGET: { - // this should not happen as the iterator shouldn't - // let us get there. - ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i); - break; - } - } - } - layer->setAcquireFence(hw, *cur); - } - } else { - // we're not using h/w composer - for (size_t i=0 ; i<count ; ++i) { - const sp<Layer>& layer(layers[i]); - const Region clip(dirty.intersect( - tr.transform(layer->visibleRegion))); - if (!clip.isEmpty()) { - layer->draw(hw, clip); - } - } - } - - // disable scissor at the end of the frame - engine.disableScissor(); - return true; -} - -void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Region& region) const { - const int32_t height = hw->getHeight(); - RenderEngine& engine(getRenderEngine()); - engine.fillRegionWithColor(region, height, 0, 0, 0, 0); -} - -status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, - const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbc, - const sp<Layer>& lbc, - const sp<Layer>& parent) -{ - // add this layer to the current state list - { - Mutex::Autolock _l(mStateLock); - if (mNumLayers >= MAX_LAYERS) { - return NO_MEMORY; - } - if (parent == nullptr) { - mCurrentState.layersSortedByZ.add(lbc); - } else { - if (mCurrentState.layersSortedByZ.indexOf(parent) < 0) { - ALOGE("addClientLayer called with a removed parent"); - return NAME_NOT_FOUND; - } - parent->addChild(lbc); - } - - mGraphicBufferProducerList.add(IInterface::asBinder(gbc)); - mLayersAdded = true; - mNumLayers++; - } - - // attach this layer to the client - client->attachLayer(handle, lbc); - - return NO_ERROR; -} - -status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) { - Mutex::Autolock _l(mStateLock); - - const auto& p = layer->getParent(); - ssize_t index; - if (p != nullptr) { - if (topLevelOnly) { - return NO_ERROR; - } - - sp<Layer> ancestor = p; - while (ancestor->getParent() != nullptr) { - ancestor = ancestor->getParent(); - } - if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) { - ALOGE("removeLayer called with a layer whose parent has been removed"); - return NAME_NOT_FOUND; - } - - index = p->removeChild(layer); - } else { - index = mCurrentState.layersSortedByZ.remove(layer); - } - - // As a matter of normal operation, the LayerCleaner will produce a second - // attempt to remove the surface. The Layer will be kept alive in mDrawingState - // so we will succeed in promoting it, but it's already been removed - // from mCurrentState. As long as we can find it in mDrawingState we have no problem - // otherwise something has gone wrong and we are leaking the layer. - if (index < 0 && mDrawingState.layersSortedByZ.indexOf(layer) < 0) { - ALOGE("Failed to find layer (%s) in layer parent (%s).", - layer->getName().string(), - (p != nullptr) ? p->getName().string() : "no-parent"); - return BAD_VALUE; - } else if (index < 0) { - return NO_ERROR; - } - - layer->onRemovedFromCurrentState(); - mLayersPendingRemoval.add(layer); - mLayersRemoved = true; - mNumLayers -= 1 + layer->getChildrenCount(); - setTransactionFlags(eTransactionNeeded); - return NO_ERROR; -} - -uint32_t SurfaceFlinger::peekTransactionFlags() { - return android_atomic_release_load(&mTransactionFlags); -} - -uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) { - return android_atomic_and(~flags, &mTransactionFlags) & flags; -} - -uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { - uint32_t old = android_atomic_or(flags, &mTransactionFlags); - if ((old & flags)==0) { // wake the server up - signalTransaction(); - } - return old; -} - -void SurfaceFlinger::setTransactionState( - const Vector<ComposerState>& state, - const Vector<DisplayState>& displays, - uint32_t flags) -{ - ATRACE_CALL(); - Mutex::Autolock _l(mStateLock); - uint32_t transactionFlags = 0; - - if (flags & eAnimation) { - // For window updates that are part of an animation we must wait for - // previous animation "frames" to be handled. - while (mAnimTransactionPending) { - status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); - if (CC_UNLIKELY(err != NO_ERROR)) { - // just in case something goes wrong in SF, return to the - // caller after a few seconds. - ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out " - "waiting for previous animation frame"); - mAnimTransactionPending = false; - break; - } - } - } - - size_t count = displays.size(); - for (size_t i=0 ; i<count ; i++) { - const DisplayState& s(displays[i]); - transactionFlags |= setDisplayStateLocked(s); - } - - count = state.size(); - for (size_t i=0 ; i<count ; i++) { - const ComposerState& s(state[i]); - // Here we need to check that the interface we're given is indeed - // one of our own. A malicious client could give us a NULL - // IInterface, or one of its own or even one of our own but a - // different type. All these situations would cause us to crash. - // - // NOTE: it would be better to use RTTI as we could directly check - // that we have a Client*. however, RTTI is disabled in Android. - if (s.client != NULL) { - sp<IBinder> binder = IInterface::asBinder(s.client); - if (binder != NULL) { - if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != NULL) { - sp<Client> client( static_cast<Client *>(s.client.get()) ); - transactionFlags |= setClientStateLocked(client, s.state); - } - } - } - } - - // If a synchronous transaction is explicitly requested without any changes, - // force a transaction anyway. This can be used as a flush mechanism for - // previous async transactions. - if (transactionFlags == 0 && (flags & eSynchronous)) { - transactionFlags = eTransactionNeeded; - } - - if (transactionFlags) { - if (mInterceptor.isEnabled()) { - mInterceptor.saveTransaction(state, mCurrentState.displays, displays, flags); - } - - // this triggers the transaction - setTransactionFlags(transactionFlags); - - // if this is a synchronous transaction, wait for it to take effect - // before returning. - if (flags & eSynchronous) { - mTransactionPending = true; - } - if (flags & eAnimation) { - mAnimTransactionPending = true; - } - while (mTransactionPending) { - status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); - if (CC_UNLIKELY(err != NO_ERROR)) { - // just in case something goes wrong in SF, return to the - // called after a few seconds. - ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!"); - mTransactionPending = false; - break; - } - } - } -} - -uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) -{ - ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token); - if (dpyIdx < 0) - return 0; - - uint32_t flags = 0; - DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx)); - if (disp.isValid()) { - const uint32_t what = s.what; - if (what & DisplayState::eSurfaceChanged) { - if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) { - disp.surface = s.surface; - flags |= eDisplayTransactionNeeded; - } - } - if (what & DisplayState::eLayerStackChanged) { - if (disp.layerStack != s.layerStack) { - disp.layerStack = s.layerStack; - flags |= eDisplayTransactionNeeded; - } - } - if (what & DisplayState::eDisplayProjectionChanged) { - if (disp.orientation != s.orientation) { - disp.orientation = s.orientation; - flags |= eDisplayTransactionNeeded; - } - if (disp.frame != s.frame) { - disp.frame = s.frame; - flags |= eDisplayTransactionNeeded; - } - if (disp.viewport != s.viewport) { - disp.viewport = s.viewport; - flags |= eDisplayTransactionNeeded; - } - } - if (what & DisplayState::eDisplaySizeChanged) { - if (disp.width != s.width) { - disp.width = s.width; - flags |= eDisplayTransactionNeeded; - } - if (disp.height != s.height) { - disp.height = s.height; - flags |= eDisplayTransactionNeeded; - } - } - } - return flags; -} - -uint32_t SurfaceFlinger::setClientStateLocked( - const sp<Client>& client, - const layer_state_t& s) -{ - uint32_t flags = 0; - sp<Layer> layer(client->getLayerUser(s.surface)); - if (layer != 0) { - const uint32_t what = s.what; - bool geometryAppliesWithResize = - what & layer_state_t::eGeometryAppliesWithResize; - if (what & layer_state_t::ePositionChanged) { - if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) { - flags |= eTraversalNeeded; - } - } - if (what & layer_state_t::eLayerChanged) { - // NOTE: index needs to be calculated before we update the state - const auto& p = layer->getParent(); - if (p == nullptr) { - ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - if (layer->setLayer(s.z) && idx >= 0) { - mCurrentState.layersSortedByZ.removeAt(idx); - mCurrentState.layersSortedByZ.add(layer); - // we need traversal (state changed) - // AND transaction (list changed) - flags |= eTransactionNeeded|eTraversalNeeded; - } - } else { - if (p->setChildLayer(layer, s.z)) { - flags |= eTransactionNeeded|eTraversalNeeded; - } - } - } - if (what & layer_state_t::eRelativeLayerChanged) { - ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) { - mCurrentState.layersSortedByZ.removeAt(idx); - mCurrentState.layersSortedByZ.add(layer); - flags |= eTransactionNeeded|eTraversalNeeded; - } - } - if (what & layer_state_t::eSizeChanged) { - if (layer->setSize(s.w, s.h)) { - flags |= eTraversalNeeded; - } - } - if (what & layer_state_t::eAlphaChanged) { - if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eMatrixChanged) { - if (layer->setMatrix(s.matrix)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eTransparentRegionChanged) { - if (layer->setTransparentRegionHint(s.transparentRegion)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eFlagsChanged) { - if (layer->setFlags(s.flags, s.mask)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eCropChanged) { - if (layer->setCrop(s.crop, !geometryAppliesWithResize)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eFinalCropChanged) { - if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize)) - flags |= eTraversalNeeded; - } - if (what & layer_state_t::eLayerStackChanged) { - ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - // We only allow setting layer stacks for top level layers, - // everything else inherits layer stack from its parent. - if (layer->hasParent()) { - ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid", - layer->getName().string()); - } else if (idx < 0) { - ALOGE("Attempt to set layer stack on layer without parent (%s) that " - "that also does not appear in the top level layer list. Something" - " has gone wrong.", layer->getName().string()); - } else if (layer->setLayerStack(s.layerStack)) { - mCurrentState.layersSortedByZ.removeAt(idx); - mCurrentState.layersSortedByZ.add(layer); - // we need traversal (state changed) - // AND transaction (list changed) - flags |= eTransactionNeeded|eTraversalNeeded; - } - } - if (what & layer_state_t::eDeferTransaction) { - if (s.barrierHandle != nullptr) { - layer->deferTransactionUntil(s.barrierHandle, s.frameNumber); - } else if (s.barrierGbp != nullptr) { - const sp<IGraphicBufferProducer>& gbp = s.barrierGbp; - if (authenticateSurfaceTextureLocked(gbp)) { - const auto& otherLayer = - (static_cast<MonitoredProducer*>(gbp.get()))->getLayer(); - layer->deferTransactionUntil(otherLayer, s.frameNumber); - } else { - ALOGE("Attempt to defer transaction to to an" - " unrecognized GraphicBufferProducer"); - } - } - // We don't trigger a traversal here because if no other state is - // changed, we don't want this to cause any more work - } - if (what & layer_state_t::eReparentChildren) { - if (layer->reparentChildren(s.reparentHandle)) { - flags |= eTransactionNeeded|eTraversalNeeded; - } - } - if (what & layer_state_t::eDetachChildren) { - layer->detachChildren(); - } - if (what & layer_state_t::eOverrideScalingModeChanged) { - layer->setOverrideScalingMode(s.overrideScalingMode); - // We don't trigger a traversal here because if no other state is - // changed, we don't want this to cause any more work - } - } - return flags; -} - -status_t SurfaceFlinger::createLayer( - const String8& name, - const sp<Client>& client, - uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, - uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent) -{ - if (int32_t(w|h) < 0) { - ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - - status_t result = NO_ERROR; - - sp<Layer> layer; - - String8 uniqueName = getUniqueLayerName(name); - - switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { - case ISurfaceComposerClient::eFXSurfaceNormal: - result = createNormalLayer(client, - uniqueName, w, h, flags, format, - handle, gbp, &layer); - break; - case ISurfaceComposerClient::eFXSurfaceDim: - result = createDimLayer(client, - uniqueName, w, h, flags, - handle, gbp, &layer); - break; - default: - result = BAD_VALUE; - break; - } - - if (result != NO_ERROR) { - return result; - } - - layer->setInfo(windowType, ownerUid); - - result = addClientLayer(client, *handle, *gbp, layer, *parent); - if (result != NO_ERROR) { - return result; - } - mInterceptor.saveSurfaceCreation(layer); - - setTransactionFlags(eTransactionNeeded); - return result; -} - -String8 SurfaceFlinger::getUniqueLayerName(const String8& name) -{ - bool matchFound = true; - uint32_t dupeCounter = 0; - - // Tack on our counter whether there is a hit or not, so everyone gets a tag - String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str()); - - // Loop over layers until we're sure there is no matching name - while (matchFound) { - matchFound = false; - mDrawingState.traverseInZOrder([&](Layer* layer) { - if (layer->getName() == uniqueName) { - matchFound = true; - uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str()); - } - }); - } - - ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str()); - - return uniqueName; -} - -status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, - const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, - sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) -{ - // initialize the surfaces - switch (format) { - case PIXEL_FORMAT_TRANSPARENT: - case PIXEL_FORMAT_TRANSLUCENT: - format = PIXEL_FORMAT_RGBA_8888; - break; - case PIXEL_FORMAT_OPAQUE: - format = PIXEL_FORMAT_RGBX_8888; - break; - } - - *outLayer = new Layer(this, client, name, w, h, flags); - status_t err = (*outLayer)->setBuffers(w, h, format, flags); - if (err == NO_ERROR) { - *handle = (*outLayer)->getHandle(); - *gbp = (*outLayer)->getProducer(); - } - - ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err)); - return err; -} - -status_t SurfaceFlinger::createDimLayer(const sp<Client>& client, - const String8& name, uint32_t w, uint32_t h, uint32_t flags, - sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) -{ - *outLayer = new LayerDim(this, client, name, w, h, flags); - *handle = (*outLayer)->getHandle(); - *gbp = (*outLayer)->getProducer(); - return NO_ERROR; -} - -status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle) -{ - // called by a client when it wants to remove a Layer - status_t err = NO_ERROR; - sp<Layer> l(client->getLayerUser(handle)); - if (l != NULL) { - mInterceptor.saveSurfaceDeletion(l); - err = removeLayer(l); - ALOGE_IF(err<0 && err != NAME_NOT_FOUND, - "error removing layer=%p (%s)", l.get(), strerror(-err)); - } - return err; -} - -status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer) -{ - // called by ~LayerCleaner() when all references to the IBinder (handle) - // are gone - sp<Layer> l = layer.promote(); - if (l == nullptr) { - // The layer has already been removed, carry on - return NO_ERROR; - } - // If we have a parent, then we can continue to live as long as it does. - return removeLayer(l, true); -} - -// --------------------------------------------------------------------------- - -void SurfaceFlinger::onInitializeDisplays() { - // reset screen orientation and use primary layer stack - Vector<ComposerState> state; - Vector<DisplayState> displays; - DisplayState d; - d.what = DisplayState::eDisplayProjectionChanged | - DisplayState::eLayerStackChanged; - d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]; - d.layerStack = 0; - d.orientation = DisplayState::eOrientationDefault; - d.frame.makeInvalid(); - d.viewport.makeInvalid(); - d.width = 0; - d.height = 0; - displays.add(d); - setTransactionState(state, displays, 0); - setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL); - - const nsecs_t period = - getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); - mAnimFrameTracker.setDisplayRefreshPeriod(period); - - // Use phase of 0 since phase is not known. - // Use latency of 0, which will snap to the ideal latency. - setCompositorTimingSnapped(0, period, 0); -} - -void SurfaceFlinger::initializeDisplays() { - class MessageScreenInitialized : public MessageBase { - SurfaceFlinger* flinger; - public: - explicit MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { } - virtual bool handler() { - flinger->onInitializeDisplays(); - return true; - } - }; - sp<MessageBase> msg = new MessageScreenInitialized(this); - postMessageAsync(msg); // we may be called from main thread, use async message -} - -void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, - int mode) { - ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), - this); - int32_t type = hw->getDisplayType(); - int currentMode = hw->getPowerMode(); - - if (mode == currentMode) { - ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode); - return; - } - - hw->setPowerMode(mode); - if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { - ALOGW("Trying to set power mode for virtual display"); - return; - } - - if (mInterceptor.isEnabled()) { - Mutex::Autolock _l(mStateLock); - ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken()); - if (idx < 0) { - ALOGW("Surface Interceptor SavePowerMode: invalid display token"); - return; - } - mInterceptor.savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode); - } - - if (currentMode == HWC_POWER_MODE_OFF) { - // Turn on the display - getHwComposer().setPowerMode(type, mode); - if (type == DisplayDevice::DISPLAY_PRIMARY && - mode != HWC_POWER_MODE_DOZE_SUSPEND) { - // FIXME: eventthread only knows about the main display right now - mEventThread->onScreenAcquired(); - resyncToHardwareVsync(true); - } - - mVisibleRegionsDirty = true; - mHasPoweredOff = true; - repaintEverything(); - - struct sched_param param = {0}; - param.sched_priority = 1; - if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) { - ALOGW("Couldn't set SCHED_FIFO on display on"); - } - } else if (mode == HWC_POWER_MODE_OFF) { - // Turn off the display - struct sched_param param = {0}; - if (sched_setscheduler(0, SCHED_OTHER, ¶m) != 0) { - ALOGW("Couldn't set SCHED_OTHER on display off"); - } - - if (type == DisplayDevice::DISPLAY_PRIMARY) { - disableHardwareVsync(true); // also cancels any in-progress resync - - // FIXME: eventthread only knows about the main display right now - mEventThread->onScreenReleased(); - } - - getHwComposer().setPowerMode(type, mode); - mVisibleRegionsDirty = true; - // from this point on, SF will stop drawing on this display - } else if (mode == HWC_POWER_MODE_DOZE || - mode == HWC_POWER_MODE_NORMAL) { - // Update display while dozing - getHwComposer().setPowerMode(type, mode); - if (type == DisplayDevice::DISPLAY_PRIMARY) { - // FIXME: eventthread only knows about the main display right now - mEventThread->onScreenAcquired(); - resyncToHardwareVsync(true); - } - } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) { - // Leave display going to doze - if (type == DisplayDevice::DISPLAY_PRIMARY) { - disableHardwareVsync(true); // also cancels any in-progress resync - // FIXME: eventthread only knows about the main display right now - mEventThread->onScreenReleased(); - } - getHwComposer().setPowerMode(type, mode); - } else { - ALOGE("Attempting to set unknown power mode: %d\n", mode); - getHwComposer().setPowerMode(type, mode); - } -} - -void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) { - class MessageSetPowerMode: public MessageBase { - SurfaceFlinger& mFlinger; - sp<IBinder> mDisplay; - int mMode; - public: - MessageSetPowerMode(SurfaceFlinger& flinger, - const sp<IBinder>& disp, int mode) : mFlinger(flinger), - mDisplay(disp) { mMode = mode; } - virtual bool handler() { - sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay)); - if (hw == NULL) { - ALOGE("Attempt to set power mode = %d for null display %p", - mMode, mDisplay.get()); - } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) { - ALOGW("Attempt to set power mode = %d for virtual display", - mMode); - } else { - mFlinger.setPowerModeInternal(hw, mMode); - } - return true; - } - }; - sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode); - postMessageSync(msg); -} - -// --------------------------------------------------------------------------- - -status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) -{ - String8 result; - - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_SHELL) && - !PermissionCache::checkPermission(sDump, pid, uid)) { - result.appendFormat("Permission Denial: " - "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); - } else { - // Try to get the main lock, but give up after one second - // (this would indicate SF is stuck, but we want to be able to - // print something in dumpsys). - status_t err = mStateLock.timedLock(s2ns(1)); - bool locked = (err == NO_ERROR); - if (!locked) { - result.appendFormat( - "SurfaceFlinger appears to be unresponsive (%s [%d]), " - "dumping anyways (no locks held)\n", strerror(-err), err); - } - - bool dumpAll = true; - size_t index = 0; - size_t numArgs = args.size(); - if (numArgs) { - if ((index < numArgs) && - (args[index] == String16("--list"))) { - index++; - listLayersLocked(args, index, result); - dumpAll = false; - } - - if ((index < numArgs) && - (args[index] == String16("--latency"))) { - index++; - dumpStatsLocked(args, index, result); - dumpAll = false; - } - - if ((index < numArgs) && - (args[index] == String16("--latency-clear"))) { - index++; - clearStatsLocked(args, index, result); - dumpAll = false; - } - - if ((index < numArgs) && - (args[index] == String16("--dispsync"))) { - index++; - mPrimaryDispSync.dump(result); - dumpAll = false; - } - - if ((index < numArgs) && - (args[index] == String16("--static-screen"))) { - index++; - dumpStaticScreenStats(result); - dumpAll = false; - } - - if ((index < numArgs) && - (args[index] == String16("--frame-events"))) { - index++; - dumpFrameEventsLocked(result); - dumpAll = false; - } - } - - if (dumpAll) { - dumpAllLocked(args, index, result); - } - - if (locked) { - mStateLock.unlock(); - } - } - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */, - size_t& /* index */, String8& result) const -{ - mCurrentState.traverseInZOrder([&](Layer* layer) { - result.appendFormat("%s\n", layer->getName().string()); - }); -} - -void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index, - String8& result) const -{ - String8 name; - if (index < args.size()) { - name = String8(args[index]); - index++; - } - - const nsecs_t period = - getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); - result.appendFormat("%" PRId64 "\n", period); - - if (name.isEmpty()) { - mAnimFrameTracker.dumpStats(result); - } else { - mCurrentState.traverseInZOrder([&](Layer* layer) { - if (name == layer->getName()) { - layer->dumpFrameStats(result); - } - }); - } -} - -void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index, - String8& /* result */) -{ - String8 name; - if (index < args.size()) { - name = String8(args[index]); - index++; - } - - mCurrentState.traverseInZOrder([&](Layer* layer) { - if (name.isEmpty() || (name == layer->getName())) { - layer->clearFrameStats(); - } - }); - - mAnimFrameTracker.clearStats(); -} - -// This should only be called from the main thread. Otherwise it would need -// the lock and should use mCurrentState rather than mDrawingState. -void SurfaceFlinger::logFrameStats() { - mDrawingState.traverseInZOrder([&](Layer* layer) { - layer->logFrameStats(); - }); - - mAnimFrameTracker.logAndResetStats(String8("<win-anim>")); -} - -void SurfaceFlinger::appendSfConfigString(String8& result) const -{ - result.append(" [sf"); - result.appendFormat(" HAS_CONTEXT_PRIORITY=%d", useContextPriority); - - if (isLayerTripleBufferingDisabled()) - result.append(" DISABLE_TRIPLE_BUFFERING"); - - result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset); - result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv); - result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize); - result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework); - result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64, - maxFrameBufferAcquiredBuffers); - result.append("]"); -} - -void SurfaceFlinger::dumpStaticScreenStats(String8& result) const -{ - result.appendFormat("Static screen stats:\n"); - for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) { - float bucketTimeSec = mFrameBuckets[b] / 1e9; - float percent = 100.0f * - static_cast<float>(mFrameBuckets[b]) / mTotalTime; - result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n", - b + 1, bucketTimeSec, percent); - } - float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9; - float percent = 100.0f * - static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime; - result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n", - NUM_BUCKETS - 1, bucketTimeSec, percent); -} - -void SurfaceFlinger::dumpFrameEventsLocked(String8& result) { - result.appendFormat("Layer frame timestamps:\n"); - - const LayerVector& currentLayers = mCurrentState.layersSortedByZ; - const size_t count = currentLayers.size(); - for (size_t i=0 ; i<count ; i++) { - currentLayers[i]->dumpFrameEvents(result); - } -} - -void SurfaceFlinger::recordBufferingStats(const char* layerName, - std::vector<OccupancyTracker::Segment>&& history) { - Mutex::Autolock lock(mBufferingStatsMutex); - auto& stats = mBufferingStats[layerName]; - for (const auto& segment : history) { - if (!segment.usedThirdBuffer) { - stats.twoBufferTime += segment.totalTime; - } - if (segment.occupancyAverage < 1.0f) { - stats.doubleBufferedTime += segment.totalTime; - } else if (segment.occupancyAverage < 2.0f) { - stats.tripleBufferedTime += segment.totalTime; - } - ++stats.numSegments; - stats.totalTime += segment.totalTime; - } -} - -void SurfaceFlinger::dumpBufferingStats(String8& result) const { - result.append("Buffering stats:\n"); - result.append(" [Layer name] <Active time> <Two buffer> " - "<Double buffered> <Triple buffered>\n"); - Mutex::Autolock lock(mBufferingStatsMutex); - typedef std::tuple<std::string, float, float, float> BufferTuple; - std::map<float, BufferTuple, std::greater<float>> sorted; - for (const auto& statsPair : mBufferingStats) { - const char* name = statsPair.first.c_str(); - const BufferingStats& stats = statsPair.second; - if (stats.numSegments == 0) { - continue; - } - float activeTime = ns2ms(stats.totalTime) / 1000.0f; - float twoBufferRatio = static_cast<float>(stats.twoBufferTime) / - stats.totalTime; - float doubleBufferRatio = static_cast<float>( - stats.doubleBufferedTime) / stats.totalTime; - float tripleBufferRatio = static_cast<float>( - stats.tripleBufferedTime) / stats.totalTime; - sorted.insert({activeTime, {name, twoBufferRatio, - doubleBufferRatio, tripleBufferRatio}}); - } - for (const auto& sortedPair : sorted) { - float activeTime = sortedPair.first; - const BufferTuple& values = sortedPair.second; - result.appendFormat(" [%s] %.2f %.3f %.3f %.3f\n", - std::get<0>(values).c_str(), activeTime, - std::get<1>(values), std::get<2>(values), - std::get<3>(values)); - } - result.append("\n"); -} - -void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, - String8& result) const -{ - bool colorize = false; - if (index < args.size() - && (args[index] == String16("--color"))) { - colorize = true; - index++; - } - - Colorizer colorizer(colorize); - - // figure out if we're stuck somewhere - const nsecs_t now = systemTime(); - const nsecs_t inSwapBuffers(mDebugInSwapBuffers); - const nsecs_t inTransaction(mDebugInTransaction); - nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0; - nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0; - - /* - * Dump library configuration. - */ - - colorizer.bold(result); - result.append("Build configuration:"); - colorizer.reset(result); - appendSfConfigString(result); - appendUiConfigString(result); - appendGuiConfigString(result); - result.append("\n"); - - colorizer.bold(result); - result.append("Sync configuration: "); - colorizer.reset(result); - result.append(SyncFeatures::getInstance().toString()); - result.append("\n"); - - colorizer.bold(result); - result.append("DispSync configuration: "); - colorizer.reset(result); - result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, " - "present offset %" PRId64 " ns (refresh %" PRId64 " ns)", - vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, dispSyncPresentTimeOffset, - mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY)); - result.append("\n"); - - // Dump static screen stats - result.append("\n"); - dumpStaticScreenStats(result); - result.append("\n"); - - dumpBufferingStats(result); - - /* - * Dump the visible layer list - */ - colorizer.bold(result); - result.appendFormat("Visible layers (count = %zu)\n", mNumLayers); - colorizer.reset(result); - mCurrentState.traverseInZOrder([&](Layer* layer) { - result.append(to_string(layer->getLayerDebugInfo()).c_str()); - }); - - /* - * Dump Display state - */ - - colorizer.bold(result); - result.appendFormat("Displays (%zu entries)\n", mDisplays.size()); - colorizer.reset(result); - for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { - const sp<const DisplayDevice>& hw(mDisplays[dpy]); - hw->dump(result); - } - - /* - * Dump SurfaceFlinger global state - */ - - colorizer.bold(result); - result.append("SurfaceFlinger global state:\n"); - colorizer.reset(result); - - HWComposer& hwc(getHwComposer()); - sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked()); - - colorizer.bold(result); - result.appendFormat("EGL implementation : %s\n", - eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION)); - colorizer.reset(result); - result.appendFormat("%s\n", - eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS)); - - mRenderEngine->dump(result); - - hw->undefinedRegion.dump(result, "undefinedRegion"); - result.appendFormat(" orientation=%d, isDisplayOn=%d\n", - hw->getOrientation(), hw->isDisplayOn()); - result.appendFormat( - " last eglSwapBuffers() time: %f us\n" - " last transaction time : %f us\n" - " transaction-flags : %08x\n" - " refresh-rate : %f fps\n" - " x-dpi : %f\n" - " y-dpi : %f\n" - " gpu_to_cpu_unsupported : %d\n" - , - mLastSwapBufferTime/1000.0, - mLastTransactionTime/1000.0, - mTransactionFlags, - 1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY), - hwc.getDpiX(HWC_DISPLAY_PRIMARY), - hwc.getDpiY(HWC_DISPLAY_PRIMARY), - !mGpuToCpuSupported); - - result.appendFormat(" eglSwapBuffers time: %f us\n", - inSwapBuffersDuration/1000.0); - - result.appendFormat(" transaction time: %f us\n", - inTransactionDuration/1000.0); - - /* - * VSYNC state - */ - mEventThread->dump(result); - - /* - * Dump HWComposer state - */ - colorizer.bold(result); - result.append("h/w composer state:\n"); - colorizer.reset(result); - result.appendFormat(" h/w composer %s and %s\n", - hwc.initCheck()==NO_ERROR ? "present" : "not present", - (mDebugDisableHWC || mDebugRegion || mDaltonize - || mHasColorMatrix) ? "disabled" : "enabled"); - hwc.dump(result); - - /* - * Dump gralloc state - */ - const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); - alloc.dump(result); -} - -const Vector< sp<Layer> >& -SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) { - // Note: mStateLock is held here - wp<IBinder> dpy; - for (size_t i=0 ; i<mDisplays.size() ; i++) { - if (mDisplays.valueAt(i)->getHwcDisplayId() == id) { - dpy = mDisplays.keyAt(i); - break; - } - } - if (dpy == NULL) { - ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id); - // Just use the primary display so we have something to return - dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY); - } - return getDisplayDeviceLocked(dpy)->getVisibleLayersSortedByZ(); -} - -bool SurfaceFlinger::startDdmConnection() -{ - void* libddmconnection_dso = - dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW); - if (!libddmconnection_dso) { - return false; - } - void (*DdmConnection_start)(const char* name); - DdmConnection_start = - (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start"); - if (!DdmConnection_start) { - dlclose(libddmconnection_dso); - return false; - } - (*DdmConnection_start)(getServiceName()); - return true; -} - -status_t SurfaceFlinger::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch (code) { - case CREATE_CONNECTION: - case CREATE_DISPLAY: - case BOOT_FINISHED: - case CLEAR_ANIMATION_FRAME_STATS: - case GET_ANIMATION_FRAME_STATS: - case SET_POWER_MODE: - case GET_HDR_CAPABILITIES: - { - // codes that require permission check - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && - !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { - ALOGE("Permission Denial: " - "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - break; - } - /* - * Calling setTransactionState is safe, because you need to have been - * granted a reference to Client* and Handle* to do anything with it. - * - * Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h - */ - case SET_TRANSACTION_STATE: - case CREATE_SCOPED_CONNECTION: - { - break; - } - case CAPTURE_SCREEN: - { - // codes that require permission check - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && - !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { - ALOGE("Permission Denial: " - "can't read framebuffer pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - break; - } - } - - status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); - if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) { - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - ALOGE("Permission Denial: " - "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - int n; - switch (code) { - case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE - case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE - return NO_ERROR; - case 1002: // SHOW_UPDATES - n = data.readInt32(); - mDebugRegion = n ? n : (mDebugRegion ? 0 : 1); - invalidateHwcGeometry(); - repaintEverything(); - return NO_ERROR; - case 1004:{ // repaint everything - repaintEverything(); - return NO_ERROR; - } - case 1005:{ // force transaction - setTransactionFlags( - eTransactionNeeded| - eDisplayTransactionNeeded| - eTraversalNeeded); - return NO_ERROR; - } - case 1006:{ // send empty update - signalRefresh(); - return NO_ERROR; - } - case 1008: // toggle use of hw composer - n = data.readInt32(); - mDebugDisableHWC = n ? 1 : 0; - invalidateHwcGeometry(); - repaintEverything(); - return NO_ERROR; - case 1009: // toggle use of transform hint - n = data.readInt32(); - mDebugDisableTransformHint = n ? 1 : 0; - invalidateHwcGeometry(); - repaintEverything(); - return NO_ERROR; - case 1010: // interrogate. - reply->writeInt32(0); - reply->writeInt32(0); - reply->writeInt32(mDebugRegion); - reply->writeInt32(0); - reply->writeInt32(mDebugDisableHWC); - return NO_ERROR; - case 1013: { - Mutex::Autolock _l(mStateLock); - sp<const DisplayDevice> hw(getDefaultDisplayDevice()); - reply->writeInt32(hw->getPageFlipCount()); - return NO_ERROR; - } - case 1014: { - // daltonize - n = data.readInt32(); - switch (n % 10) { - case 1: - mDaltonizer.setType(ColorBlindnessType::Protanomaly); - break; - case 2: - mDaltonizer.setType(ColorBlindnessType::Deuteranomaly); - break; - case 3: - mDaltonizer.setType(ColorBlindnessType::Tritanomaly); - break; - } - if (n >= 10) { - mDaltonizer.setMode(ColorBlindnessMode::Correction); - } else { - mDaltonizer.setMode(ColorBlindnessMode::Simulation); - } - mDaltonize = n > 0; - invalidateHwcGeometry(); - repaintEverything(); - return NO_ERROR; - } - case 1015: { - // apply a color matrix - n = data.readInt32(); - mHasColorMatrix = n ? 1 : 0; - if (n) { - // color matrix is sent as mat3 matrix followed by vec3 - // offset, then packed into a mat4 where the last row is - // the offset and extra values are 0 - for (size_t i = 0 ; i < 4; i++) { - for (size_t j = 0; j < 4; j++) { - mColorMatrix[i][j] = data.readFloat(); - } - } - } else { - mColorMatrix = mat4(); - } - invalidateHwcGeometry(); - repaintEverything(); - return NO_ERROR; - } - // This is an experimental interface - // Needs to be shifted to proper binder interface when we productize - case 1016: { - n = data.readInt32(); - mPrimaryDispSync.setRefreshSkipCount(n); - return NO_ERROR; - } - case 1017: { - n = data.readInt32(); - mForceFullDamage = static_cast<bool>(n); - return NO_ERROR; - } - case 1018: { // Modify Choreographer's phase offset - n = data.readInt32(); - mEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); - return NO_ERROR; - } - case 1019: { // Modify SurfaceFlinger's phase offset - n = data.readInt32(); - mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); - return NO_ERROR; - } - case 1020: { // Layer updates interceptor - n = data.readInt32(); - if (n) { - ALOGV("Interceptor enabled"); - mInterceptor.enable(mDrawingState.layersSortedByZ, mDrawingState.displays); - } - else{ - ALOGV("Interceptor disabled"); - mInterceptor.disable(); - } - return NO_ERROR; - } - case 1021: { // Disable HWC virtual displays - n = data.readInt32(); - mUseHwcVirtualDisplays = !n; - return NO_ERROR; - } - } - } - return err; -} - -void SurfaceFlinger::repaintEverything() { - android_atomic_or(1, &mRepaintEverything); - signalTransaction(); -} - -// --------------------------------------------------------------------------- -// Capture screen into an IGraphiBufferProducer -// --------------------------------------------------------------------------- - -/* The code below is here to handle b/8734824 - * - * We create a IGraphicBufferProducer wrapper that forwards all calls - * from the surfaceflinger thread to the calling binder thread, where they - * are executed. This allows the calling thread in the calling process to be - * reused and not depend on having "enough" binder threads to handle the - * requests. - */ -class GraphicProducerWrapper : public BBinder, public MessageHandler { - /* Parts of GraphicProducerWrapper are run on two different threads, - * communicating by sending messages via Looper but also by shared member - * data. Coherence maintenance is subtle and in places implicit (ugh). - * - * Don't rely on Looper's sendMessage/handleMessage providing - * release/acquire semantics for any data not actually in the Message. - * Data going from surfaceflinger to binder threads needs to be - * synchronized explicitly. - * - * Barrier open/wait do provide release/acquire semantics. This provides - * implicit synchronization for data coming back from binder to - * surfaceflinger threads. - */ - - sp<IGraphicBufferProducer> impl; - sp<Looper> looper; - status_t result; - bool exitPending; - bool exitRequested; - Barrier barrier; - uint32_t code; - Parcel const* data; - Parcel* reply; - - enum { - MSG_API_CALL, - MSG_EXIT - }; - - /* - * Called on surfaceflinger thread. This is called by our "fake" - * BpGraphicBufferProducer. We package the data and reply Parcel and - * forward them to the binder thread. - */ - virtual status_t transact(uint32_t code, - const Parcel& data, Parcel* reply, uint32_t /* flags */) { - this->code = code; - this->data = &data; - this->reply = reply; - if (exitPending) { - // if we've exited, we run the message synchronously right here. - // note (JH): as far as I can tell from looking at the code, this - // never actually happens. if it does, i'm not sure if it happens - // on the surfaceflinger or binder thread. - handleMessage(Message(MSG_API_CALL)); - } else { - barrier.close(); - // Prevent stores to this->{code, data, reply} from being - // reordered later than the construction of Message. - atomic_thread_fence(memory_order_release); - looper->sendMessage(this, Message(MSG_API_CALL)); - barrier.wait(); - } - return result; - } - - /* - * here we run on the binder thread. All we've got to do is - * call the real BpGraphicBufferProducer. - */ - virtual void handleMessage(const Message& message) { - int what = message.what; - // Prevent reads below from happening before the read from Message - atomic_thread_fence(memory_order_acquire); - if (what == MSG_API_CALL) { - result = IInterface::asBinder(impl)->transact(code, data[0], reply); - barrier.open(); - } else if (what == MSG_EXIT) { - exitRequested = true; - } - } - -public: - explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl) - : impl(impl), - looper(new Looper(true)), - result(NO_ERROR), - exitPending(false), - exitRequested(false), - code(0), - data(NULL), - reply(NULL) - {} - - // Binder thread - status_t waitForResponse() { - do { - looper->pollOnce(-1); - } while (!exitRequested); - return result; - } - - // Client thread - void exit(status_t result) { - this->result = result; - exitPending = true; - // Ensure this->result is visible to the binder thread before it - // handles the message. - atomic_thread_fence(memory_order_release); - looper->sendMessage(this, Message(MSG_EXIT)); - } -}; - - -status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { - - if (CC_UNLIKELY(display == 0)) - return BAD_VALUE; - - if (CC_UNLIKELY(producer == 0)) - return BAD_VALUE; - - // 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). - bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder(); - - // Convert to surfaceflinger's internal rotation type. - Transform::orientation_flags rotationFlags; - switch (rotation) { - case ISurfaceComposer::eRotateNone: - rotationFlags = Transform::ROT_0; - break; - case ISurfaceComposer::eRotate90: - rotationFlags = Transform::ROT_90; - break; - case ISurfaceComposer::eRotate180: - rotationFlags = Transform::ROT_180; - break; - case ISurfaceComposer::eRotate270: - rotationFlags = Transform::ROT_270; - break; - default: - rotationFlags = Transform::ROT_0; - ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation); - break; - } - - class MessageCaptureScreen : public MessageBase { - SurfaceFlinger* flinger; - sp<IBinder> display; - sp<IGraphicBufferProducer> producer; - Rect sourceCrop; - uint32_t reqWidth, reqHeight; - int32_t minLayerZ,maxLayerZ; - 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, - int32_t minLayerZ, int32_t maxLayerZ, - 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), - isLocalScreenshot(isLocalScreenshot) - { - } - status_t getResult() const { - return result; - } - virtual bool handler() { - Mutex::Autolock _l(flinger->mStateLock); - sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display)); - result = flinger->captureScreenImplLocked(hw, producer, - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, rotation, isLocalScreenshot); - static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result); - return true; - } - }; - - // this creates a "fake" BBinder which will serve as a "fake" remote - // binder to receive the marshaled calls and forward them to the - // real remote (a BpGraphicBufferProducer) - sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer); - - // the asInterface() call below creates our "fake" BpGraphicBufferProducer - // which does the marshaling work forwards to our "fake remote" above. - sp<MessageBase> msg = new MessageCaptureScreen(this, - display, IGraphicBufferProducer::asInterface( wrapper ), - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, rotationFlags, isLocalScreenshot); - - status_t res = postMessageAsync(msg); - if (res == NO_ERROR) { - res = wrapper->waitForResponse(); - } - return res; -} - - -void SurfaceFlinger::renderScreenImplLocked( - const sp<const DisplayDevice>& hw, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation) -{ - ATRACE_CALL(); - RenderEngine& engine(getRenderEngine()); - - // get screen geometry - const int32_t hw_w = hw->getWidth(); - const int32_t hw_h = hw->getHeight(); - const bool filtering = static_cast<int32_t>(reqWidth) != hw_w || - static_cast<int32_t>(reqHeight) != hw_h; - - // if a default or invalid sourceCrop is passed in, set reasonable values - if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || - !sourceCrop.isValid()) { - sourceCrop.setLeftTop(Point(0, 0)); - sourceCrop.setRightBottom(Point(hw_w, hw_h)); - } - - // ensure that sourceCrop is inside screen - if (sourceCrop.left < 0) { - ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left); - } - if (sourceCrop.right > hw_w) { - ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w); - } - if (sourceCrop.top < 0) { - ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top); - } - if (sourceCrop.bottom > hw_h) { - ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h); - } - - // make sure to clear all GL error flags - engine.checkErrors(); - - // set-up our viewport - engine.setViewportAndProjection( - reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation); - engine.disableTexturing(); - - // redraw the screen entirely... - engine.clearWithColor(0, 0, 0, 1); - - // We loop through the first level of layers without traversing, - // as we need to interpret min/max layer Z in the top level Z space. - for (const auto& layer : mDrawingState.layersSortedByZ) { - if (layer->getLayerStack() != hw->getLayerStack()) { - continue; - } - const Layer::State& state(layer->getDrawingState()); - if (state.z < minLayerZ || state.z > maxLayerZ) { - continue; - } - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (!layer->isVisible()) { - return; - } - if (filtering) layer->setFiltering(true); - layer->draw(hw, useIdentityTransform); - if (filtering) layer->setFiltering(false); - }); - } - - // compositionComplete is needed for older driver - hw->compositionComplete(); - hw->setViewportAndProjection(); -} - - -status_t SurfaceFlinger::captureScreenImplLocked( - const sp<const DisplayDevice>& hw, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, Transform::orientation_flags rotation, - bool isLocalScreenshot) -{ - ATRACE_CALL(); - - // get screen geometry - uint32_t hw_w = hw->getWidth(); - uint32_t hw_h = hw->getHeight(); - - if (rotation & Transform::ROT_90) { - std::swap(hw_w, hw_h); - } - - if ((reqWidth > hw_w) || (reqHeight > hw_h)) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", - reqWidth, reqHeight, hw_w, hw_h); - return BAD_VALUE; - } - - reqWidth = (!reqWidth) ? hw_w : reqWidth; - reqHeight = (!reqHeight) ? hw_h : reqHeight; - - bool secureLayerIsVisible = false; - for (const auto& layer : mDrawingState.layersSortedByZ) { - const Layer::State& state(layer->getDrawingState()); - if ((layer->getLayerStack() != hw->getLayerStack()) || - (state.z < minLayerZ || state.z > maxLayerZ)) { - continue; - } - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) { - secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && - layer->isSecure()); - }); - } - - 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); - ANativeWindow* window = sur.get(); - - status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); - if (result == NO_ERROR) { - uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - - int err = 0; - err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); - err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); - err |= native_window_set_usage(window, usage); - - if (err == NO_ERROR) { - ANativeWindowBuffer* buffer; - /* TODO: Once we have the sync framework everywhere this can use - * server-side waits on the fence that dequeueBuffer returns. - */ - result = native_window_dequeue_buffer_and_wait(window, &buffer); - if (result == NO_ERROR) { - int syncFd = -1; - // create an EGLImage from the buffer so we can later - // turn it into a texture - EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, - EGL_NATIVE_BUFFER_ANDROID, buffer, NULL); - if (image != EGL_NO_IMAGE_KHR) { - // this binds the given EGLImage as a framebuffer for the - // duration of this scope. - RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image); - if (imageBond.getStatus() == NO_ERROR) { - // this will in fact render into our dequeued buffer - // via an FBO, which means we didn't have to create - // an EGLSurface and therefore we're not - // dependent on the context's EGLConfig. - renderScreenImplLocked( - hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true, - useIdentityTransform, rotation); - - // Attempt to create a sync khr object that can produce a sync point. If that - // isn't available, create a non-dupable sync object in the fallback path and - // wait on it directly. - EGLSyncKHR sync; - if (!DEBUG_SCREENSHOTS) { - sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); - // native fence fd will not be populated until flush() is done. - getRenderEngine().flush(); - } else { - sync = EGL_NO_SYNC_KHR; - } - if (sync != EGL_NO_SYNC_KHR) { - // get the sync fd - syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync); - if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - ALOGW("captureScreen: failed to dup sync khr object"); - syncFd = -1; - } - eglDestroySyncKHR(mEGLDisplay, sync); - } else { - // fallback path - sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL); - if (sync != EGL_NO_SYNC_KHR) { - EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, - EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/); - EGLint eglErr = eglGetError(); - if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ALOGW("captureScreen: fence wait timed out"); - } else { - ALOGW_IF(eglErr != EGL_SUCCESS, - "captureScreen: error waiting on EGL fence: %#x", eglErr); - } - eglDestroySyncKHR(mEGLDisplay, sync); - } else { - ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); - } - } - if (DEBUG_SCREENSHOTS) { - uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; - getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); - checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, - hw, minLayerZ, maxLayerZ); - delete [] pixels; - } - - } else { - ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot"); - result = INVALID_OPERATION; - window->cancelBuffer(window, buffer, syncFd); - buffer = NULL; - } - // destroy our image - eglDestroyImageKHR(mEGLDisplay, image); - } else { - result = BAD_VALUE; - } - if (buffer) { - // queueBuffer takes ownership of syncFd - result = window->queueBuffer(window, buffer, syncFd); - } - } - } else { - result = BAD_VALUE; - } - native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); - } - - return result; -} - -void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, - const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) { - if (DEBUG_SCREENSHOTS) { - for (size_t y=0 ; y<h ; y++) { - uint32_t const * p = (uint32_t const *)vaddr + y*s; - for (size_t x=0 ; x<w ; x++) { - if (p[x] != 0xFF000000) return; - } - } - ALOGE("*** we just took a black screenshot ***\n" - "requested minz=%d, maxz=%d, layerStack=%d", - minLayerZ, maxLayerZ, hw->getLayerStack()); - size_t i = 0; - for (const auto& layer : mDrawingState.layersSortedByZ) { - const Layer::State& state(layer->getDrawingState()); - if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ && - state.z <= maxLayerZ) { - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x", - layer->isVisible() ? '+' : '-', - i, layer->getName().string(), layer->getLayerStack(), state.z, - layer->isVisible(), state.flags, state.alpha); - i++; - }); - } - } - } -} - -// --------------------------------------------------------------------------- - -void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const { - layersSortedByZ.traverseInZOrder(stateSet, visitor); -} - -void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& visitor) const { - layersSortedByZ.traverseInReverseZOrder(stateSet, visitor); -} - -}; // namespace android - - -#if defined(__gl_h_) -#error "don't include gl/gl.h in this file" -#endif - -#if defined(__gl2_h_) -#error "don't include gl2/gl2.h in this file" -#endif diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index db489b2456..eeb492978c 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -98,7 +98,7 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, addPositionLocked(transaction, layerId, layer->mCurrentState.active.transform.tx(), layer->mCurrentState.active.transform.ty()); addDepthLocked(transaction, layerId, layer->mCurrentState.z); - addAlphaLocked(transaction, layerId, layer->mCurrentState.alpha); + addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a); addTransparentRegionLocked(transaction, layerId, layer->mCurrentState.activeTransparentRegion); addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack); addCropLocked(transaction, layerId, layer->mCurrentState.crop); diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp new file mode 100644 index 0000000000..f8c466ea19 --- /dev/null +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -0,0 +1,85 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#undef LOG_TAG +#define LOG_TAG "SurfaceTracing" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "SurfaceTracing.h" + +#include <android-base/file.h> +#include <log/log.h> +#include <utils/SystemClock.h> +#include <utils/Trace.h> + +namespace android { + +void SurfaceTracing::enable() { + if (mEnabled) { + return; + } + ATRACE_CALL(); + mEnabled = true; + std::lock_guard<std::mutex> protoGuard(mTraceMutex); + + mTrace.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | + LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); +} + +status_t SurfaceTracing::disable() { + if (!mEnabled) { + return NO_ERROR; + } + ATRACE_CALL(); + std::lock_guard<std::mutex> protoGuard(mTraceMutex); + mEnabled = false; + status_t err(writeProtoFileLocked()); + ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied"); + ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields"); + mTrace.Clear(); + return err; +} + +bool SurfaceTracing::isEnabled() { + return mEnabled; +} + +void SurfaceTracing::traceLayers(const char* where, LayersProto layers) { + std::lock_guard<std::mutex> protoGuard(mTraceMutex); + + LayersTraceProto* entry = mTrace.add_entry(); + entry->set_elapsed_realtime_nanos(elapsedRealtimeNano()); + entry->set_where(where); + entry->mutable_layers()->Swap(&layers); +} + +status_t SurfaceTracing::writeProtoFileLocked() { + ATRACE_CALL(); + + if (!mTrace.IsInitialized()) { + return NOT_ENOUGH_DATA; + } + std::string output; + if (!mTrace.SerializeToString(&output)) { + return PERMISSION_DENIED; + } + if (!android::base::WriteStringToFile(output, mOutputFileName, true)) { + return PERMISSION_DENIED; + } + + return NO_ERROR; +} + +} // namespace android diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h new file mode 100644 index 0000000000..590ab9680f --- /dev/null +++ b/services/surfaceflinger/SurfaceTracing.h @@ -0,0 +1,50 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <layerproto/LayerProtoHeader.h> +#include <utils/Errors.h> + +#include <mutex> + +using namespace android::surfaceflinger; + +namespace android { + +/* + * SurfaceTracing records layer states during surface flinging. + */ +class SurfaceTracing { +public: + void enable(); + status_t disable(); + bool isEnabled(); + + void traceLayers(const char* where, LayersProto); + +private: + static constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/layers_trace.pb"; + + status_t writeProtoFileLocked(); + + bool mEnabled = false; + std::string mOutputFileName = DEFAULT_FILENAME; + std::mutex mTraceMutex; + LayersTraceFileProto mTrace; +}; + +} // namespace android diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp index 6be9ae2c5f..e05ed5375e 100644 --- a/services/surfaceflinger/Transform.cpp +++ b/services/surfaceflinger/Transform.cpp @@ -20,8 +20,8 @@ #include <utils/String8.h> #include <ui/Region.h> -#include "clz.h" #include "Transform.h" +#include "clz.h" // --------------------------------------------------------------------------- @@ -224,6 +224,27 @@ Rect Transform::transform(const Rect& bounds, bool roundOutwards) const return r; } +FloatRect Transform::transform(const FloatRect& bounds) const +{ + vec2 lt(bounds.left, bounds.top); + vec2 rt(bounds.right, bounds.top); + vec2 lb(bounds.left, bounds.bottom); + vec2 rb(bounds.right, bounds.bottom); + + lt = transform(lt); + rt = transform(rt); + lb = transform(lb); + rb = transform(rb); + + FloatRect r; + r.left = min(lt[0], rt[0], lb[0], rb[0]); + r.top = min(lt[1], rt[1], lb[1], rb[1]); + r.right = max(lt[0], rt[0], lb[0], rb[0]); + r.bottom = max(lt[1], rt[1], lb[1], rb[1]); + + return r; +} + Region Transform::transform(const Region& reg) const { Region out; @@ -388,6 +409,23 @@ void Transform::dump(const char* name) const ALOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]); } +Transform::orientation_flags Transform::fromRotation(ISurfaceComposer::Rotation rotation) { + // Convert to surfaceflinger's internal rotation type. + switch (rotation) { + case ISurfaceComposer::eRotateNone: + return Transform::ROT_0; + case ISurfaceComposer::eRotate90: + return Transform::ROT_90; + case ISurfaceComposer::eRotate180: + return Transform::ROT_180; + case ISurfaceComposer::eRotate270: + return Transform::ROT_270; + default: + ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation); + return Transform::ROT_0; + } +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h index 6640a13839..b11d0576c4 100644 --- a/services/surfaceflinger/Transform.h +++ b/services/surfaceflinger/Transform.h @@ -25,6 +25,8 @@ #include <math/vec2.h> #include <math/vec3.h> +#include <gui/ISurfaceComposer.h> + #include <hardware/hardware.h> namespace android { @@ -51,6 +53,8 @@ public: ROT_INVALID = 0x80 }; + static orientation_flags fromRotation(ISurfaceComposer::Rotation rotation); + enum type_mask { IDENTITY = 0, TRANSLATE = 0x1, @@ -80,6 +84,7 @@ public: Region transform(const Region& reg) const; Rect transform(const Rect& bounds, bool roundOutwards = false) const; + FloatRect transform(const FloatRect& bounds) const; Transform operator * (const Transform& rhs) const; // assumes the last row is < 0 , 0 , 1 > vec2 transform(const vec2& v) const; diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp new file mode 100644 index 0000000000..8eb218c96e --- /dev/null +++ b/services/surfaceflinger/layerproto/Android.bp @@ -0,0 +1,36 @@ +cc_library_shared { + name: "liblayers_proto", + vendor_available: true, + export_include_dirs: ["include"], + + srcs: [ + "LayerProtoParser.cpp", + "layers.proto", + "layerstrace.proto", + ], + + shared_libs: [ + "libui", + "libprotobuf-cpp-lite", + "libbase", + ], + + proto: { + export_proto_headers: true, + }, + + cppflags: [ + "-Werror", + "-Wno-unused-parameter", + "-Wno-format", + "-Wno-c++98-compat-pedantic", + "-Wno-float-conversion", + "-Wno-disabled-macro-expansion", + "-Wno-float-equal", + "-Wno-sign-conversion", + "-Wno-padded", + "-Wno-old-style-cast", + "-Wno-undef", + ], + +}
\ No newline at end of file diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp new file mode 100644 index 0000000000..bf37e1e156 --- /dev/null +++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/stringprintf.h> +#include <layerproto/LayerProtoParser.h> +#include <ui/DebugUtils.h> + +using android::base::StringAppendF; +using android::base::StringPrintf; + +namespace android { +namespace surfaceflinger { + +bool sortLayers(const LayerProtoParser::Layer* lhs, const LayerProtoParser::Layer* rhs) { + uint32_t ls = lhs->layerStack; + uint32_t rs = rhs->layerStack; + if (ls != rs) return ls < rs; + + int32_t lz = lhs->z; + int32_t rz = rhs->z; + if (lz != rz) { + return (lz > rz) ? 1 : -1; + } + + return lhs->id < rhs->id; +} + +std::vector<const LayerProtoParser::Layer*> LayerProtoParser::generateLayerTree( + const LayersProto& layersProto) { + auto layerMap = generateMap(layersProto); + + std::vector<const Layer*> layers; + std::for_each(layerMap.begin(), layerMap.end(), + [&](const std::pair<const int32_t, Layer*>& ref) { + if (ref.second->parent == nullptr) { + // only save top level layers + layers.push_back(ref.second); + } + }); + + std::sort(layers.begin(), layers.end(), sortLayers); + return layers; +} + +std::unordered_map<int32_t, LayerProtoParser::Layer*> LayerProtoParser::generateMap( + const LayersProto& layersProto) { + std::unordered_map<int32_t, Layer*> layerMap; + + for (int i = 0; i < layersProto.layers_size(); i++) { + const LayerProto& layerProto = layersProto.layers(i); + layerMap[layerProto.id()] = generateLayer(layerProto); + } + + for (int i = 0; i < layersProto.layers_size(); i++) { + const LayerProto& layerProto = layersProto.layers(i); + updateChildrenAndRelative(layerProto, layerMap); + } + + return layerMap; +} + +LayerProtoParser::Layer* LayerProtoParser::generateLayer(const LayerProto& layerProto) { + Layer* layer = new Layer(); + layer->id = layerProto.id(); + layer->name = layerProto.name(); + layer->type = layerProto.type(); + layer->transparentRegion = generateRegion(layerProto.transparent_region()); + layer->visibleRegion = generateRegion(layerProto.visible_region()); + layer->damageRegion = generateRegion(layerProto.damage_region()); + layer->layerStack = layerProto.layer_stack(); + layer->z = layerProto.z(); + layer->position = {layerProto.position().x(), layerProto.position().y()}; + layer->requestedPosition = {layerProto.requested_position().x(), + layerProto.requested_position().y()}; + layer->size = {layerProto.size().w(), layerProto.size().h()}; + layer->crop = generateRect(layerProto.crop()); + layer->finalCrop = generateRect(layerProto.final_crop()); + layer->isOpaque = layerProto.is_opaque(); + layer->invalidate = layerProto.invalidate(); + layer->dataspace = layerProto.dataspace(); + layer->pixelFormat = layerProto.pixel_format(); + layer->color = {layerProto.color().r(), layerProto.color().g(), layerProto.color().b(), + layerProto.color().a()}; + layer->requestedColor = {layerProto.requested_color().r(), layerProto.requested_color().g(), + layerProto.requested_color().b(), layerProto.requested_color().a()}; + layer->flags = layerProto.flags(); + layer->transform = generateTransform(layerProto.transform()); + layer->requestedTransform = generateTransform(layerProto.requested_transform()); + layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer()); + layer->queuedFrames = layerProto.queued_frames(); + layer->refreshPending = layerProto.refresh_pending(); + + return layer; +} + +LayerProtoParser::Region LayerProtoParser::generateRegion(const RegionProto& regionProto) { + LayerProtoParser::Region region; + region.id = regionProto.id(); + for (int i = 0; i < regionProto.rect_size(); i++) { + const RectProto& rectProto = regionProto.rect(i); + region.rects.push_back(generateRect(rectProto)); + } + + return region; +} + +LayerProtoParser::Rect LayerProtoParser::generateRect(const RectProto& rectProto) { + LayerProtoParser::Rect rect; + rect.left = rectProto.left(); + rect.top = rectProto.top(); + rect.right = rectProto.right(); + rect.bottom = rectProto.bottom(); + + return rect; +} + +LayerProtoParser::Transform LayerProtoParser::generateTransform( + const TransformProto& transformProto) { + LayerProtoParser::Transform transform; + transform.dsdx = transformProto.dsdx(); + transform.dtdx = transformProto.dtdx(); + transform.dsdy = transformProto.dsdy(); + transform.dtdy = transformProto.dtdy(); + + return transform; +} + +LayerProtoParser::ActiveBuffer LayerProtoParser::generateActiveBuffer( + const ActiveBufferProto& activeBufferProto) { + LayerProtoParser::ActiveBuffer activeBuffer; + activeBuffer.width = activeBufferProto.width(); + activeBuffer.height = activeBufferProto.height(); + activeBuffer.stride = activeBufferProto.stride(); + activeBuffer.format = activeBufferProto.format(); + + return activeBuffer; +} + +void LayerProtoParser::updateChildrenAndRelative(const LayerProto& layerProto, + std::unordered_map<int32_t, Layer*>& layerMap) { + auto currLayer = layerMap[layerProto.id()]; + + for (int i = 0; i < layerProto.children_size(); i++) { + if (layerMap.count(layerProto.children(i)) > 0) { + auto childLayer = layerMap[layerProto.children(i)]; + currLayer->children.push_back(childLayer); + } + } + + for (int i = 0; i < layerProto.relatives_size(); i++) { + if (layerMap.count(layerProto.relatives(i)) > 0) { + auto relativeLayer = layerMap[layerProto.relatives(i)]; + currLayer->relatives.push_back(relativeLayer); + } + } + + if (layerProto.has_parent()) { + if (layerMap.count(layerProto.parent()) > 0) { + auto parentLayer = layerMap[layerProto.parent()]; + currLayer->parent = parentLayer; + } + } + + if (layerProto.has_z_order_relative_of()) { + if (layerMap.count(layerProto.z_order_relative_of()) > 0) { + auto relativeLayer = layerMap[layerProto.z_order_relative_of()]; + currLayer->zOrderRelativeOf = relativeLayer; + } + } +} + +std::string LayerProtoParser::layersToString( + const std::vector<const LayerProtoParser::Layer*> layers) { + std::string result; + for (const LayerProtoParser::Layer* layer : layers) { + if (layer->zOrderRelativeOf != nullptr) { + continue; + } + result.append(layerToString(layer).c_str()); + } + + return result; +} + +std::string LayerProtoParser::layerToString(const LayerProtoParser::Layer* layer) { + std::string result; + + std::vector<const Layer*> traverse(layer->relatives); + for (const LayerProtoParser::Layer* child : layer->children) { + if (child->zOrderRelativeOf != nullptr) { + continue; + } + + traverse.push_back(child); + } + + std::sort(traverse.begin(), traverse.end(), sortLayers); + + size_t i = 0; + for (; i < traverse.size(); i++) { + const auto& relative = traverse[i]; + if (relative->z >= 0) { + break; + } + result.append(layerToString(relative).c_str()); + } + result.append(layer->to_string().c_str()); + result.append("\n"); + for (; i < traverse.size(); i++) { + const auto& relative = traverse[i]; + result.append(layerToString(relative).c_str()); + } + + return result; +} + +std::string LayerProtoParser::ActiveBuffer::to_string() const { + return StringPrintf("[%4ux%4u:%4u,%s]", width, height, stride, + decodePixelFormat(format).c_str()); +} + +std::string LayerProtoParser::Transform::to_string() const { + return StringPrintf("[%.2f, %.2f][%.2f, %.2f]", static_cast<double>(dsdx), + static_cast<double>(dtdx), static_cast<double>(dsdy), + static_cast<double>(dtdy)); +} + +std::string LayerProtoParser::Rect::to_string() const { + return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom); +} + +std::string LayerProtoParser::Region::to_string(const char* what) const { + std::string result = + StringPrintf(" Region %s (this=%lx count=%d)\n", what, static_cast<unsigned long>(id), + static_cast<int>(rects.size())); + + for (auto& rect : rects) { + StringAppendF(&result, " %s\n", rect.to_string().c_str()); + } + + return result; +} + +std::string LayerProtoParser::Layer::to_string() const { + std::string result; + StringAppendF(&result, "+ %s (%s)\n", type.c_str(), name.c_str()); + result.append(transparentRegion.to_string("TransparentRegion").c_str()); + result.append(visibleRegion.to_string("VisibleRegion").c_str()); + result.append(damageRegion.to_string("SurfaceDamageRegion").c_str()); + + StringAppendF(&result, " layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ", layerStack, + z, static_cast<double>(position.x), static_cast<double>(position.y), size.x, + size.y); + + StringAppendF(&result, "crop=%s, finalCrop=%s, ", crop.to_string().c_str(), + finalCrop.to_string().c_str()); + StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate); + StringAppendF(&result, "dataspace=%s, ", dataspace.c_str()); + StringAppendF(&result, "pixelformat=%s, ", pixelFormat.c_str()); + StringAppendF(&result, "color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ", + static_cast<double>(color.r), static_cast<double>(color.g), + static_cast<double>(color.b), static_cast<double>(color.a), flags); + StringAppendF(&result, "tr=%s", transform.to_string().c_str()); + result.append("\n"); + StringAppendF(&result, " parent=%s\n", parent == nullptr ? "none" : parent->name.c_str()); + StringAppendF(&result, " zOrderRelativeOf=%s\n", + zOrderRelativeOf == nullptr ? "none" : zOrderRelativeOf->name.c_str()); + StringAppendF(&result, " activeBuffer=%s,", activeBuffer.to_string().c_str()); + StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d", queuedFrames, refreshPending); + + return result; +} + +} // namespace surfaceflinger +} // namespace android diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoHeader.h index 0eda0af59a..f560562c94 100644 --- a/vulkan/libvulkan/vulkan_loader_data.cpp +++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoHeader.h @@ -1,5 +1,5 @@ /* - * Copyright 2015 The Android Open Source Project + * Copyright (C) 2007 The Android Open Source Projectlayerproto/LayerProtoHeader.h * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,11 @@ * limitations under the License. */ -#include <vulkan/vulkan_loader_data.h> - -using namespace vulkan; - -LoaderData& LoaderData::GetInstance() { - static LoaderData loader_data = {}; - return loader_data; -} +// pragma is used here to disable the warnings emitted from the protobuf +// headers. By adding #pragma before including layer.pb.h, it supresses +// protobuf warnings, but allows the rest of the files to continuing using +// the current flags. +// This file should be included instead of directly including layer.b.h +#pragma GCC system_header +#include <layers.pb.h> +#include <layerstrace.pb.h> diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h new file mode 100644 index 0000000000..78c6cd1345 --- /dev/null +++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <layerproto/LayerProtoHeader.h> + +#include <math/vec4.h> + +#include <unordered_map> +#include <vector> + +namespace android { +namespace surfaceflinger { + +class LayerProtoParser { +public: + class ActiveBuffer { + public: + uint32_t width; + uint32_t height; + uint32_t stride; + int32_t format; + + std::string to_string() const; + }; + + class Transform { + public: + float dsdx; + float dtdx; + float dsdy; + float dtdy; + + std::string to_string() const; + }; + + class Rect { + public: + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; + + std::string to_string() const; + }; + + class Region { + public: + uint64_t id; + std::vector<Rect> rects; + + std::string to_string(const char* what) const; + }; + + class Layer { + public: + int32_t id; + std::string name; + std::vector<const Layer*> children; + std::vector<const Layer*> relatives; + std::string type; + LayerProtoParser::Region transparentRegion; + LayerProtoParser::Region visibleRegion; + LayerProtoParser::Region damageRegion; + uint32_t layerStack; + int32_t z; + float2 position; + float2 requestedPosition; + int2 size; + LayerProtoParser::Rect crop; + LayerProtoParser::Rect finalCrop; + bool isOpaque; + bool invalidate; + std::string dataspace; + std::string pixelFormat; + half4 color; + half4 requestedColor; + uint32_t flags; + Transform transform; + Transform requestedTransform; + Layer* parent = 0; + Layer* zOrderRelativeOf = 0; + LayerProtoParser::ActiveBuffer activeBuffer; + int32_t queuedFrames; + bool refreshPending; + + std::string to_string() const; + }; + + static std::vector<const Layer*> generateLayerTree(const LayersProto& layersProto); + static std::string layersToString(const std::vector<const LayerProtoParser::Layer*> layers); + +private: + static std::unordered_map<int32_t, Layer*> generateMap(const LayersProto& layersProto); + static LayerProtoParser::Layer* generateLayer(const LayerProto& layerProto); + static LayerProtoParser::Region generateRegion(const RegionProto& regionProto); + static LayerProtoParser::Rect generateRect(const RectProto& rectProto); + static LayerProtoParser::Transform generateTransform(const TransformProto& transformProto); + static LayerProtoParser::ActiveBuffer generateActiveBuffer( + const ActiveBufferProto& activeBufferProto); + static void updateChildrenAndRelative(const LayerProto& layerProto, + std::unordered_map<int32_t, Layer*>& layerMap); + + static std::string layerToString(const LayerProtoParser::Layer* layer); +}; + +} // namespace surfaceflinger +} // namespace android diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto new file mode 100644 index 0000000000..d27dc9b2ea --- /dev/null +++ b/services/surfaceflinger/layerproto/layers.proto @@ -0,0 +1,110 @@ +// Definitions for SurfaceFlinger layers. + +syntax = "proto2"; +option optimize_for = LITE_RUNTIME; +package android.surfaceflinger; + +// Contains a list of all layers. +message LayersProto { + repeated LayerProto layers = 1; +} + +// Information about each layer. +message LayerProto { + // unique id per layer. + optional int32 id = 1; + // unique name per layer. + optional string name = 2; + // list of children this layer may have. May be empty. + repeated int32 children = 3; + // list of layers that are z order relative to this layer. + repeated int32 relatives = 4; + // The type of layer, ex Color, Layer + optional string type = 5; + optional RegionProto transparent_region = 6; + optional RegionProto visible_region = 7; + optional RegionProto damage_region = 8; + optional uint32 layer_stack = 9; + // The layer's z order. Can be z order in layer stack, relative to parent, + // or relative to another layer specified in zOrderRelative. + optional int32 z = 10; + // The layer's position on the display. + optional PositionProto position = 11; + // The layer's requested position. + optional PositionProto requested_position = 12; + // The layer's size. + optional SizeProto size = 13; + // The layer's crop in it's own bounds. + optional RectProto crop = 14; + // The layer's crop in it's parent's bounds. + optional RectProto final_crop = 15; + optional bool is_opaque = 16; + optional bool invalidate = 17; + optional string dataspace = 18; + optional string pixel_format = 19; + // The layer's actual color. + optional ColorProto color = 20; + // The layer's requested color. + optional ColorProto requested_color = 21; + // Can be any combination of + // hidden = 0x01 + // opaque = 0x02, + // secure = 0x80, + optional uint32 flags = 22; + // The layer's actual transform + optional TransformProto transform = 23; + // The layer's requested transform. + optional TransformProto requested_transform = 24; + // The parent layer. This value can be null if there is no parent. + optional int32 parent = 25 [default = -1]; + // The layer that this layer has a z order relative to. This value can be null. + optional int32 z_order_relative_of = 26 [default = -1]; + // This value can be null if there's nothing to draw. + optional ActiveBufferProto active_buffer = 27; + // The number of frames available. + optional int32 queued_frames = 28; + optional bool refresh_pending = 29; +} + +message PositionProto { + optional float x = 1; + optional float y = 2; +} + +message SizeProto { + optional int32 w = 1; + optional int32 h = 2; +} + +message TransformProto { + optional float dsdx = 1; + optional float dtdx = 2; + optional float dsdy = 3; + optional float dtdy = 4; +} + +message RegionProto { + optional uint64 id = 1; + repeated RectProto rect = 2; +} + +message RectProto { + optional int32 left = 1; + optional int32 top = 2; + optional int32 right = 3; + optional int32 bottom = 4; +} + +message ActiveBufferProto { + optional uint32 width = 1; + optional uint32 height = 2; + optional uint32 stride = 3; + optional int32 format = 4; +} + +message ColorProto { + optional float r = 1; + optional float g = 2; + optional float b = 3; + optional float a = 4; +}
\ No newline at end of file diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto new file mode 100644 index 0000000000..bee17d2d86 --- /dev/null +++ b/services/surfaceflinger/layerproto/layerstrace.proto @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +option optimize_for = LITE_RUNTIME; + +import "frameworks/native/services/surfaceflinger/layerproto/layers.proto"; + +package android.surfaceflinger; + +/* represents a file full of surface flinger trace entries. + Encoded, it should start with 0x4c 0x59 0x52 0x54 0x52 0x41 0x43 0x45 (.LYRTRACE), such + that they can be easily identified. */ +message LayersTraceFileProto { + + /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L + (this is needed because enums have to be 32 bits and there's no nice way to put 64bit + constants into .proto files. */ + enum MagicNumber { + INVALID = 0; + MAGIC_NUMBER_L = 0x5452594c; /* LYRT (little-endian ASCII) */ + MAGIC_NUMBER_H = 0x45434152; /* RACE (little-endian ASCII) */ + } + + optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */ + repeated LayersTraceProto entry = 2; +} + +/* one window manager trace entry. */ +message LayersTraceProto { + /* required: elapsed realtime in nanos since boot of when this entry was logged */ + optional fixed64 elapsed_realtime_nanos = 1; + + /* where the trace originated */ + optional string where = 2; + + optional LayersProto layers = 3; +} diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index e50f3ce1f9..2a924ae1c7 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -105,7 +105,8 @@ int main(int, char**) { // publish surface flinger sp<IServiceManager> sm(defaultServiceManager()); - sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false); + sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL); // publish GpuService sp<GpuService> gpuservice = new GpuService(); diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter index 6be708ad1c..be4127c915 100644 --- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter +++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter @@ -1,5 +1,5 @@ { "presubmit": { - "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*" + "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*" } -}
\ No newline at end of file +} diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 0cc763c740..ed806b87f5 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -22,10 +22,11 @@ #include <android/native_window.h> #include <gui/ISurfaceComposer.h> +#include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> + #include <private/gui/ComposerService.h> -#include <private/gui/LayerState.h> #include <ui/DisplayInfo.h> #include <fstream> @@ -34,6 +35,8 @@ namespace android { +using Transaction = SurfaceComposerClient::Transaction; + constexpr int32_t SCALING_UPDATE = 1; constexpr uint32_t BUFFER_UPDATES = 18; constexpr uint32_t LAYER_UPDATE = INT_MAX - 2; @@ -149,11 +152,11 @@ protected: ASSERT_TRUE(mBGSurfaceControl->isValid()); mBGLayerId = getSurfaceId("BG Interceptor Test Surface"); - SurfaceComposerClient::openGlobalTransaction(); - mComposerClient->setDisplayLayerStack(display, 0); - ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-3)); - ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(true); + Transaction t; + t.setDisplayLayerStack(display, 0); + ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3) + .show(mBGSurfaceControl) + .apply()); } virtual void TearDown() { @@ -169,13 +172,14 @@ protected: int32_t mTargetId; public: - void captureTest(void (SurfaceInterceptorTest::* action)(void), + void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&), bool (SurfaceInterceptorTest::* verification)(Trace *)); - void captureTest(void (SurfaceInterceptorTest::* action)(void), + void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&), SurfaceChange::SurfaceChangeCase changeCase); - void captureTest(void (SurfaceInterceptorTest::* action)(void), + void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&), Increment::IncrementCase incrementCase); - void runInTransaction(void (SurfaceInterceptorTest::* action)(void), bool intercepted = false); + void runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&), + bool intercepted = false); // Verification of changes to a surface bool positionUpdateFound(const SurfaceChange& change, bool foundPosition); @@ -206,28 +210,29 @@ public: bool bufferUpdatesFound(Trace* trace); // Perform each of the possible changes to a surface - void positionUpdate(); - void sizeUpdate(); - void alphaUpdate(); - void layerUpdate(); - void cropUpdate(); - void finalCropUpdate(); - void matrixUpdate(); - void overrideScalingModeUpdate(); - void transparentRegionHintUpdate(); - void layerStackUpdate(); - void hiddenFlagUpdate(); - void opaqueFlagUpdate(); - void secureFlagUpdate(); - void deferredTransactionUpdate(); - void runAllUpdates(); - void surfaceCreation(); + void positionUpdate(Transaction&); + void sizeUpdate(Transaction&); + void alphaUpdate(Transaction&); + void layerUpdate(Transaction&); + void cropUpdate(Transaction&); + void finalCropUpdate(Transaction&); + void matrixUpdate(Transaction&); + void overrideScalingModeUpdate(Transaction&); + void transparentRegionHintUpdate(Transaction&); + void layerStackUpdate(Transaction&); + void hiddenFlagUpdate(Transaction&); + void opaqueFlagUpdate(Transaction&); + void secureFlagUpdate(Transaction&); + void deferredTransactionUpdate(Transaction&); + void surfaceCreation(Transaction&); + void displayCreation(Transaction&); + void displayDeletion(Transaction&); + void nBufferUpdates(); - void displayCreation(); - void displayDeletion(); + void runAllUpdates(); }; -void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void), +void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&), bool (SurfaceInterceptorTest::* verification)(Trace *)) { runInTransaction(action, true); @@ -236,7 +241,7 @@ void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action) ASSERT_TRUE((this->*verification)(&capturedTrace)); } -void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void), +void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&), Increment::IncrementCase incrementCase) { runInTransaction(action, true); @@ -245,7 +250,7 @@ void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action) ASSERT_TRUE(singleIncrementFound(&capturedTrace, incrementCase)); } -void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void), +void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&), SurfaceChange::SurfaceChangeCase changeCase) { runInTransaction(action, true); @@ -254,83 +259,84 @@ void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action) ASSERT_TRUE(surfaceUpdateFound(&capturedTrace, changeCase)); } -void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(void), +void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&), bool intercepted) { if (intercepted) { enableInterceptor(); } - SurfaceComposerClient::openGlobalTransaction(); - (this->*action)(); - SurfaceComposerClient::closeGlobalTransaction(true); + Transaction t; + (this->*action)(t); + t.apply(true); + if (intercepted) { disableInterceptor(); } } -void SurfaceInterceptorTest::positionUpdate() { - mBGSurfaceControl->setPosition(POSITION_UPDATE, POSITION_UPDATE); +void SurfaceInterceptorTest::positionUpdate(Transaction& t) { + t.setPosition(mBGSurfaceControl, POSITION_UPDATE, POSITION_UPDATE); } -void SurfaceInterceptorTest::sizeUpdate() { - mBGSurfaceControl->setSize(SIZE_UPDATE, SIZE_UPDATE); +void SurfaceInterceptorTest::sizeUpdate(Transaction& t) { + t.setSize(mBGSurfaceControl, SIZE_UPDATE, SIZE_UPDATE); } -void SurfaceInterceptorTest::alphaUpdate() { - mBGSurfaceControl->setAlpha(ALPHA_UPDATE); +void SurfaceInterceptorTest::alphaUpdate(Transaction& t) { + t.setAlpha(mBGSurfaceControl, ALPHA_UPDATE); } -void SurfaceInterceptorTest::layerUpdate() { - mBGSurfaceControl->setLayer(LAYER_UPDATE); +void SurfaceInterceptorTest::layerUpdate(Transaction& t) { + t.setLayer(mBGSurfaceControl, LAYER_UPDATE); } -void SurfaceInterceptorTest::cropUpdate() { - mBGSurfaceControl->setCrop(CROP_UPDATE); +void SurfaceInterceptorTest::cropUpdate(Transaction& t) { + t.setCrop(mBGSurfaceControl, CROP_UPDATE); } -void SurfaceInterceptorTest::finalCropUpdate() { - mBGSurfaceControl->setFinalCrop(CROP_UPDATE); +void SurfaceInterceptorTest::finalCropUpdate(Transaction& t) { + t.setFinalCrop(mBGSurfaceControl, CROP_UPDATE); } -void SurfaceInterceptorTest::matrixUpdate() { - mBGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2); +void SurfaceInterceptorTest::matrixUpdate(Transaction& t) { + t.setMatrix(mBGSurfaceControl, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2); } -void SurfaceInterceptorTest::overrideScalingModeUpdate() { - mBGSurfaceControl->setOverrideScalingMode(SCALING_UPDATE); +void SurfaceInterceptorTest::overrideScalingModeUpdate(Transaction& t) { + t.setOverrideScalingMode(mBGSurfaceControl, SCALING_UPDATE); } -void SurfaceInterceptorTest::transparentRegionHintUpdate() { +void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) { Region region(CROP_UPDATE); - mBGSurfaceControl->setTransparentRegionHint(region); + t.setTransparentRegionHint(mBGSurfaceControl, region); } -void SurfaceInterceptorTest::layerStackUpdate() { - mBGSurfaceControl->setLayerStack(STACK_UPDATE); +void SurfaceInterceptorTest::layerStackUpdate(Transaction& t) { + t.setLayerStack(mBGSurfaceControl, STACK_UPDATE); } -void SurfaceInterceptorTest::hiddenFlagUpdate() { - mBGSurfaceControl->setFlags(layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); +void SurfaceInterceptorTest::hiddenFlagUpdate(Transaction& t) { + t.setFlags(mBGSurfaceControl, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); } -void SurfaceInterceptorTest::opaqueFlagUpdate() { - mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); +void SurfaceInterceptorTest::opaqueFlagUpdate(Transaction& t) { + t.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); } -void SurfaceInterceptorTest::secureFlagUpdate() { - mBGSurfaceControl->setFlags(layer_state_t::eLayerSecure, layer_state_t::eLayerSecure); +void SurfaceInterceptorTest::secureFlagUpdate(Transaction& t) { + t.setFlags(mBGSurfaceControl, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure); } -void SurfaceInterceptorTest::deferredTransactionUpdate() { - mBGSurfaceControl->deferTransactionUntil(mBGSurfaceControl->getHandle(), DEFERRED_UPDATE); +void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) { + t.deferTransactionUntil(mBGSurfaceControl, mBGSurfaceControl->getHandle(), DEFERRED_UPDATE); } -void SurfaceInterceptorTest::displayCreation() { +void SurfaceInterceptorTest::displayCreation(Transaction&) { sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); SurfaceComposerClient::destroyDisplay(testDisplay); } -void SurfaceInterceptorTest::displayDeletion() { +void SurfaceInterceptorTest::displayDeletion(Transaction&) { sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false); mTargetId = getDisplayId(DISPLAY_NAME.string()); SurfaceComposerClient::destroyDisplay(testDisplay); @@ -353,7 +359,7 @@ void SurfaceInterceptorTest::runAllUpdates() { runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate); } -void SurfaceInterceptorTest::surfaceCreation() { +void SurfaceInterceptorTest::surfaceCreation(Transaction&) { mComposerClient->createSurface(String8(LAYER_NAME), SIZE_UPDATE, SIZE_UPDATE, PIXEL_FORMAT_RGBA_8888, 0); } @@ -825,8 +831,10 @@ TEST_F(SurfaceInterceptorTest, InterceptDisplayDeletionWorks) { } TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) { - captureTest(&SurfaceInterceptorTest::nBufferUpdates, - &SurfaceInterceptorTest::bufferUpdatesFound); + nBufferUpdates(); + Trace capturedTrace; + ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace)); + ASSERT_TRUE(bufferUpdatesFound(&capturedTrace)); } // If the interceptor is enabled while buffer updates are being pushed, the interceptor should diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 4ce14f8d3a..ff81dc9461 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -14,26 +14,138 @@ * limitations under the License. */ +#include <algorithm> +#include <functional> +#include <limits> +#include <ostream> + #include <gtest/gtest.h> #include <android/native_window.h> #include <gui/ISurfaceComposer.h> +#include <gui/LayerState.h> + #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> -#include <private/gui/LayerState.h> -#include <utils/String8.h> #include <ui/DisplayInfo.h> +#include <ui/Rect.h> +#include <utils/String8.h> #include <math.h> +#include <math/vec3.h> namespace android { +namespace { + +struct Color { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + + static const Color RED; + static const Color GREEN; + static const Color BLUE; + static const Color WHITE; + static const Color BLACK; + static const Color TRANSPARENT; +}; + +const Color Color::RED{255, 0, 0, 255}; +const Color Color::GREEN{0, 255, 0, 255}; +const Color Color::BLUE{0, 0, 255, 255}; +const Color Color::WHITE{255, 255, 255, 255}; +const Color Color::BLACK{0, 0, 0, 255}; +const Color Color::TRANSPARENT{0, 0, 0, 0}; + +std::ostream& operator<<(std::ostream& os, const Color& color) { + os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a); + return os; +} + +// Fill a region with the specified color. +void fillBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect, const Color& color) { + int32_t x = rect.left; + int32_t y = rect.top; + int32_t width = rect.right - rect.left; + int32_t height = rect.bottom - rect.top; + + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + if (x + width > buffer.width) { + x = std::min(x, buffer.width); + width = buffer.width - x; + } + if (y + height > buffer.height) { + y = std::min(y, buffer.height); + height = buffer.height - y; + } + + for (int32_t j = 0; j < height; j++) { + uint8_t* dst = static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (y + j) + x) * 4; + for (int32_t i = 0; i < width; i++) { + dst[0] = color.r; + dst[1] = color.g; + dst[2] = color.b; + dst[3] = color.a; + dst += 4; + } + } +} + +// Check if a region has the specified color. +void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels, const Rect& rect, + const Color& color, uint8_t tolerance) { + int32_t x = rect.left; + int32_t y = rect.top; + int32_t width = rect.right - rect.left; + int32_t height = rect.bottom - rect.top; + + int32_t bufferWidth = int32_t(outBuffer->getWidth()); + int32_t bufferHeight = int32_t(outBuffer->getHeight()); + if (x + width > bufferWidth) { + x = std::min(x, bufferWidth); + width = bufferWidth - x; + } + if (y + height > bufferHeight) { + y = std::min(y, bufferHeight); + height = bufferHeight - y; + } + + auto colorCompare = [tolerance](uint8_t a, uint8_t b) { + uint8_t tmp = a >= b ? a - b : b - a; + return tmp <= tolerance; + }; + for (int32_t j = 0; j < height; j++) { + const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; + for (int32_t i = 0; i < width; i++) { + const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; + EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) + << "pixel @ (" << x + i << ", " << y + j << "): " + << "expected (" << color << "), " + << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; + src += 4; + } + } +} + +} // anonymous namespace + +using Transaction = SurfaceComposerClient::Transaction; + // Fill an RGBA_8888 formatted surface with a single color. -static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, - uint8_t r, uint8_t g, uint8_t b, bool unlock=true) { +static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b, + bool unlock = true) { ANativeWindow_Buffer outBuffer; sp<Surface> s = sc->getSurface(); ASSERT_TRUE(s != NULL); @@ -41,7 +153,7 @@ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits); for (int y = 0; y < outBuffer.height; y++) { for (int x = 0; x < outBuffer.width; x++) { - uint8_t* pixel = img + (4 * (y*outBuffer.stride + x)); + uint8_t* pixel = img + (4 * (y * outBuffer.stride + x)); pixel[0] = r; pixel[1] = g; pixel[2] = b; @@ -57,424 +169,1427 @@ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, // individual pixel values for testing purposes. class ScreenCapture : public RefBase { public: - static void captureScreen(sp<ScreenCapture>* sc) { - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); + static void captureScreen(sp<ScreenCapture>* sc, int32_t minLayerZ = 0, + int32_t maxLayerZ = std::numeric_limits<int32_t>::max()) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - sp<IBinder> display(sf->getBuiltInDisplay( - ISurfaceComposer::eDisplayIdMain)); - SurfaceComposerClient::openGlobalTransaction(); - SurfaceComposerClient::closeGlobalTransaction(true); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0, - 0, INT_MAX, false)); - *sc = new ScreenCapture(cpuConsumer); + sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + SurfaceComposerClient::Transaction().apply(true); + + sp<GraphicBuffer> outBuffer; + ASSERT_EQ(NO_ERROR, + sf->captureScreen(display, &outBuffer, Rect(), 0, 0, minLayerZ, maxLayerZ, + false)); + *sc = new ScreenCapture(outBuffer); + } + + static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle, + Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) { + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + SurfaceComposerClient::Transaction().apply(true); + + sp<GraphicBuffer> outBuffer; + ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale)); + *sc = std::make_unique<ScreenCapture>(outBuffer); + } + + void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) { + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); + expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance); + } + + void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) { + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); + const bool leftBorder = rect.left > 0; + const bool topBorder = rect.top > 0; + const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth()); + const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight()); + + if (topBorder) { + Rect top(rect.left, rect.top - 1, rect.right, rect.top); + if (leftBorder) { + top.left -= 1; + } + if (rightBorder) { + top.right += 1; + } + expectColor(top, color, tolerance); + } + if (leftBorder) { + Rect left(rect.left - 1, rect.top, rect.left, rect.bottom); + expectColor(left, color, tolerance); + } + if (rightBorder) { + Rect right(rect.right, rect.top, rect.right + 1, rect.bottom); + expectColor(right, color, tolerance); + } + if (bottomBorder) { + Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1); + if (leftBorder) { + bottom.left -= 1; + } + if (rightBorder) { + bottom.right += 1; + } + expectColor(bottom, color, tolerance); + } + } + + void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight, + const Color& bottomLeft, const Color& bottomRight, bool filtered = false, + uint8_t tolerance = 0) { + ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0); + + const int32_t centerX = rect.left + (rect.right - rect.left) / 2; + const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2; + // avoid checking borders due to unspecified filtering behavior + const int32_t offsetX = filtered ? 2 : 0; + const int32_t offsetY = filtered ? 2 : 0; + expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft, + tolerance); + expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight, + tolerance); + expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft, + tolerance); + expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom), + bottomRight, tolerance); } void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { - ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format); - const uint8_t* img = static_cast<const uint8_t*>(mBuf.data); - const uint8_t* pixel = img + (4 * (y * mBuf.stride + x)); + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); + const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x)); if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { String8 err(String8::format("pixel @ (%3d, %3d): " - "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", - x, y, r, g, b, pixel[0], pixel[1], pixel[2])); + "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", + x, y, r, g, b, pixel[0], pixel[1], pixel[2])); EXPECT_EQ(String8(), err) << err.string(); } } - void expectFGColor(uint32_t x, uint32_t y) { - checkPixel(x, y, 195, 63, 63); + void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); } + + void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); } + + void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); } + + ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) { + mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels)); } - void expectBGColor(uint32_t x, uint32_t y) { - checkPixel(x, y, 63, 63, 195); + ~ScreenCapture() { mOutBuffer->unlock(); } + +private: + sp<GraphicBuffer> mOutBuffer; + uint8_t* mPixels = NULL; +}; + +class LayerTransactionTest : public ::testing::Test { +protected: + void SetUp() override { + mClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient"; + + ASSERT_NO_FATAL_FAILURE(SetUpDisplay()); } - void expectChildColor(uint32_t x, uint32_t y) { - checkPixel(x, y, 200, 200, 200); + sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height, + uint32_t flags = 0) { + auto layer = + mClient->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags); + EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl"; + + status_t error = Transaction() + .setLayerStack(layer, mDisplayLayerStack) + .setLayer(layer, mLayerZBase) + .apply(); + if (error != NO_ERROR) { + ADD_FAILURE() << "failed to initialize SurfaceControl"; + layer.clear(); + } + + return layer; } -private: - ScreenCapture(const sp<CpuConsumer>& cc) : - mCC(cc) { - EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf)); + ANativeWindow_Buffer getLayerBuffer(const sp<SurfaceControl>& layer) { + // wait for previous transactions (such as setSize) to complete + Transaction().apply(true); + + ANativeWindow_Buffer buffer = {}; + EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr)); + + return buffer; } - ~ScreenCapture() { - mCC->unlockBuffer(mBuf); + void postLayerBuffer(const sp<SurfaceControl>& layer) { + ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost()); + + // wait for the newly posted buffer to be latched + waitForLayerBuffers(); } - sp<CpuConsumer> mCC; - CpuConsumer::LockedBuffer mBuf; -}; + void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color) { + ANativeWindow_Buffer buffer; + ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer)); + fillBufferColor(buffer, Rect(0, 0, buffer.width, buffer.height), color); + postLayerBuffer(layer); + } -class LayerUpdateTest : public ::testing::Test { -protected: - virtual void SetUp() { - mComposerClient = new SurfaceComposerClient; - ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + void fillLayerQuadrant(const sp<SurfaceControl>& layer, const Color& topLeft, + const Color& topRight, const Color& bottomLeft, + const Color& bottomRight) { + ANativeWindow_Buffer buffer; + ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer)); + ASSERT_TRUE(buffer.width % 2 == 0 && buffer.height % 2 == 0); + + const int32_t halfW = buffer.width / 2; + const int32_t halfH = buffer.height / 2; + fillBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft); + fillBufferColor(buffer, Rect(halfW, 0, buffer.width, halfH), topRight); + fillBufferColor(buffer, Rect(0, halfH, halfW, buffer.height), bottomLeft); + fillBufferColor(buffer, Rect(halfW, halfH, buffer.width, buffer.height), bottomRight); + + postLayerBuffer(layer); + } + + sp<ScreenCapture> screenshot() { + sp<ScreenCapture> screenshot; + ScreenCapture::captureScreen(&screenshot, mLayerZBase); + return screenshot; + } + + sp<SurfaceComposerClient> mClient; + + sp<IBinder> mDisplay; + uint32_t mDisplayWidth; + uint32_t mDisplayHeight; + uint32_t mDisplayLayerStack; + + // leave room for ~256 layers + const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256; + +private: + void SetUpDisplay() { + mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); + ASSERT_NE(nullptr, mDisplay.get()) << "failed to get built-in display"; - sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay( - ISurfaceComposer::eDisplayIdMain)); + // get display width/height DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(display, &info); + SurfaceComposerClient::getDisplayInfo(mDisplay, &info); + mDisplayWidth = info.w; + mDisplayHeight = info.h; - ssize_t displayWidth = info.w; - ssize_t displayHeight = info.h; + // After a new buffer is queued, SurfaceFlinger is notified and will + // latch the new buffer on next vsync. Let's heuristically wait for 3 + // vsyncs. + mBufferPostDelay = int32_t(1e6 / info.fps) * 3; - // Background surface - mBGSurfaceControl = mComposerClient->createSurface( - String8("BG Test Surface"), displayWidth, displayHeight, - PIXEL_FORMAT_RGBA_8888, 0); - ASSERT_TRUE(mBGSurfaceControl != NULL); - ASSERT_TRUE(mBGSurfaceControl->isValid()); - fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195); + mDisplayLayerStack = 0; + // set layer stack (b/68888219) + Transaction t; + t.setDisplayLayerStack(mDisplay, mDisplayLayerStack); + t.apply(); + } - // Foreground surface - mFGSurfaceControl = mComposerClient->createSurface( - String8("FG Test Surface"), 64, 64, PIXEL_FORMAT_RGBA_8888, 0); - ASSERT_TRUE(mFGSurfaceControl != NULL); - ASSERT_TRUE(mFGSurfaceControl->isValid()); + void waitForLayerBuffers() { usleep(mBufferPostDelay); } - fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); + int32_t mBufferPostDelay; +}; - // Synchronization surface - mSyncSurfaceControl = mComposerClient->createSurface( - String8("Sync Test Surface"), 1, 1, PIXEL_FORMAT_RGBA_8888, 0); - ASSERT_TRUE(mSyncSurfaceControl != NULL); - ASSERT_TRUE(mSyncSurfaceControl->isValid()); +TEST_F(LayerTransactionTest, SetPositionBasic) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + { + SCOPED_TRACE("default position"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + } - SurfaceComposerClient::openGlobalTransaction(); + Transaction().setPosition(layer, 5, 10).apply(); + { + SCOPED_TRACE("new position"); + auto shot = screenshot(); + shot->expectColor(Rect(5, 10, 37, 42), Color::RED); + shot->expectBorder(Rect(5, 10, 37, 42), Color::BLACK); + } +} - mComposerClient->setDisplayLayerStack(display, 0); +TEST_F(LayerTransactionTest, SetPositionRounding) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); - ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX-2)); - ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show()); + // GLES requires only 4 bits of subpixel precision during rasterization + // XXX GLES composition does not match HWC composition due to precision + // loss (b/69315223) + const float epsilon = 1.0f / 16.0f; + Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply(); + { + SCOPED_TRACE("rounding down"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX-1)); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64)); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply(); + { + SCOPED_TRACE("rounding up"); + screenshot()->expectColor(Rect(1, 1, 33, 33), Color::RED); + } +} - ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setLayer(INT32_MAX-1)); - ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setPosition(displayWidth-2, - displayHeight-2)); - ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->show()); +TEST_F(LayerTransactionTest, SetPositionOutOfBounds) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); - SurfaceComposerClient::closeGlobalTransaction(true); + Transaction().setPosition(layer, -32, -32).apply(); + { + SCOPED_TRACE("negative coordinates"); + screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } - virtual void TearDown() { - mComposerClient->dispose(); - mBGSurfaceControl = 0; - mFGSurfaceControl = 0; - mSyncSurfaceControl = 0; - mComposerClient = 0; + Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply(); + { + SCOPED_TRACE("positive coordinates"); + screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } +} - void waitForPostedBuffers() { - // Since the sync surface is in synchronous mode (i.e. double buffered) - // posting three buffers to it should ensure that at least two - // SurfaceFlinger::handlePageFlip calls have been made, which should - // guaranteed that a buffer posted to another Surface has been retired. - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); +TEST_F(LayerTransactionTest, SetPositionPartiallyOutOfBounds) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // partially out of bounds + Transaction().setPosition(layer, -30, -30).apply(); + { + SCOPED_TRACE("negative coordinates"); + screenshot()->expectColor(Rect(0, 0, 2, 2), Color::RED); } - sp<SurfaceComposerClient> mComposerClient; - sp<SurfaceControl> mBGSurfaceControl; - sp<SurfaceControl> mFGSurfaceControl; + Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply(); + { + SCOPED_TRACE("positive coordinates"); + screenshot()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth, + mDisplayHeight), + Color::RED); + } +} - // This surface is used to ensure that the buffers posted to - // mFGSurfaceControl have been picked up by SurfaceFlinger. - sp<SurfaceControl> mSyncSurfaceControl; -}; +TEST_F(LayerTransactionTest, SetPositionWithResize) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); -TEST_F(LayerUpdateTest, LayerMoveWorks) { - sp<ScreenCapture> sc; + // setPosition is applied immediately by default, with or without resize + // pending + Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply(); { - SCOPED_TRACE("before move"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(0, 12); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("resize pending"); + auto shot = screenshot(); + shot->expectColor(Rect(5, 10, 37, 42), Color::RED); + shot->expectBorder(Rect(5, 10, 37, 42), Color::BLACK); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); - SurfaceComposerClient::closeGlobalTransaction(true); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); { - // This should reflect the new position, but not the new color. - SCOPED_TRACE("after move, before redraw"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectBGColor(75, 75); - sc->expectFGColor(145, 145); + SCOPED_TRACE("resize applied"); + screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED); } +} - fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63); - waitForPostedBuffers(); +TEST_F(LayerTransactionTest, SetPositionWithNextResize) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // request setPosition to be applied with the next resize + Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply(); { - // This should reflect the new position and the new color. - SCOPED_TRACE("after redraw"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectBGColor(75, 75); - sc->checkPixel(145, 145, 63, 195, 63); + SCOPED_TRACE("new position pending"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + Transaction().setPosition(layer, 15, 20).apply(); + { + SCOPED_TRACE("pending new position modified"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + Transaction().setSize(layer, 64, 64).apply(); + { + SCOPED_TRACE("resize pending"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + // finally resize and latch the buffer + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + { + SCOPED_TRACE("new position applied"); + screenshot()->expectColor(Rect(15, 20, 79, 84), Color::RED); } } -TEST_F(LayerUpdateTest, LayerResizeWorks) { - sp<ScreenCapture> sc; +TEST_F(LayerTransactionTest, SetPositionWithNextResizeScaleToWindow) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // setPosition is not immediate even with SCALE_TO_WINDOW override + Transaction() + .setPosition(layer, 5, 10) + .setSize(layer, 64, 64) + .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) + .setGeometryAppliesWithResize(layer) + .apply(); { - SCOPED_TRACE("before resize"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(0, 12); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("new position pending"); + screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED); } - ALOGD("resizing"); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128)); - SurfaceComposerClient::closeGlobalTransaction(true); - ALOGD("resized"); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); { - // This should not reflect the new size or color because SurfaceFlinger - // has not yet received a buffer of the correct size. - SCOPED_TRACE("after resize, before redraw"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(0, 12); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("new position applied"); + screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED); } +} - ALOGD("drawing"); - fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63); - waitForPostedBuffers(); - ALOGD("drawn"); +TEST_F(LayerTransactionTest, SetSizeBasic) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + Transaction().setSize(layer, 64, 64).apply(); { - // This should reflect the new size and the new color. - SCOPED_TRACE("after redraw"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->checkPixel(75, 75, 63, 195, 63); - sc->checkPixel(145, 145, 63, 195, 63); + SCOPED_TRACE("resize pending"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + } + + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + { + SCOPED_TRACE("resize applied"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 64, 64), Color::RED); + shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); } } -TEST_F(LayerUpdateTest, LayerCropWorks) { - sp<ScreenCapture> sc; +TEST_F(LayerTransactionTest, SetSizeInvalid) { + // cannot test robustness against invalid sizes (zero or really huge) +} + +TEST_F(LayerTransactionTest, SetSizeWithScaleToWindow) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition + Transaction() + .setSize(layer, 64, 64) + .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) + .apply(); + screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED); +} + +TEST_F(LayerTransactionTest, SetZBasic) { + sp<SurfaceControl> layerR; + sp<SurfaceControl> layerG; + ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED)); + ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN)); + + Transaction().setLayer(layerR, mLayerZBase + 1).apply(); { - SCOPED_TRACE("before crop"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layerR"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); } - SurfaceComposerClient::openGlobalTransaction(); - Rect cropRect(16, 16, 32, 32); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect)); - SurfaceComposerClient::closeGlobalTransaction(true); + Transaction().setLayer(layerG, mLayerZBase + 2).apply(); { - // This should crop the foreground surface. - SCOPED_TRACE("after crop"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectBGColor(75, 75); - sc->expectFGColor(95, 80); - sc->expectFGColor(80, 95); - sc->expectBGColor(96, 96); + SCOPED_TRACE("layerG"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::GREEN); } } -TEST_F(LayerUpdateTest, LayerFinalCropWorks) { - sp<ScreenCapture> sc; +TEST_F(LayerTransactionTest, SetZNegative) { + sp<SurfaceControl> layerR; + sp<SurfaceControl> layerG; + ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED)); + ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN)); + + Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply(); { - SCOPED_TRACE("before crop"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layerR"); + sp<ScreenCapture> screenshot; + ScreenCapture::captureScreen(&screenshot, -2, -1); + screenshot->expectColor(Rect(0, 0, 32, 32), Color::RED); } - SurfaceComposerClient::openGlobalTransaction(); - Rect cropRect(16, 16, 32, 32); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); - SurfaceComposerClient::closeGlobalTransaction(true); + + Transaction().setLayer(layerR, -3).apply(); { - // This should crop the foreground surface. - SCOPED_TRACE("after crop"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectBGColor(75, 75); - sc->expectBGColor(95, 80); - sc->expectBGColor(80, 95); - sc->expectBGColor(96, 96); + SCOPED_TRACE("layerG"); + sp<ScreenCapture> screenshot; + ScreenCapture::captureScreen(&screenshot, -3, -1); + screenshot->expectColor(Rect(0, 0, 32, 32), Color::GREEN); } } -TEST_F(LayerUpdateTest, LayerSetLayerWorks) { - sp<ScreenCapture> sc; +TEST_F(LayerTransactionTest, SetRelativeZBasic) { + sp<SurfaceControl> layerR; + sp<SurfaceControl> layerG; + ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED)); + ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN)); + + Transaction() + .setPosition(layerG, 16, 16) + .setRelativeLayer(layerG, layerR->getHandle(), 1) + .apply(); { - SCOPED_TRACE("before setLayer"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layerG above"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 16, 16), Color::RED); + shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); - SurfaceComposerClient::closeGlobalTransaction(true); + Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply(); { - // This should hide the foreground surface beneath the background. - SCOPED_TRACE("after setLayer"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectBGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layerG below"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN); } } -TEST_F(LayerUpdateTest, LayerShowHideWorks) { - sp<ScreenCapture> sc; +TEST_F(LayerTransactionTest, SetRelativeZNegative) { + sp<SurfaceControl> layerR; + sp<SurfaceControl> layerG; + sp<SurfaceControl> layerB; + ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED)); + ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN)); + ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE)); + + // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2 + Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply(); + + sp<ScreenCapture> screenshot; + // only layerB is in this range + ScreenCapture::captureScreen(&screenshot, -2, -1); + screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); +} + +TEST_F(LayerTransactionTest, SetRelativeZGroup) { + sp<SurfaceControl> layerR; + sp<SurfaceControl> layerG; + sp<SurfaceControl> layerB; + ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED)); + ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN)); + ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE)); + + // layerR = 0, layerG = layerR + 3, layerB = 2 + Transaction() + .setPosition(layerG, 8, 8) + .setRelativeLayer(layerG, layerR->getHandle(), 3) + .setPosition(layerB, 16, 16) + .setLayer(layerB, mLayerZBase + 2) + .apply(); { - SCOPED_TRACE("before hide"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("(layerR < layerG) < layerB"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 8, 8), Color::RED); + shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN); + shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide()); - SurfaceComposerClient::closeGlobalTransaction(true); + // layerR = 4, layerG = layerR + 3, layerB = 2 + Transaction().setLayer(layerR, mLayerZBase + 4).apply(); { - // This should hide the foreground surface. - SCOPED_TRACE("after hide, before show"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectBGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layerB < (layerR < layerG)"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 8, 8), Color::RED); + shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN); + shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(true); + // layerR = 4, layerG = layerR - 3, layerB = 2 + Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply(); { - // This should show the foreground surface. - SCOPED_TRACE("after show"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layerB < (layerG < layerR)"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN); + shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE); + } + + // restore to absolute z + // layerR = 4, layerG = 0, layerB = 2 + Transaction().setLayer(layerG, mLayerZBase).apply(); + { + SCOPED_TRACE("layerG < layerB < layerR"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE); + } + + // layerR should not affect layerG anymore + // layerR = 1, layerG = 0, layerB = 2 + Transaction().setLayer(layerR, mLayerZBase + 1).apply(); + { + SCOPED_TRACE("layerG < layerR < layerB"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 16, 16), Color::RED); + shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE); } } -TEST_F(LayerUpdateTest, LayerSetAlphaWorks) { - sp<ScreenCapture> sc; +TEST_F(LayerTransactionTest, SetRelativeZBug64572777) { + sp<SurfaceControl> layerR; + sp<SurfaceControl> layerG; + + ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED)); + ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN)); + + Transaction() + .setPosition(layerG, 16, 16) + .setRelativeLayer(layerG, layerR->getHandle(), 1) + .apply(); + + mClient->destroySurface(layerG->getHandle()); + // layerG should have been removed + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); +} + +TEST_F(LayerTransactionTest, SetFlagsHidden) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply(); { - SCOPED_TRACE("before setAlpha"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layer hidden"); + screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f)); - SurfaceComposerClient::closeGlobalTransaction(true); + Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply(); { - // This should set foreground to be 75% opaque. - SCOPED_TRACE("after setAlpha"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->checkPixel(75, 75, 162, 63, 96); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layer shown"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); } } -TEST_F(LayerUpdateTest, LayerSetLayerStackWorks) { - sp<ScreenCapture> sc; +TEST_F(LayerTransactionTest, SetFlagsOpaque) { + const Color translucentRed = {100, 0, 0, 100}; + sp<SurfaceControl> layerR; + sp<SurfaceControl> layerG; + ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed)); + ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN)); + + Transaction() + .setLayer(layerR, mLayerZBase + 1) + .setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque) + .apply(); { - SCOPED_TRACE("before setLayerStack"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layerR opaque"); + screenshot()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255}); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1)); - SurfaceComposerClient::closeGlobalTransaction(true); + Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply(); { - // This should hide the foreground surface since it goes to a different - // layer stack. - SCOPED_TRACE("after setLayerStack"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectBGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("layerR translucent"); + const uint8_t g = uint8_t(255 - translucentRed.a); + screenshot()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255}); } } -TEST_F(LayerUpdateTest, LayerSetFlagsWorks) { - sp<ScreenCapture> sc; +TEST_F(LayerTransactionTest, SetFlagsSecure) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<GraphicBuffer> outBuffer; + Transaction() + .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure) + .apply(true); + ASSERT_EQ(PERMISSION_DENIED, + composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, mLayerZBase, mLayerZBase, + false)); + + Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true); + ASSERT_EQ(NO_ERROR, + composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, mLayerZBase, mLayerZBase, + false)); +} + +TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic) { + const Rect top(0, 0, 32, 16); + const Rect bottom(0, 16, 32, 32); + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + + ANativeWindow_Buffer buffer; + ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer)); + ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, top, Color::TRANSPARENT)); + ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, bottom, Color::RED)); + // setTransparentRegionHint always applies to the following buffer + Transaction().setTransparentRegionHint(layer, Region(top)).apply(); + ASSERT_NO_FATAL_FAILURE(postLayerBuffer(layer)); { - SCOPED_TRACE("before setFlags"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("top transparent"); + auto shot = screenshot(); + shot->expectColor(top, Color::BLACK); + shot->expectColor(bottom, Color::RED); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFlags( - layer_state_t::eLayerHidden, layer_state_t::eLayerHidden)); - SurfaceComposerClient::closeGlobalTransaction(true); + Transaction().setTransparentRegionHint(layer, Region(bottom)).apply(); { - // This should hide the foreground surface - SCOPED_TRACE("after setFlags"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectBGColor(75, 75); - sc->expectBGColor(145, 145); + SCOPED_TRACE("transparent region hint pending"); + auto shot = screenshot(); + shot->expectColor(top, Color::BLACK); + shot->expectColor(bottom, Color::RED); + } + + ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer)); + ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, top, Color::RED)); + ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, bottom, Color::TRANSPARENT)); + ASSERT_NO_FATAL_FAILURE(postLayerBuffer(layer)); + { + SCOPED_TRACE("bottom transparent"); + auto shot = screenshot(); + shot->expectColor(top, Color::RED); + shot->expectColor(bottom, Color::BLACK); + } +} + +TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds) { + sp<SurfaceControl> layerTransparent; + sp<SurfaceControl> layerR; + ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32)); + ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); + + // check that transparent region hint is bound by the layer size + Transaction() + .setTransparentRegionHint(layerTransparent, + Region(Rect(0, 0, mDisplayWidth, mDisplayHeight))) + .setPosition(layerR, 16, 16) + .setLayer(layerR, mLayerZBase + 1) + .apply(); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerTransparent, Color::TRANSPARENT)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED)); + screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED); +} + +TEST_F(LayerTransactionTest, SetAlphaBasic) { + sp<SurfaceControl> layer1; + sp<SurfaceControl> layer2; + ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32)); + ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer1, {64, 0, 0, 255})); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer2, {0, 64, 0, 255})); + + Transaction() + .setAlpha(layer1, 0.25f) + .setAlpha(layer2, 0.75f) + .setPosition(layer2, 16, 0) + .setLayer(layer2, mLayerZBase + 1) + .apply(); + { + auto shot = screenshot(); + uint8_t r = 16; // 64 * 0.25f + uint8_t g = 48; // 64 * 0.75f + shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255}); + shot->expectColor(Rect(32, 0, 48, 32), {0, g, 0, 255}); + + r /= 4; // r * (1.0f - 0.75f) + shot->expectColor(Rect(16, 0, 32, 32), {r, g, 0, 255}); } } -TEST_F(LayerUpdateTest, LayerSetMatrixWorks) { +TEST_F(LayerTransactionTest, SetAlphaClamped) { + const Color color = {64, 0, 0, 255}; + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color)); + + Transaction().setAlpha(layer, 2.0f).apply(); + { + SCOPED_TRACE("clamped to 1.0f"); + screenshot()->expectColor(Rect(0, 0, 32, 32), color); + } + + Transaction().setAlpha(layer, -1.0f).apply(); + { + SCOPED_TRACE("clamped to 0.0f"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); + } +} + +TEST_F(LayerTransactionTest, SetColorBasic) { + sp<SurfaceControl> bufferLayer; + sp<SurfaceControl> colorLayer; + ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED)); + ASSERT_NO_FATAL_FAILURE( + colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor)); + + Transaction().setLayer(colorLayer, mLayerZBase + 1).apply(); + { + SCOPED_TRACE("default color"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); + } + + const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); + const Color expected = {15, 51, 85, 255}; + // this is handwavy, but the precison loss scaled by 255 (8-bit per + // channel) should be less than one + const uint8_t tolerance = 1; + Transaction().setColor(colorLayer, color).apply(); + { + SCOPED_TRACE("new color"); + screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance); + } +} + +TEST_F(LayerTransactionTest, SetColorClamped) { + sp<SurfaceControl> colorLayer; + ASSERT_NO_FATAL_FAILURE( + colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor)); + + Transaction().setColor(colorLayer, half3(2.0f, -1.0f, 0.0f)).apply(); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); +} + +TEST_F(LayerTransactionTest, SetColorWithAlpha) { + sp<SurfaceControl> bufferLayer; + sp<SurfaceControl> colorLayer; + ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED)); + ASSERT_NO_FATAL_FAILURE( + colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor)); + + const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); + const float alpha = 0.25f; + const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f); + // this is handwavy, but the precison loss scaled by 255 (8-bit per + // channel) should be less than one + const uint8_t tolerance = 1; + Transaction() + .setColor(colorLayer, color) + .setAlpha(colorLayer, alpha) + .setLayer(colorLayer, mLayerZBase + 1) + .apply(); + screenshot()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255}, + tolerance); +} + +TEST_F(LayerTransactionTest, SetColorWithBuffer) { + sp<SurfaceControl> bufferLayer; + ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED)); + + // color is ignored + Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply(); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); +} + +TEST_F(LayerTransactionTest, SetLayerStackBasic) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply(); + { + SCOPED_TRACE("non-existing layer stack"); + screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + } + + Transaction().setLayerStack(layer, mDisplayLayerStack).apply(); + { + SCOPED_TRACE("original layer stack"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } +} + +TEST_F(LayerTransactionTest, SetMatrixBasic) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE( + fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE)); + + Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply(); + { + SCOPED_TRACE("IDENTITY"); + screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE, + Color::WHITE); + } + + Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply(); + { + SCOPED_TRACE("FLIP_H"); + screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE, + Color::BLUE); + } + + Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply(); + { + SCOPED_TRACE("FLIP_V"); + screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED, + Color::GREEN); + } + + Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply(); + { + SCOPED_TRACE("ROT_90"); + screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE, + Color::GREEN); + } + + Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply(); + { + SCOPED_TRACE("SCALE"); + screenshot()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN, Color::BLUE, + Color::WHITE, true /* filtered */); + } +} + +TEST_F(LayerTransactionTest, SetMatrixRot45) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE( + fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE)); + + const float rot = M_SQRT1_2; // 45 degrees + const float trans = M_SQRT2 * 16.0f; + Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply(); + + auto shot = screenshot(); + // check a 8x8 region inside each color + auto get8x8Rect = [](int32_t centerX, int32_t centerY) { + const int32_t halfL = 4; + return Rect(centerX - halfL, centerY - halfL, centerX + halfL, centerY + halfL); + }; + const int32_t unit = int32_t(trans / 2); + shot->expectColor(get8x8Rect(2 * unit, 1 * unit), Color::RED); + shot->expectColor(get8x8Rect(3 * unit, 2 * unit), Color::GREEN); + shot->expectColor(get8x8Rect(1 * unit, 2 * unit), Color::BLUE); + shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE); +} + +TEST_F(LayerTransactionTest, SetMatrixWithResize) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // setMatrix is applied after any pending resize, unlike setPosition + Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply(); + { + SCOPED_TRACE("resize pending"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + } + + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + { + SCOPED_TRACE("resize applied"); + screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED); + } +} + +TEST_F(LayerTransactionTest, SetMatrixWithScaleToWindow) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition + Transaction() + .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f) + .setSize(layer, 64, 64) + .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) + .apply(); + screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED); +} + +TEST_F(LayerTransactionTest, SetOverrideScalingModeBasic) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE( + fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE)); + + // XXX SCALE_CROP is not respected; calling setSize and + // setOverrideScalingMode in separate transactions does not work + // (b/69315456) + Transaction() + .setSize(layer, 64, 16) + .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) + .apply(); + { + SCOPED_TRACE("SCALE_TO_WINDOW"); + screenshot()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN, Color::BLUE, + Color::WHITE, true /* filtered */); + } +} + +TEST_F(LayerTransactionTest, SetCropBasic) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + const Rect crop(8, 8, 24, 24); + + Transaction().setCrop(layer, crop).apply(); + auto shot = screenshot(); + shot->expectColor(crop, Color::RED); + shot->expectBorder(crop, Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetCropEmpty) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + { + SCOPED_TRACE("empty rect"); + Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply(); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + { + SCOPED_TRACE("negative rect"); + Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply(); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } +} + +TEST_F(LayerTransactionTest, SetCropOutOfBounds) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + Transaction().setCrop(layer, Rect(-128, -64, 128, 64)).apply(); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetCropWithTranslation) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + const Point position(32, 32); + const Rect crop(8, 8, 24, 24); + Transaction().setPosition(layer, position.x, position.y).setCrop(layer, crop).apply(); + auto shot = screenshot(); + shot->expectColor(crop + position, Color::RED); + shot->expectBorder(crop + position, Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetCropWithScale) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // crop is affected by matrix + Transaction() + .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f) + .setCrop(layer, Rect(8, 8, 24, 24)) + .apply(); + auto shot = screenshot(); + shot->expectColor(Rect(16, 16, 48, 48), Color::RED); + shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetCropWithResize) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // setCrop is applied immediately by default, with or without resize pending + Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply(); + { + SCOPED_TRACE("resize pending"); + auto shot = screenshot(); + shot->expectColor(Rect(8, 8, 24, 24), Color::RED); + shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK); + } + + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + { + SCOPED_TRACE("resize applied"); + auto shot = screenshot(); + shot->expectColor(Rect(8, 8, 16, 16), Color::RED); + shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK); + } +} + +TEST_F(LayerTransactionTest, SetCropWithNextResize) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // request setCrop to be applied with the next resize + Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setGeometryAppliesWithResize(layer).apply(); + { + SCOPED_TRACE("waiting for next resize"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + Transaction().setCrop(layer, Rect(4, 4, 12, 12)).apply(); + { + SCOPED_TRACE("pending crop modified"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + Transaction().setSize(layer, 16, 16).apply(); + { + SCOPED_TRACE("resize pending"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + // finally resize + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + { + SCOPED_TRACE("new crop applied"); + auto shot = screenshot(); + shot->expectColor(Rect(4, 4, 12, 12), Color::RED); + shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); + } +} + +TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // setCrop is not immediate even with SCALE_TO_WINDOW override + Transaction() + .setCrop(layer, Rect(4, 4, 12, 12)) + .setSize(layer, 16, 16) + .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) + .setGeometryAppliesWithResize(layer) + .apply(); + { + SCOPED_TRACE("new crop pending"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 16, 16), Color::RED); + shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK); + } + + // XXX crop is never latched without other geometry change (b/69315677) + Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply(); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + Transaction().setPosition(layer, 0, 0).apply(); + { + SCOPED_TRACE("new crop applied"); + auto shot = screenshot(); + shot->expectColor(Rect(4, 4, 12, 12), Color::RED); + shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); + } +} + +TEST_F(LayerTransactionTest, SetFinalCropBasic) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + const Rect crop(8, 8, 24, 24); + + // same as in SetCropBasic + Transaction().setFinalCrop(layer, crop).apply(); + auto shot = screenshot(); + shot->expectColor(crop, Color::RED); + shot->expectBorder(crop, Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetFinalCropEmpty) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // same as in SetCropEmpty + { + SCOPED_TRACE("empty rect"); + Transaction().setFinalCrop(layer, Rect(8, 8, 8, 8)).apply(); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + { + SCOPED_TRACE("negative rect"); + Transaction().setFinalCrop(layer, Rect(8, 8, 0, 0)).apply(); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } +} + +TEST_F(LayerTransactionTest, SetFinalCropOutOfBounds) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // same as in SetCropOutOfBounds + Transaction().setFinalCrop(layer, Rect(-128, -64, 128, 64)).apply(); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetFinalCropWithTranslation) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // final crop is applied post-translation + Transaction().setPosition(layer, 16, 16).setFinalCrop(layer, Rect(8, 8, 24, 24)).apply(); + auto shot = screenshot(); + shot->expectColor(Rect(16, 16, 24, 24), Color::RED); + shot->expectBorder(Rect(16, 16, 24, 24), Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetFinalCropWithScale) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // final crop is not affected by matrix + Transaction() + .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f) + .setFinalCrop(layer, Rect(8, 8, 24, 24)) + .apply(); + auto shot = screenshot(); + shot->expectColor(Rect(8, 8, 24, 24), Color::RED); + shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetFinalCropWithResize) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // same as in SetCropWithResize + Transaction().setFinalCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply(); + { + SCOPED_TRACE("resize pending"); + auto shot = screenshot(); + shot->expectColor(Rect(8, 8, 24, 24), Color::RED); + shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK); + } + + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + { + SCOPED_TRACE("resize applied"); + auto shot = screenshot(); + shot->expectColor(Rect(8, 8, 16, 16), Color::RED); + shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK); + } +} + +TEST_F(LayerTransactionTest, SetFinalCropWithNextResize) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // same as in SetCropWithNextResize + Transaction() + .setFinalCrop(layer, Rect(8, 8, 24, 24)) + .setGeometryAppliesWithResize(layer) + .apply(); + { + SCOPED_TRACE("waiting for next resize"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + Transaction().setFinalCrop(layer, Rect(4, 4, 12, 12)).apply(); + { + SCOPED_TRACE("pending final crop modified"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + Transaction().setSize(layer, 16, 16).apply(); + { + SCOPED_TRACE("resize pending"); + screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED); + } + + // finally resize + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + { + SCOPED_TRACE("new final crop applied"); + auto shot = screenshot(); + shot->expectColor(Rect(4, 4, 12, 12), Color::RED); + shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); + } +} + +TEST_F(LayerTransactionTest, SetFinalCropWithNextResizeScaleToWindow) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + + // same as in SetCropWithNextResizeScaleToWindow + Transaction() + .setFinalCrop(layer, Rect(4, 4, 12, 12)) + .setSize(layer, 16, 16) + .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) + .setGeometryAppliesWithResize(layer) + .apply(); + { + SCOPED_TRACE("new final crop pending"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 16, 16), Color::RED); + shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK); + } + + // XXX final crop is never latched without other geometry change (b/69315677) + Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply(); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED)); + Transaction().setPosition(layer, 0, 0).apply(); + { + SCOPED_TRACE("new final crop applied"); + auto shot = screenshot(); + shot->expectColor(Rect(4, 4, 12, 12), Color::RED); + shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); + } +} + +class LayerUpdateTest : public LayerTransactionTest { +protected: + virtual void SetUp() { + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + + sp<IBinder> display( + SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + + ssize_t displayWidth = info.w; + ssize_t displayHeight = info.h; + + // Background surface + mBGSurfaceControl = + mComposerClient->createSurface(String8("BG Test Surface"), displayWidth, + displayHeight, PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mBGSurfaceControl != NULL); + ASSERT_TRUE(mBGSurfaceControl->isValid()); + fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195); + + // Foreground surface + mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mFGSurfaceControl != NULL); + ASSERT_TRUE(mFGSurfaceControl->isValid()); + + fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); + + // Synchronization surface + mSyncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mSyncSurfaceControl != NULL); + ASSERT_TRUE(mSyncSurfaceControl->isValid()); + + fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + + asTransaction([&](Transaction& t) { + t.setDisplayLayerStack(display, 0); + + t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl); + + t.setLayer(mFGSurfaceControl, INT32_MAX - 1) + .setPosition(mFGSurfaceControl, 64, 64) + .show(mFGSurfaceControl); + + t.setLayer(mSyncSurfaceControl, INT32_MAX - 1) + .setPosition(mSyncSurfaceControl, displayWidth - 2, displayHeight - 2) + .show(mSyncSurfaceControl); + }); + } + + virtual void TearDown() { + mComposerClient->dispose(); + mBGSurfaceControl = 0; + mFGSurfaceControl = 0; + mSyncSurfaceControl = 0; + mComposerClient = 0; + } + + void waitForPostedBuffers() { + // Since the sync surface is in synchronous mode (i.e. double buffered) + // posting three buffers to it should ensure that at least two + // SurfaceFlinger::handlePageFlip calls have been made, which should + // guaranteed that a buffer posted to another Surface has been retired. + fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + } + + void asTransaction(const std::function<void(Transaction&)>& exec) { + Transaction t; + exec(t); + t.apply(true); + } + + sp<SurfaceComposerClient> mComposerClient; + sp<SurfaceControl> mBGSurfaceControl; + sp<SurfaceControl> mFGSurfaceControl; + + // This surface is used to ensure that the buffers posted to + // mFGSurfaceControl have been picked up by SurfaceFlinger. + sp<SurfaceControl> mSyncSurfaceControl; +}; + +TEST_F(LayerUpdateTest, RelativesAreNotDetached) { sp<ScreenCapture> sc; + + sp<SurfaceControl> relative = mComposerClient->createSurface(String8("relativeTestSurface"), 10, + 10, PIXEL_FORMAT_RGBA_8888, 0); + fillSurfaceRGBA8(relative, 10, 10, 10); + waitForPostedBuffers(); + + Transaction{} + .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1) + .setPosition(relative, 64, 64) + .apply(); + { - SCOPED_TRACE("before setMatrix"); + // The relative should be on top of the FG control. ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(91, 96); - sc->expectFGColor(96, 101); - sc->expectBGColor(145, 145); + sc->checkPixel(64, 64, 10, 10, 10); } + Transaction{}.detachChildren(mFGSurfaceControl).apply(); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2, - -M_SQRT1_2, M_SQRT1_2)); - SurfaceComposerClient::closeGlobalTransaction(true); { - SCOPED_TRACE("after setMatrix"); + // Nothing should change at this point. ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(91, 96); - sc->expectBGColor(96, 91); - sc->expectBGColor(145, 145); + sc->checkPixel(64, 64, 10, 10, 10); + } + + Transaction{}.hide(relative).apply(); + + { + // Ensure that the relative was actually hidden, rather than + // being left in the detached but visible state. + ScreenCapture::captureScreen(&sc); + sc->expectFGColor(64, 64); } } class GeometryLatchingTest : public LayerUpdateTest { protected: - void EXPECT_INITIAL_STATE(const char * trace) { + void EXPECT_INITIAL_STATE(const char* trace) { SCOPED_TRACE(trace); ScreenCapture::captureScreen(&sc); // We find the leading edge of the FG surface. @@ -482,9 +1597,7 @@ protected: sc->expectBGColor(128, 128); } - void lockAndFillFGBuffer() { - fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false); - } + void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false); } void unlockFGBuffer() { sp<Surface> s = mFGSurfaceControl->getSurface(); @@ -497,65 +1610,18 @@ protected: waitForPostedBuffers(); } void restoreInitialState() { - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setSize(64, 64); - mFGSurfaceControl->setPosition(64, 64); - mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64)); - mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.setSize(mFGSurfaceControl, 64, 64); + t.setPosition(mFGSurfaceControl, 64, 64); + t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64)); + t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1)); + }); EXPECT_INITIAL_STATE("After restoring initial state"); } sp<ScreenCapture> sc; }; -TEST_F(GeometryLatchingTest, SurfacePositionLatching) { - EXPECT_INITIAL_STATE("before anything"); - - // By default position can be updated even while - // a resize is pending. - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setSize(32, 32); - mFGSurfaceControl->setPosition(100, 100); - SurfaceComposerClient::closeGlobalTransaction(true); - - { - SCOPED_TRACE("After moving surface"); - ScreenCapture::captureScreen(&sc); - // If we moved, the FG Surface should cover up what was previously BG - // however if we didn't move the FG wouldn't be large enough now. - sc->expectFGColor(163, 163); - } - - restoreInitialState(); - - // Now we repeat with setGeometryAppliesWithResize - // and verify the position DOESN'T latch. - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setSize(32, 32); - mFGSurfaceControl->setPosition(100, 100); - SurfaceComposerClient::closeGlobalTransaction(true); - - { - SCOPED_TRACE("While resize is pending"); - ScreenCapture::captureScreen(&sc); - // This time we shouldn't have moved, so the BG color - // should still be visible. - sc->expectBGColor(128, 128); - } - - completeFGResize(); - - { - SCOPED_TRACE("After the resize"); - ScreenCapture::captureScreen(&sc); - // But after the resize completes, we should move - // and the FG should be visible here. - sc->expectFGColor(128, 128); - } -} - class CropLatchingTest : public GeometryLatchingTest { protected: void EXPECT_CROPPED_STATE(const char* trace) { @@ -577,65 +1643,15 @@ protected: } }; -TEST_F(CropLatchingTest, CropLatching) { - EXPECT_INITIAL_STATE("before anything"); - // Normally the crop applies immediately even while a resize is pending. - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); - SurfaceComposerClient::closeGlobalTransaction(true); - - EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)"); - - restoreInitialState(); - - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); - SurfaceComposerClient::closeGlobalTransaction(true); - - EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)"); - - completeFGResize(); - - EXPECT_CROPPED_STATE("after the resize finishes"); -} - -TEST_F(CropLatchingTest, FinalCropLatching) { - EXPECT_INITIAL_STATE("before anything"); - // Normally the crop applies immediately even while a resize is pending. - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); - SurfaceComposerClient::closeGlobalTransaction(true); - - EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)"); - - restoreInitialState(); - - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); - SurfaceComposerClient::closeGlobalTransaction(true); - - EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)"); - - completeFGResize(); - - EXPECT_CROPPED_STATE("after the resize finishes"); -} - // In this test we ensure that setGeometryAppliesWithResize actually demands // a buffer of the new size, and not just any size. TEST_F(CropLatchingTest, FinalCropLatchingBufferOldSize) { EXPECT_INITIAL_STATE("before anything"); // Normally the crop applies immediately even while a resize is pending. - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.setSize(mFGSurfaceControl, 128, 128); + t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127)); + }); EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)"); @@ -645,11 +1661,11 @@ TEST_F(CropLatchingTest, FinalCropLatchingBufferOldSize) { // initiating the resize. lockAndFillFGBuffer(); - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.setSize(mFGSurfaceControl, 128, 128); + t.setGeometryAppliesWithResize(mFGSurfaceControl); + t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127)); + }); EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)"); @@ -664,30 +1680,6 @@ TEST_F(CropLatchingTest, FinalCropLatchingBufferOldSize) { EXPECT_CROPPED_STATE("after the resize finishes"); } -TEST_F(CropLatchingTest, FinalCropLatchingRegressionForb37531386) { - EXPECT_INITIAL_STATE("before anything"); - // In this scenario, we attempt to set the final crop a second time while the resize - // is still pending, and ensure we are successful. Success meaning the second crop - // is the one which eventually latches and not the first. - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); - SurfaceComposerClient::closeGlobalTransaction(true); - - EXPECT_INITIAL_STATE("after setting crops with geometryAppliesWithResize"); - - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); - SurfaceComposerClient::closeGlobalTransaction(true); - - EXPECT_INITIAL_STATE("after setting another crop"); - - completeFGResize(); - - EXPECT_RESIZE_STATE("after the resize finishes"); -} - TEST_F(LayerUpdateTest, DeferredTransactionTest) { sp<ScreenCapture> sc; { @@ -699,17 +1691,17 @@ TEST_F(LayerUpdateTest, DeferredTransactionTest) { } // set up two deferred transactions on different frames - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75)); - mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(), - mSyncSurfaceControl->getSurface()->getNextFrameNumber()); - SurfaceComposerClient::closeGlobalTransaction(true); - - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128,128)); - mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(), - mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.setAlpha(mFGSurfaceControl, 0.75); + t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(), + mSyncSurfaceControl->getSurface()->getNextFrameNumber()); + }); + + asTransaction([&](Transaction& t) { + t.setPosition(mFGSurfaceControl, 128, 128); + t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(), + mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1); + }); { SCOPED_TRACE("before any trigger"); @@ -730,9 +1722,7 @@ TEST_F(LayerUpdateTest, DeferredTransactionTest) { } // should show up immediately since it's not deferred - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0)); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); }); // trigger the second deferred transaction fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); @@ -745,46 +1735,55 @@ TEST_F(LayerUpdateTest, DeferredTransactionTest) { } } -TEST_F(LayerUpdateTest, LayerSetRelativeLayerWorks) { +TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) { sp<ScreenCapture> sc; + + sp<SurfaceControl> childNoBuffer = + mComposerClient->createSurface(String8("Bufferless child"), 10, 10, + PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); + sp<SurfaceControl> childBuffer = + mComposerClient->createSurface(String8("Buffered child"), 20, 20, + PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get()); + fillSurfaceRGBA8(childBuffer, 200, 200, 200); + + SurfaceComposerClient::Transaction{}.show(childNoBuffer).show(childBuffer).apply(true); + { - SCOPED_TRACE("before adding relative surface"); ScreenCapture::captureScreen(&sc); - sc->expectBGColor(24, 24); - sc->expectFGColor(75, 75); - sc->expectBGColor(145, 145); + sc->expectChildColor(73, 73); + sc->expectFGColor(74, 74); } - auto relativeSurfaceControl = mComposerClient->createSurface( - String8("Test Surface"), 64, 64, PIXEL_FORMAT_RGBA_8888, 0); - fillSurfaceRGBA8(relativeSurfaceControl, 255, 177, 177); - waitForPostedBuffers(); - - // Now we stack the surface above the foreground surface and make sure it is visible. - SurfaceComposerClient::openGlobalTransaction(); - relativeSurfaceControl->setPosition(64, 64); - relativeSurfaceControl->show(); - relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1); - SurfaceComposerClient::closeGlobalTransaction(true); + SurfaceComposerClient::Transaction{}.setSize(childNoBuffer, 20, 20).apply(true); + { + ScreenCapture::captureScreen(&sc); + sc->expectChildColor(73, 73); + sc->expectChildColor(74, 74); + } +} +TEST_F(LayerUpdateTest, MergingTransactions) { + sp<ScreenCapture> sc; { - SCOPED_TRACE("after adding relative surface"); + SCOPED_TRACE("before move"); ScreenCapture::captureScreen(&sc); - // our relative surface should be visible now. - sc->checkPixel(75, 75, 255, 177, 177); + sc->expectBGColor(0, 12); + sc->expectFGColor(75, 75); + sc->expectBGColor(145, 145); } - // A call to setLayer will override a call to setRelativeLayer - SurfaceComposerClient::openGlobalTransaction(); - relativeSurfaceControl->setLayer(0); - SurfaceComposerClient::closeGlobalTransaction(); + Transaction t1, t2; + t1.setPosition(mFGSurfaceControl, 128, 128); + t2.setPosition(mFGSurfaceControl, 0, 0); + // We expect that the position update from t2 now + // overwrites the position update from t1. + t1.merge(std::move(t2)); + t1.apply(); { - SCOPED_TRACE("after set layer"); ScreenCapture::captureScreen(&sc); - // now the FG surface should be visible again. - sc->expectFGColor(75, 75); + sc->expectFGColor(1, 1); } } @@ -792,10 +1791,8 @@ class ChildLayerTest : public LayerUpdateTest { protected: void SetUp() override { LayerUpdateTest::SetUp(); - mChild = mComposerClient->createSurface( - String8("Child surface"), - 10, 10, PIXEL_FORMAT_RGBA_8888, - 0, mFGSurfaceControl.get()); + mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(mChild, 200, 200, 200); { @@ -814,11 +1811,11 @@ protected: }; TEST_F(ChildLayerTest, ChildLayerPositioning) { - SurfaceComposerClient::openGlobalTransaction(); - mChild->show(); - mChild->setPosition(10, 10); - mFGSurfaceControl->setPosition(64, 64); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 10, 10); + t.setPosition(mFGSurfaceControl, 64, 64); + }); { ScreenCapture::captureScreen(&mCapture); @@ -830,9 +1827,7 @@ TEST_F(ChildLayerTest, ChildLayerPositioning) { mCapture->expectFGColor(84, 84); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0)); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); }); { ScreenCapture::captureScreen(&mCapture); @@ -846,12 +1841,12 @@ TEST_F(ChildLayerTest, ChildLayerPositioning) { } TEST_F(ChildLayerTest, ChildLayerCropping) { - SurfaceComposerClient::openGlobalTransaction(); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); - mFGSurfaceControl->setCrop(Rect(0, 0, 5, 5)); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 0, 0); + t.setPosition(mFGSurfaceControl, 0, 0); + t.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5)); + }); { ScreenCapture::captureScreen(&mCapture); @@ -862,12 +1857,12 @@ TEST_F(ChildLayerTest, ChildLayerCropping) { } TEST_F(ChildLayerTest, ChildLayerFinalCropping) { - SurfaceComposerClient::openGlobalTransaction(); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); - mFGSurfaceControl->setFinalCrop(Rect(0, 0, 5, 5)); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 0, 0); + t.setPosition(mFGSurfaceControl, 0, 0); + t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5)); + }); { ScreenCapture::captureScreen(&mCapture); @@ -878,11 +1873,11 @@ TEST_F(ChildLayerTest, ChildLayerFinalCropping) { } TEST_F(ChildLayerTest, ChildLayerConstraints) { - SurfaceComposerClient::openGlobalTransaction(); - mChild->show(); - mFGSurfaceControl->setPosition(0, 0); - mChild->setPosition(63, 63); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mFGSurfaceControl, 0, 0); + t.setPosition(mChild, 63, 63); + }); { ScreenCapture::captureScreen(&mCapture); @@ -896,9 +1891,7 @@ TEST_F(ChildLayerTest, ChildLayerConstraints) { } TEST_F(ChildLayerTest, ChildLayerScaling) { - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setPosition(0, 0); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); }); // Find the boundary between the parent and child { @@ -907,9 +1900,7 @@ TEST_F(ChildLayerTest, ChildLayerScaling) { mCapture->expectFGColor(10, 10); } - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0); }); // The boundary should be twice as far from the origin now. // The pixels from the last test should all be child now @@ -928,11 +1919,11 @@ TEST_F(ChildLayerTest, ChildLayerAlpha) { fillSurfaceRGBA8(mChild, 0, 254, 0); waitForPostedBuffers(); - SurfaceComposerClient::openGlobalTransaction(); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 0, 0); + t.setPosition(mFGSurfaceControl, 0, 0); + }); { ScreenCapture::captureScreen(&mCapture); @@ -940,9 +1931,7 @@ TEST_F(ChildLayerTest, ChildLayerAlpha) { mCapture->checkPixel(0, 0, 0, 254, 0); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5)); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { t.setAlpha(mChild, 0.5); }); { ScreenCapture::captureScreen(&mCapture); @@ -950,9 +1939,7 @@ TEST_F(ChildLayerTest, ChildLayerAlpha) { mCapture->checkPixel(0, 0, 127, 127, 0); } - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5)); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); }); { ScreenCapture::captureScreen(&mCapture); @@ -962,11 +1949,11 @@ TEST_F(ChildLayerTest, ChildLayerAlpha) { } TEST_F(ChildLayerTest, ReparentChildren) { - SurfaceComposerClient::openGlobalTransaction(); - mChild->show(); - mChild->setPosition(10, 10); - mFGSurfaceControl->setPosition(64, 64); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 10, 10); + t.setPosition(mFGSurfaceControl, 64, 64); + }); { ScreenCapture::captureScreen(&mCapture); @@ -977,7 +1964,11 @@ TEST_F(ChildLayerTest, ReparentChildren) { // And 10 more pixels we should be back to the foreground surface mCapture->expectFGColor(84, 84); } - mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle()); + + asTransaction([&](Transaction& t) { + t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle()); + }); + { ScreenCapture::captureScreen(&mCapture); mCapture->expectFGColor(64, 64); @@ -990,12 +1981,54 @@ TEST_F(ChildLayerTest, ReparentChildren) { } } -TEST_F(ChildLayerTest, DetachChildren) { - SurfaceComposerClient::openGlobalTransaction(); - mChild->show(); - mChild->setPosition(10, 10); - mFGSurfaceControl->setPosition(64, 64); - SurfaceComposerClient::closeGlobalTransaction(true); +TEST_F(ChildLayerTest, DetachChildrenSameClient) { + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 10, 10); + t.setPosition(mFGSurfaceControl, 64, 64); + }); + + { + ScreenCapture::captureScreen(&mCapture); + // Top left of foreground must now be visible + mCapture->expectFGColor(64, 64); + // But 10 pixels in we should see the child surface + mCapture->expectChildColor(74, 74); + // And 10 more pixels we should be back to the foreground surface + mCapture->expectFGColor(84, 84); + } + + asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); }); + + asTransaction([&](Transaction& t) { t.hide(mChild); }); + + // Since the child has the same client as the parent, it will not get + // detached and will be hidden. + { + ScreenCapture::captureScreen(&mCapture); + mCapture->expectFGColor(64, 64); + mCapture->expectFGColor(74, 74); + mCapture->expectFGColor(84, 84); + } +} + +TEST_F(ChildLayerTest, DetachChildrenDifferentClient) { + sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient; + sp<SurfaceControl> mChildNewClient = + mNewComposerClient->createSurface(String8("New Child Test Surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); + + ASSERT_TRUE(mChildNewClient != NULL); + ASSERT_TRUE(mChildNewClient->isValid()); + + fillSurfaceRGBA8(mChildNewClient, 200, 200, 200); + + asTransaction([&](Transaction& t) { + t.hide(mChild); + t.show(mChildNewClient); + t.setPosition(mChildNewClient, 10, 10); + t.setPosition(mFGSurfaceControl, 64, 64); + }); { ScreenCapture::captureScreen(&mCapture); @@ -1007,13 +2040,9 @@ TEST_F(ChildLayerTest, DetachChildren) { mCapture->expectFGColor(84, 84); } - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->detachChildren(); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); }); - SurfaceComposerClient::openGlobalTransaction(); - mChild->hide(); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { t.hide(mChildNewClient); }); // Nothing should have changed. { @@ -1025,11 +2054,11 @@ TEST_F(ChildLayerTest, DetachChildren) { } TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) { - SurfaceComposerClient::openGlobalTransaction(); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 0, 0); + t.setPosition(mFGSurfaceControl, 0, 0); + }); { ScreenCapture::captureScreen(&mCapture); @@ -1039,11 +2068,11 @@ TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) { mCapture->expectFGColor(10, 10); } - SurfaceComposerClient::openGlobalTransaction(); - mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - // We cause scaling by 2. - mFGSurfaceControl->setSize(128, 128); - SurfaceComposerClient::closeGlobalTransaction(); + asTransaction([&](Transaction& t) { + t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + // We cause scaling by 2. + t.setSize(mFGSurfaceControl, 128, 128); + }); { ScreenCapture::captureScreen(&mCapture); @@ -1058,11 +2087,11 @@ TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) { // Regression test for b/37673612 TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { - SurfaceComposerClient::openGlobalTransaction(); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 0, 0); + t.setPosition(mFGSurfaceControl, 0, 0); + }); { ScreenCapture::captureScreen(&mCapture); @@ -1071,11 +2100,9 @@ TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { // But it's only 10x10. mCapture->expectFGColor(10, 10); } - - // We set things up as in b/37673612 so that there is a mismatch between the buffer size and // the WM specified state size. - mFGSurfaceControl->setSize(128, 64); + asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); }); sp<Surface> s = mFGSurfaceControl->getSurface(); auto anw = static_cast<ANativeWindow*>(s.get()); native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); @@ -1102,11 +2129,11 @@ TEST_F(ChildLayerTest, Bug36858924) { mFGSurfaceControl.get()); // Show the child layer in a deferred transaction - SurfaceComposerClient::openGlobalTransaction(); - mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(), - mFGSurfaceControl->getSurface()->getNextFrameNumber()); - mChild->show(); - SurfaceComposerClient::closeGlobalTransaction(true); + asTransaction([&](Transaction& t) { + t.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(), + mFGSurfaceControl->getSurface()->getNextFrameNumber()); + t.show(mChild); + }); // Render the foreground surface a few times // @@ -1123,4 +2150,314 @@ TEST_F(ChildLayerTest, Bug36858924) { fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0); } +TEST_F(ChildLayerTest, Reparent) { + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 10, 10); + t.setPosition(mFGSurfaceControl, 64, 64); + }); + + { + ScreenCapture::captureScreen(&mCapture); + // Top left of foreground must now be visible + mCapture->expectFGColor(64, 64); + // But 10 pixels in we should see the child surface + mCapture->expectChildColor(74, 74); + // And 10 more pixels we should be back to the foreground surface + mCapture->expectFGColor(84, 84); + } + + asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); }); + + { + ScreenCapture::captureScreen(&mCapture); + mCapture->expectFGColor(64, 64); + // In reparenting we should have exposed the entire foreground surface. + mCapture->expectFGColor(74, 74); + // And the child layer should now begin at 10, 10 (since the BG + // layer is at (0, 0)). + mCapture->expectBGColor(9, 9); + mCapture->expectChildColor(10, 10); + } +} + +TEST_F(ChildLayerTest, ReparentToNoParent) { + asTransaction([&](Transaction& t) { + t.show(mChild); + t.setPosition(mChild, 10, 10); + t.setPosition(mFGSurfaceControl, 64, 64); + }); + + { + ScreenCapture::captureScreen(&mCapture); + // Top left of foreground must now be visible + mCapture->expectFGColor(64, 64); + // But 10 pixels in we should see the child surface + mCapture->expectChildColor(74, 74); + // And 10 more pixels we should be back to the foreground surface + mCapture->expectFGColor(84, 84); + } + asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); }); + { + ScreenCapture::captureScreen(&mCapture); + // Nothing should have changed. + mCapture->expectFGColor(64, 64); + mCapture->expectChildColor(74, 74); + mCapture->expectFGColor(84, 84); + } +} + +TEST_F(ChildLayerTest, ReparentFromNoParent) { + sp<SurfaceControl> newSurface = mComposerClient->createSurface(String8("New Surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(newSurface != NULL); + ASSERT_TRUE(newSurface->isValid()); + + fillSurfaceRGBA8(newSurface, 63, 195, 63); + asTransaction([&](Transaction& t) { + t.hide(mChild); + t.show(newSurface); + t.setPosition(newSurface, 10, 10); + t.setLayer(newSurface, INT32_MAX - 2); + t.setPosition(mFGSurfaceControl, 64, 64); + }); + + { + ScreenCapture::captureScreen(&mCapture); + // Top left of foreground must now be visible + mCapture->expectFGColor(64, 64); + // At 10, 10 we should see the new surface + mCapture->checkPixel(10, 10, 63, 195, 63); + } + + asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); }); + + { + ScreenCapture::captureScreen(&mCapture); + // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from + // mFGSurface, putting it at 74, 74. + mCapture->expectFGColor(64, 64); + mCapture->checkPixel(74, 74, 63, 195, 63); + mCapture->expectFGColor(84, 84); + } +} + +TEST_F(ChildLayerTest, NestedChildren) { + sp<SurfaceControl> grandchild = + mComposerClient->createSurface(String8("Grandchild surface"), 10, 10, + PIXEL_FORMAT_RGBA_8888, 0, mChild.get()); + fillSurfaceRGBA8(grandchild, 50, 50, 50); + + { + ScreenCapture::captureScreen(&mCapture); + // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer + // which begins at 64, 64 + mCapture->checkPixel(64, 64, 50, 50, 50); + } +} + +TEST_F(ChildLayerTest, ChildLayerRelativeLayer) { + sp<SurfaceControl> relative = mComposerClient->createSurface(String8("Relative surface"), 128, + 128, PIXEL_FORMAT_RGBA_8888, 0); + fillSurfaceRGBA8(relative, 255, 255, 255); + + Transaction t; + t.setLayer(relative, INT32_MAX) + .setRelativeLayer(mChild, relative->getHandle(), 1) + .setPosition(mFGSurfaceControl, 0, 0) + .apply(true); + + // We expect that the child should have been elevated above our + // INT_MAX layer even though it's not a child of it. + { + ScreenCapture::captureScreen(&mCapture); + mCapture->expectChildColor(0, 0); + mCapture->expectChildColor(9, 9); + mCapture->checkPixel(10, 10, 255, 255, 255); + } +} + +class ScreenCaptureTest : public LayerUpdateTest { +protected: + std::unique_ptr<ScreenCapture> mCapture; +}; + +TEST_F(ScreenCaptureTest, CaptureSingleLayer) { + auto bgHandle = mBGSurfaceControl->getHandle(); + ScreenCapture::captureLayers(&mCapture, bgHandle); + mCapture->expectBGColor(0, 0); + // Doesn't capture FG layer which is at 64, 64 + mCapture->expectBGColor(64, 64); +} + +TEST_F(ScreenCaptureTest, CaptureLayerWithChild) { + auto fgHandle = mFGSurfaceControl->getHandle(); + + sp<SurfaceControl> child = + mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + 0, mFGSurfaceControl.get()); + fillSurfaceRGBA8(child, 200, 200, 200); + + SurfaceComposerClient::Transaction().show(child).apply(true); + + // Captures mFGSurfaceControl layer and its child. + ScreenCapture::captureLayers(&mCapture, fgHandle); + mCapture->expectFGColor(10, 10); + mCapture->expectChildColor(0, 0); +} + +TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) { + auto fgHandle = mFGSurfaceControl->getHandle(); + + sp<SurfaceControl> child = + mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + 0, mFGSurfaceControl.get()); + fillSurfaceRGBA8(child, 200, 200, 200); + + sp<SurfaceControl> grandchild = + mComposerClient->createSurface(String8("Grandchild surface"), 5, 5, + PIXEL_FORMAT_RGBA_8888, 0, child.get()); + + fillSurfaceRGBA8(grandchild, 50, 50, 50); + SurfaceComposerClient::Transaction() + .show(child) + .setPosition(grandchild, 5, 5) + .show(grandchild) + .apply(true); + + // Captures mFGSurfaceControl, its child, and the grandchild. + ScreenCapture::captureLayers(&mCapture, fgHandle); + mCapture->expectFGColor(10, 10); + mCapture->expectChildColor(0, 0); + mCapture->checkPixel(5, 5, 50, 50, 50); } + +TEST_F(ScreenCaptureTest, CaptureChildOnly) { + sp<SurfaceControl> child = + mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + 0, mFGSurfaceControl.get()); + fillSurfaceRGBA8(child, 200, 200, 200); + auto childHandle = child->getHandle(); + + SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true); + + // Captures only the child layer, and not the parent. + ScreenCapture::captureLayers(&mCapture, childHandle); + mCapture->expectChildColor(0, 0); + mCapture->expectChildColor(9, 9); +} + +TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) { + sp<SurfaceControl> child = + mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + 0, mFGSurfaceControl.get()); + fillSurfaceRGBA8(child, 200, 200, 200); + auto childHandle = child->getHandle(); + + sp<SurfaceControl> grandchild = + mComposerClient->createSurface(String8("Grandchild surface"), 5, 5, + PIXEL_FORMAT_RGBA_8888, 0, child.get()); + fillSurfaceRGBA8(grandchild, 50, 50, 50); + + SurfaceComposerClient::Transaction() + .show(child) + .setPosition(grandchild, 5, 5) + .show(grandchild) + .apply(true); + + auto grandchildHandle = grandchild->getHandle(); + + // Captures only the grandchild. + ScreenCapture::captureLayers(&mCapture, grandchildHandle); + mCapture->checkPixel(0, 0, 50, 50, 50); + mCapture->checkPixel(4, 4, 50, 50, 50); +} + +TEST_F(ScreenCaptureTest, CaptureCrop) { + sp<SurfaceControl> redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60, + PIXEL_FORMAT_RGBA_8888, 0); + sp<SurfaceControl> blueLayer = + mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888, + 0, redLayer.get()); + + ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(blueLayer, Color::BLUE)); + + SurfaceComposerClient::Transaction() + .setLayer(redLayer, INT32_MAX - 1) + .show(redLayer) + .show(blueLayer) + .apply(true); + + auto redLayerHandle = redLayer->getHandle(); + + // Capturing full screen should have both red and blue are visible. + ScreenCapture::captureLayers(&mCapture, redLayerHandle); + mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE); + // red area below the blue area + mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED); + // red area to the right of the blue area + mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED); + + Rect crop = Rect(0, 0, 30, 30); + ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop); + // Capturing the cropped screen, cropping out the shown red area, should leave only the blue + // area visible. + mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE); + mCapture->checkPixel(30, 30, 0, 0, 0); +} + +TEST_F(ScreenCaptureTest, CaptureSize) { + sp<SurfaceControl> redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60, + PIXEL_FORMAT_RGBA_8888, 0); + sp<SurfaceControl> blueLayer = + mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888, + 0, redLayer.get()); + + ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(blueLayer, Color::BLUE)); + + SurfaceComposerClient::Transaction() + .setLayer(redLayer, INT32_MAX - 1) + .show(redLayer) + .show(blueLayer) + .apply(true); + + auto redLayerHandle = redLayer->getHandle(); + + // Capturing full screen should have both red and blue are visible. + ScreenCapture::captureLayers(&mCapture, redLayerHandle); + mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE); + // red area below the blue area + mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED); + // red area to the right of the blue area + mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED); + + ScreenCapture::captureLayers(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5); + // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area. + mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE); + // red area below the blue area + mCapture->expectColor(Rect(0, 15, 29, 29), Color::RED); + // red area to the right of the blue area + mCapture->expectColor(Rect(15, 0, 29, 29), Color::RED); + mCapture->checkPixel(30, 30, 0, 0, 0); +} + +TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { + sp<SurfaceControl> redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60, + PIXEL_FORMAT_RGBA_8888, 0); + + ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED)); + + auto redLayerHandle = redLayer->getHandle(); + mComposerClient->destroySurface(redLayerHandle); + SurfaceComposerClient::Transaction().apply(true); + + sp<GraphicBuffer> outBuffer; + + // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0)); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp index 94f3f2561a..47c4f4abb7 100644 --- a/services/surfaceflinger/tests/fakehwc/Android.bp +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -22,7 +22,8 @@ cc_test { "libsync", "libfmq", "libbase", - "libhidltransport" + "libhidltransport", + "liblayers_proto" ], static_libs: [ "libhwcomposer-client", @@ -30,6 +31,9 @@ cc_test { "libtrace_proto", "libgmock" ], + cppflags: [ + "-std=c++1z", + ], tags: ["tests"], test_suites: ["device-tests"] }
\ No newline at end of file diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp index 07b8cc0b0d..cb22932fbf 100644 --- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp @@ -36,7 +36,6 @@ #include <thread> constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0); -constexpr Display DEFAULT_DISPLAY = static_cast<Display>(1); using namespace sftest; @@ -172,7 +171,7 @@ void FakeComposerClient::enableCallback(bool enable) { ALOGV("enableCallback"); mCallbacksOn = enable; if (mCallbacksOn) { - mClient->onHotplug(DEFAULT_DISPLAY, IComposerCallback::Connection::CONNECTED); + mClient->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED); } } @@ -511,7 +510,7 @@ void FakeComposerClient::requestVSync(uint64_t vsyncTime) { if (mSurfaceComposer != nullptr) { mSurfaceComposer->injectVSync(timestamp); } else { - mClient->onVsync(DEFAULT_DISPLAY, timestamp); + mClient->onVsync(PRIMARY_DISPLAY, timestamp); } } } diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h index dd384c0829..de8cffdba6 100644 --- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h @@ -16,9 +16,16 @@ #pragma once +#define HWC2_USE_CPP11 +#define HWC2_INCLUDE_STRINGIFICATION #include "ComposerClient.h" +#undef HWC2_USE_CPP11 +#undef HWC2_INCLUDE_STRINGIFICATION #include "RenderState.h" +// Needed for display type/ID enums +#include <hardware/hwcomposer_defs.h> + #include <utils/Condition.h> #include <chrono> @@ -40,6 +47,13 @@ class SurfaceComposerClient; namespace sftest { +// NOTE: The ID's need to be exactly these. VR composer and parts of +// the SurfaceFlinger assume the display IDs to have these values +// despite the enum being documented as a display type. +// TODO: Reference to actual documentation +constexpr Display PRIMARY_DISPLAY = static_cast<Display>(HWC_DISPLAY_PRIMARY); +constexpr Display EXTERNAL_DISPLAY = static_cast<Display>(HWC_DISPLAY_EXTERNAL); + class FakeComposerClient : public ComposerBase { public: FakeComposerClient(); diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h index 74dc0e51bb..1258a970c7 100644 --- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h @@ -87,7 +87,7 @@ public: /* * All surface state changes are supposed to happen inside a global - * transaction. GlobalTransactionScope object at the beginning of + * transaction. TransactionScope object at the beginning of * scope automates the process. The resulting scope gives a visual cue * on the span of the transaction as well. * @@ -96,23 +96,26 @@ public: * is built to explicitly request vsyncs one at the time. A delayed * request must be made before closing the transaction or the test * thread stalls until SurfaceFlinger does an emergency vsync by - * itself. GlobalTransactionScope encapsulates this vsync magic. + * itself. TransactionScope encapsulates this vsync magic. */ -class GlobalTransactionScope { +class TransactionScope : public android::SurfaceComposerClient::Transaction { public: - GlobalTransactionScope(FakeComposerClient& composer) : mComposer(composer) { - android::SurfaceComposerClient::openGlobalTransaction(); + TransactionScope(FakeComposerClient& composer) : + Transaction(), + mComposer(composer) { } - ~GlobalTransactionScope() { + + ~TransactionScope() { int frameCount = mComposer.getFrameCount(); mComposer.runVSyncAfter(1ms); - android::SurfaceComposerClient::closeGlobalTransaction(true); + LOG_ALWAYS_FATAL_IF(android::NO_ERROR != apply()); // Make sure that exactly one frame has been rendered. mComposer.waitUntilFrame(frameCount + 1); LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(), "Unexpected frame advance. Delta: %d", mComposer.getFrameCount() - frameCount); } + FakeComposerClient& mComposer; }; diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index 68fefea135..8a97ea4a4b 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -24,11 +24,11 @@ #include <gui/ISurfaceComposer.h> #include <gui/LayerDebugInfo.h> +#include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> -#include <private/gui/LayerState.h> #include <ui/DisplayInfo.h> @@ -62,6 +62,8 @@ using ::testing::Return; using ::testing::SetArgPointee; using ::testing::_; +using Transaction = SurfaceComposerClient::Transaction; + /////////////////////////////////////////////// struct TestColor { @@ -168,17 +170,15 @@ void DisplayTest::SetUp() { android::hardware::ProcessState::self()->startThreadPool(); android::ProcessState::self()->startThreadPool(); - EXPECT_CALL(*mMockComposer, getDisplayType(1, _)) + EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _)) .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), Return(Error::NONE))); - // Seems to be doubled right now, once for display ID 1 and once for 0. This sounds fishy - // but encoding that here exactly. - EXPECT_CALL(*mMockComposer, getDisplayAttribute(1, 1, _, _)) - .Times(5) - .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); - // TODO: Find out what code is generating the ID 0. - EXPECT_CALL(*mMockComposer, getDisplayAttribute(0, 1, _, _)) - .Times(5) + // Primary display will be queried twice for all 5 attributes. One + // set of queries comes from the SurfaceFlinger proper an the + // other set from the VR composer. + // TODO: Is VR composer always present? Change to atLeast(5)? + EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _)) + .Times(2 * 5) .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); startSurfaceFlinger(); @@ -207,31 +207,32 @@ void DisplayTest::TearDown() { TEST_F(DisplayTest, Hotplug) { ALOGD("DisplayTest::Hotplug"); - EXPECT_CALL(*mMockComposer, getDisplayType(2, _)) + EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _)) .Times(2) .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL), Return(Error::NONE))); // The attribute queries will get done twice. This is for defaults - EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, _, _)) + EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _)) .Times(2 * 3) .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake)); // ... and then special handling for dimensions. Specifying this // rules later means that gmock will try them first, i.e., // ordering of width/height vs. the default implementation for // other queries is significant. - EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::WIDTH, _)) + EXPECT_CALL(*mMockComposer, + getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _)) .Times(2) .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE))); - EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::HEIGHT, _)) + EXPECT_CALL(*mMockComposer, + getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _)) .Times(2) .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE))); // TODO: Width and height queries are not actually called. Display // info returns dimensions 0x0 in display info. Why? - mMockComposer->hotplugDisplay(static_cast<Display>(2), - IComposerCallback::Connection::CONNECTED); + mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED); { sp<android::IBinder> display( @@ -249,21 +250,19 @@ TEST_F(DisplayTest, Hotplug) { fillSurfaceRGBA8(surfaceControl, BLUE); { - GlobalTransactionScope gts(*mMockComposer); - mComposerClient->setDisplayLayerStack(display, 0); + TransactionScope ts(*mMockComposer); + ts.setDisplayLayerStack(display, 0); - ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2)); - ASSERT_EQ(NO_ERROR, surfaceControl->show()); + ts.setLayer(surfaceControl, INT32_MAX - 2) + .show(surfaceControl); } } - mMockComposer->hotplugDisplay(static_cast<Display>(2), - IComposerCallback::Connection::DISCONNECTED); + mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED); mMockComposer->clearFrames(); - mMockComposer->hotplugDisplay(static_cast<Display>(2), - IComposerCallback::Connection::CONNECTED); + mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED); { sp<android::IBinder> display( @@ -281,15 +280,14 @@ TEST_F(DisplayTest, Hotplug) { fillSurfaceRGBA8(surfaceControl, BLUE); { - GlobalTransactionScope gts(*mMockComposer); - mComposerClient->setDisplayLayerStack(display, 0); + TransactionScope ts(*mMockComposer); + ts.setDisplayLayerStack(display, 0); - ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2)); - ASSERT_EQ(NO_ERROR, surfaceControl->show()); + ts.setLayer(surfaceControl, INT32_MAX - 2) + .show(surfaceControl); } } - mMockComposer->hotplugDisplay(static_cast<Display>(2), - IComposerCallback::Connection::DISCONNECTED); + mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED); } //////////////////////////////////////////////// @@ -374,25 +372,24 @@ void TransactionTest::SetUp() { fillSurfaceRGBA8(mFGSurfaceControl, RED); - SurfaceComposerClient::openGlobalTransaction(); - - mComposerClient->setDisplayLayerStack(display, 0); + Transaction t; + t.setDisplayLayerStack(display, 0); - ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX - 2)); - ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show()); + t.setLayer(mBGSurfaceControl, INT32_MAX - 2); + t.show(mBGSurfaceControl); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX - 1)); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64)); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + t.setLayer(mFGSurfaceControl, INT32_MAX - 1); + t.setPosition(mFGSurfaceControl, 64, 64); + t.show(mFGSurfaceControl); // Synchronous transaction will stop this thread, so we set up a // delayed, off-thread vsync request before closing the // transaction. In the test code this is usually done with - // GlobalTransactionScope. Leaving here in the 'vanilla' form for + // TransactionScope. Leaving here in the 'vanilla' form for // reference. ASSERT_EQ(0, sFakeComposer->getFrameCount()); sFakeComposer->runVSyncAfter(1ms); - SurfaceComposerClient::closeGlobalTransaction(true); + t.apply(); sFakeComposer->waitUntilFrame(1); // Reference data. This is what the HWC should see. @@ -449,8 +446,8 @@ TEST_F(TransactionTest, LayerMove) { // should be available in the latest frame stored by the fake // composer. { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); + TransactionScope ts(*sFakeComposer); + ts.setPosition(mFGSurfaceControl, 128, 128); // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls. // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?) // @@ -477,8 +474,8 @@ TEST_F(TransactionTest, LayerMove) { TEST_F(TransactionTest, LayerResize) { ALOGD("TransactionTest::LayerResize"); { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128)); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 128, 128); } fillSurfaceRGBA8(mFGSurfaceControl, GREEN); @@ -501,9 +498,9 @@ TEST_F(TransactionTest, LayerResize) { TEST_F(TransactionTest, LayerCrop) { // TODO: Add scaling to confirm that crop happens in buffer space? { - GlobalTransactionScope gts(*sFakeComposer); + TransactionScope ts(*sFakeComposer); Rect cropRect(16, 16, 32, 32); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect)); + ts.setCrop(mFGSurfaceControl, cropRect); } ASSERT_EQ(2, sFakeComposer->getFrameCount()); @@ -516,9 +513,9 @@ TEST_F(TransactionTest, LayerCrop) { TEST_F(TransactionTest, LayerFinalCrop) { // TODO: Add scaling to confirm that crop happens in display space? { - GlobalTransactionScope gts(*sFakeComposer); + TransactionScope ts(*sFakeComposer); Rect cropRect(32, 32, 32 + 64, 32 + 64); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); + ts.setFinalCrop(mFGSurfaceControl, cropRect); } ASSERT_EQ(2, sFakeComposer->getFrameCount()); @@ -534,9 +531,9 @@ TEST_F(TransactionTest, LayerFinalCrop) { TEST_F(TransactionTest, LayerFinalCropEmpty) { // TODO: Add scaling to confirm that crop happens in display space? { - GlobalTransactionScope gts(*sFakeComposer); + TransactionScope ts(*sFakeComposer); Rect cropRect(16, 16, 32, 32); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); + ts.setFinalCrop(mFGSurfaceControl, cropRect); } ASSERT_EQ(2, sFakeComposer->getFrameCount()); @@ -549,8 +546,8 @@ TEST_F(TransactionTest, LayerFinalCropEmpty) { TEST_F(TransactionTest, LayerSetLayer) { { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); + TransactionScope ts(*sFakeComposer); + ts.setLayer(mFGSurfaceControl, INT_MAX - 3); } ASSERT_EQ(2, sFakeComposer->getFrameCount()); @@ -564,11 +561,10 @@ TEST_F(TransactionTest, LayerSetLayer) { TEST_F(TransactionTest, LayerSetLayerOpaque) { { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); - ASSERT_EQ(NO_ERROR, - mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque, - layer_state_t::eLayerOpaque)); + TransactionScope ts(*sFakeComposer); + ts.setLayer(mFGSurfaceControl, INT_MAX - 3); + ts.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque, + layer_state_t::eLayerOpaque); } ASSERT_EQ(2, sFakeComposer->getFrameCount()); @@ -581,8 +577,8 @@ TEST_F(TransactionTest, LayerSetLayerOpaque) { TEST_F(TransactionTest, SetLayerStack) { ALOGD("TransactionTest::SetLayerStack"); { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1)); + TransactionScope ts(*sFakeComposer); + ts.setLayerStack(mFGSurfaceControl, 1); } // Foreground layer should have disappeared. @@ -595,8 +591,8 @@ TEST_F(TransactionTest, SetLayerStack) { TEST_F(TransactionTest, LayerShowHide) { ALOGD("TransactionTest::LayerShowHide"); { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide()); + TransactionScope ts(*sFakeComposer); + ts.hide(mFGSurfaceControl); } // Foreground layer should have disappeared. @@ -606,8 +602,8 @@ TEST_F(TransactionTest, LayerShowHide) { EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame())); { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + TransactionScope ts(*sFakeComposer); + ts.show(mFGSurfaceControl); } // Foreground layer should be back @@ -617,8 +613,8 @@ TEST_F(TransactionTest, LayerShowHide) { TEST_F(TransactionTest, LayerSetAlpha) { { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f)); + TransactionScope ts(*sFakeComposer); + ts.setAlpha(mFGSurfaceControl, 0.75f); } ASSERT_EQ(2, sFakeComposer->getFrameCount()); @@ -629,10 +625,9 @@ TEST_F(TransactionTest, LayerSetAlpha) { TEST_F(TransactionTest, LayerSetFlags) { { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, - mFGSurfaceControl->setFlags(layer_state_t::eLayerHidden, - layer_state_t::eLayerHidden)); + TransactionScope ts(*sFakeComposer); + ts.setFlags(mFGSurfaceControl, layer_state_t::eLayerHidden, + layer_state_t::eLayerHidden); } // Foreground layer should have disappeared. @@ -664,17 +659,16 @@ TEST_F(TransactionTest, LayerSetMatrix) { {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_H_ROT_90, {64, 64, 128, 128}}, {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_V_ROT_90, {64, 64, 128, 128}}}; // clang-format on - constexpr int TEST_COUNT = sizeof(MATRIX_TESTS)/sizeof(matrixTestData); + constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData); for (int i = 0; i < TEST_COUNT; i++) { // TODO: How to leverage the HWC2 stringifiers? const matrixTestData& xform = MATRIX_TESTS[i]; SCOPED_TRACE(i); { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, - mFGSurfaceControl->setMatrix(xform.matrix[0], xform.matrix[1], - xform.matrix[2], xform.matrix[3])); + TransactionScope ts(*sFakeComposer); + ts.setMatrix(mFGSurfaceControl, xform.matrix[0], xform.matrix[1], + xform.matrix[2], xform.matrix[3]); } auto referenceFrame = mBaseFrame; @@ -688,10 +682,10 @@ TEST_F(TransactionTest, LayerSetMatrix) { #if 0 TEST_F(TransactionTest, LayerSetMatrix2) { { - GlobalTransactionScope gts(*sFakeComposer); + TransactionScope ts(*sFakeComposer); // TODO: PLEASE SPEC THE FUNCTION! - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(0.11f, 0.123f, - -2.33f, 0.22f)); + ts.setMatrix(mFGSurfaceControl, 0.11f, 0.123f, + -2.33f, 0.22f); } auto referenceFrame = mBaseFrame; // TODO: Is this correct for sure? @@ -712,10 +706,10 @@ TEST_F(TransactionTest, DeferredTransaction) { fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, syncSurfaceControl->setLayer(INT32_MAX - 1)); - ASSERT_EQ(NO_ERROR, syncSurfaceControl->setPosition(mDisplayWidth - 2, mDisplayHeight - 2)); - ASSERT_EQ(NO_ERROR, syncSurfaceControl->show()); + TransactionScope ts(*sFakeComposer); + ts.setLayer(syncSurfaceControl, INT32_MAX - 1); + ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2); + ts.show(syncSurfaceControl); } auto referenceFrame = mBaseFrame; referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2, @@ -727,20 +721,20 @@ TEST_F(TransactionTest, DeferredTransaction) { // set up two deferred transactions on different frames - these should not yield composited // frames { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75)); - mFGSurfaceControl - ->deferTransactionUntil(syncSurfaceControl->getHandle(), - syncSurfaceControl->getSurface()->getNextFrameNumber()); + TransactionScope ts(*sFakeComposer); + ts.setAlpha(mFGSurfaceControl, 0.75); + ts.deferTransactionUntil(mFGSurfaceControl, + syncSurfaceControl->getHandle(), + syncSurfaceControl->getSurface()->getNextFrameNumber()); } EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); - mFGSurfaceControl - ->deferTransactionUntil(syncSurfaceControl->getHandle(), - syncSurfaceControl->getSurface()->getNextFrameNumber() + 1); + TransactionScope ts(*sFakeComposer); + ts.setPosition(mFGSurfaceControl, 128, 128); + ts.deferTransactionUntil(mFGSurfaceControl, + syncSurfaceControl->getHandle(), + syncSurfaceControl->getSurface()->getNextFrameNumber() + 1); } EXPECT_EQ(4, sFakeComposer->getFrameCount()); EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); @@ -756,8 +750,8 @@ TEST_F(TransactionTest, DeferredTransaction) { // should show up immediately since it's not deferred { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0)); + TransactionScope ts(*sFakeComposer); + ts.setAlpha(mFGSurfaceControl, 1.0); } referenceFrame[FG_LAYER].mPlaneAlpha = 1.f; EXPECT_EQ(6, sFakeComposer->getFrameCount()); @@ -781,10 +775,10 @@ TEST_F(TransactionTest, SetRelativeLayer) { // Now we stack the surface above the foreground surface and make sure it is visible. { - GlobalTransactionScope gts(*sFakeComposer); - relativeSurfaceControl->setPosition(64, 64); - relativeSurfaceControl->show(); - relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1); + TransactionScope ts(*sFakeComposer); + ts.setPosition(relativeSurfaceControl, 64, 64); + ts.show(relativeSurfaceControl); + ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1); } auto referenceFrame = mBaseFrame; // NOTE: All three layers will be visible as the surfaces are @@ -795,8 +789,8 @@ TEST_F(TransactionTest, SetRelativeLayer) { // A call to setLayer will override a call to setRelativeLayer { - GlobalTransactionScope gts(*sFakeComposer); - relativeSurfaceControl->setLayer(0); + TransactionScope ts(*sFakeComposer); + ts.setLayer(relativeSurfaceControl, 0); } // Previous top layer will now appear at the bottom. @@ -832,11 +826,11 @@ protected: TEST_F(ChildLayerTest, Positioning) { { - GlobalTransactionScope gts(*sFakeComposer); - mChild->show(); - mChild->setPosition(10, 10); + TransactionScope ts(*sFakeComposer); + ts.show(mChild); + ts.setPosition(mChild, 10, 10); // Move to the same position as in the original setup. - mFGSurfaceControl->setPosition(64, 64); + ts.setPosition(mFGSurfaceControl, 64, 64); } auto referenceFrame = mBaseFrame; @@ -846,8 +840,8 @@ TEST_F(ChildLayerTest, Positioning) { EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0)); + TransactionScope ts(*sFakeComposer); + ts.setPosition(mFGSurfaceControl, 0, 0); } auto referenceFrame2 = mBaseFrame; @@ -859,11 +853,11 @@ TEST_F(ChildLayerTest, Positioning) { TEST_F(ChildLayerTest, Cropping) { { - GlobalTransactionScope gts(*sFakeComposer); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); - mFGSurfaceControl->setCrop(Rect(0, 0, 5, 5)); + TransactionScope ts(*sFakeComposer); + ts.show(mChild); + ts.setPosition(mChild, 0, 0); + ts.setPosition(mFGSurfaceControl, 0, 0); + ts.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5)); } // NOTE: The foreground surface would be occluded by the child // now, but is included in the stack because the child is @@ -878,11 +872,11 @@ TEST_F(ChildLayerTest, Cropping) { TEST_F(ChildLayerTest, FinalCropping) { { - GlobalTransactionScope gts(*sFakeComposer); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); - mFGSurfaceControl->setFinalCrop(Rect(0, 0, 5, 5)); + TransactionScope ts(*sFakeComposer); + ts.show(mChild); + ts.setPosition(mChild, 0, 0); + ts.setPosition(mFGSurfaceControl, 0, 0); + ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5)); } auto referenceFrame = mBaseFrame; referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5}; @@ -894,10 +888,10 @@ TEST_F(ChildLayerTest, FinalCropping) { TEST_F(ChildLayerTest, Constraints) { { - GlobalTransactionScope gts(*sFakeComposer); - mChild->show(); - mFGSurfaceControl->setPosition(0, 0); - mChild->setPosition(63, 63); + TransactionScope ts(*sFakeComposer); + ts.show(mChild); + ts.setPosition(mFGSurfaceControl, 0, 0); + ts.setPosition(mChild, 63, 63); } auto referenceFrame = mBaseFrame; referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; @@ -908,8 +902,8 @@ TEST_F(ChildLayerTest, Constraints) { TEST_F(ChildLayerTest, Scaling) { { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setPosition(0, 0); + TransactionScope ts(*sFakeComposer); + ts.setPosition(mFGSurfaceControl, 0, 0); } auto referenceFrame = mBaseFrame; referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64}; @@ -917,8 +911,8 @@ TEST_F(ChildLayerTest, Scaling) { EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0); + TransactionScope ts(*sFakeComposer); + ts.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0); } auto referenceFrame2 = mBaseFrame; @@ -929,11 +923,11 @@ TEST_F(ChildLayerTest, Scaling) { TEST_F(ChildLayerTest, LayerAlpha) { { - GlobalTransactionScope gts(*sFakeComposer); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); - ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5)); + TransactionScope ts(*sFakeComposer); + ts.show(mChild); + ts.setPosition(mChild, 0, 0); + ts.setPosition(mFGSurfaceControl, 0, 0); + ts.setAlpha(mChild, 0.5); } auto referenceFrame = mBaseFrame; @@ -943,8 +937,8 @@ TEST_F(ChildLayerTest, LayerAlpha) { EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); { - GlobalTransactionScope gts(*sFakeComposer); - ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5)); + TransactionScope ts(*sFakeComposer); + ts.setAlpha(mFGSurfaceControl, 0.5); } auto referenceFrame2 = referenceFrame; @@ -955,10 +949,10 @@ TEST_F(ChildLayerTest, LayerAlpha) { TEST_F(ChildLayerTest, ReparentChildren) { { - GlobalTransactionScope gts(*sFakeComposer); - mChild->show(); - mChild->setPosition(10, 10); - mFGSurfaceControl->setPosition(64, 64); + TransactionScope ts(*sFakeComposer); + ts.show(mChild); + ts.setPosition(mChild, 10, 10); + ts.setPosition(mFGSurfaceControl, 64, 64); } auto referenceFrame = mBaseFrame; referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; @@ -967,8 +961,8 @@ TEST_F(ChildLayerTest, ReparentChildren) { EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle()); + TransactionScope ts(*sFakeComposer); + ts.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle()); } auto referenceFrame2 = referenceFrame; @@ -979,10 +973,10 @@ TEST_F(ChildLayerTest, ReparentChildren) { TEST_F(ChildLayerTest, DetachChildren) { { - GlobalTransactionScope gts(*sFakeComposer); - mChild->show(); - mChild->setPosition(10, 10); - mFGSurfaceControl->setPosition(64, 64); + TransactionScope ts(*sFakeComposer); + ts.show(mChild); + ts.setPosition(mChild, 10, 10); + ts.setPosition(mFGSurfaceControl, 64, 64); } auto referenceFrame = mBaseFrame; @@ -992,13 +986,13 @@ TEST_F(ChildLayerTest, DetachChildren) { EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->detachChildren(); + TransactionScope ts(*sFakeComposer); + ts.detachChildren(mFGSurfaceControl); } { - GlobalTransactionScope gts(*sFakeComposer); - mChild->hide(); + TransactionScope ts(*sFakeComposer); + ts.hide(mChild); } // Nothing should have changed. The child control becomes a no-op @@ -1009,17 +1003,17 @@ TEST_F(ChildLayerTest, DetachChildren) { TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) { { - GlobalTransactionScope gts(*sFakeComposer); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); + TransactionScope ts(*sFakeComposer); + ts.show(mChild); + ts.setPosition(mChild, 0, 0); + ts.setPosition(mFGSurfaceControl, 0, 0); } { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + TransactionScope ts(*sFakeComposer); + ts.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); // We cause scaling by 2. - mFGSurfaceControl->setSize(128, 128); + ts.setSize(mFGSurfaceControl, 128, 128); } auto referenceFrame = mBaseFrame; @@ -1033,17 +1027,17 @@ TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) { // Regression test for b/37673612 TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { { - GlobalTransactionScope gts(*sFakeComposer); - mChild->show(); - mChild->setPosition(0, 0); - mFGSurfaceControl->setPosition(0, 0); + TransactionScope ts(*sFakeComposer); + ts.show(mChild); + ts.setPosition(mChild, 0, 0); + ts.setPosition(mFGSurfaceControl, 0, 0); } // We set things up as in b/37673612 so that there is a mismatch between the buffer size and // the WM specified state size. { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(128, 64); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 128, 64); } sp<Surface> s = mFGSurfaceControl->getSurface(); @@ -1074,10 +1068,10 @@ TEST_F(ChildLayerTest, Bug36858924) { // Show the child layer in a deferred transaction { - GlobalTransactionScope gts(*sFakeComposer); - mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(), + TransactionScope ts(*sFakeComposer); + ts.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(), mFGSurfaceControl->getSurface()->getNextFrameNumber()); - mChild->show(); + ts.show(mChild); } // Render the foreground surface a few times @@ -1114,11 +1108,11 @@ protected: sFakeComposer->runVSyncAndWait(); } void restoreInitialState() { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(64, 64); - mFGSurfaceControl->setPosition(64, 64); - mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64)); - mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 64, 64); + ts.setPosition(mFGSurfaceControl, 64, 64); + ts.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64)); + ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1)); } }; @@ -1126,9 +1120,9 @@ TEST_F(LatchingTest, SurfacePositionLatching) { // By default position can be updated even while // a resize is pending. { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(32, 32); - mFGSurfaceControl->setPosition(100, 100); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 32, 32); + ts.setPosition(mFGSurfaceControl, 100, 100); } // The size should not have updated as we have not provided a new buffer. @@ -1141,10 +1135,10 @@ TEST_F(LatchingTest, SurfacePositionLatching) { // Now we repeat with setGeometryAppliesWithResize // and verify the position DOESN'T latch. { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setSize(32, 32); - mFGSurfaceControl->setPosition(100, 100); + TransactionScope ts(*sFakeComposer); + ts.setGeometryAppliesWithResize(mFGSurfaceControl); + ts.setSize(mFGSurfaceControl, 32, 32); + ts.setPosition(mFGSurfaceControl, 100, 100); } EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); @@ -1160,9 +1154,9 @@ TEST_F(LatchingTest, SurfacePositionLatching) { TEST_F(LatchingTest, CropLatching) { // Normally the crop applies immediately even while a resize is pending. { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 128, 128); + ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63)); } auto referenceFrame1 = mBaseFrame; @@ -1173,10 +1167,10 @@ TEST_F(LatchingTest, CropLatching) { restoreInitialState(); { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63)); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 128, 128); + ts.setGeometryAppliesWithResize(mFGSurfaceControl); + ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63)); } EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); @@ -1192,9 +1186,9 @@ TEST_F(LatchingTest, CropLatching) { TEST_F(LatchingTest, FinalCropLatching) { // Normally the crop applies immediately even while a resize is pending. { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 128, 128); + ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127)); } auto referenceFrame1 = mBaseFrame; @@ -1206,10 +1200,10 @@ TEST_F(LatchingTest, FinalCropLatching) { restoreInitialState(); { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 128, 128); + ts.setGeometryAppliesWithResize(mFGSurfaceControl); + ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127)); } EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); @@ -1228,9 +1222,9 @@ TEST_F(LatchingTest, FinalCropLatching) { TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) { // Normally the crop applies immediately even while a resize is pending. { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 128, 128); + ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127)); } auto referenceFrame1 = mBaseFrame; @@ -1246,10 +1240,10 @@ TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) { lockAndFillFGBuffer(); { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 128, 128); + ts.setGeometryAppliesWithResize(mFGSurfaceControl); + ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127)); } EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); @@ -1275,15 +1269,15 @@ TEST_F(LatchingTest, FinalCropLatchingRegressionForb37531386) { // is still pending, and ensure we are successful. Success meaning the second crop // is the one which eventually latches and not the first. { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setSize(128, 128); - mFGSurfaceControl->setGeometryAppliesWithResize(); - mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127)); + TransactionScope ts(*sFakeComposer); + ts.setSize(mFGSurfaceControl, 128, 128); + ts.setGeometryAppliesWithResize(mFGSurfaceControl); + ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127)); } { - GlobalTransactionScope gts(*sFakeComposer); - mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1)); + TransactionScope ts(*sFakeComposer); + ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1)); } EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); diff --git a/services/surfaceflinger/tests/hwc2/Android.mk b/services/surfaceflinger/tests/hwc2/Android.mk index 203ced5c3a..010ac9c890 100644 --- a/services/surfaceflinger/tests/hwc2/Android.mk +++ b/services/surfaceflinger/tests/hwc2/Android.mk @@ -36,7 +36,9 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libgui \ liblog \ - libsync + libsync \ + libhwui \ + android.hardware.graphics.common@1.0 LOCAL_STATIC_LIBRARIES := \ libbase \ libadf \ @@ -49,6 +51,7 @@ LOCAL_SRC_FILES := \ Hwc2TestLayers.cpp \ Hwc2TestBuffer.cpp \ Hwc2TestClientTarget.cpp \ - Hwc2TestVirtualDisplay.cpp + Hwc2TestVirtualDisplay.cpp \ + Hwc2TestPixelComparator.cpp include $(BUILD_NATIVE_TEST) diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp index 4055527b13..4878c140ed 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp @@ -1775,6 +1775,145 @@ protected: } } + void createAndPresentVirtualDisplay(size_t layerCnt, + Hwc2TestCoverage coverage, + const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>& + coverageExceptions) + { + Hwc2TestVirtualDisplay testVirtualDisplay(coverage); + hwc2_display_t display; + android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888; + + do { + // Items dependent on the display dimensions + hwc2_error_t err = HWC2_ERROR_NONE; + const UnsignedArea& dimension = + testVirtualDisplay.getDisplayDimension(); + ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width, + dimension.height, &desiredFormat, &display, &err)); + ASSERT_TRUE(err == HWC2_ERROR_NONE) + << "Cannot allocate virtual display"; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + ASSERT_NO_FATAL_FAILURE(enableVsync(display)); + + std::vector<hwc2_config_t> configs; + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + + Area displayArea; + ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, + &displayArea)); + + std::vector<hwc2_layer_t> layers; + ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, + layerCnt)); + Hwc2TestLayers testLayers(layers, coverage, displayArea, + coverageExceptions); + + /* + * Layouts that do not cover an entire virtual display will + * cause undefined behavior. + * Enable optimizeLayouts to avoid this. + */ + testLayers.optimizeLayouts(); + do { + // Items dependent on the testLayers properties + std::set<hwc2_layer_t> clientLayers; + std::set<hwc2_layer_t> clearLayers; + uint32_t numTypes, numRequests; + bool hasChanges, skip; + bool flipClientTarget; + int32_t presentFence; + Hwc2TestClientTarget testClientTarget; + buffer_handle_t outputBufferHandle; + android::base::unique_fd outputBufferReleaseFence; + + ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers, + &testLayers, &skip)); + + if (skip) + continue; + + ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, + &numRequests, &hasChanges)); + + if (hasChanges) + EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size())) + << "wrong number of requests"; + + ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display, + testLayers, layers, numTypes, &clientLayers)); + + ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers, + numRequests, &clearLayers, &flipClientTarget)); + ASSERT_NO_FATAL_FAILURE(setClientTarget(display, + &testClientTarget, testLayers, clientLayers, + clearLayers, flipClientTarget, displayArea)); + ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display)); + + ASSERT_EQ(testVirtualDisplay.getOutputBuffer( + &outputBufferHandle, &outputBufferReleaseFence), 0); + ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, + outputBufferHandle, outputBufferReleaseFence)); + + EXPECT_NO_FATAL_FAILURE(presentDisplay(display, + &presentFence)); + ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence)); + + ASSERT_EQ(testVirtualDisplay.verifyOutputBuffer(&testLayers, + &layers, &clearLayers), 0); + + /* + * Upscaling the image causes minor pixel differences. + * Work around this by using some threshold. + * + * Fail test if we are off by more than 1% of our + * pixels. + */ + ComparatorResult& comparatorResult = ComparatorResult::get(); + int threshold = (dimension.width * dimension.height) / 100; + double diffPercent = (comparatorResult.getDifferentPixelCount() * 100.0) / + (dimension.width * dimension.height); + + if (comparatorResult.getDifferentPixelCount() != 0) + EXPECT_TRUE(false) + << comparatorResult.getDifferentPixelCount() << " pixels (" + << diffPercent << "%) are different."; + + if (comparatorResult.getDifferentPixelCount() > threshold) { + EXPECT_TRUE(false) + << "Mismatched pixel count exceeds threshold. " + << "Writing buffers to file."; + + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance() + ->current_test_info(); + + EXPECT_EQ(testVirtualDisplay.writeBuffersToFile( + test_info->name()), 0) + << "Failed to write buffers."; + } + + ASSERT_LE(comparatorResult.getDifferentPixelCount(), threshold) + << comparatorResult.getDifferentPixelCount() << " pixels (" + << diffPercent << "%) are different. " + << "Exceeds 1% threshold, terminating test. " + << "Test case: " << testLayers.dump(); + + } while (testLayers.advance()); + + ASSERT_NO_FATAL_FAILURE(destroyLayers(display, + std::move(layers))); + } + ASSERT_NO_FATAL_FAILURE(disableVsync(display)); + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display)); + } while (testVirtualDisplay.advance()); + } + hwc2_device_t* mHwc2Device = nullptr; enum class Hwc2TestHotplugStatus { @@ -4479,7 +4618,7 @@ TEST_F(Hwc2Test, SET_OUTPUT_BUFFER) buffer_handle_t handle; android::base::unique_fd acquireFence; - if (testVirtualDisplay->getBuffer(&handle, &acquireFence) >= 0) + if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) >= 0) EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display, handle, acquireFence)); })); @@ -4499,7 +4638,7 @@ TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_display) ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay)); - if (testVirtualDisplay->getBuffer(&handle, &acquireFence) < 0) + if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) < 0) return; ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay, @@ -4539,7 +4678,7 @@ TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_unsupported) android::base::unique_fd acquireFence; hwc2_error_t err = HWC2_ERROR_NONE; - if (testVirtualDisplay.getBuffer(&handle, &acquireFence) < 0) + if (testVirtualDisplay.getOutputBuffer(&handle, &acquireFence) < 0) continue; ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle, @@ -4557,3 +4696,74 @@ TEST_F(Hwc2Test, DUMP) ASSERT_NO_FATAL_FAILURE(dump(&buffer)); } + +/* + * TODO(b/64724708): Hwc2TestPropertyName::BufferArea MUST be default for all + * virtual display tests as we don't handle this case correctly. + * + * Only default dataspace is supported in our drawing code. + */ +const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> + virtualDisplayExceptions = + {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Default}, + {Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Default}}; + +/* TESTCASE: Tests that the HWC2 can present 1 layer with default coverage on a + * virtual display. */ +TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_1) +{ + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + const size_t layerCnt = 1; + ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, + virtualDisplayExceptions)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with basic coverage on a + * virtual display. */ +TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_basic_1) +{ + Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic; + const size_t layerCnt = 1; + ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, + virtualDisplayExceptions)); +} + +/* TESTCASE: Tests that the HWC2 can present 2 layers with default coverage on a + * virtual display. */ +TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_2) +{ + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + const size_t layerCnt = 2; + ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, + virtualDisplayExceptions)); +} + +/* TESTCASE: Tests that the HWC2 can present 3 layers with default coverage on a + * virtual display. */ +TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_3) +{ + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + const size_t layerCnt = 3; + ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, + virtualDisplayExceptions)); +} + +/* TESTCASE: Tests that the HWC2 can present 4 layers with default coverage on a + * virtual display. */ +TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_4) +{ + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + const size_t layerCnt = 4; + ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, + virtualDisplayExceptions)); +} + +/* TESTCASE: Tests that the HWC2 can present 5 layers with default coverage on a + * virtual display. */ +TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_5) +{ + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + const size_t layerCnt = 5; + ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, + virtualDisplayExceptions)); +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp index 1d3a1d38ac..648456295d 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp @@ -23,14 +23,17 @@ #include <gui/BufferItemConsumer.h> #include <ui/GraphicBuffer.h> +#include <android/hardware/graphics/common/1.0/types.h> #include <math/vec4.h> #include <GLES3/gl3.h> - +#include <SkImageEncoder.h> +#include <SkStream.h> #include "Hwc2TestBuffer.h" #include "Hwc2TestLayers.h" using namespace android; +using android::hardware::graphics::common::V1_0::BufferUsage; /* Returns a fence from egl */ typedef void (*FenceCallback)(int32_t fence, void* callbackArgs); @@ -396,8 +399,9 @@ int Hwc2TestBuffer::generateBuffer() { /* Create new graphic buffer with correct dimensions */ mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height, - mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER, - "hwc2_test_buffer"); + mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer"); + int ret = mGraphicBuffer->initCheck(); if (ret) { return ret; @@ -408,7 +412,8 @@ int Hwc2TestBuffer::generateBuffer() /* Locks the buffer for writing */ uint8_t* img; - mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), + (void**)(&img)); uint32_t stride = mGraphicBuffer->getStride(); @@ -458,31 +463,22 @@ Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer() Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { } -/* Generates a client target buffer using the layers assigned for client - * composition. Takes into account the individual layer properties such as +/* Generates a buffer from layersToDraw. + * Takes into account the individual layer properties such as * transform, blend mode, source crop, etc. */ -int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, - int32_t* outFence, const Area& bufferArea, +static void compositeBufferFromLayers( + const android::sp<android::GraphicBuffer>& graphicBuffer, + android_pixel_format_t format, const Area& bufferArea, const Hwc2TestLayers* testLayers, - const std::set<hwc2_layer_t>* clientLayers, + const std::set<hwc2_layer_t>* layersToDraw, const std::set<hwc2_layer_t>* clearLayers) { - /* Create new graphic buffer with correct dimensions */ - mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height, - mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER, - "hwc2_test_buffer"); - int ret = mGraphicBuffer->initCheck(); - if (ret) { - return ret; - } - if (!mGraphicBuffer->handle) { - return -EINVAL; - } - + /* Locks the buffer for writing */ uint8_t* img; - mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), + (void**)(&img)); - uint32_t stride = mGraphicBuffer->getStride(); + uint32_t stride = graphicBuffer->getStride(); float bWDiv3 = bufferArea.width / 3; float bW2Div3 = bufferArea.width * 2 / 3; @@ -497,10 +493,10 @@ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, uint8_t r = 0, g = 0, b = 0; float a = 0.0f; - /* Cycle through each client layer from back to front and + /* Cycle through each layer from back to front and * update the pixel color. */ - for (auto layer = clientLayers->rbegin(); - layer != clientLayers->rend(); ++layer) { + for (auto layer = layersToDraw->rbegin(); + layer != layersToDraw->rend(); ++layer) { const hwc_rect_t df = testLayers->getDisplayFrame(*layer); @@ -570,8 +566,8 @@ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, * (100x50) at the end of the transformation. */ if (transform & HWC_TRANSFORM_ROT_90) { float tmp = xPos; - xPos = -yPos * dfW / dfH; - yPos = tmp * dfH / dfW; + xPos = yPos * dfW / dfH; + yPos = -tmp * dfH / dfW; } /* Change origin back to the top left corner of the @@ -682,14 +678,114 @@ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, } /* Set the pixel color */ - setColor(x, y, mFormat, stride, img, r, g, b, a * 255); + setColor(x, y, format, stride, img, r, g, b, a * 255); } } - mGraphicBuffer->unlock(); + graphicBuffer->unlock(); +} + +/* Generates a client target buffer using the layers assigned for client + * composition. Takes into account the individual layer properties such as + * transform, blend mode, source crop, etc. */ +int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, + int32_t* outFence, const Area& bufferArea, + const Hwc2TestLayers* testLayers, + const std::set<hwc2_layer_t>* clientLayers, + const std::set<hwc2_layer_t>* clearLayers) +{ + /* Create new graphic buffer with correct dimensions */ + mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height, + mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer"); + + int ret = mGraphicBuffer->initCheck(); + if (ret) + return ret; + + if (!mGraphicBuffer->handle) + return -EINVAL; + + compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers, + clientLayers, clearLayers); *outFence = mFenceGenerator->get(); *outHandle = mGraphicBuffer->handle; return 0; } + +void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea) +{ + mBufferArea.width = bufferArea.width; + mBufferArea.height = bufferArea.height; +} + +bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path) +{ + SkFILEWStream file(path.c_str()); + const SkImageInfo info = SkImageInfo::Make(mBufferArea.width, + mBufferArea.height, SkColorType::kRGBA_8888_SkColorType, + SkAlphaType::kPremul_SkAlphaType); + + uint8_t* img; + mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), + (void**)(&img)); + + SkPixmap pixmap(info, img, mGraphicBuffer->getStride()); + bool result = file.isValid() && SkEncodeImage(&file, pixmap, + SkEncodedImageFormat::kPNG, 100); + + mGraphicBuffer->unlock(); + return result; +} + +/* Generates a buffer that holds the expected result of compositing all of our + * layers */ +int Hwc2TestExpectedBuffer::generateExpectedBuffer( + const Hwc2TestLayers* testLayers, + const std::vector<hwc2_layer_t>* allLayers, + const std::set<hwc2_layer_t>* clearLayers) +{ + mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height, + mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN, + "hwc2_test_buffer"); + + int ret = mGraphicBuffer->initCheck(); + if (ret) + return ret; + + if (!mGraphicBuffer->handle) + return -EINVAL; + + const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(), + allLayers->end()); + + compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers, + &allLayerSet, clearLayers); + + return 0; +} + +int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle, + int32_t* outFence) +{ + if (mBufferArea.width == -1 || mBufferArea.height == -1) + return -EINVAL; + + mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height, + mFormat, BufferUsage::CPU_READ_OFTEN | + BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer"); + + int ret = mGraphicBuffer->initCheck(); + if (ret) + return ret; + + if (!mGraphicBuffer->handle) + return -EINVAL; + + *outFence = -1; + *outHandle = mGraphicBuffer->handle; + + return 0; +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h index b2b3a6696a..fd54fef2d7 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h @@ -71,4 +71,38 @@ protected: const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888; }; + +class Hwc2TestVirtualBuffer { +public: + void updateBufferArea(const Area& bufferArea); + + bool writeBufferToFile(std::string path); + + android::sp<android::GraphicBuffer>& graphicBuffer() + { + return mGraphicBuffer; + } + +protected: + android::sp<android::GraphicBuffer> mGraphicBuffer; + + Area mBufferArea = {-1, -1}; + + const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888; +}; + + +class Hwc2TestExpectedBuffer : public Hwc2TestVirtualBuffer { +public: + int generateExpectedBuffer(const Hwc2TestLayers* testLayers, + const std::vector<hwc2_layer_t>* allLayers, + const std::set<hwc2_layer_t>* clearLayers); +}; + + +class Hwc2TestOutputBuffer : public Hwc2TestVirtualBuffer { +public: + int getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence); +}; + #endif /* ifndef _HWC2_TEST_BUFFER_H */ diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp new file mode 100644 index 0000000000..904b927abf --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sstream> +#include <android/hardware/graphics/common/1.0/types.h> + +#include "Hwc2TestPixelComparator.h" + +using android::hardware::graphics::common::V1_0::BufferUsage; + +uint32_t ComparatorResult::getPixel(int32_t x, int32_t y, uint32_t stride, + uint8_t* img) const +{ + uint32_t r = img[(y * stride + x) * 4 + 0]; + uint32_t g = img[(y * stride + x) * 4 + 1]; + uint32_t b = img[(y * stride + x) * 4 + 2]; + uint32_t a = img[(y * stride + x) * 4 + 3]; + + uint32_t pixel = 0; + pixel |= r; + pixel |= g << 8; + pixel |= b << 16; + pixel |= a << 24; + return pixel; +} + +void ComparatorResult::CompareBuffers( + android::sp<android::GraphicBuffer>& resultBuffer, + android::sp<android::GraphicBuffer>& expectedBuffer) +{ + uint8_t* resultBufferImg; + uint8_t* expectedBufferImg; + resultBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN), + (void**)(&resultBufferImg)); + + expectedBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN), + (void**)(&expectedBufferImg)); + mComparisons.clear(); + int32_t mDifferentPixelCount = 0; + int32_t mBlankPixelCount = 0; + + for (uint32_t y = 0; y < resultBuffer->getHeight(); y++) { + for (uint32_t x = 0; x < resultBuffer->getWidth(); x++) { + uint32_t result = getPixel(x, y, resultBuffer->getStride(), + resultBufferImg); + uint32_t expected = getPixel(x, y, expectedBuffer->getStride(), + expectedBufferImg); + + if (result == 0) + mBlankPixelCount++; + + if (result != expected) + mDifferentPixelCount++; + + mComparisons.emplace_back(std::make_tuple(x, y, result, expected)); + } + } + resultBuffer->unlock(); + expectedBuffer->unlock(); +} + +std::string ComparatorResult::pixelDiff(uint32_t x, uint32_t y, + uint32_t resultPixel, uint32_t expectedPixel) const +{ + uint32_t resultAlpha = (resultPixel >> 24) & 0xFF; + uint32_t resultBlue = (resultPixel >> 16) & 0xFF; + uint32_t resultGreen = (resultPixel >> 8) & 0xFF; + uint32_t resultRed = resultPixel & 0xFF; + + uint32_t expectedAlpha = (expectedPixel >> 24) & 0xFF; + uint32_t expectedBlue = (expectedPixel >> 16) & 0xFF; + uint32_t expectedGreen = (expectedPixel >> 8) & 0xFF; + uint32_t expectedRed = expectedPixel & 0xFF; + + std::ostringstream stream; + + stream << "x: " << x << " y: " << y << std::endl; + stream << std::hex; + stream << "Result pixel: " << resultRed << "|" << resultGreen << "|" + << resultBlue << "|" << resultAlpha << std::endl; + + stream << "Expected pixel: " << expectedRed << "|" << expectedGreen << "|" + << expectedBlue << "|" << expectedAlpha << std::endl; + + return stream.str(); +} + +std::string ComparatorResult::dumpComparison() const +{ + std::ostringstream stream; + stream << "Number of different pixels: " << mDifferentPixelCount; + + for (const auto& comparison : mComparisons) { + if (std::get<2>(comparison) != std::get<3>(comparison)) + stream << pixelDiff(std::get<0>(comparison), + std::get<1>(comparison), std::get<2>(comparison), + std::get<3>(comparison)); + } + return stream.str(); +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h new file mode 100644 index 0000000000..55fa936943 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _HWC2_TEST_PIXEL_COMPARATOR_H +#define _HWC2_TEST_PIXEL_COMPARATOR_H + +#include <ui/GraphicBuffer.h> +#include <cstdint> +#include <string> +#include <utility> +#include <vector> + +class ComparatorResult { +public: + static ComparatorResult& get() + { + static ComparatorResult instance; + return instance; + } + + void CompareBuffers(android::sp<android::GraphicBuffer>& resultBuffer, + android::sp<android::GraphicBuffer>& expectedBuffer); + + std::string dumpComparison() const; + + ComparatorResult(const ComparatorResult&) = delete; + ComparatorResult(ComparatorResult&&) = delete; + ComparatorResult& operator=(ComparatorResult const&) = delete; + ComparatorResult& operator=(ComparatorResult&&) = delete; + + int32_t getDifferentPixelCount() const { return mDifferentPixelCount; } + int32_t getBlankPixelCount() const { return mBlankPixelCount; } + +private: + ComparatorResult() = default; + uint32_t getPixel(int32_t x, int32_t y, uint32_t stride, uint8_t* img) const; + std::string pixelDiff(uint32_t x, uint32_t y, uint32_t resultPixel, + uint32_t expectedPixel) const; + + int32_t mDifferentPixelCount; + int32_t mBlankPixelCount; + /* std::tuple<X coordinate, Y coordinate, resultPixel, expectedPixel> */ + std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>> + mComparisons; +}; + +#endif /* ifndef _HWC2_TEST_PIXEL_COMPARATOR_H */ diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp index b5522de3a5..5b3bbeb708 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp @@ -335,9 +335,9 @@ std::string Hwc2TestDisplayDimension::dump() const return dmp.str(); } -void Hwc2TestDisplayDimension::setDependent(Hwc2TestBuffer* buffer) +void Hwc2TestDisplayDimension::setDependent(Hwc2TestVirtualBuffer* buffer) { - mBuffer = buffer; + mBuffers.insert(buffer); updateDependents(); } @@ -345,8 +345,8 @@ void Hwc2TestDisplayDimension::updateDependents() { const UnsignedArea& curr = get(); - if (mBuffer) - mBuffer->updateBufferArea({static_cast<int32_t>(curr.width), + for (Hwc2TestVirtualBuffer* buffer : mBuffers) + buffer->updateBufferArea({static_cast<int32_t>(curr.width), static_cast<int32_t>(curr.height)}); } diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h index c2029aba04..cb811e06e2 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h @@ -243,6 +243,7 @@ protected: static const std::array<bool, 6> mCompositionSupport; }; +class Hwc2TestVirtualBuffer; class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> { public: @@ -250,12 +251,12 @@ public: std::string dump() const; - void setDependent(Hwc2TestBuffer* buffer); + void setDependent(Hwc2TestVirtualBuffer* buffer); private: void updateDependents(); - Hwc2TestBuffer* mBuffer; + std::set<Hwc2TestVirtualBuffer*> mBuffers; static const std::vector<UnsignedArea> mDefaultDisplayDimensions; static const std::vector<UnsignedArea> mBasicDisplayDimensions; diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp index d0fbc0b5ad..e6cceb82eb 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp @@ -15,14 +15,18 @@ */ #include <sstream> +#include <sys/stat.h> #include "Hwc2TestVirtualDisplay.h" +#define DIR_NAME "images" + Hwc2TestVirtualDisplay::Hwc2TestVirtualDisplay( Hwc2TestCoverage coverage) : mDisplayDimension(coverage) { - mDisplayDimension.setDependent(&mBuffer); + mDisplayDimension.setDependent(&mOutputBuffer); + mDisplayDimension.setDependent(&mExpectedBuffer); } std::string Hwc2TestVirtualDisplay::dump() const @@ -36,11 +40,11 @@ std::string Hwc2TestVirtualDisplay::dump() const return dmp.str(); } -int Hwc2TestVirtualDisplay::getBuffer(buffer_handle_t* outHandle, +int Hwc2TestVirtualDisplay::getOutputBuffer(buffer_handle_t* outHandle, android::base::unique_fd* outAcquireFence) { int32_t acquireFence; - int ret = mBuffer.get(outHandle, &acquireFence); + int ret = mOutputBuffer.getOutputBuffer(outHandle, &acquireFence); outAcquireFence->reset(acquireFence); return ret; } @@ -59,3 +63,36 @@ UnsignedArea Hwc2TestVirtualDisplay::getDisplayDimension() const { return mDisplayDimension.get(); } + +int Hwc2TestVirtualDisplay::verifyOutputBuffer(const Hwc2TestLayers* testLayers, + const std::vector<hwc2_layer_t>* allLayers, + const std::set<hwc2_layer_t>* clearLayers) +{ + int ret = mExpectedBuffer.generateExpectedBuffer(testLayers, allLayers, + clearLayers); + if (ret) + return ret; + + ComparatorResult::get().CompareBuffers(mOutputBuffer.graphicBuffer(), + mExpectedBuffer.graphicBuffer()); + + return 0; +} + +int Hwc2TestVirtualDisplay::writeBuffersToFile(std::string name) +{ + std::ostringstream expectedPath; + std::ostringstream resultPath; + int ret = mkdir(DIR_NAME, DEFFILEMODE); + if (ret && errno != EEXIST) + return ret; + + expectedPath << DIR_NAME << "/expected-" << name << ".png"; + resultPath << DIR_NAME << "/result-" << name << ".png"; + + if (!mExpectedBuffer.writeBufferToFile(expectedPath.str()) || + !mOutputBuffer.writeBufferToFile(resultPath.str())) + return -1; + + return 0; +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h index 09420ef629..10c8ef0f1c 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h @@ -18,6 +18,7 @@ #define _HWC2_TEST_VIRTUAL_DISPLAY_H #include "Hwc2TestBuffer.h" +#include "Hwc2TestPixelComparator.h" #include "Hwc2TestProperties.h" #define HWC2_INCLUDE_STRINGIFICATION @@ -32,17 +33,22 @@ public: std::string dump() const; - int getBuffer(buffer_handle_t* outHandle, + int getOutputBuffer(buffer_handle_t* outHandle, android::base::unique_fd* outAcquireFence); + int verifyOutputBuffer(const Hwc2TestLayers* testLayers, + const std::vector<hwc2_layer_t>* allLayers, + const std::set<hwc2_layer_t>* clearLayers); + + int writeBuffersToFile(std::string name); void reset(); bool advance(); UnsignedArea getDisplayDimension() const; private: - Hwc2TestBuffer mBuffer; - + Hwc2TestOutputBuffer mOutputBuffer; + Hwc2TestExpectedBuffer mExpectedBuffer; Hwc2TestDisplayDimension mDisplayDimension; }; diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc index b9836cec80..94c2c78df3 100644 --- a/services/thermalservice/thermalservice.rc +++ b/services/thermalservice/thermalservice.rc @@ -1,2 +1,4 @@ service thermalservice /system/bin/thermalserviced class core + user system + group system diff --git a/services/utils/Android.bp b/services/utils/Android.bp new file mode 100644 index 0000000000..6132956eeb --- /dev/null +++ b/services/utils/Android.bp @@ -0,0 +1,34 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +// Static library used in testing and executables +// +cc_library_static { + name: "libserviceutils", + + cflags: [ + "-Wall", + "-Werror", + ], + + srcs: [ + "PriorityDumper.cpp", + ], + + clang: true, + export_include_dirs: ["include"], +} + +subdirs = ["tests"] diff --git a/services/utils/PriorityDumper.cpp b/services/utils/PriorityDumper.cpp new file mode 100644 index 0000000000..967dee5d29 --- /dev/null +++ b/services/utils/PriorityDumper.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/serviceutils/PriorityDumper.h" + +namespace android { + +const char16_t PriorityDumper::PROTO_ARG[] = u"--proto"; +const char16_t PriorityDumper::PRIORITY_ARG[] = u"--dump-priority"; +const char16_t PriorityDumper::PRIORITY_ARG_CRITICAL[] = u"CRITICAL"; +const char16_t PriorityDumper::PRIORITY_ARG_HIGH[] = u"HIGH"; +const char16_t PriorityDumper::PRIORITY_ARG_NORMAL[] = u"NORMAL"; + +enum class PriorityType { INVALID, CRITICAL, HIGH, NORMAL }; + +static PriorityType getPriorityType(const String16& arg) { + if (arg == PriorityDumper::PRIORITY_ARG_CRITICAL) { + return PriorityType::CRITICAL; + } else if (arg == PriorityDumper::PRIORITY_ARG_HIGH) { + return PriorityType::HIGH; + } else if (arg == PriorityDumper::PRIORITY_ARG_NORMAL) { + return PriorityType::NORMAL; + } + return PriorityType::INVALID; +} + +status_t PriorityDumper::dumpAll(int fd, const Vector<String16>& args, bool asProto) { + status_t status; + status = dumpCritical(fd, args, asProto); + if (status != OK) return status; + status = dumpHigh(fd, args, asProto); + if (status != OK) return status; + status = dumpNormal(fd, args, asProto); + if (status != OK) return status; + return status; +} + +status_t PriorityDumper::priorityDump(int fd, const Vector<String16>& args) { + status_t status; + bool asProto = false; + PriorityType priority = PriorityType::INVALID; + + Vector<String16> strippedArgs; + for (uint32_t argIndex = 0; argIndex < args.size(); argIndex++) { + if (args[argIndex] == PROTO_ARG) { + asProto = true; + } else if (args[argIndex] == PRIORITY_ARG) { + if (argIndex + 1 < args.size()) { + argIndex++; + priority = getPriorityType(args[argIndex]); + } + } else { + strippedArgs.add(args[argIndex]); + } + } + + switch (priority) { + case PriorityType::CRITICAL: + status = dumpCritical(fd, strippedArgs, asProto); + break; + case PriorityType::HIGH: + status = dumpHigh(fd, strippedArgs, asProto); + break; + case PriorityType::NORMAL: + status = dumpNormal(fd, strippedArgs, asProto); + break; + default: + status = dumpAll(fd, strippedArgs, asProto); + break; + } + return status; +} +} // namespace android diff --git a/services/utils/include/serviceutils/PriorityDumper.h b/services/utils/include/serviceutils/PriorityDumper.h new file mode 100644 index 0000000000..d01a102497 --- /dev/null +++ b/services/utils/include/serviceutils/PriorityDumper.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_UTILS_PRIORITYDUMPER_H +#define ANDROID_UTILS_PRIORITYDUMPER_H + +#include <utils/Errors.h> +#include <utils/String16.h> +#include <utils/Vector.h> + +namespace android { + +// Helper class to parse common arguments responsible for splitting dumps into +// various priority buckets and changing the output format of the dump. +class PriorityDumper { +public: + static const char16_t PRIORITY_ARG[]; + static const char16_t PRIORITY_ARG_CRITICAL[]; + static const char16_t PRIORITY_ARG_HIGH[]; + static const char16_t PRIORITY_ARG_NORMAL[]; + static const char16_t PROTO_ARG[]; + + // Parses the argument list searching for --dump_priority with a priority type + // (HIGH, CRITICAL or NORMAL) and --proto. Matching arguments are stripped. + // If a valid priority type is found, the associated PriorityDumper + // method is called otherwise all supported sections are dumped. + // If --proto is found, the dumpAsProto flag is set to dump sections in proto + // format. + status_t priorityDump(int fd, const Vector<String16>& args); + + // Dumps CRITICAL priority sections. + virtual status_t dumpCritical(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) { + return OK; + } + + // Dumps HIGH priority sections. + virtual status_t dumpHigh(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) { + return OK; + } + + // Dumps normal priority sections. + virtual status_t dumpNormal(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) { + return OK; + } + + // Dumps all sections. + // This method is called when priorityDump is called without priority + // arguments. By default, it calls all three dump methods. + virtual status_t dumpAll(int fd, const Vector<String16>& args, bool asProto); + virtual ~PriorityDumper() = default; +}; + +} // namespace android + +#endif // ANDROID_UTILS_PRIORITYDUMPER_H diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp new file mode 100644 index 0000000000..15829fa12b --- /dev/null +++ b/services/utils/tests/Android.bp @@ -0,0 +1,29 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Build unit tests. + +cc_test { + name: "prioritydumper_test", + test_suites: ["device-tests"], + srcs: [ "PriorityDumper_test.cpp"], + shared_libs: [ + "libutils", + ], + static_libs = [ + "libgmock", + "libserviceutils" + ], + clang: true, +}
\ No newline at end of file diff --git a/services/utils/tests/AndroidTest.xml b/services/utils/tests/AndroidTest.xml new file mode 100644 index 0000000000..83c890da40 --- /dev/null +++ b/services/utils/tests/AndroidTest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Config for prioritydumper_test"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="prioritydumper_test->/data/local/tmp/prioritydumper_test" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="prioritydumper_test" /> + </test> +</configuration>
\ No newline at end of file diff --git a/services/utils/tests/PriorityDumper_test.cpp b/services/utils/tests/PriorityDumper_test.cpp new file mode 100644 index 0000000000..90cc6de790 --- /dev/null +++ b/services/utils/tests/PriorityDumper_test.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "serviceutils/PriorityDumper.h" + +#include <vector> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <utils/String16.h> +#include <utils/Vector.h> + +using namespace android; + +using ::testing::ElementsAreArray; +using ::testing::Mock; +using ::testing::Test; + +class PriorityDumperMock : public PriorityDumper { +public: + MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool)); + MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool)); + MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool)); + MOCK_METHOD3(dumpAll, status_t(int, const Vector<String16>&, bool)); +}; + +class DumpAllMock : public PriorityDumper { +public: + MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool)); + MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool)); + MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool)); +}; + +class PriorityDumperTest : public Test { +public: + PriorityDumperTest() : dumper_(), dumpAlldumper_(), fd(1) {} + PriorityDumperMock dumper_; + DumpAllMock dumpAlldumper_; + int fd; +}; + +static void addAll(Vector<String16>& av, const std::vector<std::string>& v) { + for (auto element : v) { + av.add(String16(element.c_str())); + } +} + +TEST_F(PriorityDumperTest, noArgsPassed) { + Vector<String16> args; + EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false)); + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, noPriorityArgsPassed) { + Vector<String16> args; + addAll(args, {"bunch", "of", "args"}); + EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false)); + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, priorityArgsOnly) { + Vector<String16> args; + addAll(args, {"--dump-priority", "CRITICAL"}); + Vector<String16> strippedArgs; + EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false)); + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, dumpCritical) { + Vector<String16> args; + addAll(args, {"--dump-priority", "CRITICAL", "args", "left", "behind"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"args", "left", "behind"}); + + EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false)); + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, dumpCriticalInMiddle) { + Vector<String16> args; + addAll(args, {"args", "left", "--dump-priority", "CRITICAL", "behind"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"args", "left", "behind"}); + + EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false)); + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, dumpHigh) { + Vector<String16> args; + addAll(args, {"--dump-priority", "HIGH", "args", "left", "behind"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"args", "left", "behind"}); + + EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false)); + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, dumpHighInEnd) { + Vector<String16> args; + addAll(args, {"args", "left", "behind", "--dump-priority", "HIGH"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"args", "left", "behind"}); + + EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false)); + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, dumpNormal) { + Vector<String16> args; + addAll(args, {"--dump-priority", "NORMAL", "args", "left", "behind"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"args", "left", "behind"}); + + EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/false)); + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, dumpAll) { + Vector<String16> args; + addAll(args, {"args", "left", "behind"}); + + EXPECT_CALL(dumpAlldumper_, dumpCritical(fd, ElementsAreArray(args), /*asProto=*/false)); + EXPECT_CALL(dumpAlldumper_, dumpHigh(fd, ElementsAreArray(args), /*asProto=*/false)); + EXPECT_CALL(dumpAlldumper_, dumpNormal(fd, ElementsAreArray(args), /*asProto=*/false)); + + dumpAlldumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, priorityArgWithPriorityMissing) { + Vector<String16> args; + addAll(args, {"--dump-priority"}); + Vector<String16> strippedArgs; + EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false)); + + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, priorityArgWithInvalidPriority) { + Vector<String16> args; + addAll(args, {"--dump-priority", "REALLY_HIGH"}); + Vector<String16> strippedArgs; + EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false)); + + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, protoArg) { + Vector<String16> args; + addAll(args, {"--proto"}); + Vector<String16> strippedArgs; + EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true)); + + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, protoArgWithPriorityArgs) { + Vector<String16> args; + addAll(args, {"--proto", "args", "--dump-priority", "NORMAL", "left", "behind"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"args", "left", "behind"}); + EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true)); + + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, protoArgWithPriorityArgsInReverseOrder) { + Vector<String16> args; + addAll(args, {"--dump-priority", "NORMAL", "--proto", "args", "left", "behind"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"args", "left", "behind"}); + EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true)); + + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, protoArgInMiddle) { + Vector<String16> args; + addAll(args, {"--unknown", "args", "--proto", "args", "left", "behind"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"}); + EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true)); + + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, protoArgAtEnd) { + Vector<String16> args; + addAll(args, {"--unknown", "args", "args", "left", "behind", "--proto"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"}); + EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true)); + + dumper_.priorityDump(fd, args); +} + +TEST_F(PriorityDumperTest, protoArgWithInvalidPriorityType) { + Vector<String16> args; + addAll(args, {"--dump-priority", "NOT_SO_HIGH", "--proto", "args", "left", "behind"}); + Vector<String16> strippedArgs; + addAll(strippedArgs, {"args", "left", "behind"}); + EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true)); + + dumper_.priorityDump(fd, args); +}
\ No newline at end of file diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk index 28cf53dd82..e1997d74e1 100644 --- a/services/vr/bufferhubd/Android.mk +++ b/services/vr/bufferhubd/Android.mk @@ -32,6 +32,7 @@ staticLibraries := \ sharedLibraries := \ libbase \ + libbinder \ libcutils \ liblog \ libsync \ diff --git a/services/vr/bufferhubd/bufferhubd.rc b/services/vr/bufferhubd/bufferhubd.rc index 46fe5f95c7..c470de5c4a 100644 --- a/services/vr/bufferhubd/bufferhubd.rc +++ b/services/vr/bufferhubd/bufferhubd.rc @@ -2,5 +2,4 @@ service bufferhubd /system/bin/bufferhubd class core user system group system - writepid /dev/cpuset/tasks socket pdx/system/buffer_hub/client stream 0660 system system u:object_r:pdx_bufferhub_client_endpoint_socket:s0 diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index e92b8d8019..76ec42d1d9 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -20,6 +20,7 @@ cc_library_shared { "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0", "libbase", + "libbinder", "libcutils", "libfmq", "libhardware", diff --git a/services/vr/performanced/performanced.rc b/services/vr/performanced/performanced.rc index 2605a47588..af9760eba3 100644 --- a/services/vr/performanced/performanced.rc +++ b/services/vr/performanced/performanced.rc @@ -2,5 +2,4 @@ service performanced /system/bin/performanced class core user root group system readproc - writepid /dev/cpuset/tasks socket pdx/system/performance/client stream 0666 system system u:object_r:pdx_performance_client_endpoint_socket:s0 diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api index 2981a95196..2bbe5e6caa 100644 --- a/vulkan/api/vulkan.api +++ b/vulkan/api/vulkan.api @@ -27,7 +27,7 @@ import platform "platform.api" // API version (major.minor.patch) define VERSION_MAJOR 1 -define VERSION_MINOR 0 +define VERSION_MINOR 1 define VERSION_PATCH 61 // API limits @@ -37,11 +37,10 @@ define VK_MAX_EXTENSION_NAME_SIZE 256 define VK_MAX_DESCRIPTION_SIZE 256 define VK_MAX_MEMORY_TYPES 32 define VK_MAX_MEMORY_HEAPS 16 /// The maximum number of unique memory heaps, each of which supporting 1 or more memory types. -define VK_MAX_DEVICE_GROUP_SIZE_KHX 32 -//@extension("VK_KHR_external_memory_capabilities") -define VK_LUID_SIZE_KHR 8 -//@extension("VK_KHR_external_memory") -define VK_QUEUE_FAMILY_EXTERNAL_KHR -2 +@vulkan1_1 +define VK_MAX_DEVICE_GROUP_SIZE 32 +define VK_LUID_SIZE 8 +define VK_QUEUE_FAMILY_EXTERNAL -2 // API keywords define VK_TRUE 1 @@ -55,7 +54,7 @@ define NULL_HANDLE 0 @extension("VK_KHR_surface") define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" // 2 -@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION 68 +@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 @extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" // 3 @@ -95,7 +94,7 @@ define NULL_HANDLE 0 @extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer" // 12 -@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 8 +@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 @extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report" // 13 @@ -163,8 +162,8 @@ define NULL_HANDLE 0 @extension("VK_AMD_texture_gather_bias_lod") define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" // 54 -@extension("VK_KHX_multiview") define VK_KHX_MULTIVIEW_SPEC_VERSION 1 -@extension("VK_KHX_multiview") define VK_KHX_MULTIVIEW_EXTENSION_NAME "VK_KHX_multiview" +@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_SPEC_VERSION 1 +@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" // 56 @extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 @@ -187,8 +186,8 @@ define NULL_HANDLE 0 @extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" // 61 -@extension("VK_KHX_device_group") define VK_KHX_DEVICE_GROUP_SPEC_VERSION 2 -@extension("VK_KHX_device_group") define VK_KHX_DEVICE_GROUP_EXTENSION_NAME "VK_KHX_device_group" +@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_SPEC_VERSION 3 +@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group" // 62 @extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1 @@ -215,8 +214,8 @@ define NULL_HANDLE 0 @extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" // 71 -@extension("VK_KHX_device_group_creation") define VK_KHX_DEVICE_GROUP_CREATION_SPEC_VERSION 1 -@extension("VK_KHX_device_group_creation") define VK_KHX_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHX_device_group_creation" +@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1 +@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation" // 72 @extension("VK_KHR_external_memory_capabilities") define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 @@ -255,7 +254,7 @@ define NULL_HANDLE 0 @extension("VK_KHR_external_semaphore_fd") define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd" // 81 -@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 1 +@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 @extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" // 84 @@ -450,6 +449,10 @@ define NULL_HANDLE 0 @extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 @extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" +// 169 +@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_SPEC_VERSION 1 +@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3" + ///////////// // Types // ///////////// @@ -488,6 +491,10 @@ type u32 VkSampleMask @nonDispatchHandle type u64 VkRenderPass @nonDispatchHandle type u64 VkPipelineCache +@vulkan1_1 +@nonDispatchHandle type u64 VkSamplerYcbcrConversion +@nonDispatchHandle type u64 VkDescriptorUpdateTemplate + // 1 @extension("VK_KHR_surface") @nonDispatchHandle type u64 VkSurfaceKHR @@ -529,6 +536,10 @@ enum VkImageLayout { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 0x00000007, /// Optimal layout when image is used only as destination of transfer operations VK_IMAGE_LAYOUT_PREINITIALIZED = 0x00000008, /// Initial layout used when the data is populated by the CPU + //@vulkan1_1 + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, + //@extension("VK_KHR_swapchain") // 2 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, @@ -1012,6 +1023,42 @@ enum VkFormat { VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, + //@vulkan1_1 + VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, + VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, + VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, + VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, + VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, + VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, + //@extension("VK_IMG_format_pvrtc") // 28 VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, @@ -1111,9 +1158,83 @@ enum VkStructureType { VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, + //@vulkan1_1 + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, + VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, + VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, + VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = 1000120000, + VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, + VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, + VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, + VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, + VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001, + VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, + VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = 1000063000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, + //@extension("VK_KHR_swapchain") // 2 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, + // added as interaction from VK_KHR_device_group / VK 1.1 + VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, + VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, //@extension("VK_KHR_display") // 3 VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, @@ -1164,10 +1285,10 @@ enum VkStructureType { //@extension("VK_AMD_texture_gather_bias_lod") // 42 VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, - //@extension("VK_KHX_multiview") // 54 - VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX = 1000053000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX = 1000053001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX = 1000053002, + //@extension("VK_KHR_multiview") // 54 + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = 1000053000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = 1000053001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = 1000053002, //@extension("VK_NV_external_memory") // 57 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, @@ -1191,20 +1312,16 @@ enum VkStructureType { VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008, - //@extension("VK_KHX_device_group") // 61 - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX = 1000060000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX = 1000060003, - VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX = 1000060004, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX = 1000060005, - VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX = 1000060006, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX = 1000060007, - VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX = 1000060008, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX = 1000060009, - VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX = 1000060010, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX = 1000060011, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX = 1000060012, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHX = 1000060013, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHX = 1000060014, + //@extension("VK_KHR_device_group") // 61 + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = 1000060000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = 1000060003, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = 1000060004, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = 1000060005, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = 1000060006, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, + // tokens 08-12 are listed with VK_KHR_swapchain + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = 1000060013, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = 1000060014, //@extension("VK_EXT_validation_flags") // 62 VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, @@ -1212,9 +1329,9 @@ enum VkStructureType { //@extension("VK_NN_vi_surface") // 63 VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, - //@extension("VK_KHX_device_group_creation") // 71 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX = 1000070000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX = 1000070001, + //@extension("VK_KHR_device_group_creation") // 71 + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = 1000070000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = 1000070001, //@extension("VK_KHR_external_memory_capabilities") // 72 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = 1000071000, @@ -1394,6 +1511,10 @@ enum VkStructureType { //@extension("VK_EXT_validation_cache") // 161 VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, + + //@extension("VK_KHR_maintenance3") // 169 + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = 1000168000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = 1000168001, } enum VkSubpassContents { @@ -1433,6 +1554,10 @@ enum VkResult { VK_ERROR_FORMAT_NOT_SUPPORTED = 0xFFFFFFF5, // -11 VK_ERROR_FRAGMENTED_POOL = 0xFFFFFFF4, // -12 + //@vulkan1_1 + VK_ERROR_OUT_OF_POOL_MEMORY = 0xC4642878, // -1000069000 + VK_ERROR_INVALID_EXTERNAL_HANDLE = 0xC4641CBD, // -1000072003 + //@extension("VK_KHR_surface") // 1 VK_ERROR_SURFACE_LOST_KHR = 0xC4653600, // -1000000000 VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = 0xC46535FF, // -1000000001 @@ -1505,6 +1630,10 @@ enum VkObjectType { VK_OBJECT_TYPE_FRAMEBUFFER = 24, VK_OBJECT_TYPE_COMMAND_POOL = 25, + //@vulkan1_1 + VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, + VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, + //@extension("VK_KHR_surface") // 1 VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, @@ -1532,6 +1661,42 @@ enum VkObjectType { VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, } + +//@vulkan1_1 enums + +enum VkPointClippingBehavior { + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, +} + +enum VkTessellationDomainOrigin { + VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, +} + +enum VkSamplerYcbcrModelConversion { + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4, +} + +enum VkSamplerYcbcrRange { + VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, +} + +enum VkChromaLocation { + VK_CHROMA_LOCATION_COSITED_EVEN = 0, + VK_CHROMA_LOCATION_MIDPOINT = 1, +} + +enum VkDescriptorUpdateTemplateType { + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, +} + @extension("VK_KHR_surface") // 1 enum VkPresentModeKHR { VK_PRESENT_MODE_IMMEDIATE_KHR = 0x00000000, @@ -1546,7 +1711,7 @@ enum VkPresentModeKHR { @extension("VK_KHR_surface") // 1 enum VkColorSpaceKHR { - VK_COLORSPACE_SRGB_NONLINEAR_KHR = 0x00000000, + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0x00000000, //@extension("VK_EXT_swapchain_colorspace") // 105 VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, @@ -1756,6 +1921,9 @@ bitfield VkQueueFlagBits { VK_QUEUE_COMPUTE_BIT = 0x00000002, /// Queue supports compute operations VK_QUEUE_TRANSFER_BIT = 0x00000004, /// Queue supports transfer operations VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, /// Queue supports sparse resource memory management operations + + //@vulkan1_1 + VK_QUEUE_PROTECTED_BIT = 0x00000010, } /// Memory properties passed into vkAllocMemory(). @@ -1766,6 +1934,9 @@ bitfield VkMemoryPropertyFlagBits { VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, + + //@vulkan1_1 + VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020, } /// Memory heap flags @@ -1773,8 +1944,11 @@ type VkFlags VkMemoryHeapFlags bitfield VkMemoryHeapFlagBits { VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, - //@extension("VK_KHX_device_group_creation") // 71 - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX = 0x00000002, + //@vulkan1_1 + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002, + + //@extension("VK_KHR_device_group_creation") // 71 + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = 0x00000002, } /// Access flags @@ -1826,6 +2000,9 @@ bitfield VkBufferCreateFlagBits { VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, /// Buffer should support sparse backing VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, /// Buffer should support sparse backing with partial residency VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, /// Buffer should support constent data access to physical memory blocks mapped into multiple locations of sparse buffers + + //@vulkan1_1 + VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, } /// Shader stage flags @@ -1875,14 +2052,20 @@ bitfield VkImageCreateFlagBits { VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, /// Allows image views to have different format than the base image VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, /// Allows creating image views with cube type from the created image + //@vulkan1_1 + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020, + VK_IMAGE_CREATE_BIND_SFR_BIT = 0x00000040, + VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080, + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, + VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, + VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400, + VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, + //@extension("VK_KHR_maintenance1") // 70 VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020, - //@extension("VK_KHX_device_group") // 61 - VK_IMAGE_CREATE_BIND_SFR_BIT_KHX = 0x00000040, - - //@extension("VK_EXT_sample_locations") // 144 - VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, + //@extension("VK_KHR_device_group") // 61 + VK_IMAGE_CREATE_BIND_SFR_BIT_KHR = 0x00000040, //@extension("VK_KHR_maintenance2") // 118 VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = 0x00000080, @@ -1893,6 +2076,9 @@ bitfield VkImageCreateFlagBits { //@extension("VK_KHR_bind_memory2") // 158 VK_IMAGE_CREATE_ALIAS_BIT_KHR = 0x00000400, + + //@extension("VK_EXT_sample_locations") // 144 + VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, } /// Image view creation flags @@ -1907,9 +2093,13 @@ bitfield VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, - //@extension("VK_KHX_device_group") // 61 - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX = 0x00000008, - VK_PIPELINE_CREATE_DISPATCH_BASE_KHX = 0x00000010, + //@vulkan1_1 + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, + VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010, + + //@extension("VK_KHR_device_group") // 61 + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008, + VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = 0x00000010, } /// Color component flags @@ -1949,6 +2139,17 @@ bitfield VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, /// Format can be used as the destination image of blits with vkCommandBlitImage VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, + //@vulkan1_1 + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000, + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, + VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, + //@extension("VK_IMG_filter_cubic") // 16 VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, @@ -2031,6 +2232,11 @@ bitfield VkImageAspectFlagBits { VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, + //@vulkan1_1 + VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, + VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, + VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, + //@extension("VK_KHR_sampler_ycbcr_conversion") // 157 VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = 0x00000010, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = 0x00000020, @@ -2096,6 +2302,9 @@ type VkFlags VkCommandPoolCreateFlags bitfield VkCommandPoolCreateFlagBits { VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, /// Command buffers have a short lifetime VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, /// Command buffers may release their memory individually + + //@vulkan1_1 + VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004, } /// Command pool reset flags @@ -2139,8 +2348,10 @@ type VkFlags VkDeviceCreateFlags /// Device queue creation flags type VkFlags VkDeviceQueueCreateFlags -//bitfield VkDeviceQueueCreateFlagBits { -//} +@vulkan1_1 +bitfield VkDeviceQueueCreateFlagBits { + VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, +} /// Query pool creation flags type VkFlags VkQueryPoolCreateFlags @@ -2239,11 +2450,15 @@ type VkFlags VkDependencyFlags bitfield VkDependencyFlagBits { VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, - //@extension("VK_KHX_multiview") // 54 - VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX = 0x00000002, + //@vulkan1_1 + VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004, + VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002, - //@extension("VK_KHX_device_group") // 61 - VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX = 0x00000004, + //@extension("VK_KHR_multiview") // 54 + VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = 0x00000002, + + //@extension("VK_KHR_device_group") // 61 + VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = 0x00000004, } /// Cull mode flags @@ -2255,6 +2470,109 @@ bitfield VkCullModeFlagBits { VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, } +//@vulkan1_1 flags + +/// Subgroup feature flags +type VkFlags VkSubgroupFeatureFlags +bitfield VkSubgroupFeatureFlagBits { + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, +} + +/// Peer memory feature flags +type VkFlags VkPeerMemoryFeatureFlags +bitfield VkPeerMemoryFeatureFlagBits { + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008, +} + +/// Memory allocation flags +type VkFlags VkMemoryAllocateFlags +bitfield VkMemoryAllocateFlagBits { + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, +} + +type VkFlags VkCommandPoolTrimFlags +//bitfield VkCommandPoolTrimFlagBits { +//} + +type VkFlags VkDescriptorUpdateTemplateCreateFlags +//bitfield VkDescriptorUpdateTemplateCreateFlagBits { +//} + +/// External memory handle type flags +type VkFlags VkExternalMemoryHandleTypeFlags +bitfield VkExternalMemoryHandleTypeFlagBits { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, +} + +/// External memory feature flags +type VkFlags VkExternalMemoryFeatureFlags +bitfield VkExternalMemoryFeatureFlagBits { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004, +} + +/// External fence handle type flags +type VkFlags VkExternalFenceHandleTypeFlags +bitfield VkExternalFenceHandleTypeFlagBits { + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008, +} + +/// External fence feature flags +type VkFlags VkExternalFenceFeatureFlags +bitfield VkExternalFenceFeatureFlagBits { + VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002, +} + +/// Fence import flags +type VkFlags VkFenceImportFlags +bitfield VkFenceImportFlagBits { + VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001, +} + +/// Semaphore import flags +type VkFlags VkSemaphoreImportFlags +bitfield VkSemaphoreImportFlagBits { + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001, +} + +/// External semaphore handle type flags +type VkFlags VkExternalSemaphoreHandleTypeFlags +bitfield VkExternalSemaphoreHandleTypeFlagBits { + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010, +} + +/// External semaphore feature flags +type VkFlags VkExternalSemaphoreFeatureFlags +bitfield VkExternalSemaphoreFeatureFlagBits { + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002, +} + @extension("VK_KHR_surface") // 1 type VkFlags VkSurfaceTransformFlagsKHR @extension("VK_KHR_surface") // 1 @@ -2284,8 +2602,21 @@ bitfield VkCompositeAlphaFlagBitsKHR { type VkFlags VkSwapchainCreateFlagsKHR @extension("VK_KHR_swapchain") // 2 bitfield VkSwapchainCreateFlagBitsKHR { - //@extension("VK_KHX_device_group") // 61 - VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX = 0x00000001, + //@vulkan1_1 + VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHR = 0x00000001, + VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, +} + +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +type VkFlags VkDeviceGroupPresentModeFlagsKHR +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +bitfield VkDeviceGroupPresentModeFlagBitsKHR { + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001, + VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002, + VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004, + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008, } @extension("VK_KHR_display") // 3 @@ -2383,31 +2714,21 @@ bitfield VkExternalMemoryFeatureFlagBitsNV { VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004, } -@extension("VK_KHX_device_group") // 61 -type VkFlags VkPeerMemoryFeatureFlagsKHX -@extension("VK_KHX_device_group") // 61 -bitfield VkPeerMemoryFeatureFlagBitsKHX { - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX = 0x00000001, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX = 0x00000002, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX = 0x00000004, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX = 0x00000008, -} - -@extension("VK_KHX_device_group") // 61 -type VkFlags VkMemoryAllocateFlagsKHX -@extension("VK_KHX_device_group") // 61 -bitfield VkMemoryAllocateFlagBitsKHX { - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX = 0x00000001, +@extension("VK_KHR_device_group") // 61 +type VkFlags VkPeerMemoryFeatureFlagsKHR +@extension("VK_KHR_device_group") // 61 +bitfield VkPeerMemoryFeatureFlagBitsKHR { + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = 0x00000001, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = 0x00000002, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = 0x00000004, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = 0x00000008, } -@extension("VK_KHX_device_group") // 61 -type VkFlags VkDeviceGroupPresentModeFlagsKHX -@extension("VK_KHX_device_group") // 61 -bitfield VkDeviceGroupPresentModeFlagBitsKHX { - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX = 0x00000001, - VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX = 0x00000002, - VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX = 0x00000004, - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX = 0x00000008, +@extension("VK_KHR_device_group") // 61 +type VkFlags VkMemoryAllocateFlagsKHR +@extension("VK_KHR_device_group") // 61 +bitfield VkMemoryAllocateFlagBitsKHR { + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = 0x00000001, } @extension("VK_NN_vi_surface") // 63 @@ -3672,6 +3993,493 @@ class VkDispatchIndirectCommand { u32 z } +//@vulkan1_1 structures + +class VkPhysicalDeviceSubgroupProperties { + VkStructureType sType + void* pNext + u32 subgroupSize + VkShaderStageFlags supportedStages + VkSubgroupFeatureFlags supportedOperations + VkBool32 quadOperationsInAllStages +} + +class VkBindBufferMemoryInfo { + VkStructureType sType + const void* pNext + VkBuffer buffer + VkDeviceMemory memory + VkDeviceSize memoryOffset +} + +class VkBindImageMemoryInfo { + VkStructureType sType + const void* pNext + VkImage image + VkDeviceMemory memory + VkDeviceSize memoryOffset +} + +class VkPhysicalDevice16BitStorageFeatures { + VkStructureType sType + void* pNext + VkBool32 storageBuffer16BitAccess + VkBool32 uniformAndStorageBuffer16BitAccess + VkBool32 storagePushConstant16 + VkBool32 storageInputOutput16 +} + +class VkMemoryDedicatedRequirements { + VkStructureType sType + void* pNext + VkBool32 prefersDedicatedAllocation + VkBool32 requiresDedicatedAllocation +} + +class VkMemoryDedicatedAllocateInfo { + VkStructureType sType + const void* pNext + VkImage image + VkBuffer buffer +} + +class VkMemoryAllocateFlagsInfo { + VkStructureType sType + const void* pNext + VkMemoryAllocateFlags flags + u32 deviceMask +} + +class VkDeviceGroupRenderPassBeginInfo { + VkStructureType sType + const void* pNext + u32 deviceMask + u32 deviceRenderAreaCount + const VkRect2D* pDeviceRenderAreas +} + +class VkDeviceGroupCommandBufferBeginInfo { + VkStructureType sType + const void* pNext + u32 deviceMask +} + +class VkDeviceGroupSubmitInfo { + VkStructureType sType + const void* pNext + u32 waitSemaphoreCount + const u32* pWaitSemaphoreDeviceIndices + u32 commandBufferCount + const u32* pCommandBufferDeviceMasks + u32 signalSemaphoreCount + const u32* pSignalSemaphoreDeviceIndices +} + +class VkDeviceGroupBindSparseInfo { + VkStructureType sType + const void* pNext + u32 resourceDeviceIndex + u32 memoryDeviceIndex +} + +class VkBindBufferMemoryDeviceGroupInfo { + VkStructureType sType + const void* pNext + u32 deviceIndexCount + const u32* pDeviceIndices +} + +class VkBindImageMemoryDeviceGroupInfo { + VkStructureType sType + const void* pNext + u32 deviceIndexCount + const u32* pDeviceIndices + u32 SFRRectCount + const VkRect2D* pSFRRects +} + +class VkPhysicalDeviceGroupProperties { + VkStructureType sType + void* pNext + u32 physicalDeviceCount + VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE] physicalDevices + VkBool32 subsetAllocation +} + +class VkDeviceGroupDeviceCreateInfo { + VkStructureType sType + const void* pNext + u32 physicalDeviceCount + const VkPhysicalDevice* pPhysicalDevices +} + +class VkBufferMemoryRequirementsInfo2 { + VkStructureType sType + const void* pNext + VkBuffer buffer +} + +class VkImageMemoryRequirementsInfo2 { + VkStructureType sType + const void* pNext + VkImage image +} + +class VkImageSparseMemoryRequirementsInfo2 { + VkStructureType sType + const void* pNext + VkImage image +} + +class VkMemoryRequirements2 { + VkStructureType sType + void* pNext + VkMemoryRequirements memoryRequirements +} + +class VkSparseImageMemoryRequirements2 { + VkStructureType sType + void* pNext + VkSparseImageMemoryRequirements memoryRequirements +} + +class VkPhysicalDeviceFeatures2 { + VkStructureType sType + void* pNext + VkPhysicalDeviceFeatures features +} + +class VkPhysicalDeviceProperties2 { + VkStructureType sType + void* pNext + VkPhysicalDeviceProperties properties +} + +class VkFormatProperties2 { + VkStructureType sType + void* pNext + VkFormatProperties formatProperties +} + +class VkImageFormatProperties2 { + VkStructureType sType + void* pNext + VkImageFormatProperties imageFormatProperties +} + +class VkPhysicalDeviceImageFormatInfo2 { + VkStructureType sType + const void* pNext + VkFormat format + VkImageType type + VkImageTiling tiling + VkImageUsageFlags usage + VkImageCreateFlags flags +} + +class VkQueueFamilyProperties2 { + VkStructureType sType + void* pNext + VkQueueFamilyProperties queueFamilyProperties +} + +class VkPhysicalDeviceMemoryProperties2 { + VkStructureType sType + void* pNext + VkPhysicalDeviceMemoryProperties memoryProperties +} + +class VkSparseImageFormatProperties2 { + VkStructureType sType + void* pNext + VkSparseImageFormatProperties properties +} + +class VkPhysicalDeviceSparseImageFormatInfo2 { + VkStructureType sType + const void* pNext + VkFormat format + VkImageType type + VkSampleCountFlagBits samples + VkImageUsageFlags usage + VkImageTiling tiling +} + +class VkPhysicalDevicePointClippingProperties { + VkStructureType sType + void* pNext + VkPointClippingBehavior pointClippingBehavior +} + +class VkInputAttachmentAspectReference { + u32 subpass + u32 inputAttachmentIndex + VkImageAspectFlags aspectMask +} + +class VkRenderPassInputAttachmentAspectCreateInfo { + VkStructureType sType + const void* pNext + u32 aspectReferenceCount + const VkInputAttachmentAspectReference* pAspectReferences +} + +class VkImageViewUsageCreateInfo { + VkStructureType sType + const void* pNext + VkImageUsageFlags usage +} + +class VkPipelineTessellationDomainOriginStateCreateInfo { + VkStructureType sType + const void* pNext + VkTessellationDomainOrigin domainOrigin +} + +class VkRenderPassMultiviewCreateInfo { + VkStructureType sType + const void* pNext + u32 subpassCount + const u32* pViewMasks + u32 dependencyCount + const s32* pViewOffsets + u32 correlationMaskCount + const u32* pCorrelationMasks +} + +class VkPhysicalDeviceMultiviewFeatures { + VkStructureType sType + void* pNext + VkBool32 multiview + VkBool32 multiviewGeometryShader + VkBool32 multiviewTessellationShader +} + +class VkPhysicalDeviceMultiviewProperties { + VkStructureType sType + void* pNext + u32 maxMultiviewViewCount + u32 maxMultiviewInstanceIndex +} + +class VkPhysicalDeviceVariablePointerFeatures { + VkStructureType sType + void* pNext + VkBool32 variablePointersStorageBuffer + VkBool32 variablePointers +} + +class VkPhysicalDeviceProtectedMemoryFeatures { + VkStructureType sType + void* pNext + VkBool32 protectedMemory +} + +class VkPhysicalDeviceProtectedMemoryProperties { + VkStructureType sType + void* pNext + VkBool32 protectedNoFault +} + +class VkDeviceQueueInfo2 { + VkStructureType sType + const void* pNext + VkDeviceQueueCreateFlags flags + u32 queueFamilyIndex + u32 queueIndex +} + +class VkProtectedSubmitInfo { + VkStructureType sType + const void* pNext + VkBool32 protectedSubmit +} + +class VkSamplerYcbcrConversionCreateInfo { + VkStructureType sType + const void* pNext + VkFormat format + VkSamplerYcbcrModelConversion ycbcrModel + VkSamplerYcbcrRange ycbcrRange + VkComponentMapping components + VkChromaLocation xChromaOffset + VkChromaLocation yChromaOffset + VkFilter chromaFilter + VkBool32 forceExplicitReconstruction +} + +class VkSamplerYcbcrConversionInfo { + VkStructureType sType + const void* pNext + VkSamplerYcbcrConversion conversion +} + +class VkBindImagePlaneMemoryInfo { + VkStructureType sType + const void* pNext + VkImageAspectFlagBits planeAspect +} + +class VkImagePlaneMemoryRequirementsInfo { + VkStructureType sType + const void* pNext + VkImageAspectFlagBits planeAspect +} + +class VkPhysicalDeviceSamplerYcbcrConversionFeatures { + VkStructureType sType + void* pNext + VkBool32 samplerYcbcrConversion +} + +class VkSamplerYcbcrConversionImageFormatProperties { + VkStructureType sType + void* pNext + u32 combinedImageSamplerDescriptorCount +} + +class VkDescriptorUpdateTemplateEntry { + u32 dstBinding + u32 dstArrayElement + u32 descriptorCount + VkDescriptorType descriptorType + platform.size_t offset + platform.size_t stride +} + +class VkDescriptorUpdateTemplateCreateInfo { + VkStructureType sType + void* pNext + VkDescriptorUpdateTemplateCreateFlags flags + u32 descriptorUpdateEntryCount + const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries + VkDescriptorUpdateTemplateType templateType + VkDescriptorSetLayout descriptorSetLayout + VkPipelineBindPoint pipelineBindPoint + VkPipelineLayout pipelineLayout + u32 set +} + +class VkExternalMemoryProperties { + VkExternalMemoryFeatureFlags externalMemoryFeatures + VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes + VkExternalMemoryHandleTypeFlags compatibleHandleTypes +} + +class VkPhysicalDeviceExternalImageFormatInfo { + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagBits handleType +} + +class VkExternalImageFormatProperties { + VkStructureType sType + void* pNext + VkExternalMemoryProperties externalMemoryProperties +} + +class VkPhysicalDeviceExternalBufferInfo { + VkStructureType sType + const void* pNext + VkBufferCreateFlags flags + VkBufferUsageFlags usage + VkExternalMemoryHandleTypeFlagBits handleType +} + +class VkExternalBufferProperties { + VkStructureType sType + void* pNext + VkExternalMemoryProperties externalMemoryProperties +} + +class VkPhysicalDeviceIDProperties { + VkStructureType sType + void* pNext + u8[VK_UUID_SIZE] deviceUUID + u8[VK_UUID_SIZE] driverUUID + u8[VK_LUID_SIZE] deviceLUID + u32 deviceNodeMask + VkBool32 deviceLUIDValid +} + +class VkExternalMemoryImageCreateInfo { + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlags handleTypes +} + +class VkExternalMemoryBufferCreateInfo { + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlags handleTypes +} + +class VkExportMemoryAllocateInfo { + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlags handleTypes +} + +class VkPhysicalDeviceExternalFenceInfo { + VkStructureType sType + const void* pNext + VkExternalFenceHandleTypeFlagBits handleType +} + +class VkExternalFenceProperties { + VkStructureType sType + void* pNext + VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes + VkExternalFenceHandleTypeFlags compatibleHandleTypes + VkExternalFenceFeatureFlags externalFenceFeatures +} + +class VkExportFenceCreateInfo { + VkStructureType sType + const void* pNext + VkExternalFenceHandleTypeFlags handleTypes +} + +class VkExportSemaphoreCreateInfo { + VkStructureType sType + const void* pNext + VkExternalSemaphoreHandleTypeFlags handleTypes +} + +class VkPhysicalDeviceExternalSemaphoreInfo { + VkStructureType sType + const void* pNext + VkExternalSemaphoreHandleTypeFlagBits handleType +} + +class VkExternalSemaphoreProperties { + VkStructureType sType + void* pNext + VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes + VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes + VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures +} + +class VkPhysicalDeviceMaintenance3Properties { + VkStructureType sType + void* pNext + u32 maxPerSetDescriptors + VkDeviceSize maxMemoryAllocationSize +} + +class VkDescriptorSetLayoutSupport { + VkStructureType sType + void* pNext + VkBool32 supported +} + +class VkPhysicalDeviceShaderDrawParameterFeatures { + VkStructureType sType + void* pNext + VkBool32 shaderDrawParameters +} + + @extension("VK_KHR_surface") // 1 class VkSurfaceCapabilitiesKHR { u32 minImageCount @@ -3726,6 +4534,62 @@ class VkPresentInfoKHR { VkResult* pResults } +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +class VkImageSwapchainCreateInfoKHR { + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchain +} + +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +class VkBindImageMemorySwapchainInfoKHR { + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchain + u32 imageIndex +} + +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +class VkAcquireNextImageInfoKHR { + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchain + u64 timeout + VkSemaphore semaphore + VkFence fence + u32 deviceMask +} + +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +class VkDeviceGroupPresentCapabilitiesKHR { + VkStructureType sType + const void* pNext + u32[VK_MAX_DEVICE_GROUP_SIZE] presentMask + VkDeviceGroupPresentModeFlagsKHR modes +} + +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +class VkDeviceGroupPresentInfoKHR { + VkStructureType sType + const void* pNext + u32 swapchainCount + const u32* pDeviceMasks + VkDeviceGroupPresentModeFlagBitsKHR mode +} + +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +class VkDeviceGroupSwapchainCreateInfoKHR { + VkStructureType sType + const void* pNext + VkDeviceGroupPresentModeFlagsKHR modes +} + @extension("VK_KHR_display") // 3 class VkDisplayPropertiesKHR { VkDisplayKHR display @@ -3956,8 +4820,8 @@ class VkTextureLODGatherFormatPropertiesAMD { VkBool32 supportsTextureGatherLODBiasAMD } -@extension("VK_KHX_multiview") // 54 -class VkRenderPassMultiviewCreateInfoKHX { +@extension("VK_KHR_multiview") // 54 +class VkRenderPassMultiviewCreateInfoKHR { VkStructureType sType const void* pNext u32 subpassCount @@ -3968,8 +4832,8 @@ class VkRenderPassMultiviewCreateInfoKHX { const u32* pCorrelationMasks } -@extension("VK_KHX_multiview") // 54 -class VkPhysicalDeviceMultiviewFeaturesKHX { +@extension("VK_KHR_multiview") // 54 +class VkPhysicalDeviceMultiviewFeaturesKHR { VkStructureType sType void* pNext VkBool32 multiview @@ -3977,8 +4841,8 @@ class VkPhysicalDeviceMultiviewFeaturesKHX { VkBool32 multiviewTessellationShader } -@extension("VK_KHX_multiview") // 54 -class VkPhysicalDeviceMultiviewPropertiesKHX { +@extension("VK_KHR_multiview") // 54 +class VkPhysicalDeviceMultiviewPropertiesKHR { VkStructureType sType void* pNext u32 maxMultiviewViewCount @@ -4107,24 +4971,24 @@ class VkPhysicalDeviceSparseImageFormatInfo2KHR { VkImageTiling tiling } -@extension("VK_KHX_device_group") // 61 -class VkMemoryAllocateFlagsInfoKHX { +@extension("VK_KHR_device_group") // 61 +class VkMemoryAllocateFlagsInfoKHR { VkStructureType sType const void* pNext - VkMemoryAllocateFlagsKHX flags + VkMemoryAllocateFlagsKHR flags u32 deviceMask } -@extension("VK_KHX_device_group") // 61 -class VkBindBufferMemoryDeviceGroupInfoKHX { +@extension("VK_KHR_device_group") // 61 +class VkBindBufferMemoryDeviceGroupInfoKHR { VkStructureType sType const void* pNext u32 deviceIndexCount const u32* pDeviceIndices } -@extension("VK_KHX_device_group") // 61 -class VkBindImageMemoryDeviceGroupInfoKHX { +@extension("VK_KHR_device_group") // 61 +class VkBindImageMemoryDeviceGroupInfoKHR { VkStructureType sType const void* pNext u32 deviceIndexCount @@ -4133,8 +4997,8 @@ class VkBindImageMemoryDeviceGroupInfoKHX { const VkRect2D* pSFRRects } -@extension("VK_KHX_device_group") // 61 -class VkDeviceGroupRenderPassBeginInfoKHX { +@extension("VK_KHR_device_group") // 61 +class VkDeviceGroupRenderPassBeginInfoKHR { VkStructureType sType const void* pNext u32 deviceMask @@ -4142,15 +5006,15 @@ class VkDeviceGroupRenderPassBeginInfoKHX { const VkRect2D* pDeviceRenderAreas } -@extension("VK_KHX_device_group") // 61 -class VkDeviceGroupCommandBufferBeginInfoKHX { +@extension("VK_KHR_device_group") // 61 +class VkDeviceGroupCommandBufferBeginInfoKHR { VkStructureType sType const void* pNext u32 deviceMask } -@extension("VK_KHX_device_group") // 61 -class VkDeviceGroupSubmitInfoKHX { +@extension("VK_KHR_device_group") // 61 +class VkDeviceGroupSubmitInfoKHR { VkStructureType sType const void* pNext u32 waitSemaphoreCount @@ -4161,64 +5025,14 @@ class VkDeviceGroupSubmitInfoKHX { const u32* pSignalSemaphoreDeviceIndices } -@extension("VK_KHX_device_group") // 61 -class VkDeviceGroupBindSparseInfoKHX { +@extension("VK_KHR_device_group") // 61 +class VkDeviceGroupBindSparseInfoKHR { VkStructureType sType const void* pNext u32 resourceDeviceIndex u32 memoryDeviceIndex } -@extension("VK_KHX_device_group") // 61 -class VkDeviceGroupPresentCapabilitiesKHX { - VkStructureType sType - const void* pNext - u32[VK_MAX_DEVICE_GROUP_SIZE_KHX] presentMask - VkDeviceGroupPresentModeFlagsKHX modes -} - -@extension("VK_KHX_device_group") // 61 -class VkImageSwapchainCreateInfoKHX { - VkStructureType sType - const void* pNext - VkSwapchainKHR swapchain -} - -@extension("VK_KHX_device_group") // 61 -class VkBindImageMemorySwapchainInfoKHX { - VkStructureType sType - const void* pNext - VkSwapchainKHR swapchain - u32 imageIndex -} - -@extension("VK_KHX_device_group") // 61 -class VkAcquireNextImageInfoKHX { - VkStructureType sType - const void* pNext - VkSwapchainKHR swapchain - u64 timeout - VkSemaphore semaphore - VkFence fence - u32 deviceMask -} - -@extension("VK_KHX_device_group") // 61 -class VkDeviceGroupPresentInfoKHX { - VkStructureType sType - const void* pNext - u32 swapchainCount - const u32* pDeviceMasks - VkDeviceGroupPresentModeFlagBitsKHX mode -} - -@extension("VK_KHX_device_group") // 61 -class VkDeviceGroupSwapchainCreateInfoKHX { - VkStructureType sType - const void* pNext - VkDeviceGroupPresentModeFlagsKHX modes -} - @extension("VK_EXT_validation_flags") // 62 class VkValidationFlagsEXT { VkStructureType sType @@ -4235,17 +5049,17 @@ class VkViSurfaceCreateInfoNN { void* window } -@extension("VK_KHX_device_group_creation") // 71 -class VkPhysicalDeviceGroupPropertiesKHX { +@extension("VK_KHR_device_group_creation") // 71 +class VkPhysicalDeviceGroupPropertiesKHR { VkStructureType sType void* pNext u32 physicalDeviceCount - VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE_KHX] physicalDevices + VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE] physicalDevices VkBool32 subsetAllocation } -@extension("VK_KHX_device_group_creation") // 71 -class VkDeviceGroupDeviceCreateInfoKHX { +@extension("VK_KHR_device_group_creation") // 71 +class VkDeviceGroupDeviceCreateInfoKHR { VkStructureType sType const void* pNext u32 physicalDeviceCount @@ -4295,7 +5109,7 @@ class VkPhysicalDeviceIDPropertiesKHR { void* pNext u8[VK_UUID_SIZE] deviceUUID u8[VK_UUID_SIZE] driverUUID - u8[VK_LUID_SIZE_KHR] deviceLUID + u8[VK_LUID_SIZE] deviceLUID u32 deviceNodeMask VkBool32 deviceLUIDValid } @@ -5233,6 +6047,22 @@ class VkShaderModuleValidationCacheCreateInfoEXT { VkValidationCacheEXT validationCache } +@extension("VK_KHR_maintenance3") // 169 +class VkPhysicalDeviceMaintenance3PropertiesKHR { + VkStructureType sType + void* pNext + u32 maxPerSetDescriptors + VkDeviceSize maxMemoryAllocationSize +} + +@extension("VK_KHR_maintenance3") // 169 +class VkDescriptorSetLayoutSupportKHR { + VkStructureType sType + void* pNext + VkBool32 supported +} + + //////////////// // Commands // //////////////// @@ -7428,6 +8258,241 @@ cmd void vkCmdExecuteCommands( } } +//@vulkan1_1 functions + +@vulkan1_1 +cmd VkResult vkEnumerateInstanceVersion( + u32* pApiVersion) { + return ? +} + +@vulkan1_1 +cmd VkResult vkBindBufferMemory2( + VkDevice device, + u32 bindInfoCount, + const VkBindBufferMemoryInfo* pBindInfos) { + return ? +} + +@vulkan1_1 +cmd VkResult vkBindImageMemory2( + VkDevice device, + u32 bindInfoCount, + const VkBindImageMemoryInfo* pBindInfos) { + return ? +} + +@vulkan1_1 +cmd void vkGetDeviceGroupPeerMemoryFeatures( + VkDevice device, + u32 heapIndex, + u32 localDeviceIndex, + u32 remoteDeviceIndex, + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) { +} + +@vulkan1_1 +cmd void vkCmdSetDeviceMask( + VkCommandBuffer commandBuffer, + u32 deviceMask) { +} + +@vulkan1_1 +cmd void vkCmdDispatchBase( + VkCommandBuffer commandBuffer, + u32 baseGroupX, + u32 baseGroupY, + u32 baseGroupZ, + u32 groupCountX, + u32 groupCountY, + u32 groupCountZ) { +} + +@threadSafety("system") +@vulkan1_1 +cmd VkResult vkEnumeratePhysicalDeviceGroups( + VkInstance instance, + u32* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { + instanceObject := GetInstance(instance) + + physicalDeviceGroupCount := as!u32(?) + pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount + physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount] + + for i in (0 .. physicalDeviceGroupCount) { + physicalDevice := ? + physicalDevices[i] = physicalDevice + if !(physicalDevice in State.PhysicalDevices) { + State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance) + } + } + + return ? +} + +@vulkan1_1 +cmd void vkGetImageMemoryRequirements2( + VkDevice device, + const VkImageMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements) { +} + +@vulkan1_1 +cmd void vkGetBufferMemoryRequirements2( + VkDevice device, + const VkBufferMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements) { +} + +@vulkan1_1 +cmd void vkGetImageSparseMemoryRequirements2( + VkDevice device, + const VkImageSparseMemoryRequirementsInfo2* pInfo, + u32* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) { +} + +@vulkan1_1 +cmd void vkGetPhysicalDeviceFeatures2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2* pFeatures) { +} + +@vulkan1_1 +cmd void vkGetPhysicalDeviceProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2* pProperties) { +} + +@vulkan1_1 +cmd void vkGetPhysicalDeviceFormatProperties2( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2* pFormatProperties) { +} + +@vulkan1_1 +cmd VkResult vkGetPhysicalDeviceImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, + VkImageFormatProperties2* pImageFormatProperties) { + return ? +} + +@vulkan1_1 +cmd void vkGetPhysicalDeviceQueueFamilyProperties2( + VkPhysicalDevice physicalDevice, + u32* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2* pQueueFamilyProperties) { +} + +@vulkan1_1 +cmd void vkGetPhysicalDeviceMemoryProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2* pMemoryProperties) { +} + +@vulkan1_1 +cmd void vkGetPhysicalDeviceSparseImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, + u32* pPropertyCount, + VkSparseImageFormatProperties2* pProperties) { +} + +@vulkan1_1 +cmd void vkTrimCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlags flags) { +} + + +@vulkan1_1 +cmd void vkGetDeviceQueue2( + VkDevice device, + const VkDeviceQueueInfo2* pQueueInfo, + VkQueue* pQueue) { + deviceObject := GetDevice(device) + + queue := ? + pQueue[0] = queue + + if !(queue in State.Queues) { + State.Queues[queue] = new!QueueObject(device: device) + } +} + +@vulkan1_1 +cmd VkResult vkCreateSamplerYcbcrConversion( + VkDevice device, + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSamplerYcbcrConversion* pYcbcrConversion) { + return ? +} + +@vulkan1_1 +cmd void vkDestroySamplerYcbcrConversion( + VkDevice device, + VkSamplerYcbcrConversion ycbcrConversion, + const VkAllocationCallbacks* pAllocator) { +} + +@vulkan1_1 +cmd VkResult vkCreateDescriptorUpdateTemplate( + VkDevice device, + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) { + return ? +} + +@vulkan1_1 +cmd void vkDestroyDescriptorUpdateTemplate( + VkDevice device, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const VkAllocationCallbacks* pAllocator) { +} + +@vulkan1_1 +cmd void vkUpdateDescriptorSetWithTemplate( + VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const void* pData) { +} + +@vulkan1_1 +cmd void vkGetPhysicalDeviceExternalBufferProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties) { +} + +@vulkan1_1 +cmd void vkGetPhysicalDeviceExternalFenceProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, + VkExternalFenceProperties* pExternalFenceProperties) { +} + +@vulkan1_1 +cmd void vkGetPhysicalDeviceExternalSemaphoreProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, + VkExternalSemaphoreProperties* pExternalSemaphoreProperties) { +} + +@vulkan1_1 +cmd void vkGetDescriptorSetLayoutSupport( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupport* pSupport) { +} + + @extension("VK_KHR_surface") // 1 cmd void vkDestroySurfaceKHR( VkInstance instance, @@ -7582,6 +8647,42 @@ cmd VkResult vkQueuePresentKHR( return ? } +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +cmd VkResult vkGetDeviceGroupPresentCapabilitiesKHR( + VkDevice device, + VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { + return ? +} + +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +cmd VkResult vkGetDeviceGroupSurfacePresentModesKHR( + VkDevice device, + VkSurfaceKHR surface, + VkDeviceGroupPresentModeFlagsKHR* pModes) { + return ? +} + +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +cmd VkResult vkGetPhysicalDevicePresentRectanglesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + u32* pRectCount, + VkRect2D* pRects) { + return ? +} + +@vulkan1_1 +@extension("VK_KHR_swapchain") // 2 +cmd VkResult vkAcquireNextImage2KHR( + VkDevice device, + const VkAcquireNextImageInfoKHR* pAcquireInfo, + u32* pImageIndex) { + return ? +} + @extension("VK_KHR_display") // 3 cmd VkResult vkGetPhysicalDeviceDisplayPropertiesKHR( VkPhysicalDevice physicalDevice, @@ -7974,46 +9075,24 @@ cmd void vkGetPhysicalDeviceSparseImageFormatProperties2KHR( VkSparseImageFormatProperties2KHR* pProperties) { } -@extension("VK_KHX_device_group") // 61 -cmd void vkGetDeviceGroupPeerMemoryFeaturesKHX( +@extension("VK_KHR_device_group") // 61 +cmd void vkGetDeviceGroupPeerMemoryFeaturesKHR( VkDevice device, u32 heapIndex, u32 localDeviceIndex, u32 remoteDeviceIndex, - VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures) { + VkPeerMemoryFeatureFlagsKHR* pPeerMemoryFeatures) { } -@extension("VK_KHX_device_group") // 61 -cmd void vkCmdSetDeviceMaskKHX( +@extension("VK_KHR_device_group") // 61 +cmd void vkCmdSetDeviceMaskKHR( VkCommandBuffer commandBuffer, u32 deviceMask) { } -@extension("VK_KHX_device_group") // 61 -cmd VkResult vkGetDeviceGroupPresentCapabilitiesKHX( - VkDevice device, - VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities) { - return ? -} - -@extension("VK_KHX_device_group") // 61 -cmd VkResult vkGetDeviceGroupSurfacePresentModesKHX( - VkDevice device, - VkSurfaceKHR surface, - VkDeviceGroupPresentModeFlagsKHX* pModes) { - return ? -} - -@extension("VK_KHX_device_group") // 61 -cmd VkResult vkAcquireNextImage2KHX( - VkDevice device, - const VkAcquireNextImageInfoKHX* pAcquireInfo, - u32* pImageIndex) { - return ? -} -@extension("VK_KHX_device_group") // 61 -cmd void vkCmdDispatchBaseKHX( +@extension("VK_KHR_device_group") // 61 +cmd void vkCmdDispatchBaseKHR( VkCommandBuffer commandBuffer, u32 baseGroupX, u32 baseGroupY, @@ -8023,15 +9102,6 @@ cmd void vkCmdDispatchBaseKHX( u32 groupCountZ) { } -@extension("VK_KHX_device_group") // 61 -cmd VkResult vkGetPhysicalDevicePresentRectanglesKHX( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - u32* pRectCount, - VkRect2D* pRects) { - return ? -} - @extension("VK_NN_vi_surface") // 63 cmd VkResult vkCreateViSurfaceNN( VkInstance instance, @@ -8048,11 +9118,26 @@ cmd void vkTrimCommandPoolKHR( VkCommandPoolTrimFlagsKHR flags) { } -@extension("VK_KHX_device_group_creation") // 71 -cmd VkResult vkEnumeratePhysicalDeviceGroupsKHX( +@extension("VK_KHR_device_group_creation") // 71 +@threadSafety("system") +cmd VkResult vkEnumeratePhysicalDeviceGroupsKHR( VkInstance instance, u32* pPhysicalDeviceGroupCount, - VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties) { + VkPhysicalDeviceGroupPropertiesKHR* pPhysicalDeviceGroupProperties) { + instanceObject := GetInstance(instance) + + physicalDeviceGroupCount := as!u32(?) + pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount + physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount] + + for i in (0 .. physicalDeviceGroupCount) { + physicalDevice := ? + physicalDevices[i] = physicalDevice + if !(physicalDevice in State.PhysicalDevices) { + State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance) + } + } + return ? } @@ -8543,6 +9628,13 @@ cmd VkResult vkGetValidationCacheDataEXT( return ? } +@extension("VK_KHR_maintenance3") // 169 +cmd void vkGetDescriptorSetLayoutSupportKHR( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupportKHR* pSupport) { +} + //////////////// // Validation // //////////////// diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h index 7813e4b394..f96a9fa260 100644 --- a/vulkan/include/vulkan/vulkan.h +++ b/vulkan/include/vulkan/vulkan.h @@ -138,6 +138,8 @@ typedef enum VkResult { VK_ERROR_TOO_MANY_OBJECTS = -10, VK_ERROR_FORMAT_NOT_SUPPORTED = -11, VK_ERROR_FRAGMENTED_POOL = -12, + VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000, + VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, VK_ERROR_SURFACE_LOST_KHR = -1000000000, VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, VK_SUBOPTIMAL_KHR = 1000001003, @@ -145,8 +147,6 @@ typedef enum VkResult { VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, VK_ERROR_INVALID_SHADER_NV = -1000012000, - VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000, - VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = -1000072003, VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL, VK_RESULT_END_RANGE = VK_INCOMPLETE, VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1), @@ -203,8 +203,79 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, + VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, + VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, + VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = 1000120000, + VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, + VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, + VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, + VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, + VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001, + VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, + VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = 1000063000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, + VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, + VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, @@ -223,48 +294,13 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, - VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX = 1000053000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX = 1000053001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX = 1000053002, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX = 1000060000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX = 1000060003, - VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX = 1000060004, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX = 1000060005, - VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX = 1000060006, - VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX = 1000060010, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHX = 1000060013, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHX = 1000060014, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX = 1000060007, - VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX = 1000060008, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX = 1000060009, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX = 1000060011, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX = 1000060012, VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX = 1000070000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX = 1000070001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = 1000071000, - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = 1000071001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = 1000071002, - VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = 1000071003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = 1000071004, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = 1000072000, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = 1000072001, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = 1000072002, VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, @@ -273,9 +309,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001, VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR = 1000074002, VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = 1000076000, - VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = 1000076001, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = 1000077000, VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000, VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001, VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002, @@ -283,9 +316,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = 1000083000, VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, - VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000, VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000, VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001, VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002, @@ -305,26 +336,16 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = 1000112000, - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = 1000112001, - VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = 1000113000, VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000, VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = 1000117000, - VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = 1000117001, - VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = 1000117002, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = 1000117003, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = 1000120000, VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000, VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = 1000127000, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = 1000127001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000, VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001, VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, @@ -332,25 +353,12 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146000, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146001, - VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146002, - VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = 1000146003, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = 1000146004, VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = 1000147000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = 1000156000, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = 1000156001, - VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = 1000156002, - VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = 1000156003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = 1000156004, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = 1000156005, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = 1000157000, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = 1000157001, VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO, @@ -565,6 +573,40 @@ typedef enum VkFormat { VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, + VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, + VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, + VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, + VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, + VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, + VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, @@ -573,40 +615,6 @@ typedef enum VkFormat { VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - VK_FORMAT_G8B8G8R8_422_UNORM_KHR = 1000156000, - VK_FORMAT_B8G8R8G8_422_UNORM_KHR = 1000156001, - VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = 1000156002, - VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = 1000156003, - VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = 1000156004, - VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = 1000156005, - VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = 1000156006, - VK_FORMAT_R10X6_UNORM_PACK16_KHR = 1000156007, - VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = 1000156008, - VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = 1000156009, - VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = 1000156010, - VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = 1000156011, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = 1000156012, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = 1000156013, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = 1000156014, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = 1000156015, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = 1000156016, - VK_FORMAT_R12X4_UNORM_PACK16_KHR = 1000156017, - VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = 1000156018, - VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = 1000156019, - VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = 1000156020, - VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = 1000156021, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = 1000156022, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = 1000156023, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = 1000156024, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = 1000156025, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = 1000156026, - VK_FORMAT_G16B16G16R16_422_UNORM_KHR = 1000156027, - VK_FORMAT_B16G16R16G16_422_UNORM_KHR = 1000156028, - VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = 1000156029, - VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = 1000156030, - VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = 1000156031, - VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = 1000156032, - VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = 1000156033, VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED, VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK, VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1), @@ -673,10 +681,10 @@ typedef enum VkImageLayout { VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, VK_IMAGE_LAYOUT_PREINITIALIZED = 8, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = 1000117000, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = 1000117001, VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1), @@ -1058,15 +1066,15 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_DESCRIPTOR_SET = 23, VK_OBJECT_TYPE_FRAMEBUFFER = 24, VK_OBJECT_TYPE_COMMAND_POOL = 25, + VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, + VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, - VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = 1000085000, VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000, VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001, - VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = 1000156000, VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN, VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL, @@ -1090,17 +1098,17 @@ typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000, + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, + VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000, - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 0x00020000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 0x00040000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 0x00080000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 0x00100000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 0x00200000, - VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = 0x00400000, - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = 0x00800000, VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFormatFeatureFlagBits; typedef VkFlags VkFormatFeatureFlags; @@ -1124,13 +1132,14 @@ typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, - VK_IMAGE_CREATE_BIND_SFR_BIT_KHX = 0x00000040, - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020, - VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = 0x00000080, - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = 0x00000100, + VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400, + VK_IMAGE_CREATE_BIND_SFR_BIT = 0x00000040, + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020, + VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080, + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, + VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, + VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, - VK_IMAGE_CREATE_DISJOINT_BIT_KHR = 0x00000200, - VK_IMAGE_CREATE_ALIAS_BIT_KHR = 0x00000400, VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageCreateFlagBits; typedef VkFlags VkImageCreateFlags; @@ -1152,6 +1161,7 @@ typedef enum VkQueueFlagBits { VK_QUEUE_COMPUTE_BIT = 0x00000002, VK_QUEUE_TRANSFER_BIT = 0x00000004, VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, + VK_QUEUE_PROTECTED_BIT = 0x00000010, VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueueFlagBits; typedef VkFlags VkQueueFlags; @@ -1162,17 +1172,23 @@ typedef enum VkMemoryPropertyFlagBits { VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, + VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020, VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryPropertyFlagBits; typedef VkFlags VkMemoryPropertyFlags; typedef enum VkMemoryHeapFlagBits { VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX = 0x00000002, + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002, VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryHeapFlagBits; typedef VkFlags VkMemoryHeapFlags; typedef VkFlags VkDeviceCreateFlags; + +typedef enum VkDeviceQueueCreateFlagBits { + VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, + VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDeviceQueueCreateFlagBits; typedef VkFlags VkDeviceQueueCreateFlags; typedef enum VkPipelineStageFlagBits { @@ -1204,9 +1220,9 @@ typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, - VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = 0x00000010, - VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = 0x00000020, - VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = 0x00000040, + VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, + VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, + VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageAspectFlagBits; typedef VkFlags VkImageAspectFlags; @@ -1263,6 +1279,7 @@ typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferCreateFlagBits; typedef VkFlags VkBufferCreateFlags; @@ -1289,8 +1306,8 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX = 0x00000008, - VK_PIPELINE_CREATE_DISPATCH_BASE_KHX = 0x00000010, + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, + VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010, VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineCreateFlagBits; typedef VkFlags VkPipelineCreateFlags; @@ -1393,8 +1410,8 @@ typedef VkFlags VkAccessFlags; typedef enum VkDependencyFlagBits { VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, - VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX = 0x00000002, - VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX = 0x00000004, + VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004, + VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002, VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDependencyFlagBits; typedef VkFlags VkDependencyFlags; @@ -1402,6 +1419,7 @@ typedef VkFlags VkDependencyFlags; typedef enum VkCommandPoolCreateFlagBits { VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, + VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004, VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandPoolCreateFlagBits; typedef VkFlags VkCommandPoolCreateFlags; @@ -3483,10 +3501,837 @@ VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( const VkCommandBuffer* pCommandBuffers); #endif +#define VK_VERSION_1_1 1 +// Vulkan 1.1 version number +#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)// Patch version should always be set to 0 + + +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) + +#define VK_MAX_DEVICE_GROUP_SIZE 32 +#define VK_LUID_SIZE 8 +#define VK_QUEUE_FAMILY_EXTERNAL (~0U-1) + + +typedef enum VkPointClippingBehavior { + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, + VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, + VK_POINT_CLIPPING_BEHAVIOR_END_RANGE = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, + VK_POINT_CLIPPING_BEHAVIOR_RANGE_SIZE = (VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES + 1), + VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPointClippingBehavior; + +typedef enum VkTessellationDomainOrigin { + VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, + VK_TESSELLATION_DOMAIN_ORIGIN_BEGIN_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_END_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_RANGE_SIZE = (VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT + 1), + VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF +} VkTessellationDomainOrigin; + +typedef enum VkSamplerYcbcrModelConversion { + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_BEGIN_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_END_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RANGE_SIZE = (VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY + 1), + VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF +} VkSamplerYcbcrModelConversion; + +typedef enum VkSamplerYcbcrRange { + VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, + VK_SAMPLER_YCBCR_RANGE_BEGIN_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, + VK_SAMPLER_YCBCR_RANGE_END_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, + VK_SAMPLER_YCBCR_RANGE_RANGE_SIZE = (VK_SAMPLER_YCBCR_RANGE_ITU_NARROW - VK_SAMPLER_YCBCR_RANGE_ITU_FULL + 1), + VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerYcbcrRange; + +typedef enum VkChromaLocation { + VK_CHROMA_LOCATION_COSITED_EVEN = 0, + VK_CHROMA_LOCATION_MIDPOINT = 1, + VK_CHROMA_LOCATION_BEGIN_RANGE = VK_CHROMA_LOCATION_COSITED_EVEN, + VK_CHROMA_LOCATION_END_RANGE = VK_CHROMA_LOCATION_MIDPOINT, + VK_CHROMA_LOCATION_RANGE_SIZE = (VK_CHROMA_LOCATION_MIDPOINT - VK_CHROMA_LOCATION_COSITED_EVEN + 1), + VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF +} VkChromaLocation; + +typedef enum VkDescriptorUpdateTemplateType { + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET + 1), + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorUpdateTemplateType; + + +typedef enum VkSubgroupFeatureFlagBits { + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; + +typedef enum VkPeerMemoryFeatureFlagBits { + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008, + VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPeerMemoryFeatureFlagBits; +typedef VkFlags VkPeerMemoryFeatureFlags; + +typedef enum VkMemoryAllocateFlagBits { + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, + VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryAllocateFlagBits; +typedef VkFlags VkMemoryAllocateFlags; +typedef VkFlags VkCommandPoolTrimFlags; +typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; + +typedef enum VkExternalMemoryHandleTypeFlagBits { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalMemoryHandleTypeFlagBits; +typedef VkFlags VkExternalMemoryHandleTypeFlags; + +typedef enum VkExternalMemoryFeatureFlagBits { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalMemoryFeatureFlagBits; +typedef VkFlags VkExternalMemoryFeatureFlags; + +typedef enum VkExternalFenceHandleTypeFlagBits { + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008, + VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalFenceHandleTypeFlagBits; +typedef VkFlags VkExternalFenceHandleTypeFlags; + +typedef enum VkExternalFenceFeatureFlagBits { + VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalFenceFeatureFlagBits; +typedef VkFlags VkExternalFenceFeatureFlags; + +typedef enum VkFenceImportFlagBits { + VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001, + VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFenceImportFlagBits; +typedef VkFlags VkFenceImportFlags; + +typedef enum VkSemaphoreImportFlagBits { + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001, + VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreImportFlagBits; +typedef VkFlags VkSemaphoreImportFlags; + +typedef enum VkExternalSemaphoreHandleTypeFlagBits { + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalSemaphoreHandleTypeFlagBits; +typedef VkFlags VkExternalSemaphoreHandleTypeFlags; + +typedef enum VkExternalSemaphoreFeatureFlagBits { + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalSemaphoreFeatureFlagBits; +typedef VkFlags VkExternalSemaphoreFeatureFlags; + +typedef struct VkPhysicalDeviceSubgroupProperties { + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; + +typedef struct VkBindBufferMemoryInfo { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindBufferMemoryInfo; + +typedef struct VkBindImageMemoryInfo { + VkStructureType sType; + const void* pNext; + VkImage image; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindImageMemoryInfo; + +typedef struct VkPhysicalDevice16BitStorageFeatures { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; +} VkPhysicalDevice16BitStorageFeatures; + +typedef struct VkMemoryDedicatedRequirements { + VkStructureType sType; + void* pNext; + VkBool32 prefersDedicatedAllocation; + VkBool32 requiresDedicatedAllocation; +} VkMemoryDedicatedRequirements; + +typedef struct VkMemoryDedicatedAllocateInfo { + VkStructureType sType; + const void* pNext; + VkImage image; + VkBuffer buffer; +} VkMemoryDedicatedAllocateInfo; + +typedef struct VkMemoryAllocateFlagsInfo { + VkStructureType sType; + const void* pNext; + VkMemoryAllocateFlags flags; + uint32_t deviceMask; +} VkMemoryAllocateFlagsInfo; + +typedef struct VkDeviceGroupRenderPassBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceMask; + uint32_t deviceRenderAreaCount; + const VkRect2D* pDeviceRenderAreas; +} VkDeviceGroupRenderPassBeginInfo; + +typedef struct VkDeviceGroupCommandBufferBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceMask; +} VkDeviceGroupCommandBufferBeginInfo; + +typedef struct VkDeviceGroupSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const uint32_t* pWaitSemaphoreDeviceIndices; + uint32_t commandBufferCount; + const uint32_t* pCommandBufferDeviceMasks; + uint32_t signalSemaphoreCount; + const uint32_t* pSignalSemaphoreDeviceIndices; +} VkDeviceGroupSubmitInfo; + +typedef struct VkDeviceGroupBindSparseInfo { + VkStructureType sType; + const void* pNext; + uint32_t resourceDeviceIndex; + uint32_t memoryDeviceIndex; +} VkDeviceGroupBindSparseInfo; + +typedef struct VkBindBufferMemoryDeviceGroupInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindBufferMemoryDeviceGroupInfo; + +typedef struct VkBindImageMemoryDeviceGroupInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; + uint32_t SFRRectCount; + const VkRect2D* pSFRRects; +} VkBindImageMemoryDeviceGroupInfo; + +typedef struct VkPhysicalDeviceGroupProperties { + VkStructureType sType; + void* pNext; + uint32_t physicalDeviceCount; + VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE]; + VkBool32 subsetAllocation; +} VkPhysicalDeviceGroupProperties; + +typedef struct VkDeviceGroupDeviceCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t physicalDeviceCount; + const VkPhysicalDevice* pPhysicalDevices; +} VkDeviceGroupDeviceCreateInfo; + +typedef struct VkBufferMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferMemoryRequirementsInfo2; + +typedef struct VkImageMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageMemoryRequirementsInfo2; + +typedef struct VkImageSparseMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageSparseMemoryRequirementsInfo2; + +typedef struct VkMemoryRequirements2 { + VkStructureType sType; + void* pNext; + VkMemoryRequirements memoryRequirements; +} VkMemoryRequirements2; + +typedef struct VkSparseImageMemoryRequirements2 { + VkStructureType sType; + void* pNext; + VkSparseImageMemoryRequirements memoryRequirements; +} VkSparseImageMemoryRequirements2; + +typedef struct VkPhysicalDeviceFeatures2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceFeatures features; +} VkPhysicalDeviceFeatures2; + +typedef struct VkPhysicalDeviceProperties2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceProperties properties; +} VkPhysicalDeviceProperties2; + +typedef struct VkFormatProperties2 { + VkStructureType sType; + void* pNext; + VkFormatProperties formatProperties; +} VkFormatProperties2; + +typedef struct VkImageFormatProperties2 { + VkStructureType sType; + void* pNext; + VkImageFormatProperties imageFormatProperties; +} VkImageFormatProperties2; + +typedef struct VkPhysicalDeviceImageFormatInfo2 { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkImageCreateFlags flags; +} VkPhysicalDeviceImageFormatInfo2; + +typedef struct VkQueueFamilyProperties2 { + VkStructureType sType; + void* pNext; + VkQueueFamilyProperties queueFamilyProperties; +} VkQueueFamilyProperties2; + +typedef struct VkPhysicalDeviceMemoryProperties2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceMemoryProperties memoryProperties; +} VkPhysicalDeviceMemoryProperties2; + +typedef struct VkSparseImageFormatProperties2 { + VkStructureType sType; + void* pNext; + VkSparseImageFormatProperties properties; +} VkSparseImageFormatProperties2; + +typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkSampleCountFlagBits samples; + VkImageUsageFlags usage; + VkImageTiling tiling; +} VkPhysicalDeviceSparseImageFormatInfo2; + +typedef struct VkPhysicalDevicePointClippingProperties { + VkStructureType sType; + void* pNext; + VkPointClippingBehavior pointClippingBehavior; +} VkPhysicalDevicePointClippingProperties; + +typedef struct VkInputAttachmentAspectReference { + uint32_t subpass; + uint32_t inputAttachmentIndex; + VkImageAspectFlags aspectMask; +} VkInputAttachmentAspectReference; + +typedef struct VkRenderPassInputAttachmentAspectCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t aspectReferenceCount; + const VkInputAttachmentAspectReference* pAspectReferences; +} VkRenderPassInputAttachmentAspectCreateInfo; + +typedef struct VkImageViewUsageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags usage; +} VkImageViewUsageCreateInfo; + +typedef struct VkPipelineTessellationDomainOriginStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkTessellationDomainOrigin domainOrigin; +} VkPipelineTessellationDomainOriginStateCreateInfo; + +typedef struct VkRenderPassMultiviewCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t subpassCount; + const uint32_t* pViewMasks; + uint32_t dependencyCount; + const int32_t* pViewOffsets; + uint32_t correlationMaskCount; + const uint32_t* pCorrelationMasks; +} VkRenderPassMultiviewCreateInfo; + +typedef struct VkPhysicalDeviceMultiviewFeatures { + VkStructureType sType; + void* pNext; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; +} VkPhysicalDeviceMultiviewFeatures; + +typedef struct VkPhysicalDeviceMultiviewProperties { + VkStructureType sType; + void* pNext; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; +} VkPhysicalDeviceMultiviewProperties; + +typedef struct VkPhysicalDeviceVariablePointerFeatures { + VkStructureType sType; + void* pNext; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; +} VkPhysicalDeviceVariablePointerFeatures; + +typedef struct VkPhysicalDeviceProtectedMemoryFeatures { + VkStructureType sType; + void* pNext; + VkBool32 protectedMemory; +} VkPhysicalDeviceProtectedMemoryFeatures; + +typedef struct VkPhysicalDeviceProtectedMemoryProperties { + VkStructureType sType; + void* pNext; + VkBool32 protectedNoFault; +} VkPhysicalDeviceProtectedMemoryProperties; + +typedef struct VkDeviceQueueInfo2 { + VkStructureType sType; + const void* pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} VkDeviceQueueInfo2; + +typedef struct VkProtectedSubmitInfo { + VkStructureType sType; + const void* pNext; + VkBool32 protectedSubmit; +} VkProtectedSubmitInfo; + +typedef struct VkSamplerYcbcrConversionCreateInfo { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkSamplerYcbcrModelConversion ycbcrModel; + VkSamplerYcbcrRange ycbcrRange; + VkComponentMapping components; + VkChromaLocation xChromaOffset; + VkChromaLocation yChromaOffset; + VkFilter chromaFilter; + VkBool32 forceExplicitReconstruction; +} VkSamplerYcbcrConversionCreateInfo; + +typedef struct VkSamplerYcbcrConversionInfo { + VkStructureType sType; + const void* pNext; + VkSamplerYcbcrConversion conversion; +} VkSamplerYcbcrConversionInfo; + +typedef struct VkBindImagePlaneMemoryInfo { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits planeAspect; +} VkBindImagePlaneMemoryInfo; + +typedef struct VkImagePlaneMemoryRequirementsInfo { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits planeAspect; +} VkImagePlaneMemoryRequirementsInfo; + +typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { + VkStructureType sType; + void* pNext; + VkBool32 samplerYcbcrConversion; +} VkPhysicalDeviceSamplerYcbcrConversionFeatures; + +typedef struct VkSamplerYcbcrConversionImageFormatProperties { + VkStructureType sType; + void* pNext; + uint32_t combinedImageSamplerDescriptorCount; +} VkSamplerYcbcrConversionImageFormatProperties; + +typedef struct VkDescriptorUpdateTemplateEntry { + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + size_t offset; + size_t stride; +} VkDescriptorUpdateTemplateEntry; + +typedef struct VkDescriptorUpdateTemplateCreateInfo { + VkStructureType sType; + void* pNext; + VkDescriptorUpdateTemplateCreateFlags flags; + uint32_t descriptorUpdateEntryCount; + const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries; + VkDescriptorUpdateTemplateType templateType; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineBindPoint pipelineBindPoint; + VkPipelineLayout pipelineLayout; + uint32_t set; +} VkDescriptorUpdateTemplateCreateInfo; + +typedef struct VkExternalMemoryProperties { + VkExternalMemoryFeatureFlags externalMemoryFeatures; + VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlags compatibleHandleTypes; +} VkExternalMemoryProperties; + +typedef struct VkPhysicalDeviceExternalImageFormatInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalImageFormatInfo; + +typedef struct VkExternalImageFormatProperties { + VkStructureType sType; + void* pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalImageFormatProperties; + +typedef struct VkPhysicalDeviceExternalBufferInfo { + VkStructureType sType; + const void* pNext; + VkBufferCreateFlags flags; + VkBufferUsageFlags usage; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalBufferInfo; + +typedef struct VkExternalBufferProperties { + VkStructureType sType; + void* pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalBufferProperties; + +typedef struct VkPhysicalDeviceIDProperties { + VkStructureType sType; + void* pNext; + uint8_t deviceUUID[VK_UUID_SIZE]; + uint8_t driverUUID[VK_UUID_SIZE]; + uint8_t deviceLUID[VK_LUID_SIZE]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; +} VkPhysicalDeviceIDProperties; + +typedef struct VkExternalMemoryImageCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryImageCreateInfo; + +typedef struct VkExternalMemoryBufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryBufferCreateInfo; + +typedef struct VkExportMemoryAllocateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExportMemoryAllocateInfo; + +typedef struct VkPhysicalDeviceExternalFenceInfo { + VkStructureType sType; + const void* pNext; + VkExternalFenceHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalFenceInfo; + +typedef struct VkExternalFenceProperties { + VkStructureType sType; + void* pNext; + VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; + VkExternalFenceHandleTypeFlags compatibleHandleTypes; + VkExternalFenceFeatureFlags externalFenceFeatures; +} VkExternalFenceProperties; + +typedef struct VkExportFenceCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalFenceHandleTypeFlags handleTypes; +} VkExportFenceCreateInfo; + +typedef struct VkExportSemaphoreCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalSemaphoreHandleTypeFlags handleTypes; +} VkExportSemaphoreCreateInfo; + +typedef struct VkPhysicalDeviceExternalSemaphoreInfo { + VkStructureType sType; + const void* pNext; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalSemaphoreInfo; + +typedef struct VkExternalSemaphoreProperties { + VkStructureType sType; + void* pNext; + VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; + VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; + VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; +} VkExternalSemaphoreProperties; + +typedef struct VkPhysicalDeviceMaintenance3Properties { + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; + +typedef struct VkDescriptorSetLayoutSupport { + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; + +typedef struct VkPhysicalDeviceShaderDrawParameterFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceShaderDrawParameterFeatures; + + +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t* pApiVersion); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); +typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion( + uint32_t* pApiVersion); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2( + VkDevice device, + uint32_t bindInfoCount, + const VkBindBufferMemoryInfo* pBindInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2( + VkDevice device, + uint32_t bindInfoCount, + const VkBindImageMemoryInfo* pBindInfos); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures( + VkDevice device, + uint32_t heapIndex, + uint32_t localDeviceIndex, + uint32_t remoteDeviceIndex, + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMask( + VkCommandBuffer commandBuffer, + uint32_t deviceMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBase( + VkCommandBuffer commandBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( + VkInstance instance, + uint32_t* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2( + VkDevice device, + const VkImageMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2( + VkDevice device, + const VkBufferMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2( + VkDevice device, + const VkImageSparseMemoryRequirementsInfo2* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, + VkImageFormatProperties2* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2* pMemoryProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkTrimCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2( + VkDevice device, + const VkDeviceQueueInfo2* pQueueInfo, + VkQueue* pQueue); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion( + VkDevice device, + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSamplerYcbcrConversion* pYcbcrConversion); + +VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversion( + VkDevice device, + VkSamplerYcbcrConversion ycbcrConversion, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplate( + VkDevice device, + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplate( + VkDevice device, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplate( + VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const void* pData); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFenceProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, + VkExternalFenceProperties* pExternalFenceProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphoreProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, + VkExternalSemaphoreProperties* pExternalSemaphoreProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupport* pSupport); +#endif + #define VK_KHR_surface 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) -#define VK_KHR_SURFACE_SPEC_VERSION 25 +#define VK_KHR_SURFACE_SPEC_VERSION 26 #define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" #define VK_COLORSPACE_SRGB_NONLINEAR_KHR VK_COLOR_SPACE_SRGB_NONLINEAR_KHR @@ -3550,6 +4395,15 @@ typedef enum VkCompositeAlphaFlagBitsKHR { } VkCompositeAlphaFlagBitsKHR; typedef VkFlags VkCompositeAlphaFlagsKHR; +typedef enum VkDeviceGroupPresentModeFlagBitsKHR { + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001, + VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002, + VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004, + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008, + VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDeviceGroupPresentModeFlagBitsKHR; +typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; + typedef struct VkSurfaceCapabilitiesKHR { uint32_t minImageCount; uint32_t maxImageCount; @@ -3608,12 +4462,13 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( #define VK_KHR_swapchain 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) -#define VK_KHR_SWAPCHAIN_SPEC_VERSION 68 +#define VK_KHR_SWAPCHAIN_SPEC_VERSION 69 #define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" typedef enum VkSwapchainCreateFlagBitsKHR { - VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX = 0x00000001, + VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHR = 0x00000001, + VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkSwapchainCreateFlagBitsKHR; typedef VkFlags VkSwapchainCreateFlagsKHR; @@ -3650,12 +4505,60 @@ typedef struct VkPresentInfoKHR { VkResult* pResults; } VkPresentInfoKHR; +typedef struct VkImageSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; +} VkImageSwapchainCreateInfoKHR; + +typedef struct VkBindImageMemorySwapchainInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint32_t imageIndex; +} VkBindImageMemorySwapchainInfoKHR; + +typedef struct VkAcquireNextImageInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint64_t timeout; + VkSemaphore semaphore; + VkFence fence; + uint32_t deviceMask; +} VkAcquireNextImageInfoKHR; + +typedef struct VkDeviceGroupPresentCapabilitiesKHR { + VkStructureType sType; + const void* pNext; + uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE]; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupPresentCapabilitiesKHR; + +typedef struct VkDeviceGroupPresentInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const uint32_t* pDeviceMasks; + VkDeviceGroupPresentModeFlagBitsKHR mode; +} VkDeviceGroupPresentInfoKHR; + +typedef struct VkDeviceGroupSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupSwapchainCreateInfoKHR; + typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( @@ -3686,6 +4589,26 @@ VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( VkQueue queue, const VkPresentInfoKHR* pPresentInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR( + VkDevice device, + VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR( + VkDevice device, + VkSurfaceKHR surface, + VkDeviceGroupPresentModeFlagsKHR* pModes); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pRectCount, + VkRect2D* pRects); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR( + VkDevice device, + const VkAcquireNextImageInfoKHR* pAcquireInfo, + uint32_t* pImageIndex); #endif #define VK_KHR_display 1 @@ -4048,114 +4971,141 @@ VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR( #define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" -#define VK_KHR_get_physical_device_properties2 1 -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1 -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" +#define VK_KHR_multiview 1 +typedef VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; +typedef VkPhysicalDeviceMultiviewProperties VkPhysicalDeviceMultiviewPropertiesKHR; +typedef VkRenderPassMultiviewCreateInfo VkRenderPassMultiviewCreateInfoKHR; -typedef struct VkPhysicalDeviceFeatures2KHR { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceFeatures features; -} VkPhysicalDeviceFeatures2KHR; +#define VK_KHR_MULTIVIEW_SPEC_VERSION 1 +#define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" +#define VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR VK_DEPENDENCY_VIEW_LOCAL_BIT +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES +#define VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO -typedef struct VkPhysicalDeviceProperties2KHR { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceProperties properties; -} VkPhysicalDeviceProperties2KHR; - -typedef struct VkFormatProperties2KHR { - VkStructureType sType; - void* pNext; - VkFormatProperties formatProperties; -} VkFormatProperties2KHR; - -typedef struct VkImageFormatProperties2KHR { - VkStructureType sType; - void* pNext; - VkImageFormatProperties imageFormatProperties; -} VkImageFormatProperties2KHR; - -typedef struct VkPhysicalDeviceImageFormatInfo2KHR { - VkStructureType sType; - const void* pNext; - VkFormat format; - VkImageType type; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkImageCreateFlags flags; -} VkPhysicalDeviceImageFormatInfo2KHR; - -typedef struct VkQueueFamilyProperties2KHR { - VkStructureType sType; - void* pNext; - VkQueueFamilyProperties queueFamilyProperties; -} VkQueueFamilyProperties2KHR; - -typedef struct VkPhysicalDeviceMemoryProperties2KHR { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceMemoryProperties memoryProperties; -} VkPhysicalDeviceMemoryProperties2KHR; - -typedef struct VkSparseImageFormatProperties2KHR { - VkStructureType sType; - void* pNext; - VkSparseImageFormatProperties properties; -} VkSparseImageFormatProperties2KHR; - -typedef struct VkPhysicalDeviceSparseImageFormatInfo2KHR { - VkStructureType sType; - const void* pNext; - VkFormat format; - VkImageType type; - VkSampleCountFlagBits samples; - VkImageUsageFlags usage; - VkImageTiling tiling; -} VkPhysicalDeviceSparseImageFormatInfo2KHR; +#define VK_KHR_get_physical_device_properties2 1 +typedef VkFormatProperties2 VkFormatProperties2KHR; +typedef VkImageFormatProperties2 VkImageFormatProperties2KHR; +typedef VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; +typedef VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; +typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR; +typedef VkPhysicalDeviceProperties2 VkPhysicalDeviceProperties2KHR; +typedef VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; +typedef VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; +typedef VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties); +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1 +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" +#define VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 +#define VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 +#define VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 +#define VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures2KHR* pFeatures); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties2KHR* pProperties); + VkPhysicalDeviceFeatures2* pFeatures); VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( VkPhysicalDevice physicalDevice, VkFormat format, - VkFormatProperties2KHR* pFormatProperties); + VkFormatProperties2* pFormatProperties); VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, - VkImageFormatProperties2KHR* pImageFormatProperties); + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, + VkImageFormatProperties2* pImageFormatProperties); -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( VkPhysicalDevice physicalDevice, - uint32_t* pQueueFamilyPropertyCount, - VkQueueFamilyProperties2KHR* pQueueFamilyProperties); + VkPhysicalDeviceMemoryProperties2* pMemoryProperties); -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties); + VkPhysicalDeviceProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2* pQueueFamilyProperties); VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, - VkSparseImageFormatProperties2KHR* pProperties); + VkSparseImageFormatProperties2* pProperties); +#endif + +#define VK_KHR_device_group 1 +typedef VkDeviceGroupBindSparseInfo VkDeviceGroupBindSparseInfoKHR; +typedef VkDeviceGroupCommandBufferBeginInfo VkDeviceGroupCommandBufferBeginInfoKHR; +typedef VkDeviceGroupRenderPassBeginInfo VkDeviceGroupRenderPassBeginInfoKHR; +typedef VkDeviceGroupSubmitInfo VkDeviceGroupSubmitInfoKHR; +typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR; +typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; +typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR; +typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR; +typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR; +typedef VkBindBufferMemoryDeviceGroupInfo VkBindBufferMemoryDeviceGroupInfoKHR; +typedef VkBindImageMemoryDeviceGroupInfo VkBindImageMemoryDeviceGroupInfoKHR; + +#define VK_KHR_DEVICE_GROUP_SPEC_VERSION 2 +#define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group" +#define VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR VK_DEPENDENCY_DEVICE_GROUP_BIT +#define VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT +#define VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR VK_PEER_MEMORY_FEATURE_COPY_DST_BIT +#define VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT +#define VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT +#define VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT +#define VK_PIPELINE_CREATE_DISPATCH_BASE_KHR VK_PIPELINE_CREATE_DISPATCH_BASE +#define VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT +#define VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO +#define VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO +#define VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO +#define VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO +#define VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO +#define VK_IMAGE_CREATE_BIND_SFR_BIT_KHR VK_IMAGE_CREATE_BIND_SFR_BIT +#define VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO +#define VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO + +typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask); +typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR( + VkCommandBuffer commandBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHR( + VkCommandBuffer commandBuffer, + uint32_t deviceMask); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR( + VkDevice device, + uint32_t heapIndex, + uint32_t localDeviceIndex, + uint32_t remoteDeviceIndex, + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); #endif #define VK_KHR_shader_draw_parameters 1 @@ -4164,121 +5114,96 @@ VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( #define VK_KHR_maintenance1 1 +typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR; + #define VK_KHR_MAINTENANCE1_SPEC_VERSION 1 #define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" +#define VK_ERROR_OUT_OF_POOL_MEMORY_KHR VK_ERROR_OUT_OF_POOL_MEMORY +#define VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR VK_FORMAT_FEATURE_TRANSFER_DST_BIT +#define VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR VK_FORMAT_FEATURE_TRANSFER_SRC_BIT +#define VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT -typedef VkFlags VkCommandPoolTrimFlagsKHR; - -typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR flags); +typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR( VkDevice device, VkCommandPool commandPool, - VkCommandPoolTrimFlagsKHR flags); + VkCommandPoolTrimFlags flags); #endif -#define VK_KHR_external_memory_capabilities 1 -#define VK_LUID_SIZE_KHR 8 -#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" - +#define VK_KHR_device_group_creation 1 +typedef VkDeviceGroupDeviceCreateInfo VkDeviceGroupDeviceCreateInfoKHR; +typedef VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; -typedef enum VkExternalMemoryHandleTypeFlagBitsKHR { - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = 0x00000008, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = 0x00000010, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = 0x00000020, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = 0x00000040, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkExternalMemoryHandleTypeFlagBitsKHR; -typedef VkFlags VkExternalMemoryHandleTypeFlagsKHR; - -typedef enum VkExternalMemoryFeatureFlagBitsKHR { - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = 0x00000004, - VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkExternalMemoryFeatureFlagBitsKHR; -typedef VkFlags VkExternalMemoryFeatureFlagsKHR; - -typedef struct VkExternalMemoryPropertiesKHR { - VkExternalMemoryFeatureFlagsKHR externalMemoryFeatures; - VkExternalMemoryHandleTypeFlagsKHR exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlagsKHR compatibleHandleTypes; -} VkExternalMemoryPropertiesKHR; - -typedef struct VkPhysicalDeviceExternalImageFormatInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagBitsKHR handleType; -} VkPhysicalDeviceExternalImageFormatInfoKHR; +#define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1 +#define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation" +#define VK_MAX_DEVICE_GROUP_SIZE_KHR VK_MAX_DEVICE_GROUP_SIZE +#define VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR VK_MEMORY_HEAP_MULTI_INSTANCE_BIT +#define VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES -typedef struct VkExternalImageFormatPropertiesKHR { - VkStructureType sType; - void* pNext; - VkExternalMemoryPropertiesKHR externalMemoryProperties; -} VkExternalImageFormatPropertiesKHR; +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); -typedef struct VkPhysicalDeviceExternalBufferInfoKHR { - VkStructureType sType; - const void* pNext; - VkBufferCreateFlags flags; - VkBufferUsageFlags usage; - VkExternalMemoryHandleTypeFlagBitsKHR handleType; -} VkPhysicalDeviceExternalBufferInfoKHR; - -typedef struct VkExternalBufferPropertiesKHR { - VkStructureType sType; - void* pNext; - VkExternalMemoryPropertiesKHR externalMemoryProperties; -} VkExternalBufferPropertiesKHR; - -typedef struct VkPhysicalDeviceIDPropertiesKHR { - VkStructureType sType; - void* pNext; - uint8_t deviceUUID[VK_UUID_SIZE]; - uint8_t driverUUID[VK_UUID_SIZE]; - uint8_t deviceLUID[VK_LUID_SIZE_KHR]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; -} VkPhysicalDeviceIDPropertiesKHR; +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHR( + VkInstance instance, + uint32_t* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +#endif +#define VK_KHR_external_memory_capabilities 1 +typedef VkExternalBufferProperties VkExternalBufferPropertiesKHR; +typedef VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; +typedef VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR; +typedef VkExternalMemoryFeatureFlags VkExternalMemoryFeatureFlagsKHR; +typedef VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR; +typedef VkExternalMemoryHandleTypeFlags VkExternalMemoryHandleTypeFlagsKHR; +typedef VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; +typedef VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; +typedef VkPhysicalDeviceExternalImageFormatInfo VkPhysicalDeviceExternalImageFormatInfoKHR; +typedef VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfoKHR* pExternalBufferInfo, VkExternalBufferPropertiesKHR* pExternalBufferProperties); +#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" +#define VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT +#define VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT +#define VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT +#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT +#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT +#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT +#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT +#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT +#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT +#define VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT +#define VK_LUID_SIZE_KHR VK_LUID_SIZE +#define VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES +#define VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR( VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalBufferInfoKHR* pExternalBufferInfo, - VkExternalBufferPropertiesKHR* pExternalBufferProperties); + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties); #endif #define VK_KHR_external_memory 1 +typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; +typedef VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; +typedef VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; + #define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory" -#define VK_QUEUE_FAMILY_EXTERNAL_KHR (~0U-1) - -typedef struct VkExternalMemoryImageCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsKHR handleTypes; -} VkExternalMemoryImageCreateInfoKHR; - -typedef struct VkExternalMemoryBufferCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsKHR handleTypes; -} VkExternalMemoryBufferCreateInfoKHR; - -typedef struct VkExportMemoryAllocateInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsKHR handleTypes; -} VkExportMemoryAllocateInfoKHR; - +#define VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR VK_ERROR_INVALID_EXTERNAL_HANDLE +#define VK_QUEUE_FAMILY_EXTERNAL_KHR VK_QUEUE_FAMILY_EXTERNAL +#define VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO +#define VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO +#define VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO #ifdef VK_USE_PLATFORM_WIN32_KHR @@ -4287,11 +5212,11 @@ typedef struct VkExportMemoryAllocateInfoKHR { #define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32" typedef struct VkImportMemoryWin32HandleInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagBitsKHR handleType; - HANDLE handle; - LPCWSTR name; + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; } VkImportMemoryWin32HandleInfoKHR; typedef struct VkExportMemoryWin32HandleInfoKHR { @@ -4309,15 +5234,15 @@ typedef struct VkMemoryWin32HandlePropertiesKHR { } VkMemoryWin32HandlePropertiesKHR; typedef struct VkMemoryGetWin32HandleInfoKHR { - VkStructureType sType; - const void* pNext; - VkDeviceMemory memory; - VkExternalMemoryHandleTypeFlagBitsKHR handleType; + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; } VkMemoryGetWin32HandleInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice device, const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle); -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHR handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR( @@ -4327,7 +5252,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR( VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR( VkDevice device, - VkExternalMemoryHandleTypeFlagBitsKHR handleType, + VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties); #endif @@ -4338,10 +5263,10 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR( #define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd" typedef struct VkImportMemoryFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagBitsKHR handleType; - int fd; + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + int fd; } VkImportMemoryFdInfoKHR; typedef struct VkMemoryFdPropertiesKHR { @@ -4351,15 +5276,15 @@ typedef struct VkMemoryFdPropertiesKHR { } VkMemoryFdPropertiesKHR; typedef struct VkMemoryGetFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkDeviceMemory memory; - VkExternalMemoryHandleTypeFlagBitsKHR handleType; + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; } VkMemoryGetFdInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR* pGetFdInfo, int* pFd); -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHR handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR( @@ -4369,7 +5294,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR( VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR( VkDevice device, - VkExternalMemoryHandleTypeFlagBitsKHR handleType, + VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties); #endif @@ -4395,68 +5320,43 @@ typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR { #endif /* VK_USE_PLATFORM_WIN32_KHR */ #define VK_KHR_external_semaphore_capabilities 1 +typedef VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR; +typedef VkExternalSemaphoreFeatureFlags VkExternalSemaphoreFeatureFlagsKHR; +typedef VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR; +typedef VkExternalSemaphoreHandleTypeFlags VkExternalSemaphoreHandleTypeFlagsKHR; +typedef VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; +typedef VkPhysicalDeviceExternalSemaphoreInfo VkPhysicalDeviceExternalSemaphoreInfoKHR; + #define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" - - -typedef enum VkExternalSemaphoreHandleTypeFlagBitsKHR { - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = 0x00000008, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = 0x00000010, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkExternalSemaphoreHandleTypeFlagBitsKHR; -typedef VkFlags VkExternalSemaphoreHandleTypeFlagsKHR; - -typedef enum VkExternalSemaphoreFeatureFlagBitsKHR { - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002, - VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkExternalSemaphoreFeatureFlagBitsKHR; -typedef VkFlags VkExternalSemaphoreFeatureFlagsKHR; - -typedef struct VkPhysicalDeviceExternalSemaphoreInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalSemaphoreHandleTypeFlagBitsKHR handleType; -} VkPhysicalDeviceExternalSemaphoreInfoKHR; - -typedef struct VkExternalSemaphorePropertiesKHR { - VkStructureType sType; - void* pNext; - VkExternalSemaphoreHandleTypeFlagsKHR exportFromImportedHandleTypes; - VkExternalSemaphoreHandleTypeFlagsKHR compatibleHandleTypes; - VkExternalSemaphoreFeatureFlagsKHR externalSemaphoreFeatures; -} VkExternalSemaphorePropertiesKHR; - - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo, VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties); +#define VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT +#define VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT +#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT +#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT +#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT +#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT +#define VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT +#define VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR( VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo, - VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties); + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, + VkExternalSemaphoreProperties* pExternalSemaphoreProperties); #endif #define VK_KHR_external_semaphore 1 +typedef VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; +typedef VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR; +typedef VkSemaphoreImportFlags VkSemaphoreImportFlagsKHR; + #define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore" - - -typedef enum VkSemaphoreImportFlagBitsKHR { - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001, - VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkSemaphoreImportFlagBitsKHR; -typedef VkFlags VkSemaphoreImportFlagsKHR; - -typedef struct VkExportSemaphoreCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalSemaphoreHandleTypeFlagsKHR handleTypes; -} VkExportSemaphoreCreateInfoKHR; - +#define VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR VK_SEMAPHORE_IMPORT_TEMPORARY_BIT +#define VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO #ifdef VK_USE_PLATFORM_WIN32_KHR @@ -4465,13 +5365,13 @@ typedef struct VkExportSemaphoreCreateInfoKHR { #define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32" typedef struct VkImportSemaphoreWin32HandleInfoKHR { - VkStructureType sType; - const void* pNext; - VkSemaphore semaphore; - VkSemaphoreImportFlagsKHR flags; - VkExternalSemaphoreHandleTypeFlagBitsKHR handleType; - HANDLE handle; - LPCWSTR name; + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; } VkImportSemaphoreWin32HandleInfoKHR; typedef struct VkExportSemaphoreWin32HandleInfoKHR { @@ -4492,10 +5392,10 @@ typedef struct VkD3D12FenceSubmitInfoKHR { } VkD3D12FenceSubmitInfoKHR; typedef struct VkSemaphoreGetWin32HandleInfoKHR { - VkStructureType sType; - const void* pNext; - VkSemaphore semaphore; - VkExternalSemaphoreHandleTypeFlagBitsKHR handleType; + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; } VkSemaphoreGetWin32HandleInfoKHR; @@ -4519,19 +5419,19 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHR( #define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd" typedef struct VkImportSemaphoreFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkSemaphore semaphore; - VkSemaphoreImportFlagsKHR flags; - VkExternalSemaphoreHandleTypeFlagBitsKHR handleType; - int fd; + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + int fd; } VkImportSemaphoreFdInfoKHR; typedef struct VkSemaphoreGetFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkSemaphore semaphore; - VkExternalSemaphoreHandleTypeFlagBitsKHR handleType; + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; } VkSemaphoreGetFdInfoKHR; @@ -4550,7 +5450,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHR( #endif #define VK_KHR_push_descriptor 1 -#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 1 +#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 #define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR { @@ -4561,6 +5461,7 @@ typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR { typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR( @@ -4570,21 +5471,21 @@ VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR( uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( + VkCommandBuffer commandBuffer, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + VkPipelineLayout layout, + uint32_t set, + const void* pData); #endif #define VK_KHR_16bit_storage 1 +typedef VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; + #define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 #define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage" - -typedef struct VkPhysicalDevice16BitStorageFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; -} VkPhysicalDevice16BitStorageFeaturesKHR; - +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES #define VK_KHR_incremental_present 1 @@ -4612,74 +5513,39 @@ typedef struct VkPresentRegionsKHR { #define VK_KHR_descriptor_update_template 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplateKHR) +typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR; +typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; +typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR; +typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR; +typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR; #define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1 #define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" +#define VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET +#define VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE +#define VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO +#define VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT - -typedef enum VkDescriptorUpdateTemplateTypeKHR { - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = 0, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE_KHR = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR + 1), - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkDescriptorUpdateTemplateTypeKHR; - -typedef VkFlags VkDescriptorUpdateTemplateCreateFlagsKHR; - -typedef struct VkDescriptorUpdateTemplateEntryKHR { - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - size_t offset; - size_t stride; -} VkDescriptorUpdateTemplateEntryKHR; - -typedef struct VkDescriptorUpdateTemplateCreateInfoKHR { - VkStructureType sType; - void* pNext; - VkDescriptorUpdateTemplateCreateFlagsKHR flags; - uint32_t descriptorUpdateEntryCount; - const VkDescriptorUpdateTemplateEntryKHR* pDescriptorUpdateEntries; - VkDescriptorUpdateTemplateTypeKHR templateType; - VkDescriptorSetLayout descriptorSetLayout; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout pipelineLayout; - uint32_t set; -} VkDescriptorUpdateTemplateCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData); -typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR( VkDevice device, - const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, - VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate); + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR( VkDevice device, - VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR( VkDevice device, VkDescriptorSet descriptorSet, - VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, - const void* pData); - -VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( - VkCommandBuffer commandBuffer, - VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, - VkPipelineLayout layout, - uint32_t set, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); #endif @@ -4703,67 +5569,42 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR( #endif #define VK_KHR_external_fence_capabilities 1 +typedef VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR; +typedef VkExternalFenceFeatureFlags VkExternalFenceFeatureFlagsKHR; +typedef VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR; +typedef VkExternalFenceHandleTypeFlags VkExternalFenceHandleTypeFlagsKHR; +typedef VkExternalFenceProperties VkExternalFencePropertiesKHR; +typedef VkPhysicalDeviceExternalFenceInfo VkPhysicalDeviceExternalFenceInfoKHR; + #define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" +#define VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT +#define VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT +#define VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT +#define VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT +#define VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT +#define VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT +#define VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO - -typedef enum VkExternalFenceHandleTypeFlagBitsKHR { - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = 0x00000008, - VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkExternalFenceHandleTypeFlagBitsKHR; -typedef VkFlags VkExternalFenceHandleTypeFlagsKHR; - -typedef enum VkExternalFenceFeatureFlagBitsKHR { - VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002, - VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkExternalFenceFeatureFlagBitsKHR; -typedef VkFlags VkExternalFenceFeatureFlagsKHR; - -typedef struct VkPhysicalDeviceExternalFenceInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalFenceHandleTypeFlagBitsKHR handleType; -} VkPhysicalDeviceExternalFenceInfoKHR; - -typedef struct VkExternalFencePropertiesKHR { - VkStructureType sType; - void* pNext; - VkExternalFenceHandleTypeFlagsKHR exportFromImportedHandleTypes; - VkExternalFenceHandleTypeFlagsKHR compatibleHandleTypes; - VkExternalFenceFeatureFlagsKHR externalFenceFeatures; -} VkExternalFencePropertiesKHR; - - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfoKHR* pExternalFenceInfo, VkExternalFencePropertiesKHR* pExternalFenceProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR( VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalFenceInfoKHR* pExternalFenceInfo, - VkExternalFencePropertiesKHR* pExternalFenceProperties); + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, + VkExternalFenceProperties* pExternalFenceProperties); #endif #define VK_KHR_external_fence 1 +typedef VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; +typedef VkFenceImportFlagBits VkFenceImportFlagBitsKHR; +typedef VkFenceImportFlags VkFenceImportFlagsKHR; + #define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" - - -typedef enum VkFenceImportFlagBitsKHR { - VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001, - VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkFenceImportFlagBitsKHR; -typedef VkFlags VkFenceImportFlagsKHR; - -typedef struct VkExportFenceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalFenceHandleTypeFlagsKHR handleTypes; -} VkExportFenceCreateInfoKHR; - +#define VK_FENCE_IMPORT_TEMPORARY_BIT_KHR VK_FENCE_IMPORT_TEMPORARY_BIT +#define VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO #ifdef VK_USE_PLATFORM_WIN32_KHR @@ -4772,13 +5613,13 @@ typedef struct VkExportFenceCreateInfoKHR { #define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32" typedef struct VkImportFenceWin32HandleInfoKHR { - VkStructureType sType; - const void* pNext; - VkFence fence; - VkFenceImportFlagsKHR flags; - VkExternalFenceHandleTypeFlagBitsKHR handleType; - HANDLE handle; - LPCWSTR name; + VkStructureType sType; + const void* pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; } VkImportFenceWin32HandleInfoKHR; typedef struct VkExportFenceWin32HandleInfoKHR { @@ -4790,10 +5631,10 @@ typedef struct VkExportFenceWin32HandleInfoKHR { } VkExportFenceWin32HandleInfoKHR; typedef struct VkFenceGetWin32HandleInfoKHR { - VkStructureType sType; - const void* pNext; - VkFence fence; - VkExternalFenceHandleTypeFlagBitsKHR handleType; + VkStructureType sType; + const void* pNext; + VkFence fence; + VkExternalFenceHandleTypeFlagBits handleType; } VkFenceGetWin32HandleInfoKHR; @@ -4817,19 +5658,19 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceWin32HandleKHR( #define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd" typedef struct VkImportFenceFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkFence fence; - VkFenceImportFlagsKHR flags; - VkExternalFenceHandleTypeFlagBitsKHR handleType; - int fd; + VkStructureType sType; + const void* pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + int fd; } VkImportFenceFdInfoKHR; typedef struct VkFenceGetFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkFence fence; - VkExternalFenceHandleTypeFlagBitsKHR handleType; + VkStructureType sType; + const void* pNext; + VkFence fence; + VkExternalFenceHandleTypeFlagBits handleType; } VkFenceGetFdInfoKHR; @@ -4848,59 +5689,28 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR( #endif #define VK_KHR_maintenance2 1 +typedef VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; +typedef VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; +typedef VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR; +typedef VkPipelineTessellationDomainOriginStateCreateInfo VkPipelineTessellationDomainOriginStateCreateInfoKHR; +typedef VkPointClippingBehavior VkPointClippingBehaviorKHR; +typedef VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; +typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR; + #define VK_KHR_MAINTENANCE2_SPEC_VERSION 1 #define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2" - - -typedef enum VkPointClippingBehaviorKHR { - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = 0, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = 1, - VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR, - VK_POINT_CLIPPING_BEHAVIOR_END_RANGE_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR, - VK_POINT_CLIPPING_BEHAVIOR_RANGE_SIZE_KHR = (VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR + 1), - VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM_KHR = 0x7FFFFFFF -} VkPointClippingBehaviorKHR; - -typedef enum VkTessellationDomainOriginKHR { - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = 0, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = 1, - VK_TESSELLATION_DOMAIN_ORIGIN_BEGIN_RANGE_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR, - VK_TESSELLATION_DOMAIN_ORIGIN_END_RANGE_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR, - VK_TESSELLATION_DOMAIN_ORIGIN_RANGE_SIZE_KHR = (VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR + 1), - VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM_KHR = 0x7FFFFFFF -} VkTessellationDomainOriginKHR; - -typedef struct VkPhysicalDevicePointClippingPropertiesKHR { - VkStructureType sType; - void* pNext; - VkPointClippingBehaviorKHR pointClippingBehavior; -} VkPhysicalDevicePointClippingPropertiesKHR; - -typedef struct VkInputAttachmentAspectReferenceKHR { - uint32_t subpass; - uint32_t inputAttachmentIndex; - VkImageAspectFlags aspectMask; -} VkInputAttachmentAspectReferenceKHR; - -typedef struct VkRenderPassInputAttachmentAspectCreateInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t aspectReferenceCount; - const VkInputAttachmentAspectReferenceKHR* pAspectReferences; -} VkRenderPassInputAttachmentAspectCreateInfoKHR; - -typedef struct VkImageViewUsageCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkImageUsageFlags usage; -} VkImageViewUsageCreateInfoKHR; - -typedef struct VkPipelineTessellationDomainOriginStateCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkTessellationDomainOriginKHR domainOrigin; -} VkPipelineTessellationDomainOriginStateCreateInfoKHR; - +#define VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT +#define VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR VK_IMAGE_CREATE_EXTENDED_USAGE_BIT +#define VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL +#define VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL +#define VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES +#define VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY +#define VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES +#define VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO +#define VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO +#define VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT +#define VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT #define VK_KHR_get_surface_capabilities2 1 @@ -4943,36 +5753,21 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR( #endif #define VK_KHR_variable_pointers 1 +typedef VkPhysicalDeviceVariablePointerFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; + #define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 #define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" - -typedef struct VkPhysicalDeviceVariablePointerFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; -} VkPhysicalDeviceVariablePointerFeaturesKHR; - +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES #define VK_KHR_dedicated_allocation 1 +typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR; +typedef VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; + #define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 #define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" - -typedef struct VkMemoryDedicatedRequirementsKHR { - VkStructureType sType; - void* pNext; - VkBool32 prefersDedicatedAllocation; - VkBool32 requiresDedicatedAllocation; -} VkMemoryDedicatedRequirementsKHR; - -typedef struct VkMemoryDedicatedAllocateInfoKHR { - VkStructureType sType; - const void* pNext; - VkImage image; - VkBuffer buffer; -} VkMemoryDedicatedAllocateInfoKHR; - +#define VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO +#define VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS #define VK_KHR_storage_buffer_storage_class 1 @@ -4986,60 +5781,40 @@ typedef struct VkMemoryDedicatedAllocateInfoKHR { #define VK_KHR_get_memory_requirements2 1 +typedef VkBufferMemoryRequirementsInfo2 VkBufferMemoryRequirementsInfo2KHR; +typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR; +typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR; +typedef VkMemoryRequirements2 VkMemoryRequirements2KHR; +typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; + #define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1 #define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" +#define VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 +#define VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 +#define VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 +#define VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 +#define VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 -typedef struct VkBufferMemoryRequirementsInfo2KHR { - VkStructureType sType; - const void* pNext; - VkBuffer buffer; -} VkBufferMemoryRequirementsInfo2KHR; - -typedef struct VkImageMemoryRequirementsInfo2KHR { - VkStructureType sType; - const void* pNext; - VkImage image; -} VkImageMemoryRequirementsInfo2KHR; - -typedef struct VkImageSparseMemoryRequirementsInfo2KHR { - VkStructureType sType; - const void* pNext; - VkImage image; -} VkImageSparseMemoryRequirementsInfo2KHR; - -typedef struct VkMemoryRequirements2KHR { - VkStructureType sType; - void* pNext; - VkMemoryRequirements memoryRequirements; -} VkMemoryRequirements2KHR; - -typedef struct VkSparseImageMemoryRequirements2KHR { - VkStructureType sType; - void* pNext; - VkSparseImageMemoryRequirements memoryRequirements; -} VkSparseImageMemoryRequirements2KHR; - - -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2KHR* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2KHR* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2KHR* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); #ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR( +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR( VkDevice device, - const VkImageMemoryRequirementsInfo2KHR* pInfo, - VkMemoryRequirements2KHR* pMemoryRequirements); + const VkBufferMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); -VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR( +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR( VkDevice device, - const VkBufferMemoryRequirementsInfo2KHR* pInfo, - VkMemoryRequirements2KHR* pMemoryRequirements); + const VkImageMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR( VkDevice device, - const VkImageSparseMemoryRequirementsInfo2KHR* pInfo, + const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements); + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); #endif #define VK_KHR_image_format_list 1 @@ -5056,142 +5831,145 @@ typedef struct VkImageFormatListCreateInfoKHR { #define VK_KHR_sampler_ycbcr_conversion 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversionKHR) +typedef VkBindImagePlaneMemoryInfo VkBindImagePlaneMemoryInfoKHR; +typedef VkChromaLocation VkChromaLocationKHR; +typedef VkImagePlaneMemoryRequirementsInfo VkImagePlaneMemoryRequirementsInfoKHR; +typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; +typedef VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; +typedef VkSamplerYcbcrConversionImageFormatProperties VkSamplerYcbcrConversionImageFormatPropertiesKHR; +typedef VkSamplerYcbcrConversionInfo VkSamplerYcbcrConversionInfoKHR; +typedef VkSamplerYcbcrConversion VkSamplerYcbcrConversionKHR; +typedef VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR; +typedef VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR; #define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 1 #define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" - - -typedef enum VkSamplerYcbcrModelConversionKHR { - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = 0, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = 1, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = 2, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = 3, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = 4, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_BEGIN_RANGE_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_END_RANGE_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RANGE_SIZE_KHR = (VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR + 1), - VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM_KHR = 0x7FFFFFFF -} VkSamplerYcbcrModelConversionKHR; - -typedef enum VkSamplerYcbcrRangeKHR { - VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = 0, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = 1, - VK_SAMPLER_YCBCR_RANGE_BEGIN_RANGE_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR, - VK_SAMPLER_YCBCR_RANGE_END_RANGE_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR, - VK_SAMPLER_YCBCR_RANGE_RANGE_SIZE_KHR = (VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR - VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR + 1), - VK_SAMPLER_YCBCR_RANGE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkSamplerYcbcrRangeKHR; - -typedef enum VkChromaLocationKHR { - VK_CHROMA_LOCATION_COSITED_EVEN_KHR = 0, - VK_CHROMA_LOCATION_MIDPOINT_KHR = 1, - VK_CHROMA_LOCATION_BEGIN_RANGE_KHR = VK_CHROMA_LOCATION_COSITED_EVEN_KHR, - VK_CHROMA_LOCATION_END_RANGE_KHR = VK_CHROMA_LOCATION_MIDPOINT_KHR, - VK_CHROMA_LOCATION_RANGE_SIZE_KHR = (VK_CHROMA_LOCATION_MIDPOINT_KHR - VK_CHROMA_LOCATION_COSITED_EVEN_KHR + 1), - VK_CHROMA_LOCATION_MAX_ENUM_KHR = 0x7FFFFFFF -} VkChromaLocationKHR; - -typedef struct VkSamplerYcbcrConversionCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkFormat format; - VkSamplerYcbcrModelConversionKHR ycbcrModel; - VkSamplerYcbcrRangeKHR ycbcrRange; - VkComponentMapping components; - VkChromaLocationKHR xChromaOffset; - VkChromaLocationKHR yChromaOffset; - VkFilter chromaFilter; - VkBool32 forceExplicitReconstruction; -} VkSamplerYcbcrConversionCreateInfoKHR; - -typedef struct VkSamplerYcbcrConversionInfoKHR { - VkStructureType sType; - const void* pNext; - VkSamplerYcbcrConversionKHR conversion; -} VkSamplerYcbcrConversionInfoKHR; - -typedef struct VkBindImagePlaneMemoryInfoKHR { - VkStructureType sType; - const void* pNext; - VkImageAspectFlagBits planeAspect; -} VkBindImagePlaneMemoryInfoKHR; - -typedef struct VkImagePlaneMemoryRequirementsInfoKHR { - VkStructureType sType; - const void* pNext; - VkImageAspectFlagBits planeAspect; -} VkImagePlaneMemoryRequirementsInfoKHR; - -typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 samplerYcbcrConversion; -} VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; - -typedef struct VkSamplerYcbcrConversionImageFormatPropertiesKHR { - VkStructureType sType; - void* pNext; - uint32_t combinedImageSamplerDescriptorCount; -} VkSamplerYcbcrConversionImageFormatPropertiesKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversionKHR* pYcbcrConversion); -typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversionKHR ycbcrConversion, const VkAllocationCallbacks* pAllocator); +#define VK_CHROMA_LOCATION_COSITED_EVEN_KHR VK_CHROMA_LOCATION_COSITED_EVEN +#define VK_CHROMA_LOCATION_MIDPOINT_KHR VK_CHROMA_LOCATION_MIDPOINT +#define VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT +#define VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 +#define VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 +#define VK_FORMAT_B16G16R16G16_422_UNORM_KHR VK_FORMAT_B16G16R16G16_422_UNORM +#define VK_FORMAT_B8G8R8G8_422_UNORM_KHR VK_FORMAT_B8G8R8G8_422_UNORM +#define VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT +#define VK_FORMAT_FEATURE_DISJOINT_BIT_KHR VK_FORMAT_FEATURE_DISJOINT_BIT +#define VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT +#define VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT +#define VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT +#define VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT +#define VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT +#define VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 +#define VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 +#define VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 +#define VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 +#define VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 +#define VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 +#define VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 +#define VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 +#define VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 +#define VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 +#define VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 +#define VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 +#define VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM +#define VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM +#define VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM +#define VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR VK_FORMAT_G16_B16R16_2PLANE_420_UNORM +#define VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR VK_FORMAT_G16_B16R16_2PLANE_422_UNORM +#define VK_FORMAT_G16B16G16R16_422_UNORM_KHR VK_FORMAT_G16B16G16R16_422_UNORM +#define VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM +#define VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM +#define VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM +#define VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR VK_FORMAT_G8_B8R8_2PLANE_420_UNORM +#define VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR VK_FORMAT_G8_B8R8_2PLANE_422_UNORM +#define VK_FORMAT_G8B8G8R8_422_UNORM_KHR VK_FORMAT_G8B8G8R8_422_UNORM +#define VK_FORMAT_R10X6_UNORM_PACK16_KHR VK_FORMAT_R10X6_UNORM_PACK16 +#define VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR VK_FORMAT_R10X6G10X6_UNORM_2PACK16 +#define VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 +#define VK_FORMAT_R12X4_UNORM_PACK16_KHR VK_FORMAT_R12X4_UNORM_PACK16 +#define VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR VK_FORMAT_R12X4G12X4_UNORM_2PACK16 +#define VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 +#define VK_IMAGE_ASPECT_PLANE_0_BIT_KHR VK_IMAGE_ASPECT_PLANE_0_BIT +#define VK_IMAGE_ASPECT_PLANE_1_BIT_KHR VK_IMAGE_ASPECT_PLANE_1_BIT +#define VK_IMAGE_ASPECT_PLANE_2_BIT_KHR VK_IMAGE_ASPECT_PLANE_2_BIT +#define VK_IMAGE_CREATE_DISJOINT_BIT_KHR VK_IMAGE_CREATE_DISJOINT_BIT +#define VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION +#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY +#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 +#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 +#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 +#define VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY +#define VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR VK_SAMPLER_YCBCR_RANGE_ITU_FULL +#define VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR VK_SAMPLER_YCBCR_RANGE_ITU_NARROW +#define VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO +#define VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES +#define VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO +#define VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES +#define VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversionKHR( VkDevice device, - const VkSamplerYcbcrConversionCreateInfoKHR* pCreateInfo, + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, - VkSamplerYcbcrConversionKHR* pYcbcrConversion); + VkSamplerYcbcrConversion* pYcbcrConversion); VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversionKHR( VkDevice device, - VkSamplerYcbcrConversionKHR ycbcrConversion, + VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); #endif #define VK_KHR_bind_memory2 1 +typedef VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; +typedef VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; + #define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1 #define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2" +#define VK_IMAGE_CREATE_ALIAS_BIT_KHR VK_IMAGE_CREATE_ALIAS_BIT +#define VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO +#define VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO -typedef struct VkBindBufferMemoryInfoKHR { - VkStructureType sType; - const void* pNext; - VkBuffer buffer; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; -} VkBindBufferMemoryInfoKHR; - -typedef struct VkBindImageMemoryInfoKHR { - VkStructureType sType; - const void* pNext; - VkImage image; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; -} VkBindImageMemoryInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHR* pBindInfos); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR( VkDevice device, uint32_t bindInfoCount, - const VkBindBufferMemoryInfoKHR* pBindInfos); + const VkBindBufferMemoryInfo* pBindInfos); VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR( VkDevice device, uint32_t bindInfoCount, - const VkBindImageMemoryInfoKHR* pBindInfos); + const VkBindImageMemoryInfo* pBindInfos); +#endif + +#define VK_KHR_maintenance3 1 +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; + +#define VK_KHR_MAINTENANCE3_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3" +#define VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT +#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES + +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupport* pSupport); #endif #define VK_EXT_debug_report 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) -#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 8 +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 #define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" #define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT #define VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT @@ -5232,8 +6010,8 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31, VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32, VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = 33, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = 1000156000, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), @@ -5486,38 +6264,6 @@ typedef struct VkTextureLODGatherFormatPropertiesAMD { -#define VK_KHX_multiview 1 -#define VK_KHX_MULTIVIEW_SPEC_VERSION 1 -#define VK_KHX_MULTIVIEW_EXTENSION_NAME "VK_KHX_multiview" - -typedef struct VkRenderPassMultiviewCreateInfoKHX { - VkStructureType sType; - const void* pNext; - uint32_t subpassCount; - const uint32_t* pViewMasks; - uint32_t dependencyCount; - const int32_t* pViewOffsets; - uint32_t correlationMaskCount; - const uint32_t* pCorrelationMasks; -} VkRenderPassMultiviewCreateInfoKHX; - -typedef struct VkPhysicalDeviceMultiviewFeaturesKHX { - VkStructureType sType; - void* pNext; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; -} VkPhysicalDeviceMultiviewFeaturesKHX; - -typedef struct VkPhysicalDeviceMultiviewPropertiesKHX { - VkStructureType sType; - void* pNext; - uint32_t maxMultiviewViewCount; - uint32_t maxMultiviewInstanceIndex; -} VkPhysicalDeviceMultiviewPropertiesKHX; - - - #define VK_IMG_format_pvrtc 1 #define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 #define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" @@ -5636,186 +6382,6 @@ typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV { #endif /* VK_USE_PLATFORM_WIN32_KHR */ -#define VK_KHX_device_group 1 -#define VK_KHX_DEVICE_GROUP_SPEC_VERSION 2 -#define VK_KHX_DEVICE_GROUP_EXTENSION_NAME "VK_KHX_device_group" -#define VK_MAX_DEVICE_GROUP_SIZE_KHX 32 - - -typedef enum VkPeerMemoryFeatureFlagBitsKHX { - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX = 0x00000001, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX = 0x00000002, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX = 0x00000004, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX = 0x00000008, - VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF -} VkPeerMemoryFeatureFlagBitsKHX; -typedef VkFlags VkPeerMemoryFeatureFlagsKHX; - -typedef enum VkMemoryAllocateFlagBitsKHX { - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX = 0x00000001, - VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF -} VkMemoryAllocateFlagBitsKHX; -typedef VkFlags VkMemoryAllocateFlagsKHX; - -typedef enum VkDeviceGroupPresentModeFlagBitsKHX { - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX = 0x00000001, - VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX = 0x00000002, - VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX = 0x00000004, - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX = 0x00000008, - VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF -} VkDeviceGroupPresentModeFlagBitsKHX; -typedef VkFlags VkDeviceGroupPresentModeFlagsKHX; - -typedef struct VkMemoryAllocateFlagsInfoKHX { - VkStructureType sType; - const void* pNext; - VkMemoryAllocateFlagsKHX flags; - uint32_t deviceMask; -} VkMemoryAllocateFlagsInfoKHX; - -typedef struct VkDeviceGroupRenderPassBeginInfoKHX { - VkStructureType sType; - const void* pNext; - uint32_t deviceMask; - uint32_t deviceRenderAreaCount; - const VkRect2D* pDeviceRenderAreas; -} VkDeviceGroupRenderPassBeginInfoKHX; - -typedef struct VkDeviceGroupCommandBufferBeginInfoKHX { - VkStructureType sType; - const void* pNext; - uint32_t deviceMask; -} VkDeviceGroupCommandBufferBeginInfoKHX; - -typedef struct VkDeviceGroupSubmitInfoKHX { - VkStructureType sType; - const void* pNext; - uint32_t waitSemaphoreCount; - const uint32_t* pWaitSemaphoreDeviceIndices; - uint32_t commandBufferCount; - const uint32_t* pCommandBufferDeviceMasks; - uint32_t signalSemaphoreCount; - const uint32_t* pSignalSemaphoreDeviceIndices; -} VkDeviceGroupSubmitInfoKHX; - -typedef struct VkDeviceGroupBindSparseInfoKHX { - VkStructureType sType; - const void* pNext; - uint32_t resourceDeviceIndex; - uint32_t memoryDeviceIndex; -} VkDeviceGroupBindSparseInfoKHX; - -typedef struct VkBindBufferMemoryDeviceGroupInfoKHX { - VkStructureType sType; - const void* pNext; - uint32_t deviceIndexCount; - const uint32_t* pDeviceIndices; -} VkBindBufferMemoryDeviceGroupInfoKHX; - -typedef struct VkBindImageMemoryDeviceGroupInfoKHX { - VkStructureType sType; - const void* pNext; - uint32_t deviceIndexCount; - const uint32_t* pDeviceIndices; - uint32_t SFRRectCount; - const VkRect2D* pSFRRects; -} VkBindImageMemoryDeviceGroupInfoKHX; - -typedef struct VkDeviceGroupPresentCapabilitiesKHX { - VkStructureType sType; - const void* pNext; - uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE_KHX]; - VkDeviceGroupPresentModeFlagsKHX modes; -} VkDeviceGroupPresentCapabilitiesKHX; - -typedef struct VkImageSwapchainCreateInfoKHX { - VkStructureType sType; - const void* pNext; - VkSwapchainKHR swapchain; -} VkImageSwapchainCreateInfoKHX; - -typedef struct VkBindImageMemorySwapchainInfoKHX { - VkStructureType sType; - const void* pNext; - VkSwapchainKHR swapchain; - uint32_t imageIndex; -} VkBindImageMemorySwapchainInfoKHX; - -typedef struct VkAcquireNextImageInfoKHX { - VkStructureType sType; - const void* pNext; - VkSwapchainKHR swapchain; - uint64_t timeout; - VkSemaphore semaphore; - VkFence fence; - uint32_t deviceMask; -} VkAcquireNextImageInfoKHX; - -typedef struct VkDeviceGroupPresentInfoKHX { - VkStructureType sType; - const void* pNext; - uint32_t swapchainCount; - const uint32_t* pDeviceMasks; - VkDeviceGroupPresentModeFlagBitsKHX mode; -} VkDeviceGroupPresentInfoKHX; - -typedef struct VkDeviceGroupSwapchainCreateInfoKHX { - VkStructureType sType; - const void* pNext; - VkDeviceGroupPresentModeFlagsKHX modes; -} VkDeviceGroupSwapchainCreateInfoKHX; - - -typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHX)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures); -typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHX)(VkCommandBuffer commandBuffer, uint32_t deviceMask); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHX)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHX)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHX)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHX* pModes); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHX)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); -typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHX)(VkDevice device, const VkAcquireNextImageInfoKHX* pAcquireInfo, uint32_t* pImageIndex); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHX( - VkDevice device, - uint32_t heapIndex, - uint32_t localDeviceIndex, - uint32_t remoteDeviceIndex, - VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHX( - VkCommandBuffer commandBuffer, - uint32_t deviceMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHX( - VkCommandBuffer commandBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHX( - VkDevice device, - VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHX( - VkDevice device, - VkSurfaceKHR surface, - VkDeviceGroupPresentModeFlagsKHX* pModes); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHX( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - uint32_t* pRectCount, - VkRect2D* pRects); - -VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHX( - VkDevice device, - const VkAcquireNextImageInfoKHX* pAcquireInfo, - uint32_t* pImageIndex); -#endif - #define VK_EXT_validation_flags 1 #define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1 #define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" @@ -5875,35 +6441,6 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN( #define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" -#define VK_KHX_device_group_creation 1 -#define VK_KHX_DEVICE_GROUP_CREATION_SPEC_VERSION 1 -#define VK_KHX_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHX_device_group_creation" - -typedef struct VkPhysicalDeviceGroupPropertiesKHX { - VkStructureType sType; - void* pNext; - uint32_t physicalDeviceCount; - VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE_KHX]; - VkBool32 subsetAllocation; -} VkPhysicalDeviceGroupPropertiesKHX; - -typedef struct VkDeviceGroupDeviceCreateInfoKHX { - VkStructureType sType; - const void* pNext; - uint32_t physicalDeviceCount; - const VkPhysicalDevice* pPhysicalDevices; -} VkDeviceGroupDeviceCreateInfoKHX; - - -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHX)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHX( - VkInstance instance, - uint32_t* pPhysicalDeviceGroupCount, - VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties); -#endif - #define VK_NVX_device_generated_commands 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX) diff --git a/vulkan/include/vulkan/vulkan_loader_data.h b/vulkan/include/vulkan/vulkan_loader_data.h deleted file mode 100644 index 8ea46666c5..0000000000 --- a/vulkan/include/vulkan/vulkan_loader_data.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 VULKAN_VULKAN_LOADER_DATA_H -#define VULKAN_VULKAN_LOADER_DATA_H - -#include <string> - -struct android_namespace_t; - -namespace vulkan { - struct LoaderData { - std::string layer_path; - android_namespace_t* app_namespace; - - __attribute__((visibility("default"))) static LoaderData& GetInstance(); - }; -} - -#endif diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 5f9b357a35..c9faf28606 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -61,7 +61,6 @@ cc_library_shared { "layers_extensions.cpp", "stubhal.cpp", "swapchain.cpp", - "vulkan_loader_data.cpp", ], export_header_lib_headers: ["vulkan_headers"], @@ -80,6 +79,7 @@ cc_library_shared { "libcutils", "libz", "libnativewindow", + "android.hardware.graphics.common@1.0", ], static_libs: ["libgrallocusage"], } diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp index e05ca5a83a..673a066182 100644 --- a/vulkan/libvulkan/api.cpp +++ b/vulkan/libvulkan/api.cpp @@ -29,14 +29,17 @@ #include <new> #include <utility> +#include <android-base/strings.h> #include <cutils/properties.h> #include <log/log.h> #include <vulkan/vk_layer_interface.h> +#include <graphicsenv/GraphicsEnv.h> #include "api.h" #include "driver.h" #include "layers_extensions.h" + namespace vulkan { namespace api { @@ -121,15 +124,33 @@ class OverrideLayerNames { if (!is_instance_ || !driver::Debuggable()) return; - ParseDebugVulkanLayers(); - property_list(ParseDebugVulkanLayer, this); + GetLayersFromSettings(); - // sort by priorities - auto& arr = implicit_layers_; - std::sort(arr.elements, arr.elements + arr.count, - [](const ImplicitLayer& a, const ImplicitLayer& b) { - return (a.priority < b.priority); - }); + // If no layers specified via Settings, check legacy properties + if (implicit_layers_.count <= 0) { + ParseDebugVulkanLayers(); + property_list(ParseDebugVulkanLayer, this); + + // sort by priorities + auto& arr = implicit_layers_; + std::sort(arr.elements, arr.elements + arr.count, + [](const ImplicitLayer& a, const ImplicitLayer& b) { + return (a.priority < b.priority); + }); + } + } + + void GetLayersFromSettings() { + // These will only be available if conditions are met in GraphicsEnvironemnt + // gpu_debug_layers = layer1:layer2:layerN + const std::string layers = android::GraphicsEnv::getInstance().getDebugLayers(); + if (!layers.empty()) { + ALOGV("Debug layer list: %s", layers.c_str()); + std::vector<std::string> paths = android::base::Split(layers, ":"); + for (uint32_t i = 0; i < paths.size(); i++) { + AddImplicitLayer(int(i), paths[i].c_str(), paths[i].length()); + } + } } void ParseDebugVulkanLayers() { @@ -1280,5 +1301,10 @@ VkResult EnumerateDeviceExtensionProperties( physicalDevice, nullptr, pPropertyCount, pProperties); } +VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) { + *pApiVersion = VK_API_VERSION_1_1; + return VK_SUCCESS; +} + } // namespace api } // namespace vulkan diff --git a/vulkan/libvulkan/api.h b/vulkan/libvulkan/api.h index ded7d1779f..416cba0125 100644 --- a/vulkan/libvulkan/api.h +++ b/vulkan/libvulkan/api.h @@ -33,6 +33,7 @@ VKAPI_ATTR VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount, V VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); VKAPI_ATTR VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion); // clang-format on inline InstanceData& GetData(VkInstance instance) { diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp index 8dd55f458f..2aa1d5a4fc 100644 --- a/vulkan/libvulkan/api_gen.cpp +++ b/vulkan/libvulkan/api_gen.cpp @@ -103,6 +103,26 @@ VKAPI_ATTR VkResult disabledQueuePresentKHR(VkQueue queue, const VkPresentInfoKH return VK_SUCCESS; } +VKAPI_ATTR VkResult disabledGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR*) { + driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkGetDeviceGroupPresentCapabilitiesKHR not executed."); + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult disabledGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR*) { + driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkGetDeviceGroupSurfacePresentModesKHR not executed."); + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult disabledGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, uint32_t*, VkRect2D*) { + driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_swapchain not enabled. Exported vkGetPhysicalDevicePresentRectanglesKHR not executed."); + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult disabledAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR*, uint32_t*) { + driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkAcquireNextImage2KHR not executed."); + return VK_SUCCESS; +} + VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) { driver::Logger(instance).Err(instance, "VK_KHR_android_surface not enabled. Exported vkCreateAndroidSurfaceKHR not executed."); return VK_SUCCESS; @@ -132,11 +152,23 @@ bool InitDispatchTable( INIT_PROC(true, instance, CreateDevice); INIT_PROC(true, instance, EnumerateDeviceExtensionProperties); INIT_PROC(true, instance, GetPhysicalDeviceSparseImageFormatProperties); + INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups); + INIT_PROC(false, instance, GetPhysicalDeviceFeatures2); + INIT_PROC(false, instance, GetPhysicalDeviceProperties2); + INIT_PROC(false, instance, GetPhysicalDeviceFormatProperties2); + INIT_PROC(false, instance, GetPhysicalDeviceImageFormatProperties2); + INIT_PROC(false, instance, GetPhysicalDeviceQueueFamilyProperties2); + INIT_PROC(false, instance, GetPhysicalDeviceMemoryProperties2); + INIT_PROC(false, instance, GetPhysicalDeviceSparseImageFormatProperties2); + INIT_PROC(false, instance, GetPhysicalDeviceExternalBufferProperties); + INIT_PROC(false, instance, GetPhysicalDeviceExternalFenceProperties); + INIT_PROC(false, instance, GetPhysicalDeviceExternalSemaphoreProperties); INIT_PROC_EXT(KHR_surface, true, instance, DestroySurfaceKHR); INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceSupportKHR); INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceCapabilitiesKHR); INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceFormatsKHR); INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfacePresentModesKHR); + INIT_PROC_EXT(KHR_swapchain, false, instance, GetPhysicalDevicePresentRectanglesKHR); INIT_PROC_EXT(KHR_android_surface, true, instance, CreateAndroidSurfaceKHR); // clang-format on @@ -272,11 +304,30 @@ bool InitDispatchTable( INIT_PROC(true, dev, CmdNextSubpass); INIT_PROC(true, dev, CmdEndRenderPass); INIT_PROC(true, dev, CmdExecuteCommands); + INIT_PROC(false, dev, BindBufferMemory2); + INIT_PROC(false, dev, BindImageMemory2); + INIT_PROC(false, dev, GetDeviceGroupPeerMemoryFeatures); + INIT_PROC(false, dev, CmdSetDeviceMask); + INIT_PROC(false, dev, CmdDispatchBase); + INIT_PROC(false, dev, GetImageMemoryRequirements2); + INIT_PROC(false, dev, GetBufferMemoryRequirements2); + INIT_PROC(false, dev, GetImageSparseMemoryRequirements2); + INIT_PROC(false, dev, TrimCommandPool); + INIT_PROC(false, dev, GetDeviceQueue2); + INIT_PROC(false, dev, CreateSamplerYcbcrConversion); + INIT_PROC(false, dev, DestroySamplerYcbcrConversion); + INIT_PROC(false, dev, CreateDescriptorUpdateTemplate); + INIT_PROC(false, dev, DestroyDescriptorUpdateTemplate); + INIT_PROC(false, dev, UpdateDescriptorSetWithTemplate); + INIT_PROC(false, dev, GetDescriptorSetLayoutSupport); INIT_PROC_EXT(KHR_swapchain, true, dev, CreateSwapchainKHR); INIT_PROC_EXT(KHR_swapchain, true, dev, DestroySwapchainKHR); INIT_PROC_EXT(KHR_swapchain, true, dev, GetSwapchainImagesKHR); INIT_PROC_EXT(KHR_swapchain, true, dev, AcquireNextImageKHR); INIT_PROC_EXT(KHR_swapchain, true, dev, QueuePresentKHR); + INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupPresentCapabilitiesKHR); + INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupSurfacePresentModesKHR); + INIT_PROC_EXT(KHR_swapchain, false, dev, AcquireNextImage2KHR); // clang-format on return success; @@ -416,6 +467,33 @@ VKAPI_ATTR void CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRender VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents); VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer); VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); +VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask); +VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); +VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); +VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); +VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); +VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); +VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); +VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); @@ -426,6 +504,10 @@ VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, c VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); +VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); +VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes); +VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); +VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex); VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) { @@ -451,29 +533,41 @@ VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pNa "vkEnumerateDeviceLayerProperties", "vkEnumerateInstanceExtensionProperties", "vkEnumerateInstanceLayerProperties", - "vkEnumeratePhysicalDeviceGroupsKHX", + "vkEnumerateInstanceVersion", + "vkEnumeratePhysicalDeviceGroups", + "vkEnumeratePhysicalDeviceGroupsKHR", "vkEnumeratePhysicalDevices", "vkGetInstanceProcAddr", + "vkGetPhysicalDeviceExternalBufferProperties", "vkGetPhysicalDeviceExternalBufferPropertiesKHR", + "vkGetPhysicalDeviceExternalFenceProperties", "vkGetPhysicalDeviceExternalFencePropertiesKHR", "vkGetPhysicalDeviceExternalImageFormatPropertiesNV", + "vkGetPhysicalDeviceExternalSemaphoreProperties", "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR", "vkGetPhysicalDeviceFeatures", + "vkGetPhysicalDeviceFeatures2", "vkGetPhysicalDeviceFeatures2KHR", "vkGetPhysicalDeviceFormatProperties", + "vkGetPhysicalDeviceFormatProperties2", "vkGetPhysicalDeviceFormatProperties2KHR", "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX", "vkGetPhysicalDeviceImageFormatProperties", + "vkGetPhysicalDeviceImageFormatProperties2", "vkGetPhysicalDeviceImageFormatProperties2KHR", "vkGetPhysicalDeviceMemoryProperties", + "vkGetPhysicalDeviceMemoryProperties2", "vkGetPhysicalDeviceMemoryProperties2KHR", "vkGetPhysicalDeviceMultisamplePropertiesEXT", - "vkGetPhysicalDevicePresentRectanglesKHX", + "vkGetPhysicalDevicePresentRectanglesKHR", "vkGetPhysicalDeviceProperties", + "vkGetPhysicalDeviceProperties2", "vkGetPhysicalDeviceProperties2KHR", "vkGetPhysicalDeviceQueueFamilyProperties", + "vkGetPhysicalDeviceQueueFamilyProperties2", "vkGetPhysicalDeviceQueueFamilyProperties2KHR", "vkGetPhysicalDeviceSparseImageFormatProperties", + "vkGetPhysicalDeviceSparseImageFormatProperties2", "vkGetPhysicalDeviceSparseImageFormatProperties2KHR", "vkGetPhysicalDeviceSurfaceCapabilities2KHR", "vkGetPhysicalDeviceSurfaceCapabilitiesKHR", @@ -508,6 +602,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha if (strcmp(pName, "vkCreateInstance") == 0) return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance); if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties); if (strcmp(pName, "vkEnumerateInstanceExtensionProperties") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties); + if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceVersion); ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \"%s\") call", pName); return nullptr; @@ -517,13 +612,16 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha const char* name; PFN_vkVoidFunction proc; } hooks[] = { + { "vkAcquireNextImage2KHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImage2KHR) }, { "vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR) }, { "vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers) }, { "vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets) }, { "vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory) }, { "vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer) }, { "vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory) }, + { "vkBindBufferMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory2) }, { "vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory) }, + { "vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2) }, { "vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery) }, { "vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass) }, { "vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets) }, @@ -540,6 +638,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha { "vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer) }, { "vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults) }, { "vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch) }, + { "vkCmdDispatchBase", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchBase) }, { "vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect) }, { "vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw) }, { "vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed) }, @@ -558,6 +657,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha { "vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants) }, { "vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias) }, { "vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds) }, + { "vkCmdSetDeviceMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDeviceMask) }, { "vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent) }, { "vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth) }, { "vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor) }, @@ -574,6 +674,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha { "vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines) }, { "vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool) }, { "vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout) }, + { "vkCreateDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorUpdateTemplate) }, { "vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice) }, { "vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent) }, { "vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence) }, @@ -587,6 +688,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha { "vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool) }, { "vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass) }, { "vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler) }, + { "vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(CreateSamplerYcbcrConversion) }, { "vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore) }, { "vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule) }, { "vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR) }, @@ -595,6 +697,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha { "vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool) }, { "vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool) }, { "vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout) }, + { "vkDestroyDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorUpdateTemplate) }, { "vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice) }, { "vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent) }, { "vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence) }, @@ -608,6 +711,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha { "vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool) }, { "vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass) }, { "vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler) }, + { "vkDestroySamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(DestroySamplerYcbcrConversion) }, { "vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore) }, { "vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule) }, { "vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR) }, @@ -617,18 +721,27 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha { "vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties) }, { "vkEnumerateInstanceExtensionProperties", nullptr }, { "vkEnumerateInstanceLayerProperties", nullptr }, + { "vkEnumerateInstanceVersion", nullptr }, { "vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges) }, { "vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers) }, { "vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets) }, { "vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory) }, { "vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements) }, + { "vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements2) }, + { "vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(GetDescriptorSetLayoutSupport) }, + { "vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPeerMemoryFeatures) }, + { "vkGetDeviceGroupPresentCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR) }, + { "vkGetDeviceGroupSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR) }, { "vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryCommitment) }, { "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) }, { "vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue) }, + { "vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2) }, { "vkGetEventStatus", reinterpret_cast<PFN_vkVoidFunction>(GetEventStatus) }, { "vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus) }, { "vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements) }, + { "vkGetImageMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements2) }, { "vkGetImageSparseMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageSparseMemoryRequirements) }, + { "vkGetImageSparseMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetImageSparseMemoryRequirements2) }, { "vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(GetImageSubresourceLayout) }, { "vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr) }, { "vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData) }, @@ -648,7 +761,9 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha { "vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(ResetEvent) }, { "vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences) }, { "vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent) }, + { "vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(TrimCommandPool) }, { "vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory) }, + { "vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSetWithTemplate) }, { "vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets) }, { "vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences) }, }; @@ -1174,6 +1289,114 @@ VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t comma GetData(commandBuffer).dispatch.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers); } +VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) { + return GetData(device).dispatch.BindBufferMemory2(device, bindInfoCount, pBindInfos); +} + +VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { + return GetData(device).dispatch.BindImageMemory2(device, bindInfoCount, pBindInfos); +} + +VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) { + GetData(device).dispatch.GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures); +} + +VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) { + GetData(commandBuffer).dispatch.CmdSetDeviceMask(commandBuffer, deviceMask); +} + +VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { + GetData(commandBuffer).dispatch.CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ); +} + +VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { + return GetData(instance).dispatch.EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); +} + +VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { + GetData(device).dispatch.GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements); +} + +VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { + GetData(device).dispatch.GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements); +} + +VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) { + GetData(device).dispatch.GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements); +} + +VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures); +} + +VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceProperties2(physicalDevice, pProperties); +} + +VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties); +} + +VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) { + return GetData(physicalDevice).dispatch.GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties); +} + +VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties); +} + +VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties); +} + +VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties); +} + +VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) { + GetData(device).dispatch.TrimCommandPool(device, commandPool, flags); +} + +VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) { + GetData(device).dispatch.GetDeviceQueue2(device, pQueueInfo, pQueue); +} + +VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) { + return GetData(device).dispatch.CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion); +} + +VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) { + GetData(device).dispatch.DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator); +} + +VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) { + return GetData(device).dispatch.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate); +} + +VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) { + GetData(device).dispatch.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator); +} + +VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) { + GetData(device).dispatch.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData); +} + +VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties); +} + +VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties); +} + +VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties); +} + +VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) { + GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport); +} + VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) { GetData(instance).dispatch.DestroySurfaceKHR(instance, surface, pAllocator); } @@ -1214,6 +1437,22 @@ VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPres return GetData(queue).dispatch.QueuePresentKHR(queue, pPresentInfo); } +VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { + return GetData(device).dispatch.GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities); +} + +VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) { + return GetData(device).dispatch.GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes); +} + +VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) { + return GetData(physicalDevice).dispatch.GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects); +} + +VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) { + return GetData(device).dispatch.AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex); +} + VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { return GetData(instance).dispatch.CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); } @@ -1914,6 +2153,146 @@ VKAPI_ATTR void vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t com } __attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkEnumerateInstanceVersion(uint32_t* pApiVersion) { + return vulkan::api::EnumerateInstanceVersion(pApiVersion); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) { + return vulkan::api::BindBufferMemory2(device, bindInfoCount, pBindInfos); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { + return vulkan::api::BindImageMemory2(device, bindInfoCount, pBindInfos); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) { + vulkan::api::GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) { + vulkan::api::CmdSetDeviceMask(commandBuffer, deviceMask); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { + vulkan::api::CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { + return vulkan::api::EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { + vulkan::api::GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { + vulkan::api::GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) { + vulkan::api::GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) { + vulkan::api::GetPhysicalDeviceFeatures2(physicalDevice, pFeatures); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) { + vulkan::api::GetPhysicalDeviceProperties2(physicalDevice, pProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) { + vulkan::api::GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) { + return vulkan::api::GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) { + vulkan::api::GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) { + vulkan::api::GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) { + vulkan::api::GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) { + vulkan::api::TrimCommandPool(device, commandPool, flags); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) { + vulkan::api::GetDeviceQueue2(device, pQueueInfo, pQueue); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) { + return vulkan::api::CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) { + vulkan::api::DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) { + return vulkan::api::CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) { + vulkan::api::DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) { + vulkan::api::UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) { + vulkan::api::GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) { + vulkan::api::GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) { + vulkan::api::GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR void vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) { + vulkan::api::GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport); +} + +__attribute__((visibility("default"))) VKAPI_ATTR void vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroySurfaceKHR(instance, surface, pAllocator); } @@ -1964,6 +2343,26 @@ VKAPI_ATTR VkResult vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPr } __attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { + return vulkan::api::GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) { + return vulkan::api::GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) { + return vulkan::api::GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) { + return vulkan::api::AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex); +} + +__attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { return vulkan::api::CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); } diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h index 3e50fda949..939dc734ee 100644 --- a/vulkan/libvulkan/api_gen.h +++ b/vulkan/libvulkan/api_gen.h @@ -40,11 +40,23 @@ struct InstanceDispatchTable { PFN_vkCreateDevice CreateDevice; PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties; PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties; + PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups; + PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2; + PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2; + PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysicalDeviceFormatProperties2; + PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysicalDeviceImageFormatProperties2; + PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysicalDeviceQueueFamilyProperties2; + PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysicalDeviceMemoryProperties2; + PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysicalDeviceSparseImageFormatProperties2; + PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties; + PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties; + PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties; PFN_vkDestroySurfaceKHR DestroySurfaceKHR; PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR; PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR; PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR; PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR; + PFN_vkGetPhysicalDevicePresentRectanglesKHR GetPhysicalDevicePresentRectanglesKHR; PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR; // clang-format on }; @@ -172,11 +184,30 @@ struct DeviceDispatchTable { PFN_vkCmdNextSubpass CmdNextSubpass; PFN_vkCmdEndRenderPass CmdEndRenderPass; PFN_vkCmdExecuteCommands CmdExecuteCommands; + PFN_vkBindBufferMemory2 BindBufferMemory2; + PFN_vkBindImageMemory2 BindImageMemory2; + PFN_vkGetDeviceGroupPeerMemoryFeatures GetDeviceGroupPeerMemoryFeatures; + PFN_vkCmdSetDeviceMask CmdSetDeviceMask; + PFN_vkCmdDispatchBase CmdDispatchBase; + PFN_vkGetImageMemoryRequirements2 GetImageMemoryRequirements2; + PFN_vkGetBufferMemoryRequirements2 GetBufferMemoryRequirements2; + PFN_vkGetImageSparseMemoryRequirements2 GetImageSparseMemoryRequirements2; + PFN_vkTrimCommandPool TrimCommandPool; + PFN_vkGetDeviceQueue2 GetDeviceQueue2; + PFN_vkCreateSamplerYcbcrConversion CreateSamplerYcbcrConversion; + PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion; + PFN_vkCreateDescriptorUpdateTemplate CreateDescriptorUpdateTemplate; + PFN_vkDestroyDescriptorUpdateTemplate DestroyDescriptorUpdateTemplate; + PFN_vkUpdateDescriptorSetWithTemplate UpdateDescriptorSetWithTemplate; + PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport; PFN_vkCreateSwapchainKHR CreateSwapchainKHR; PFN_vkDestroySwapchainKHR DestroySwapchainKHR; PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR; PFN_vkAcquireNextImageKHR AcquireNextImageKHR; PFN_vkQueuePresentKHR QueuePresentKHR; + PFN_vkGetDeviceGroupPresentCapabilitiesKHR GetDeviceGroupPresentCapabilitiesKHR; + PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR; + PFN_vkAcquireNextImage2KHR AcquireNextImage2KHR; // clang-format on }; diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl index cb2d26aaab..3b48e08a4f 100644 --- a/vulkan/libvulkan/code-generator.tmpl +++ b/vulkan/libvulkan/code-generator.tmpl @@ -419,7 +419,7 @@ bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, INIT_PROC(§ {{end}} - {{if GetAnnotation $ "optional"}}false{{else}}true{{end}}, § + {{if GetAnnotation $ "optional"}}false{{else if GetAnnotation $ "vulkan1_1"}}false{{else}}true{{end}}, § {{if (Macro "IsInstanceDispatched" $)}} instance, § @@ -733,7 +733,9 @@ VK_KHR_get_physical_device_properties2 {{ if eq $.Name "vkCreateInstance"}}true {{else if eq $.Name "vkCreateDevice"}}true {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true + {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true {{else if eq $.Name "vkGetDeviceQueue"}}true + {{else if eq $.Name "vkGetDeviceQueue2"}}true {{else if eq $.Name "vkAllocateCommandBuffers"}}true {{/* Destroy functions of dispatchable objects */}} @@ -958,6 +960,7 @@ VK_KHR_get_physical_device_properties2 {{/* Create functions of dispatchable objects */}} {{ if eq $.Name "vkCreateDevice"}}true {{else if eq $.Name "vkGetDeviceQueue"}}true + {{else if eq $.Name "vkGetDeviceQueue2"}}true {{else if eq $.Name "vkAllocateCommandBuffers"}}true {{/* Destroy functions of dispatchable objects */}} @@ -969,6 +972,7 @@ VK_KHR_get_physical_device_properties2 {{/* We cache physical devices in loader.cpp */}} {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true + {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true {{else if eq $.Name "vkGetInstanceProcAddr"}}true {{else if eq $.Name "vkGetDeviceProcAddr"}}true diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 947a2f7bfe..ade0bde8f9 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -880,19 +880,6 @@ VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks& data_allocator = (pAllocator) ? *pAllocator : GetDefaultAllocator(); - if (pCreateInfo->pApplicationInfo && - pCreateInfo->pApplicationInfo->apiVersion >= VK_MAKE_VERSION(1, 1, 0)) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wold-style-cast" - ALOGI( - "Requested Vulkan instance version %d.%d is greater than max " - "supported version (1.0)", - VK_VERSION_MAJOR(pCreateInfo->pApplicationInfo->apiVersion), - VK_VERSION_MINOR(pCreateInfo->pApplicationInfo->apiVersion)); -#pragma clang diagnostic pop - return VK_ERROR_INCOMPATIBLE_DRIVER; - } - CreateInfoWrapper wrapper(*pCreateInfo, data_allocator); VkResult result = wrapper.Validate(); if (result != VK_SUCCESS) @@ -1056,6 +1043,28 @@ VkResult EnumeratePhysicalDevices(VkInstance instance, return result; } +VkResult EnumeratePhysicalDeviceGroups( + VkInstance instance, + uint32_t* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { + const auto& data = GetData(instance); + + VkResult result = data.driver.EnumeratePhysicalDeviceGroups( + instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); + if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && + *pPhysicalDeviceGroupCount && pPhysicalDeviceGroupProperties) { + for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) { + for (uint32_t j = 0; + j < pPhysicalDeviceGroupProperties->physicalDeviceCount; j++) { + SetData(pPhysicalDeviceGroupProperties->physicalDevices[j], + data); + } + } + } + + return result; +} + void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, @@ -1066,6 +1075,15 @@ void GetDeviceQueue(VkDevice device, SetData(*pQueue, data); } +void GetDeviceQueue2(VkDevice device, + const VkDeviceQueueInfo2* pQueueInfo, + VkQueue* pQueue) { + const auto& data = GetData(device); + + data.driver.GetDeviceQueue2(device, pQueueInfo, pQueue); + SetData(*pQueue, data); +} + VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h index 7f8ae98b02..57c956d9a4 100644 --- a/vulkan/libvulkan/driver.h +++ b/vulkan/libvulkan/driver.h @@ -126,7 +126,10 @@ VKAPI_ATTR VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDevice VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); + VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); +VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); // clang-format on diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index 82b464e5bc..c6e8a7aeda 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -75,6 +75,33 @@ VKAPI_ATTR VkResult checkedQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR } } +VKAPI_ATTR VkResult checkedGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { + if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) { + return GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities); + } else { + Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkGetDeviceGroupPresentCapabilitiesKHR not executed."); + return VK_SUCCESS; + } +} + +VKAPI_ATTR VkResult checkedGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) { + if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) { + return GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes); + } else { + Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkGetDeviceGroupSurfacePresentModesKHR not executed."); + return VK_SUCCESS; + } +} + +VKAPI_ATTR VkResult checkedAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) { + if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) { + return AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex); + } else { + Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkAcquireNextImage2KHR not executed."); + return VK_SUCCESS; + } +} + VKAPI_ATTR VkResult checkedGetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) { if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) { return GetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties); @@ -122,6 +149,13 @@ const ProcHook g_proc_hooks[] = { nullptr, }, { + "vkAcquireNextImage2KHR", + ProcHook::DEVICE, + ProcHook::KHR_swapchain, + reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImage2KHR), + reinterpret_cast<PFN_vkVoidFunction>(checkedAcquireNextImage2KHR), + }, + { "vkAcquireNextImageKHR", ProcHook::DEVICE, ProcHook::KHR_swapchain, @@ -227,6 +261,13 @@ const ProcHook g_proc_hooks[] = { nullptr, }, { + "vkEnumeratePhysicalDeviceGroups", + ProcHook::INSTANCE, + ProcHook::EXTENSION_CORE, + reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroups), + nullptr, + }, + { "vkEnumeratePhysicalDevices", ProcHook::INSTANCE, ProcHook::EXTENSION_CORE, @@ -234,6 +275,20 @@ const ProcHook g_proc_hooks[] = { nullptr, }, { + "vkGetDeviceGroupPresentCapabilitiesKHR", + ProcHook::DEVICE, + ProcHook::KHR_swapchain, + reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR), + reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceGroupPresentCapabilitiesKHR), + }, + { + "vkGetDeviceGroupSurfacePresentModesKHR", + ProcHook::DEVICE, + ProcHook::KHR_swapchain, + reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR), + reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceGroupSurfacePresentModesKHR), + }, + { "vkGetDeviceProcAddr", ProcHook::DEVICE, ProcHook::EXTENSION_CORE, @@ -248,6 +303,13 @@ const ProcHook g_proc_hooks[] = { nullptr, }, { + "vkGetDeviceQueue2", + ProcHook::DEVICE, + ProcHook::EXTENSION_CORE, + reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2), + nullptr, + }, + { "vkGetInstanceProcAddr", ProcHook::INSTANCE, ProcHook::EXTENSION_CORE, @@ -262,6 +324,13 @@ const ProcHook g_proc_hooks[] = { reinterpret_cast<PFN_vkVoidFunction>(checkedGetPastPresentationTimingGOOGLE), }, { + "vkGetPhysicalDevicePresentRectanglesKHR", + ProcHook::INSTANCE, + ProcHook::KHR_swapchain, + reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDevicePresentRectanglesKHR), + nullptr, + }, + { "vkGetPhysicalDeviceSurfaceCapabilities2KHR", ProcHook::INSTANCE, ProcHook::KHR_get_surface_capabilities2, @@ -423,6 +492,7 @@ bool InitDriverTable(VkInstance instance, INIT_PROC(true, instance, GetPhysicalDeviceProperties); INIT_PROC(true, instance, CreateDevice); INIT_PROC(true, instance, EnumerateDeviceExtensionProperties); + INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups); INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT); INIT_PROC_EXT(EXT_debug_report, true, instance, DestroyDebugReportCallbackEXT); INIT_PROC_EXT(EXT_debug_report, true, instance, DebugReportMessageEXT); @@ -445,6 +515,7 @@ bool InitDriverTable(VkDevice dev, INIT_PROC(true, dev, CreateImage); INIT_PROC(true, dev, DestroyImage); INIT_PROC(true, dev, AllocateCommandBuffers); + INIT_PROC(false, dev, GetDeviceQueue2); INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID); INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID); INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID); diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 3b26a8072c..646662fffc 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -67,6 +67,7 @@ struct InstanceDriverTable { PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties; PFN_vkCreateDevice CreateDevice; PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties; + PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups; PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT; PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT; PFN_vkDebugReportMessageEXT DebugReportMessageEXT; @@ -82,6 +83,7 @@ struct DeviceDriverTable { PFN_vkCreateImage CreateImage; PFN_vkDestroyImage DestroyImage; PFN_vkAllocateCommandBuffers AllocateCommandBuffers; + PFN_vkGetDeviceQueue2 GetDeviceQueue2; PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID; PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID; PFN_vkAcquireImageANDROID AcquireImageANDROID; diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp index 05856d3c1c..3a59208446 100644 --- a/vulkan/libvulkan/layers_extensions.cpp +++ b/vulkan/libvulkan/layers_extensions.cpp @@ -29,11 +29,10 @@ #include <android/dlext.h> #include <android-base/strings.h> #include <cutils/properties.h> +#include <graphicsenv/GraphicsEnv.h> #include <log/log.h> #include <ziparchive/zip_archive.h> -#include <vulkan/vulkan_loader_data.h> - // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and // not a good long-term solution. Having a hard-coded enum of extensions is // bad, of course. Representing sets of extensions (requested, supported, etc.) @@ -69,11 +68,16 @@ const char kSystemLayerLibraryDir[] = "/data/local/debug/vulkan"; class LayerLibrary { public: - explicit LayerLibrary(const std::string& path) - : path_(path), dlhandle_(nullptr), refcount_(0) {} + explicit LayerLibrary(const std::string& path, + const std::string& filename) + : path_(path), + filename_(filename), + dlhandle_(nullptr), + refcount_(0) {} LayerLibrary(LayerLibrary&& other) : path_(std::move(other.path_)), + filename_(std::move(other.filename_)), dlhandle_(other.dlhandle_), refcount_(other.refcount_) { other.dlhandle_ = nullptr; @@ -94,9 +98,14 @@ class LayerLibrary { const char* gpa_name, size_t gpa_name_len) const; + const std::string GetFilename() { return filename_; } + private: const std::string path_; + // Track the filename alone so we can detect duplicates + const std::string filename_; + std::mutex mutex_; void* dlhandle_; size_t refcount_; @@ -111,7 +120,7 @@ bool LayerLibrary::Open() { // any symbol dependencies will be resolved by system libraries. They // can't safely use libc++_shared, for example. Which is one reason // (among several) we only allow them in non-user builds. - auto app_namespace = LoaderData::GetInstance().app_namespace; + auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace(); if (app_namespace && !android::base::StartsWith(path_, kSystemLayerLibraryDir)) { android_dlextinfo dlextinfo = {}; @@ -305,8 +314,8 @@ void* LayerLibrary::GetGPA(const Layer& layer, std::vector<LayerLibrary> g_layer_libraries; std::vector<Layer> g_instance_layers; -void AddLayerLibrary(const std::string& path) { - LayerLibrary library(path); +void AddLayerLibrary(const std::string& path, const std::string& filename) { + LayerLibrary library(path + "/" + filename, filename); if (!library.Open()) return; @@ -398,7 +407,25 @@ void DiscoverLayersInPathList(const std::string& pathstr) { ForEachFileInPath(path, [&](const std::string& filename) { if (android::base::StartsWith(filename, "libVkLayer") && android::base::EndsWith(filename, ".so")) { - AddLayerLibrary(path + "/" + filename); + + // Check to ensure we haven't seen this layer already + // Let the first instance of the shared object be enumerated + // We're searching for layers in following order: + // 1. system path + // 2. libraryPermittedPath (if enabled) + // 3. libraryPath + + bool duplicate = false; + for (auto& layer : g_layer_libraries) { + if (layer.GetFilename() == filename) { + ALOGV("Skipping duplicate layer %s in %s", + filename.c_str(), path.c_str()); + duplicate = true; + } + } + + if (!duplicate) + AddLayerLibrary(path, filename); } }); } @@ -428,8 +455,8 @@ void DiscoverLayers() { prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { DiscoverLayersInPathList(kSystemLayerLibraryDir); } - if (!LoaderData::GetInstance().layer_path.empty()) - DiscoverLayersInPathList(LoaderData::GetInstance().layer_path); + if (!android::GraphicsEnv::getInstance().getLayerPaths().empty()) + DiscoverLayersInPathList(android::GraphicsEnv::getInstance().getLayerPaths()); } uint32_t GetLayerCount() { diff --git a/vulkan/libvulkan/stubhal.cpp b/vulkan/libvulkan/stubhal.cpp index 2926268488..726e8549d7 100644 --- a/vulkan/libvulkan/stubhal.cpp +++ b/vulkan/libvulkan/stubhal.cpp @@ -97,7 +97,7 @@ VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance /*instance*/, return VK_SUCCESS; } -VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance /*instance*/, +VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) { if (strcmp(name, "vkCreateInstance") == 0) return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance); @@ -110,7 +110,9 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance /*instance*/, return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices); if (strcmp(name, "vkGetInstanceProcAddr") == 0) return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr); - + // Per the spec, return NULL if instance is NULL. + if (!instance) + return nullptr; // None of the other Vulkan functions should ever be called, as they all // take a VkPhysicalDevice or other object obtained from a physical device. return reinterpret_cast<PFN_vkVoidFunction>(NoOp); diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 665a32b90c..03e6ee0870 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -23,9 +23,12 @@ #include <utils/StrongPointer.h> #include <utils/Vector.h> #include <system/window.h> +#include <android/hardware/graphics/common/1.0/types.h> #include "driver.h" +using android::hardware::graphics::common::V1_0::BufferUsage; + // TODO(jessehall): Currently we don't have a good error code for when a native // window operation fails. Just returning INITIALIZATION_FAILED for now. Later // versions (post SDK 0.9) of the API/extension have a better error code. @@ -771,6 +774,77 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, } VKAPI_ATTR +VkResult GetDeviceGroupPresentCapabilitiesKHR( + VkDevice, + VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { + ALOGV_IF(pDeviceGroupPresentCapabilities->sType != + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR, + "vkGetDeviceGroupPresentCapabilitiesKHR: invalid " + "VkDeviceGroupPresentCapabilitiesKHR structure type %d", + pDeviceGroupPresentCapabilities->sType); + + memset(pDeviceGroupPresentCapabilities->presentMask, 0, + sizeof(pDeviceGroupPresentCapabilities->presentMask)); + + // assume device group of size 1 + pDeviceGroupPresentCapabilities->presentMask[0] = 1 << 0; + pDeviceGroupPresentCapabilities->modes = + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR; + + return VK_SUCCESS; +} + +VKAPI_ATTR +VkResult GetDeviceGroupSurfacePresentModesKHR( + VkDevice, + VkSurfaceKHR, + VkDeviceGroupPresentModeFlagsKHR* pModes) { + *pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR; + return VK_SUCCESS; +} + +VKAPI_ATTR +VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice, + VkSurfaceKHR surface, + uint32_t* pRectCount, + VkRect2D* pRects) { + if (!pRects) { + *pRectCount = 1; + } else { + uint32_t count = std::min(*pRectCount, 1u); + bool incomplete = *pRectCount < 1; + + *pRectCount = count; + + if (incomplete) { + return VK_INCOMPLETE; + } + + int err; + ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); + + int width = 0, height = 0; + err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); + if (err != 0) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + } + err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); + if (err != 0) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + } + + // TODO: Return something better than "whole window" + pRects[0].offset.x = 0; + pRects[0].offset.y = 0; + pRects[0].extent = VkExtent2D{static_cast<uint32_t>(width), + static_cast<uint32_t>(height)}; + } + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, @@ -996,7 +1070,7 @@ VkResult CreateSwapchainKHR(VkDevice device, return VK_ERROR_SURFACE_LOST_KHR; } - int gralloc_usage = 0; + int32_t legacy_usage = 0; if (dispatch.GetSwapchainGrallocUsage2ANDROID) { uint64_t consumer_usage, producer_usage; result = dispatch.GetSwapchainGrallocUsage2ANDROID( @@ -1006,18 +1080,25 @@ VkResult CreateSwapchainKHR(VkDevice device, ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result); return VK_ERROR_SURFACE_LOST_KHR; } - gralloc_usage = + legacy_usage = android_convertGralloc1To0Usage(producer_usage, consumer_usage); } else if (dispatch.GetSwapchainGrallocUsageANDROID) { result = dispatch.GetSwapchainGrallocUsageANDROID( device, create_info->imageFormat, create_info->imageUsage, - &gralloc_usage); + &legacy_usage); if (result != VK_SUCCESS) { ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result); return VK_ERROR_SURFACE_LOST_KHR; } } - err = native_window_set_usage(surface.window.get(), uint64_t(gralloc_usage)); + uint64_t native_usage = static_cast<uint64_t>(legacy_usage); + + bool createProtectedSwapchain = false; + if (create_info->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) { + createProtectedSwapchain = true; + native_usage |= BufferUsage::PROTECTED; + } + err = native_window_set_usage(surface.window.get(), native_usage); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? @@ -1065,7 +1146,7 @@ VkResult CreateSwapchainKHR(VkDevice device, .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_OPTIMAL, .usage = create_info->imageUsage, - .flags = 0, + .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, .sharingMode = create_info->imageSharingMode, .queueFamilyIndexCount = create_info->queueFamilyIndexCount, .pQueueFamilyIndices = create_info->pQueueFamilyIndices, @@ -1273,6 +1354,17 @@ VkResult AcquireNextImageKHR(VkDevice device, return VK_SUCCESS; } +VKAPI_ATTR +VkResult AcquireNextImage2KHR(VkDevice device, + const VkAcquireNextImageInfoKHR* pAcquireInfo, + uint32_t* pImageIndex) { + // TODO: this should actually be the other way around and this function + // should handle any additional structures that get passed in + return AcquireNextImageKHR(device, pAcquireInfo->swapchain, + pAcquireInfo->timeout, pAcquireInfo->semaphore, + pAcquireInfo->fence, pImageIndex); +} + static VkResult WorstPresentResult(VkResult a, VkResult b) { // See the error ranking for vkQueuePresentKHR at the end of section 29.6 // (in spec version 1.0.14). diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h index e3cf624664..ed5718c75f 100644 --- a/vulkan/libvulkan/swapchain.h +++ b/vulkan/libvulkan/swapchain.h @@ -29,11 +29,15 @@ VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice pdev, ui VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface_handle, uint32_t* count, VkSurfaceFormatKHR* formats); VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes); +VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); +VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes); +VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle); VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator); VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images); VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index); VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info); +VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex); VKAPI_ATTR VkResult GetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); VKAPI_ATTR VkResult GetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings); VKAPI_ATTR VkResult GetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain); diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp index e2d5c83d78..4647a80e91 100644 --- a/vulkan/nulldrv/null_driver.cpp +++ b/vulkan/nulldrv/null_driver.cpp @@ -259,6 +259,12 @@ namespace null_driver { // Global VKAPI_ATTR +VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) { + *pApiVersion = VK_API_VERSION_1_1; + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties( const char* layer_name, uint32_t* count, @@ -1475,6 +1481,93 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage) { } +VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) { + return VK_SUCCESS; +} + +VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { + return VK_SUCCESS; +} + +void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) { +} + +void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) { +} + +void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { +} + +VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { + return VK_SUCCESS; +} + +void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { +} + +void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { +} + +void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) { +} + +void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) { +} + +void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) { +} + +void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) { +} + +VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) { + return VK_SUCCESS; +} + +void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) { +} + +void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) { +} + +void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) { +} + +void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) { +} + +void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) { +} + +VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) { + return VK_SUCCESS; +} + +void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) { +} + +VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) { + return VK_SUCCESS; +} + +void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) { +} + +void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) { +} + +void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) { +} + +void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) { +} + +void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) { +} + +void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) { +} + #pragma clang diagnostic pop // clang-format on diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp index 25ee65add5..92b7468321 100644 --- a/vulkan/nulldrv/null_driver_gen.cpp +++ b/vulkan/nulldrv/null_driver_gen.cpp @@ -49,6 +49,7 @@ const NameProc kGlobalProcs[] = { {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateInstance>(CreateInstance))}, {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceExtensionProperties>(EnumerateInstanceExtensionProperties))}, {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceLayerProperties>(EnumerateInstanceLayerProperties))}, + {"vkEnumerateInstanceVersion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceVersion>(EnumerateInstanceVersion))}, // clang-format on }; @@ -60,7 +61,9 @@ const NameProc kInstanceProcs[] = { {"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateMemory>(AllocateMemory))}, {"vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBeginCommandBuffer>(BeginCommandBuffer))}, {"vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindBufferMemory>(BindBufferMemory))}, + {"vkBindBufferMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindBufferMemory2>(BindBufferMemory2))}, {"vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory>(BindImageMemory))}, + {"vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory2>(BindImageMemory2))}, {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginQuery>(CmdBeginQuery))}, {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass>(CmdBeginRenderPass))}, {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindDescriptorSets>(CmdBindDescriptorSets))}, @@ -77,6 +80,7 @@ const NameProc kInstanceProcs[] = { {"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdCopyImageToBuffer>(CmdCopyImageToBuffer))}, {"vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdCopyQueryPoolResults>(CmdCopyQueryPoolResults))}, {"vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDispatch>(CmdDispatch))}, + {"vkCmdDispatchBase", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDispatchBase>(CmdDispatchBase))}, {"vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDispatchIndirect>(CmdDispatchIndirect))}, {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDraw>(CmdDraw))}, {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexed>(CmdDrawIndexed))}, @@ -95,6 +99,7 @@ const NameProc kInstanceProcs[] = { {"vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetBlendConstants>(CmdSetBlendConstants))}, {"vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetDepthBias>(CmdSetDepthBias))}, {"vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetDepthBounds>(CmdSetDepthBounds))}, + {"vkCmdSetDeviceMask", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetDeviceMask>(CmdSetDeviceMask))}, {"vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetEvent>(CmdSetEvent))}, {"vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetLineWidth>(CmdSetLineWidth))}, {"vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetScissor>(CmdSetScissor))}, @@ -112,6 +117,7 @@ const NameProc kInstanceProcs[] = { {"vkCreateDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDebugReportCallbackEXT>(CreateDebugReportCallbackEXT))}, {"vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDescriptorPool>(CreateDescriptorPool))}, {"vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDescriptorSetLayout>(CreateDescriptorSetLayout))}, + {"vkCreateDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDescriptorUpdateTemplate>(CreateDescriptorUpdateTemplate))}, {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDevice>(CreateDevice))}, {"vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateEvent>(CreateEvent))}, {"vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateFence>(CreateFence))}, @@ -125,6 +131,7 @@ const NameProc kInstanceProcs[] = { {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateQueryPool>(CreateQueryPool))}, {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass>(CreateRenderPass))}, {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSampler>(CreateSampler))}, + {"vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSamplerYcbcrConversion>(CreateSamplerYcbcrConversion))}, {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSemaphore>(CreateSemaphore))}, {"vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateShaderModule>(CreateShaderModule))}, {"vkDebugReportMessageEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDebugReportMessageEXT>(DebugReportMessageEXT))}, @@ -134,6 +141,7 @@ const NameProc kInstanceProcs[] = { {"vkDestroyDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDebugReportCallbackEXT>(DestroyDebugReportCallbackEXT))}, {"vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDescriptorPool>(DestroyDescriptorPool))}, {"vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDescriptorSetLayout>(DestroyDescriptorSetLayout))}, + {"vkDestroyDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDescriptorUpdateTemplate>(DestroyDescriptorUpdateTemplate))}, {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDevice>(DestroyDevice))}, {"vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyEvent>(DestroyEvent))}, {"vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyFence>(DestroyFence))}, @@ -147,6 +155,7 @@ const NameProc kInstanceProcs[] = { {"vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyQueryPool>(DestroyQueryPool))}, {"vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyRenderPass>(DestroyRenderPass))}, {"vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySampler>(DestroySampler))}, + {"vkDestroySamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySamplerYcbcrConversion>(DestroySamplerYcbcrConversion))}, {"vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySemaphore>(DestroySemaphore))}, {"vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyShaderModule>(DestroyShaderModule))}, {"vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDeviceWaitIdle>(DeviceWaitIdle))}, @@ -155,34 +164,52 @@ const NameProc kInstanceProcs[] = { {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateDeviceLayerProperties>(EnumerateDeviceLayerProperties))}, {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceExtensionProperties>(EnumerateInstanceExtensionProperties))}, {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceLayerProperties>(EnumerateInstanceLayerProperties))}, + {"vkEnumerateInstanceVersion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceVersion>(EnumerateInstanceVersion))}, + {"vkEnumeratePhysicalDeviceGroups", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumeratePhysicalDeviceGroups>(EnumeratePhysicalDeviceGroups))}, {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumeratePhysicalDevices>(EnumeratePhysicalDevices))}, {"vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFlushMappedMemoryRanges>(FlushMappedMemoryRanges))}, {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeCommandBuffers>(FreeCommandBuffers))}, {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeDescriptorSets>(FreeDescriptorSets))}, {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeMemory>(FreeMemory))}, {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements>(GetBufferMemoryRequirements))}, + {"vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements2>(GetBufferMemoryRequirements2))}, + {"vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDescriptorSetLayoutSupport>(GetDescriptorSetLayoutSupport))}, + {"vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceGroupPeerMemoryFeatures>(GetDeviceGroupPeerMemoryFeatures))}, {"vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceMemoryCommitment))}, {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr))}, {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue>(GetDeviceQueue))}, + {"vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue2>(GetDeviceQueue2))}, {"vkGetEventStatus", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetEventStatus>(GetEventStatus))}, {"vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetFenceStatus>(GetFenceStatus))}, {"vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageMemoryRequirements>(GetImageMemoryRequirements))}, + {"vkGetImageMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageMemoryRequirements2>(GetImageMemoryRequirements2))}, {"vkGetImageSparseMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageSparseMemoryRequirements>(GetImageSparseMemoryRequirements))}, + {"vkGetImageSparseMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageSparseMemoryRequirements2>(GetImageSparseMemoryRequirements2))}, {"vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageSubresourceLayout>(GetImageSubresourceLayout))}, {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr))}, + {"vkGetPhysicalDeviceExternalBufferProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceExternalBufferProperties>(GetPhysicalDeviceExternalBufferProperties))}, + {"vkGetPhysicalDeviceExternalFenceProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(GetPhysicalDeviceExternalFenceProperties))}, + {"vkGetPhysicalDeviceExternalSemaphoreProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(GetPhysicalDeviceExternalSemaphoreProperties))}, {"vkGetPhysicalDeviceFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures>(GetPhysicalDeviceFeatures))}, + {"vkGetPhysicalDeviceFeatures2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures2>(GetPhysicalDeviceFeatures2))}, {"vkGetPhysicalDeviceFeatures2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(GetPhysicalDeviceFeatures2KHR))}, {"vkGetPhysicalDeviceFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties>(GetPhysicalDeviceFormatProperties))}, + {"vkGetPhysicalDeviceFormatProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(GetPhysicalDeviceFormatProperties2))}, {"vkGetPhysicalDeviceFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties2KHR>(GetPhysicalDeviceFormatProperties2KHR))}, {"vkGetPhysicalDeviceImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(GetPhysicalDeviceImageFormatProperties))}, + {"vkGetPhysicalDeviceImageFormatProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(GetPhysicalDeviceImageFormatProperties2))}, {"vkGetPhysicalDeviceImageFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2KHR>(GetPhysicalDeviceImageFormatProperties2KHR))}, {"vkGetPhysicalDeviceMemoryProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(GetPhysicalDeviceMemoryProperties))}, + {"vkGetPhysicalDeviceMemoryProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties2>(GetPhysicalDeviceMemoryProperties2))}, {"vkGetPhysicalDeviceMemoryProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties2KHR>(GetPhysicalDeviceMemoryProperties2KHR))}, {"vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties>(GetPhysicalDeviceProperties))}, + {"vkGetPhysicalDeviceProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties2>(GetPhysicalDeviceProperties2))}, {"vkGetPhysicalDeviceProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(GetPhysicalDeviceProperties2KHR))}, {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(GetPhysicalDeviceQueueFamilyProperties))}, + {"vkGetPhysicalDeviceQueueFamilyProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2>(GetPhysicalDeviceQueueFamilyProperties2))}, {"vkGetPhysicalDeviceQueueFamilyProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR>(GetPhysicalDeviceQueueFamilyProperties2KHR))}, {"vkGetPhysicalDeviceSparseImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(GetPhysicalDeviceSparseImageFormatProperties))}, + {"vkGetPhysicalDeviceSparseImageFormatProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2>(GetPhysicalDeviceSparseImageFormatProperties2))}, {"vkGetPhysicalDeviceSparseImageFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR>(GetPhysicalDeviceSparseImageFormatProperties2KHR))}, {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPipelineCacheData>(GetPipelineCacheData))}, {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetQueryPoolResults>(GetQueryPoolResults))}, @@ -202,7 +229,9 @@ const NameProc kInstanceProcs[] = { {"vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetEvent>(ResetEvent))}, {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetFences>(ResetFences))}, {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSetEvent>(SetEvent))}, + {"vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkTrimCommandPool>(TrimCommandPool))}, {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUnmapMemory>(UnmapMemory))}, + {"vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSetWithTemplate>(UpdateDescriptorSetWithTemplate))}, {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSets>(UpdateDescriptorSets))}, {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitForFences>(WaitForFences))}, // clang-format on diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h index 8a9a963675..c6ad537cb8 100644 --- a/vulkan/nulldrv/null_driver_gen.h +++ b/vulkan/nulldrv/null_driver_gen.h @@ -165,6 +165,34 @@ VKAPI_ATTR void CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRender VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents); VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer); VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); +VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion); +VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask); +VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); +VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); +VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); +VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); +VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); +VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); +VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int32_t* grallocUsage); VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage); VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence); |