Merge "Add explicit 64-bit postFrameCallback APIs"
diff --git a/cmds/atrace/TEST_MAPPING b/cmds/atrace/TEST_MAPPING
new file mode 100644
index 0000000..f43db22
--- /dev/null
+++ b/cmds/atrace/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsAtraceHostTestCases"
+ }
+ ]
+}
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index bd3d2d8..5836f11 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -193,10 +193,12 @@
{ REQ, "events/cpufreq_interactive/enable" },
} },
{ "sync", "Synchronization", 0, {
- // before linux kernel 4.9
+ // linux kernel < 4.9
{ OPT, "events/sync/enable" },
- // starting in linux kernel 4.9
+ // linux kernel == 4.9.x
{ OPT, "events/fence/enable" },
+ // linux kernel > 4.9
+ { OPT, "events/dma_fence/enable" },
} },
{ "workq", "Kernel Workqueues", 0, {
{ REQ, "events/workqueue/enable" },
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index a282424..66c9cc6 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -91,6 +91,8 @@
chmod 0666 /sys/kernel/tracing/events/sync/enable
chmod 0666 /sys/kernel/debug/tracing/events/fence/enable
chmod 0666 /sys/kernel/tracing/events/fence/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/dma_fence/enable
+ chmod 0666 /sys/kernel/tracing/events/dma_fence/enable
chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/enable
chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/enable
chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 03a15bb..21de4db 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1752,7 +1752,9 @@
}
// TODO: Should truncate the existing file.
// ... and re-open it for further logging.
- redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
+ if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
+ return false;
+ }
fprintf(stderr, "\n");
int32_t err = zip_writer_->Finish();
@@ -2372,12 +2374,17 @@
// If we are going to use a socket, do it as early as possible
// to avoid timeouts from bugreport.
if (options_->use_socket) {
- redirect_to_socket(stdout, "dumpstate");
+ if (!redirect_to_socket(stdout, "dumpstate")) {
+ return ERROR;
+ }
}
if (options_->use_control_socket) {
MYLOGD("Opening control socket\n");
control_socket_fd_ = open_socket("dumpstate");
+ if (control_socket_fd_ == -1) {
+ return ERROR;
+ }
options_->do_progress_updates = 1;
}
@@ -2436,7 +2443,9 @@
if (is_redirecting) {
// Redirect stderr to log_path_ for debugging.
TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
- redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()));
+ if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
+ return ERROR;
+ }
if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
strerror(errno));
@@ -2449,7 +2458,9 @@
/* TODO: rather than generating a text file now and zipping it later,
it would be more efficient to redirect stdout to the zip entry
directly, but the libziparchive doesn't support that option yet. */
- redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()));
+ if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
+ return ERROR;
+ }
if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
tmp_path_.c_str(), strerror(errno));
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 9803f00..c326bb6 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -519,14 +519,26 @@
/** opens a socket and returns its file descriptor */
int open_socket(const char *service);
-/* redirect output to a service control socket */
-void redirect_to_socket(FILE *redirect, const char *service);
+/*
+ * Redirects 'redirect' to a service control socket.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_socket(FILE* redirect, const char* service);
-/* redirect output to a new file */
-void redirect_to_file(FILE *redirect, char *path);
+/*
+ * Redirects 'redirect' to a file indicated by 'path', truncating it.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_file(FILE* redirect, char* path);
-/* redirect output to an existing file */
-void redirect_to_existing_file(FILE *redirect, char *path);
+/*
+ * Redirects 'redirect' to an existing file indicated by 'path', appending it.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_existing_file(FILE* redirect, char* path);
/* create leading directories, if necessary */
void create_parent_dirs(const char *path);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 4bc0e1d..2a5516d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -712,12 +712,12 @@
int s = android_get_control_socket(service);
if (s < 0) {
MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
- exit(1);
+ return -1;
}
fcntl(s, F_SETFD, FD_CLOEXEC);
if (listen(s, 4) < 0) {
MYLOGE("listen(control socket): %s\n", strerror(errno));
- exit(1);
+ return -1;
}
struct sockaddr addr;
@@ -725,18 +725,23 @@
int fd = accept(s, &addr, &alen);
if (fd < 0) {
MYLOGE("accept(control socket): %s\n", strerror(errno));
- exit(1);
+ return -1;
}
return fd;
}
/* redirect output to a service control socket */
-void redirect_to_socket(FILE *redirect, const char *service) {
+bool redirect_to_socket(FILE* redirect, const char* service) {
int fd = open_socket(service);
+ if (fd == -1) {
+ return false;
+ }
fflush(redirect);
- dup2(fd, fileno(redirect));
+ // TODO: handle dup2 failure
+ TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
close(fd);
+ return true;
}
// TODO: should call is_valid_output_file and/or be merged into it.
@@ -766,7 +771,7 @@
}
}
-void _redirect_to_file(FILE *redirect, char *path, int truncate_flag) {
+bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
create_parent_dirs(path);
int fd = TEMP_FAILURE_RETRY(open(path,
@@ -774,19 +779,20 @@
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
if (fd < 0) {
MYLOGE("%s: %s\n", path, strerror(errno));
- exit(1);
+ return false;
}
TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
close(fd);
+ return true;
}
-void redirect_to_file(FILE *redirect, char *path) {
- _redirect_to_file(redirect, path, O_TRUNC);
+bool redirect_to_file(FILE* redirect, char* path) {
+ return _redirect_to_file(redirect, path, O_TRUNC);
}
-void redirect_to_existing_file(FILE *redirect, char *path) {
- _redirect_to_file(redirect, path, O_APPEND);
+bool redirect_to_existing_file(FILE* redirect, char* path) {
+ return _redirect_to_file(redirect, path, O_APPEND);
}
// Dump Dalvik and native stack traces, return the trace file location (nullptr if none).
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index f523725..ffd1191 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -261,6 +261,40 @@
return "";
}
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+static const char* select_execution_binary(const char* binary, const char* debug_binary,
+ bool background_job_compile) {
+ return select_execution_binary(
+ binary,
+ debug_binary,
+ background_job_compile,
+ is_debug_runtime(),
+ (android::base::GetProperty("ro.build.version.codename", "") == "REL"),
+ is_debuggable_build());
+}
+
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+// This is convenient method which is much easier to test because it doesn't read
+// system properties.
+const char* select_execution_binary(
+ const char* binary,
+ const char* debug_binary,
+ bool background_job_compile,
+ bool is_debug_runtime,
+ bool is_release,
+ bool is_debuggable_build) {
+ // Do not use debug binaries for release candidates (to give more soak time).
+ bool is_debug_bg_job = background_job_compile && is_debuggable_build && !is_release;
+
+ // If the runtime was requested to use libartd.so, we'll run the debug version - assuming
+ // the file is present (it may not be on images with very little space available).
+ bool useDebug = (is_debug_runtime || is_debug_bg_job) && (access(debug_binary, X_OK) == 0);
+
+ return useDebug ? debug_binary : binary;
+}
+
// Namespace for Android Runtime flags applied during boot time.
static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
// Feature flag name for running the JIT in Zygote experiment, b/119800099.
@@ -354,16 +388,9 @@
std::string dex2oat_large_app_threshold_arg =
MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
- // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
- const char* dex2oat_bin = kDex2oatPath;
- // Do not use dex2oatd for release candidates (give dex2oat more soak time).
- bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
- if (is_debug_runtime() ||
- (background_job_compile && is_debuggable_build() && !is_release)) {
- if (access(kDex2oatDebugPath, X_OK) == 0) {
- dex2oat_bin = kDex2oatDebugPath;
- }
- }
+
+ const char* dex2oat_bin = select_execution_binary(
+ kDex2oatPath, kDex2oatDebugPath, background_job_compile);
bool generate_minidebug_info = kEnableMinidebugInfo &&
GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
@@ -676,7 +703,12 @@
const std::vector<std::string>& dex_locations,
bool copy_and_update,
bool store_aggregation_counters) {
- const char* profman_bin = is_debug_runtime() ? kProfmanDebugPath: kProfmanPath;
+
+ // TODO(calin): Assume for now we run in the bg compile job (which is in
+ // most of the invocation). With the current data flow, is not very easy or
+ // clean to discover this in RunProfman (it will require quite a messy refactoring).
+ const char* profman_bin = select_execution_binary(
+ kProfmanPath, kProfmanDebugPath, /*background_job_compile=*/ true);
if (copy_and_update) {
CHECK_EQ(1u, profile_fds.size());
@@ -1491,8 +1523,10 @@
bool downgrade,
const char* class_loader_context) {
CHECK_GE(zip_fd, 0);
- const char* dexoptanalyzer_bin =
- is_debug_runtime() ? kDexoptanalyzerDebugPath : kDexoptanalyzerPath;
+
+ // We always run the analyzer in the background job.
+ const char* dexoptanalyzer_bin = select_execution_binary(
+ kDexoptanalyzerPath, kDexoptanalyzerDebugPath, /*background_job_compile=*/ true);
std::string dex_file_arg = "--dex-file=" + dex_file;
std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 5902659..a8c48c5 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -36,7 +36,7 @@
// Location of binaries in the Android Runtime APEX.
static constexpr const char* kDex2oatPath = ANDROID_RUNTIME_APEX_BIN "/dex2oat";
static constexpr const char* kDex2oatDebugPath = ANDROID_RUNTIME_APEX_BIN "/dex2oatd";
-static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
+static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profman";
static constexpr const char* kProfmanDebugPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
static constexpr const char* kDexoptanalyzerPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzer";
static constexpr const char* kDexoptanalyzerDebugPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzerd";
@@ -128,6 +128,14 @@
bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
+const char* select_execution_binary(
+ const char* binary,
+ const char* debug_binary,
+ bool background_job_compile,
+ bool is_debug_runtime,
+ bool is_release,
+ bool is_debuggable_build);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 78edce0..71b710b 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -1175,5 +1175,64 @@
ASSERT_TRUE(std::find(profiles.begin(), profiles.end(), ref_prof) != profiles.end());
}
+TEST_F(DexoptTest, select_execution_binary) {
+ LOG(INFO) << "DexoptTestselect_execution_binary";
+
+ std::string release_str = app_private_dir_ce_ + "/release";
+ std::string debug_str = app_private_dir_ce_ + "/debug";
+
+ // Setup the binaries. Note that we only need executable files to actually
+ // test the execution binary selection
+ run_cmd("touch " + release_str);
+ run_cmd("touch " + debug_str);
+ run_cmd("chmod 777 " + release_str);
+ run_cmd("chmod 777 " + debug_str);
+
+ const char* release = release_str.c_str();
+ const char* debug = debug_str.c_str();
+
+ ASSERT_STREQ(release, select_execution_binary(
+ release,
+ debug,
+ /*background_job_compile=*/ false,
+ /*is_debug_runtime=*/ false,
+ /*is_release=*/ false,
+ /*is_debuggable_build=*/ false));
+
+ ASSERT_STREQ(release, select_execution_binary(
+ release,
+ debug,
+ /*background_job_compile=*/ true,
+ /*is_debug_runtime=*/ false,
+ /*is_release=*/ true,
+ /*is_debuggable_build=*/ true));
+
+ ASSERT_STREQ(debug, select_execution_binary(
+ release,
+ debug,
+ /*background_job_compile=*/ false,
+ /*is_debug_runtime=*/ true,
+ /*is_release=*/ false,
+ /*is_debuggable_build=*/ false));
+
+ ASSERT_STREQ(debug, select_execution_binary(
+ release,
+ debug,
+ /*background_job_compile=*/ true,
+ /*is_debug_runtime=*/ false,
+ /*is_release=*/ false,
+ /*is_debuggable_build=*/ true));
+
+
+ // Select the release when the debug file is not there.
+ ASSERT_STREQ(release, select_execution_binary(
+ release,
+ "does_not_exist",
+ /*background_job_compile=*/ false,
+ /*is_debug_runtime=*/ true,
+ /*is_release=*/ false,
+ /*is_debuggable_build=*/ false));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c
index 3b8955b..71f0837 100644
--- a/cmds/ip-up-vpn/ip-up-vpn.c
+++ b/cmds/ip-up-vpn/ip-up-vpn.c
@@ -95,6 +95,7 @@
strncpy(ifr.ifr_name, interface, IFNAMSIZ);
if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
ALOGE("Cannot bring up %s: %s", interface, strerror(errno));
+ fclose(state);
return 1;
}
@@ -102,6 +103,7 @@
if (!set_address(&ifr.ifr_addr, address) ||
ioctl(s, SIOCSIFADDR, &ifr)) {
ALOGE("Cannot set address: %s", strerror(errno));
+ fclose(state);
return 1;
}
@@ -109,6 +111,7 @@
if (set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4"))) {
if (ioctl(s, SIOCSIFNETMASK, &ifr)) {
ALOGE("Cannot set netmask: %s", strerror(errno));
+ fclose(state);
return 1;
}
}
@@ -123,6 +126,7 @@
fprintf(state, "%s\n", env("REMOTE_ADDR"));
} else {
ALOGE("Cannot parse parameters");
+ fclose(state);
return 1;
}
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 6cbe4ae..5c1cab6 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -40,7 +40,6 @@
<feature name="android.software.voice_recognizers" notLowRam="true" />
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
- <feature name="android.software.input_methods" />
<feature name="android.software.print" />
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index f9c8c8a..bdbc0d3 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -31,6 +31,7 @@
using ::android::sp;
using ::android::status_t;
using ::android::String16;
+using ::android::String8;
using ::android::wp;
namespace ABBinderTag {
@@ -67,8 +68,6 @@
AIBinder::~AIBinder() {}
bool AIBinder::associateClass(const AIBinder_Class* clazz) {
- using ::android::String8;
-
if (clazz == nullptr) return false;
if (mClazz == clazz) return true;
@@ -119,6 +118,33 @@
return getClass()->getInterfaceDescriptor();
}
+status_t ABBinder::dump(int fd, const ::android::Vector<String16>& args) {
+ AIBinder_onDump onDump = getClass()->onDump;
+
+ if (onDump == nullptr) {
+ return STATUS_OK;
+ }
+
+ // technically UINT32_MAX would be okay here, but INT32_MAX is expected since this may be
+ // null in Java
+ if (args.size() > INT32_MAX) {
+ LOG(ERROR) << "ABBinder::dump received too many arguments: " << args.size();
+ return STATUS_BAD_VALUE;
+ }
+
+ std::vector<String8> utf8Args; // owns memory of utf8s
+ utf8Args.reserve(args.size());
+ std::vector<const char*> utf8Pointers; // what can be passed over NDK API
+ utf8Pointers.reserve(args.size());
+
+ for (size_t i = 0; i < args.size(); i++) {
+ utf8Args.push_back(String8(args[i]));
+ utf8Pointers.push_back(utf8Args[i].c_str());
+ }
+
+ return onDump(this, fd, utf8Pointers.data(), utf8Pointers.size());
+}
+
status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
binder_flags_t flags) {
if (isUserCommand(code)) {
@@ -232,6 +258,13 @@
return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact);
}
+void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) {
+ CHECK(clazz != nullptr) << "setOnDump requires non-null clazz";
+
+ // this is required to be called before instances are instantiated
+ clazz->onDump = onDump;
+}
+
void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
CHECK(who == mWho);
@@ -325,6 +358,30 @@
return PruneStatusT(binder->getBinder()->pingBinder());
}
+binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint32_t numArgs) {
+ if (binder == nullptr) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+
+ ABBinder* bBinder = binder->asABBinder();
+ if (bBinder != nullptr) {
+ AIBinder_onDump onDump = binder->getClass()->onDump;
+ if (onDump == nullptr) {
+ return STATUS_OK;
+ }
+ return PruneStatusT(onDump(bBinder, fd, args, numArgs));
+ }
+
+ ::android::Vector<String16> utf16Args;
+ utf16Args.setCapacity(numArgs);
+ for (uint32_t i = 0; i < numArgs; i++) {
+ utf16Args.push(String16(String8(args[i])));
+ }
+
+ status_t status = binder->getBinder()->dump(fd, utf16Args);
+ return PruneStatusT(status);
+}
+
binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
void* cookie) {
if (binder == nullptr || recipient == nullptr) {
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 7852298..0dd795a 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -25,6 +25,7 @@
#include <binder/Binder.h>
#include <binder/IBinder.h>
+#include <utils/Vector.h>
inline bool isUserCommand(transaction_code_t code) {
return code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION;
@@ -66,6 +67,7 @@
ABBinder* asABBinder() override { return this; }
const ::android::String16& getInterfaceDescriptor() const override;
+ ::android::status_t dump(int fd, const ::android::Vector<::android::String16>& args) override;
::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
::android::Parcel* reply, binder_flags_t flags) override;
@@ -106,10 +108,14 @@
const ::android::String16& getInterfaceDescriptor() const { return mInterfaceDescriptor; }
+ // required to be non-null, implemented for every class
const AIBinder_Class_onCreate onCreate;
const AIBinder_Class_onDestroy onDestroy;
const AIBinder_Class_onTransact onTransact;
+ // optional methods for a class
+ AIBinder_onDump onDump;
+
private:
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
// one.
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 9c6c55e..bddc10d 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -179,6 +179,31 @@
__INTRODUCED_IN(29);
/**
+ * Dump information about an AIBinder (usually for debugging).
+ *
+ * When no arguments are provided, a brief overview of the interview should be given.
+ *
+ * \param binder interface being dumped
+ * \param fd file descriptor to be dumped to, should be flushed, ownership is not passed.
+ * \param args array of null-terminated strings for dump (may be null if numArgs is 0)
+ * \param numArgs number of args to be sent
+ *
+ * \return binder_status_t result of transaction (if remote, for instance)
+ */
+typedef binder_status_t (*AIBinder_onDump)(AIBinder* binder, int fd, const char** args,
+ uint32_t numArgs);
+
+/**
+ * This sets the implementation of the dump method for a class.
+ *
+ * If this isn't set, nothing will be dumped when dump is called (for instance with
+ * android.os.Binder#dump). Must be called before any instance of the class is created.
+ *
+ * \param dump function to call when an instance of this binder class is being dumped.
+ */
+void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
+
+/**
* Creates a new binder object of the appropriate class.
*
* Ownership of args is passed to this object. The lifecycle is implemented with AIBinder_incStrong
@@ -237,6 +262,21 @@
binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29);
/**
+ * Built-in transaction for all binder objects. This dumps information about a given binder.
+ *
+ * See also AIBinder_Class_setOnDump, AIBinder_onDump
+ *
+ * \param binder the binder to dump information about
+ * \param fd where information should be dumped to
+ * \param args null-terminated arguments to pass (may be null if numArgs is 0)
+ * \param numArgs number of args to send
+ *
+ * \return STATUS_OK if dump succeeds (or if there is nothing to dump)
+ */
+binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint32_t numArgs)
+ __INTRODUCED_IN(29);
+
+/**
* Registers for notifications that the associated binder is dead. The same death recipient may be
* associated with multiple different binders. If the binder is local, then no death recipient will
* be given (since if the local process dies, then no recipient will exist to recieve a
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index a42c60b..b82141c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -104,6 +104,30 @@
* this will be checked using AIBinder_isRemote.
*/
virtual bool isRemote() = 0;
+
+ /**
+ * Dumps information about the interface.
+ */
+ virtual binder_status_t dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/) {
+ return STATUS_OK;
+ }
+
+ /**
+ * Helper method to create a class
+ */
+ static AIBinder_Class* defineClass(const char* interfaceDescriptor,
+ AIBinder_Class_onCreate onCreate,
+ AIBinder_Class_onDestroy onDestroy,
+ AIBinder_Class_onTransact onTransact,
+ AIBinder_onDump onDump = nullptr) {
+ AIBinder_Class* clazz =
+ AIBinder_Class_define(interfaceDescriptor, onCreate, onDestroy, onTransact);
+ if (clazz == nullptr) {
+ return nullptr;
+ }
+ AIBinder_Class_setOnDump(clazz, onDump);
+ return clazz;
+ }
};
/**
@@ -144,6 +168,10 @@
bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override {
+ return AIBinder_dump(asBinder().get(), fd, args, numArgs);
+ }
+
private:
SpAIBinder mBinder;
};
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 655f4d5..7e65817 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -2,10 +2,12 @@
global:
AIBinder_associateClass;
AIBinder_Class_define;
+ AIBinder_Class_setOnDump;
AIBinder_DeathRecipient_delete;
AIBinder_DeathRecipient_new;
AIBinder_debugGetRefCount;
AIBinder_decStrong;
+ AIBinder_dump;
AIBinder_fromJavaBinder;
AIBinder_getCallingPid;
AIBinder_getCallingUid;
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 4cddf94..5fd4a95 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -45,14 +45,14 @@
namespace android {
namespace bpf {
-typedef struct {
+struct time_key_t {
uint32_t uid;
uint32_t freq;
-} time_key_t;
+};
-typedef struct {
+struct val_t {
uint64_t ar[100];
-} val_t;
+};
static std::mutex gInitializedMutex;
static bool gInitialized = false;
@@ -65,19 +65,13 @@
static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) {
std::string data;
- if (!android::base::ReadFileToString(path, &data)) {
- ALOGD("Failed to read file %s", path.c_str());
- return false;
- }
+ if (!android::base::ReadFileToString(path, &data)) return false;
auto strings = android::base::Split(data, " \n");
for (const auto &s : strings) {
if (s.empty()) continue;
uint32_t n;
- if (!android::base::ParseUint(s, &n)) {
- ALOGD("Failed to parse file %s", path.c_str());
- return false;
- }
+ if (!android::base::ParseUint(s, &n)) return false;
out->emplace_back(n);
}
return true;
@@ -141,16 +135,8 @@
std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
eventType.c_str(), eventName.c_str());
int prog_fd = bpf_obj_get(path.c_str());
- if (prog_fd < 0) {
- ALOGD("bpf_obj_get() failed for program %s", path.c_str());
- return false;
- }
- if (bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) < 0) {
- ALOGD("Failed to attach bpf program to tracepoint %s/%s", eventType.c_str(),
- eventName.c_str());
- return false;
- }
- return true;
+ if (prog_fd < 0) return false;
+ return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
}
// Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
@@ -224,20 +210,16 @@
auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val,
const BpfMap<time_key_t, val_t> &) {
if (freqTimeMap->find(key.uid) == freqTimeMap->end()) {
- std::vector<std::vector<uint64_t>> v;
+ (*freqTimeMap)[key.uid].resize(gNPolicies);
for (uint32_t i = 0; i < gNPolicies; ++i) {
- std::vector<uint64_t> v2(gPolicyFreqs[i].size(), 0);
- v.emplace_back(v2);
+ (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
}
- (*freqTimeMap)[key.uid] = v;
}
for (size_t policy = 0; policy < gNPolicies; ++policy) {
for (const auto &cpu : gPolicyCpus[policy]) {
- uint32_t cpuTime = val.ar[cpu];
- if (cpuTime == 0) continue;
auto freqIdx = policyFreqIdxs[policy][key.freq];
- (*freqTimeMap)[key.uid][policy][freqIdx] += cpuTime;
+ (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu];
}
}
return android::netdutils::status::ok;
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 0205452..9f6103e 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#pragma once
+
#include <unordered_map>
#include <vector>
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index d940752..0571dcc 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -16,6 +16,7 @@
name: "libgraphicsenv",
srcs: [
+ "GpuStatsInfo.cpp",
"GraphicsEnv.cpp",
"IGpuService.cpp"
],
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
new file mode 100644
index 0000000..0fa0d9e
--- /dev/null
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 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 <inttypes.h>
+
+#include <android-base/stringprintf.h>
+#include <binder/Parcel.h>
+#include <graphicsenv/GpuStatsInfo.h>
+
+namespace android {
+
+using base::StringAppendF;
+
+status_t GpuStatsGlobalInfo::writeToParcel(Parcel* parcel) const {
+ status_t status;
+ if ((status = parcel->writeUtf8AsUtf16(driverPackageName)) != OK) return status;
+ if ((status = parcel->writeUtf8AsUtf16(driverVersionName)) != OK) return status;
+ if ((status = parcel->writeUint64(driverVersionCode)) != OK) return status;
+ if ((status = parcel->writeInt64(driverBuildTime)) != OK) return status;
+ if ((status = parcel->writeInt32(glLoadingCount)) != OK) return status;
+ if ((status = parcel->writeInt32(glLoadingFailureCount)) != OK) return status;
+ if ((status = parcel->writeInt32(vkLoadingCount)) != OK) return status;
+ if ((status = parcel->writeInt32(vkLoadingFailureCount)) != OK) return status;
+ return OK;
+}
+
+status_t GpuStatsGlobalInfo::readFromParcel(const Parcel* parcel) {
+ status_t status;
+ if ((status = parcel->readUtf8FromUtf16(&driverPackageName)) != OK) return status;
+ if ((status = parcel->readUtf8FromUtf16(&driverVersionName)) != OK) return status;
+ if ((status = parcel->readUint64(&driverVersionCode)) != OK) return status;
+ if ((status = parcel->readInt64(&driverBuildTime)) != OK) return status;
+ if ((status = parcel->readInt32(&glLoadingCount)) != OK) return status;
+ if ((status = parcel->readInt32(&glLoadingFailureCount)) != OK) return status;
+ if ((status = parcel->readInt32(&vkLoadingCount)) != OK) return status;
+ if ((status = parcel->readInt32(&vkLoadingFailureCount)) != OK) return status;
+ return OK;
+}
+
+std::string GpuStatsGlobalInfo::toString() const {
+ std::string result;
+ StringAppendF(&result, "driverPackageName = %s\n", driverPackageName.c_str());
+ StringAppendF(&result, "driverVersionName = %s\n", driverVersionName.c_str());
+ StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode);
+ StringAppendF(&result, "driverBuildTime = %" PRId64 "\n", driverBuildTime);
+ StringAppendF(&result, "glLoadingCount = %d\n", glLoadingCount);
+ StringAppendF(&result, "glLoadingFailureCount = %d\n", glLoadingFailureCount);
+ StringAppendF(&result, "vkLoadingCount = %d\n", vkLoadingCount);
+ StringAppendF(&result, "vkLoadingFailureCount = %d\n", vkLoadingFailureCount);
+ return result;
+}
+
+status_t GpuStatsAppInfo::writeToParcel(Parcel* parcel) const {
+ status_t status;
+ if ((status = parcel->writeUtf8AsUtf16(appPackageName)) != OK) return status;
+ if ((status = parcel->writeUint64(driverVersionCode)) != OK) return status;
+ if ((status = parcel->writeInt64Vector(glDriverLoadingTime)) != OK) return status;
+ if ((status = parcel->writeInt64Vector(vkDriverLoadingTime)) != OK) return status;
+ return OK;
+}
+
+status_t GpuStatsAppInfo::readFromParcel(const Parcel* parcel) {
+ status_t status;
+ if ((status = parcel->readUtf8FromUtf16(&appPackageName)) != OK) return status;
+ if ((status = parcel->readUint64(&driverVersionCode)) != OK) return status;
+ if ((status = parcel->readInt64Vector(&glDriverLoadingTime)) != OK) return status;
+ if ((status = parcel->readInt64Vector(&vkDriverLoadingTime)) != OK) return status;
+ return OK;
+}
+
+std::string GpuStatsAppInfo::toString() const {
+ std::string result;
+ StringAppendF(&result, "appPackageName = %s\n", appPackageName.c_str());
+ StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode);
+ result.append("glDriverLoadingTime:");
+ for (int32_t loadingTime : glDriverLoadingTime) {
+ StringAppendF(&result, " %d", loadingTime);
+ }
+ result.append("\n");
+ result.append("vkDriverLoadingTime:");
+ for (int32_t loadingTime : vkDriverLoadingTime) {
+ StringAppendF(&result, " %d", loadingTime);
+ }
+ result.append("\n");
+ return result;
+}
+
+} // namespace android
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index f755e00..0b0bf44 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -46,6 +46,27 @@
remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
+ if (!outStats) return UNEXPECTED_NULL;
+
+ Parcel data, reply;
+ status_t status;
+
+ if ((status = data.writeInterfaceToken(IGpuService::getInterfaceDescriptor())) != OK)
+ return status;
+
+ if ((status = remote()->transact(BnGpuService::GET_GPU_STATS_GLOBAL_INFO, data, &reply)) !=
+ OK)
+ return status;
+
+ int32_t result = 0;
+ if ((status = reply.readInt32(&result)) != OK) return status;
+ if (result != OK) return result;
+
+ outStats->clear();
+ return reply.readParcelableVector(outStats);
+ }
};
IMPLEMENT_META_INTERFACE(GpuService, "android.graphicsenv.IGpuService");
@@ -89,6 +110,19 @@
return OK;
}
+ case GET_GPU_STATS_GLOBAL_INFO: {
+ CHECK_INTERFACE(IGpuService, data, reply);
+
+ std::vector<GpuStatsGlobalInfo> stats;
+ const status_t result = getGpuStatsGlobalInfo(&stats);
+
+ if ((status = reply->writeInt32(result)) != OK) return status;
+ if (result != OK) return result;
+
+ if ((status = reply->writeParcelableVector(stats)) != OK) return status;
+
+ return OK;
+ }
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsAtoms.h b/libs/graphicsenv/include/graphicsenv/GpuStatsAtoms.h
deleted file mode 100644
index f8b0ad7..0000000
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsAtoms.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2019 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 <string>
-#include <vector>
-
-namespace android {
-
-struct GpuStatsGlobalAtom {
- std::string driverPackageName = "";
- std::string driverVersionName = "";
- uint64_t driverVersionCode = 0;
- int64_t driverBuildTime = 0;
- int32_t glLoadingCount = 0;
- int32_t glLoadingFailureCount = 0;
- int32_t vkLoadingCount = 0;
- int32_t vkLoadingFailureCount = 0;
-};
-
-struct GpuStatsAppAtom {
- std::string appPackageName = "";
- uint64_t driverVersionCode = 0;
- std::vector<int64_t> glDriverLoadingTime = {};
- std::vector<int64_t> vkDriverLoadingTime = {};
-};
-
-} // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
new file mode 100644
index 0000000..a92ca70
--- /dev/null
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 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 <string>
+#include <vector>
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+/*
+ * class for transporting gpu global stats from GpuService to authorized
+ * recipents. This class is intended to be a data container.
+ */
+class GpuStatsGlobalInfo : public Parcelable {
+public:
+ GpuStatsGlobalInfo() = default;
+ GpuStatsGlobalInfo(const GpuStatsGlobalInfo&) = default;
+ virtual ~GpuStatsGlobalInfo() = default;
+ virtual status_t writeToParcel(Parcel* parcel) const;
+ virtual status_t readFromParcel(const Parcel* parcel);
+ std::string toString() const;
+
+ std::string driverPackageName = "";
+ std::string driverVersionName = "";
+ uint64_t driverVersionCode = 0;
+ int64_t driverBuildTime = 0;
+ int32_t glLoadingCount = 0;
+ int32_t glLoadingFailureCount = 0;
+ int32_t vkLoadingCount = 0;
+ int32_t vkLoadingFailureCount = 0;
+};
+
+/*
+ * class for transporting gpu app stats from GpuService to authorized recipents.
+ * This class is intended to be a data container.
+ */
+class GpuStatsAppInfo : public Parcelable {
+public:
+ GpuStatsAppInfo() = default;
+ GpuStatsAppInfo(const GpuStatsAppInfo&) = default;
+ virtual ~GpuStatsAppInfo() = default;
+ virtual status_t writeToParcel(Parcel* parcel) const;
+ virtual status_t readFromParcel(const Parcel* parcel);
+ std::string toString() const;
+
+ std::string appPackageName = "";
+ uint64_t driverVersionCode = 0;
+ std::vector<int64_t> glDriverLoadingTime = {};
+ std::vector<int64_t> vkDriverLoadingTime = {};
+};
+
+} // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index 5f9340d..e7cdb38 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -16,12 +16,13 @@
#pragma once
+#include <vector>
+
#include <binder/IInterface.h>
#include <cutils/compiler.h>
+#include <graphicsenv/GpuStatsInfo.h>
#include <graphicsenv/GraphicsEnv.h>
-#include <vector>
-
namespace android {
/*
@@ -38,12 +39,16 @@
int64_t driverBuildTime, const std::string& appPackageName,
GraphicsEnv::Driver driver, bool isDriverLoaded,
int64_t driverLoadingTime) = 0;
+
+ // get GPU global stats from GpuStats module.
+ virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const = 0;
};
class BnGpuService : public BnInterface<IGpuService> {
public:
enum IGpuServiceTag {
SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION,
+ GET_GPU_STATS_GLOBAL_INFO,
// Always append new enum to the end.
};
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index b9c601e..400daf0 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -792,18 +792,18 @@
Parcel data, reply;
status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (error != NO_ERROR) {
- ALOGE("addRegionSamplingListener: Failed to write interface token");
+ ALOGE("removeRegionSamplingListener: Failed to write interface token");
return error;
}
error = data.writeStrongBinder(IInterface::asBinder(listener));
if (error != NO_ERROR) {
- ALOGE("addRegionSamplingListener: Failed to write listener");
+ ALOGE("removeRegionSamplingListener: Failed to write listener");
return error;
}
error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data,
&reply);
if (error != NO_ERROR) {
- ALOGE("addRegionSamplingListener: Failed to transact");
+ ALOGE("removeRegionSamplingListener: Failed to transact");
}
return error;
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 962d263..84ba644 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -100,6 +100,7 @@
output.writeFloat(bgColorAlpha);
output.writeUint32(static_cast<uint32_t>(bgColorDataspace));
+ output.writeBool(colorSpaceAgnostic);
return NO_ERROR;
}
@@ -177,6 +178,7 @@
bgColorAlpha = input.readFloat();
bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32());
+ colorSpaceAgnostic = input.readBool();
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7a39222..d6708ab 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -189,7 +189,7 @@
}
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
- std::lock_guard lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
/* This listener knows all the sp<IBinder> to sp<SurfaceControl> for all its registered
* callbackIds, except for when Transactions are merged together. This probably cannot be
@@ -242,7 +242,7 @@
}
int32_t getId(const sp<GraphicBuffer>& buffer) {
- std::lock_guard lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
auto itr = mBuffers.find(buffer);
if (itr == mBuffers.end()) {
@@ -253,7 +253,7 @@
}
int32_t cache(const sp<GraphicBuffer>& buffer) {
- std::lock_guard lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
int32_t bufferId = getNextAvailableId();
@@ -989,6 +989,20 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorSpaceAgnostic(
+ const sp<SurfaceControl>& sc, const bool agnostic) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eColorSpaceAgnosticChanged;
+ s->colorSpaceAgnostic = agnostic;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
@@ -1476,6 +1490,19 @@
outIsWideColorDisplay);
}
+status_t SurfaceComposerClient::addRegionSamplingListener(
+ const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) {
+ return ComposerService::getComposerService()->addRegionSamplingListener(samplingArea,
+ stopLayerHandle,
+ listener);
+}
+
+status_t SurfaceComposerClient::removeRegionSamplingListener(
+ const sp<IRegionSamplingListener>& listener) {
+ return ComposerService::getComposerService()->removeRegionSamplingListener(listener);
+}
+
// ----------------------------------------------------------------------------
status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 32d7391..35e795c 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -88,6 +88,7 @@
eCachedBufferChanged = 0x2'00000000,
eBackgroundColorChanged = 0x4'00000000,
eMetadataChanged = 0x8'00000000,
+ eColorSpaceAgnosticChanged = 0x10'00000000,
};
layer_state_t()
@@ -115,7 +116,8 @@
api(-1),
colorTransform(mat4()),
bgColorAlpha(0),
- bgColorDataspace(ui::Dataspace::UNKNOWN) {
+ bgColorDataspace(ui::Dataspace::UNKNOWN),
+ colorSpaceAgnostic(false) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -192,6 +194,10 @@
// the background color layer
float bgColorAlpha;
ui::Dataspace bgColorDataspace;
+
+ // A color space agnostic layer means the color of this layer can be
+ // interpreted in any color space.
+ bool colorSpaceAgnostic;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e062339..48c978f 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -50,6 +50,7 @@
class HdrCapabilities;
class ISurfaceComposerClient;
class IGraphicBufferProducer;
+class IRegionSamplingListener;
class Region;
// ---------------------------------------------------------------------------
@@ -360,6 +361,7 @@
Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
const sp<NativeHandle>& sidebandStream);
Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
+ Transaction& setColorSpaceAgnostic(const sp<SurfaceControl>& sc, const bool agnostic);
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
@@ -448,6 +450,10 @@
static status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
uint64_t timestamp, DisplayedFrameStats* outStats);
+ static status_t addRegionSamplingListener(const Rect& samplingArea,
+ const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener);
+ static status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener);
private:
virtual void onFirstRef();
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index 5652c0c..d33ecfb 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -240,7 +240,7 @@
float const luma_gray = 0.50;
};
-TEST_F(RegionSamplingTest, CollectsLuma) {
+TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
fill_render(rgba_green);
sp<ISurfaceComposer> composer = ComposerService::getComposerService();
@@ -254,7 +254,7 @@
composer->removeRegionSamplingListener(listener);
}
-TEST_F(RegionSamplingTest, CollectsChangingLuma) {
+TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) {
fill_render(rgba_green);
sp<ISurfaceComposer> composer = ComposerService::getComposerService();
@@ -275,7 +275,7 @@
composer->removeRegionSamplingListener(listener);
}
-TEST_F(RegionSamplingTest, CollectsLumaFromTwoRegions) {
+TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) {
fill_render(rgba_green);
sp<ISurfaceComposer> composer = ComposerService::getComposerService();
sp<Listener> greenListener = new Listener();
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 3c67542..515209e 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -90,6 +90,7 @@
MotionEvent* event = new MotionEvent();
PointerCoords coords;
+ coords.clear();
constexpr size_t pointerCount = 1;
PointerProperties properties[pointerCount];
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 3ac1c58..2899bcf 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -75,7 +75,7 @@
* scRGB:
*
* The red, green, and blue components are stored in extended sRGB space,
- * but are linear, not gamma-encoded.
+ * and gamma-encoded using the SRGB transfer function.
* The RGB primaries and the white point are the same as BT.709.
*
* The values are floating point.
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 5d0aa1e..8069a1a 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -626,22 +626,13 @@
}
status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> bufferFence, bool readCache) {
- return bindExternalTextureBuffer(texName, buffer, bufferFence, readCache,
- /*persistCache=*/false);
-}
-
-status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> bufferFence, bool readCache,
- bool persistCache) {
+ sp<Fence> bufferFence) {
ATRACE_CALL();
- if (readCache) {
- auto cachedImage = mImageCache.find(buffer->getId());
+ auto cachedImage = mImageCache.find(buffer->getId());
- if (cachedImage != mImageCache.end()) {
- bindExternalTextureImage(texName, *cachedImage->second);
- return NO_ERROR;
- }
+ if (cachedImage != mImageCache.end()) {
+ bindExternalTextureImage(texName, *cachedImage->second);
+ return NO_ERROR;
}
std::unique_ptr<Image> newImage = createImage();
@@ -678,35 +669,19 @@
}
}
}
-
- // We don't always want to persist to the cache, e.g. on older devices we
- // might bind for synchronization purposes, but that might leak if we never
- // call drawLayers again, so it's just better to recreate the image again
- // if needed when we draw.
- if (persistCache) {
- mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
- }
+ mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
return NO_ERROR;
}
-void GLESRenderEngine::evictImages(const std::vector<LayerSettings>& layers) {
- ATRACE_CALL();
- // destroy old image references that we're not going to draw with.
- std::unordered_set<uint64_t> bufIds;
- for (auto layer : layers) {
- if (layer.source.buffer.buffer != nullptr) {
- bufIds.emplace(layer.source.buffer.buffer->getId());
- }
+void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
+ const auto& cachedImage = mImageCache.find(bufferId);
+ if (cachedImage != mImageCache.end()) {
+ ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
+ mImageCache.erase(bufferId);
+ return;
}
-
- for (auto it = mImageCache.begin(); it != mImageCache.end();) {
- if (bufIds.count(it->first) == 0) {
- it = mImageCache.erase(it);
- } else {
- it++;
- }
- }
+ ALOGV("Failed to find image for buffer: %" PRIu64, bufferId);
}
FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) {
@@ -844,8 +819,6 @@
return fbo.getStatus();
}
- evictImages(layers);
-
// clear the entire buffer, sometimes when we reuse buffers we'd persist
// ghost images otherwise.
// we also require a full transparent framebuffer for overlays. This is
@@ -888,10 +861,8 @@
isOpaque = layer.source.buffer.isOpaque;
sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
-
- bool readCache = layer.source.buffer.cacheHint == Buffer::CachingHint::USE_CACHE;
bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
- layer.source.buffer.fence, readCache, /*persistCache=*/true);
+ layer.source.buffer.fence);
usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index e37c91d..728882a 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -74,8 +74,8 @@
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
void bindExternalTextureImage(uint32_t texName, const Image& image) override;
- status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence,
- bool readCache);
+ status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence);
+ void unbindExternalTextureBuffer(uint64_t bufferId);
status_t bindFrameBuffer(Framebuffer* framebuffer) override;
void unbindFrameBuffer(Framebuffer* framebuffer) override;
void checkErrors() const override;
@@ -143,8 +143,6 @@
// Defines the viewport, and sets the projection matrix to the projection
// defined by the clip.
void setViewportAndProjection(Rect viewport, Rect clip);
- status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence,
- bool readCache, bool persistCache);
// Evicts stale images from the buffer cache.
void evictImages(const std::vector<LayerSettings>& layers);
// Computes the cropping window for the layer and sets up cropping
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index aa45ed8..b8bf801 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -32,16 +32,6 @@
// Metadata describing the input buffer to render from.
struct Buffer {
- // Hint for whether to use the Image cache or not.
- // If NO_CACHE is specified, then upload the contents of the GraphicBuffer
- // to the GPU, without checking against any implementation defined cache.
- // If USE_CACHE is specified, then check against an implementation defined
- // cache first. If there is an Image cached for the given GraphicBuffer id,
- // then use that instead of the provided buffer contents. If there is no
- // cached image or the RenderEngine implementation does not support caching,
- // then use the GraphicBuffer contents.
- enum class CachingHint { NO_CACHE, USE_CACHE };
-
// Buffer containing the image that we will render.
// If buffer == nullptr, then the rest of the fields in this struct will be
// ignored.
@@ -50,9 +40,6 @@
// Fence that will fire when the buffer is ready to be bound.
sp<Fence> fence = nullptr;
- // Caching hint to use when uploading buffer contents.
- CachingHint cacheHint = CachingHint::NO_CACHE;
-
// Texture identifier to bind the external texture to.
// TODO(alecmouri): This is GL-specific...make the type backend-agnostic.
uint32_t textureName = 0;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 2a2b48f..ab34274 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -110,7 +110,11 @@
virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
virtual status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> fence, bool cleanCache) = 0;
+ sp<Fence> fence) = 0;
+ // Removes internal resources referenced by the bufferId. This method should be
+ // invoked when the caller will no longer hold a reference to a GraphicBuffer
+ // and needs to clean up its resources.
+ virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0;
// When binding a native buffer, it must be done before setViewportAndProjection
// Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 5956c46..ddf7420 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -53,7 +53,8 @@
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
- MOCK_METHOD4(bindExternalTextureBuffer, status_t(uint32_t, sp<GraphicBuffer>, sp<Fence>, bool));
+ MOCK_METHOD3(bindExternalTextureBuffer, status_t(uint32_t, sp<GraphicBuffer>, sp<Fence>));
+ MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
MOCK_CONST_METHOD0(checkErrors, void());
MOCK_METHOD4(setViewportAndProjection,
void(size_t, size_t, Rect, ui::Transform::orientation_flags));
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 00e227f..4ca1781 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -45,6 +45,8 @@
// Don't warn about struct padding
"-Wno-padded",
+
+ "-Wno-switch-enum",
],
sanitize: {
@@ -68,6 +70,7 @@
"GraphicBufferMapper.cpp",
"HdrCapabilities.cpp",
"PixelFormat.cpp",
+ "PublicFormat.cpp",
"Rect.cpp",
"Region.cpp",
"Size.cpp",
@@ -87,8 +90,6 @@
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
- "android.hardware.configstore@1.2",
- "android.hardware.configstore-utils",
"libbase",
"libcutils",
"libhardware",
@@ -102,7 +103,6 @@
],
export_shared_lib_headers: [
- "android.hardware.configstore@1.2",
"android.hardware.graphics.common@1.2",
],
diff --git a/libs/ui/PublicFormat.cpp b/libs/ui/PublicFormat.cpp
new file mode 100644
index 0000000..70e3ce7
--- /dev/null
+++ b/libs/ui/PublicFormat.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 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 <ui/GraphicTypes.h> // ui::Dataspace
+#include <ui/PublicFormat.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+using ui::Dataspace;
+
+int mapPublicFormatToHalFormat(PublicFormat f) {
+ switch (f) {
+ case PublicFormat::JPEG:
+ case PublicFormat::DEPTH_POINT_CLOUD:
+ case PublicFormat::DEPTH_JPEG:
+ case PublicFormat::HEIC:
+ return HAL_PIXEL_FORMAT_BLOB;
+ case PublicFormat::DEPTH16:
+ return HAL_PIXEL_FORMAT_Y16;
+ case PublicFormat::RAW_SENSOR:
+ case PublicFormat::RAW_DEPTH:
+ return HAL_PIXEL_FORMAT_RAW16;
+ default:
+ // Most formats map 1:1
+ return static_cast<int>(f);
+ }
+}
+
+android_dataspace mapPublicFormatToHalDataspace(PublicFormat f) {
+ Dataspace dataspace;
+ switch (f) {
+ case PublicFormat::JPEG:
+ dataspace = Dataspace::V0_JFIF;
+ break;
+ case PublicFormat::DEPTH_POINT_CLOUD:
+ case PublicFormat::DEPTH16:
+ case PublicFormat::RAW_DEPTH:
+ dataspace = Dataspace::DEPTH;
+ break;
+ case PublicFormat::RAW_SENSOR:
+ case PublicFormat::RAW_PRIVATE:
+ case PublicFormat::RAW10:
+ case PublicFormat::RAW12:
+ dataspace = Dataspace::ARBITRARY;
+ break;
+ case PublicFormat::YUV_420_888:
+ case PublicFormat::NV21:
+ case PublicFormat::YV12:
+ dataspace = Dataspace::V0_JFIF;
+ break;
+ case PublicFormat::DEPTH_JPEG:
+ dataspace = Dataspace::DYNAMIC_DEPTH;
+ break;
+ case PublicFormat::HEIC:
+ dataspace = Dataspace::HEIF;
+ break;
+ default:
+ // Most formats map to UNKNOWN
+ dataspace = Dataspace::UNKNOWN;
+ break;
+ }
+ return static_cast<android_dataspace>(dataspace);
+}
+
+PublicFormat mapHalFormatDataspaceToPublicFormat(int format, android_dataspace dataSpace) {
+ Dataspace ds = static_cast<Dataspace>(dataSpace);
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ case HAL_PIXEL_FORMAT_RGB_888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_Y8:
+ case HAL_PIXEL_FORMAT_RAW10:
+ case HAL_PIXEL_FORMAT_RAW12:
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ case HAL_PIXEL_FORMAT_YV12:
+ // Enums overlap in both name and value
+ return static_cast<PublicFormat>(format);
+ case HAL_PIXEL_FORMAT_RAW16:
+ switch (ds) {
+ case Dataspace::DEPTH:
+ return PublicFormat::RAW_DEPTH;
+ default:
+ return PublicFormat::RAW_SENSOR;
+ }
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+ // Name differs, though value is the same
+ return PublicFormat::RAW_PRIVATE;
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ // Name differs, though the value is the same
+ return PublicFormat::NV16;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ // Name differs, though the value is the same
+ return PublicFormat::NV21;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ // Name differs, though the value is the same
+ return PublicFormat::YUY2;
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ // Name differs, though the value is the same
+ return PublicFormat::PRIVATE;
+ case HAL_PIXEL_FORMAT_Y16:
+ // Dataspace-dependent
+ switch (ds) {
+ case Dataspace::DEPTH:
+ return PublicFormat::DEPTH16;
+ default:
+ // Assume non-depth Y16 is just Y16.
+ return PublicFormat::Y16;
+ }
+ case HAL_PIXEL_FORMAT_BLOB:
+ // Dataspace-dependent
+ switch (ds) {
+ case Dataspace::DEPTH:
+ return PublicFormat::DEPTH_POINT_CLOUD;
+ case Dataspace::V0_JFIF:
+ return PublicFormat::JPEG;
+ case Dataspace::HEIF:
+ return PublicFormat::HEIC;
+ default:
+ if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_DYNAMIC_DEPTH)) {
+ return PublicFormat::DEPTH_JPEG;
+ } else {
+ // Assume otherwise-marked blobs are also JPEG
+ return PublicFormat::JPEG;
+ }
+ }
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ // Not defined in public API
+ return PublicFormat::UNKNOWN;
+
+ default:
+ return PublicFormat::UNKNOWN;
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/ConfigStoreTypes.h b/libs/ui/include/ui/ConfigStoreTypes.h
index 37a2bd5..4445ae9 100644
--- a/libs/ui/include/ui/ConfigStoreTypes.h
+++ b/libs/ui/include/ui/ConfigStoreTypes.h
@@ -16,14 +16,22 @@
#pragma once
-#include <android/hardware/configstore/1.2/types.h>
-
// android::ui::* in this header file will alias different types as
// the HIDL interface is updated.
namespace android {
namespace ui {
-using android::hardware::configstore::V1_2::DisplayPrimaries;
+struct CieXyz {
+ float X;
+ float Y;
+ float Z;
+};
+struct DisplayPrimaries {
+ CieXyz red;
+ CieXyz green;
+ CieXyz blue;
+ CieXyz white;
+};
} // namespace ui
} // namespace android
diff --git a/libs/ui/include/ui/PublicFormat.h b/libs/ui/include/ui/PublicFormat.h
new file mode 100644
index 0000000..1152cc5
--- /dev/null
+++ b/libs/ui/include/ui/PublicFormat.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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 UI_PUBLICFORMAT_H
+#define UI_PUBLICFORMAT_H
+
+#include <system/graphics.h>
+
+namespace android {
+
+/**
+ * Enum mirroring the public API definitions for image and pixel formats.
+ * Some of these are hidden in the public API
+ *
+ * Keep up to date with android.graphics.ImageFormat and
+ * android.graphics.PixelFormat
+ *
+ * TODO: PublicFormat is going to be deprecated(b/126594675)
+ */
+enum class PublicFormat {
+ UNKNOWN = 0x0,
+ RGBA_8888 = 0x1,
+ RGBX_8888 = 0x2,
+ RGB_888 = 0x3,
+ RGB_565 = 0x4,
+ NV16 = 0x10,
+ NV21 = 0x11,
+ YUY2 = 0x14,
+ RGBA_FP16 = 0x16,
+ RAW_SENSOR = 0x20,
+ PRIVATE = 0x22,
+ YUV_420_888 = 0x23,
+ RAW_PRIVATE = 0x24,
+ RAW10 = 0x25,
+ RAW12 = 0x26,
+ RGBA_1010102 = 0x2b,
+ JPEG = 0x100,
+ DEPTH_POINT_CLOUD = 0x101,
+ RAW_DEPTH = 0x1002, // @hide
+ YV12 = 0x32315659,
+ Y8 = 0x20203859,
+ Y16 = 0x20363159, // @hide
+ DEPTH16 = 0x44363159,
+ DEPTH_JPEG = 0x69656963,
+ HEIC = 0x48454946,
+};
+
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * format */
+extern int mapPublicFormatToHalFormat(PublicFormat f);
+
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * dataspace */
+extern android_dataspace mapPublicFormatToHalDataspace(PublicFormat f);
+
+/* Convert from HAL format, dataspace pair to
+ * android.graphics.ImageFormat/PixelFormat.
+ * For unknown/unspecified pairs, returns PublicFormat::UNKNOWN */
+extern PublicFormat mapHalFormatDataspaceToPublicFormat(int format, android_dataspace dataSpace);
+
+}; // namespace android
+
+#endif // UI_PUBLICFORMAT_H
diff --git a/libs/ui/include_vndk/ui/ConfigStoreTypes.h b/libs/ui/include_vndk/ui/ConfigStoreTypes.h
index 37a2bd5..4445ae9 100644
--- a/libs/ui/include_vndk/ui/ConfigStoreTypes.h
+++ b/libs/ui/include_vndk/ui/ConfigStoreTypes.h
@@ -16,14 +16,22 @@
#pragma once
-#include <android/hardware/configstore/1.2/types.h>
-
// android::ui::* in this header file will alias different types as
// the HIDL interface is updated.
namespace android {
namespace ui {
-using android::hardware::configstore::V1_2::DisplayPrimaries;
+struct CieXyz {
+ float X;
+ float Y;
+ float Z;
+};
+struct DisplayPrimaries {
+ CieXyz red;
+ CieXyz green;
+ CieXyz blue;
+ CieXyz white;
+};
} // namespace ui
} // namespace android
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index a73705b..5e5cf35 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -59,6 +59,14 @@
appPackageName, driver, isDriverLoaded, driverLoadingTime);
}
+status_t GpuService::getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
+ ATRACE_CALL();
+
+ mGpuStats->pullGlobalStats(outStats);
+
+ return OK;
+}
+
status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
ATRACE_CALL();
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 0cf48bb..b984e0f 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -19,6 +19,7 @@
#include <binder/IInterface.h>
#include <cutils/compiler.h>
+#include <graphicsenv/GpuStatsInfo.h>
#include <graphicsenv/IGpuService.h>
#include <serviceutils/PriorityDumper.h>
@@ -45,7 +46,8 @@
void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
uint64_t driverVersionCode, int64_t driverBuildTime,
const std::string& appPackageName, GraphicsEnv::Driver driver,
- bool isDriverLoaded, int64_t driverLoadingTime);
+ bool isDriverLoaded, int64_t driverLoadingTime) override;
+ status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const override;
/*
* IBinder interface
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 43c9492..146e2c2 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -19,28 +19,25 @@
#include "GpuStats.h"
-#include <android-base/stringprintf.h>
+#include <unordered_set>
+
#include <log/log.h>
#include <utils/Trace.h>
-#include <unordered_set>
-
namespace android {
-using base::StringAppendF;
-
static bool addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded,
- GpuStatsGlobalAtom* const outGlobalAtom) {
+ GpuStatsGlobalInfo* const outGlobalInfo) {
switch (driver) {
case GraphicsEnv::Driver::GL:
case GraphicsEnv::Driver::GL_UPDATED:
- outGlobalAtom->glLoadingCount++;
- if (!isDriverLoaded) outGlobalAtom->glLoadingFailureCount++;
+ outGlobalInfo->glLoadingCount++;
+ if (!isDriverLoaded) outGlobalInfo->glLoadingFailureCount++;
break;
case GraphicsEnv::Driver::VULKAN:
case GraphicsEnv::Driver::VULKAN_UPDATED:
- outGlobalAtom->vkLoadingCount++;
- if (!isDriverLoaded) outGlobalAtom->vkLoadingFailureCount++;
+ outGlobalInfo->vkLoadingCount++;
+ if (!isDriverLoaded) outGlobalInfo->vkLoadingFailureCount++;
break;
default:
// Currently we don't support GraphicsEnv::Driver::ANGLE because the
@@ -52,15 +49,15 @@
}
static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime,
- GpuStatsAppAtom* const outAppAtom) {
+ GpuStatsAppInfo* const outAppInfo) {
switch (driver) {
case GraphicsEnv::Driver::GL:
case GraphicsEnv::Driver::GL_UPDATED:
- outAppAtom->glDriverLoadingTime.emplace_back(driverLoadingTime);
+ outAppInfo->glDriverLoadingTime.emplace_back(driverLoadingTime);
break;
case GraphicsEnv::Driver::VULKAN:
case GraphicsEnv::Driver::VULKAN_UPDATED:
- outAppAtom->vkDriverLoadingTime.emplace_back(driverLoadingTime);
+ outAppInfo->vkDriverLoadingTime.emplace_back(driverLoadingTime);
break;
default:
break;
@@ -87,31 +84,31 @@
appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
if (!mGlobalStats.count(driverVersionCode)) {
- GpuStatsGlobalAtom globalAtom;
- if (!addLoadingCount(driver, isDriverLoaded, &globalAtom)) {
+ GpuStatsGlobalInfo globalInfo;
+ if (!addLoadingCount(driver, isDriverLoaded, &globalInfo)) {
return;
}
- globalAtom.driverPackageName = driverPackageName;
- globalAtom.driverVersionName = driverVersionName;
- globalAtom.driverVersionCode = driverVersionCode;
- globalAtom.driverBuildTime = driverBuildTime;
- mGlobalStats.insert({driverVersionCode, globalAtom});
+ globalInfo.driverPackageName = driverPackageName;
+ globalInfo.driverVersionName = driverVersionName;
+ globalInfo.driverVersionCode = driverVersionCode;
+ globalInfo.driverBuildTime = driverBuildTime;
+ mGlobalStats.insert({driverVersionCode, globalInfo});
} else if (!addLoadingCount(driver, isDriverLoaded, &mGlobalStats[driverVersionCode])) {
return;
}
if (mAppStats.size() >= MAX_NUM_APP_RECORDS) {
- ALOGV("GpuStatsAppAtom has reached maximum size. Ignore new stats.");
+ ALOGV("GpuStatsAppInfo has reached maximum size. Ignore new stats.");
return;
}
const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
if (!mAppStats.count(appStatsKey)) {
- GpuStatsAppAtom appAtom;
- addLoadingTime(driver, driverLoadingTime, &appAtom);
- appAtom.appPackageName = appPackageName;
- appAtom.driverVersionCode = driverVersionCode;
- mAppStats.insert({appStatsKey, appAtom});
+ GpuStatsAppInfo appInfo;
+ addLoadingTime(driver, driverLoadingTime, &appInfo);
+ appInfo.appPackageName = appPackageName;
+ appInfo.driverVersionCode = driverVersionCode;
+ mAppStats.insert({appStatsKey, appInfo});
return;
}
@@ -174,40 +171,31 @@
}
void GpuStats::dumpGlobalLocked(std::string* result) {
- result->append("GpuStats global:\n");
-
for (const auto& ele : mGlobalStats) {
- StringAppendF(result, " driverPackageName = %s\n", ele.second.driverPackageName.c_str());
- StringAppendF(result, " driverVersionName = %s\n", ele.second.driverVersionName.c_str());
- StringAppendF(result, " driverVersionCode = %" PRIu64 "\n", ele.second.driverVersionCode);
- StringAppendF(result, " driverBuildTime = %" PRId64 "\n", ele.second.driverBuildTime);
- StringAppendF(result, " glLoadingCount = %d\n", ele.second.glLoadingCount);
- StringAppendF(result, " glLoadingFailureCount = %d\n", ele.second.glLoadingFailureCount);
- StringAppendF(result, " vkLoadingCount = %d\n", ele.second.vkLoadingCount);
- StringAppendF(result, " vkLoadingFailureCount = %d\n", ele.second.vkLoadingFailureCount);
+ result->append(ele.second.toString());
result->append("\n");
}
}
void GpuStats::dumpAppLocked(std::string* result) {
- result->append("GpuStats app:\n");
-
for (const auto& ele : mAppStats) {
- StringAppendF(result, " appPackageName = %s\n", ele.second.appPackageName.c_str());
- StringAppendF(result, " driverVersionCode = %" PRIu64 "\n", ele.second.driverVersionCode);
-
- result->append(" glDriverLoadingTime:");
- for (int32_t loadingTime : ele.second.glDriverLoadingTime) {
- StringAppendF(result, " %d", loadingTime);
- }
+ result->append(ele.second.toString());
result->append("\n");
-
- result->append(" vkDriverLoadingTime:");
- for (int32_t loadingTime : ele.second.vkDriverLoadingTime) {
- StringAppendF(result, " %d", loadingTime);
- }
- result->append("\n\n");
}
}
+void GpuStats::pullGlobalStats(std::vector<GpuStatsGlobalInfo>* outStats) {
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mLock);
+ outStats->clear();
+ outStats->reserve(mGlobalStats.size());
+
+ for (const auto& ele : mGlobalStats) {
+ outStats->emplace_back(ele.second);
+ }
+
+ mGlobalStats.clear();
+}
+
} // namespace android
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h
index 8837c39..9cdcd95 100644
--- a/services/gpuservice/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/GpuStats.h
@@ -20,7 +20,7 @@
#include <unordered_map>
#include <vector>
-#include <graphicsenv/GpuStatsAtoms.h>
+#include <graphicsenv/GpuStatsInfo.h>
#include <graphicsenv/GraphicsEnv.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -39,6 +39,8 @@
int64_t driverLoadingTime);
// dumpsys interface
void dump(const Vector<String16>& args, std::string* result);
+ // Pull gpu global stats
+ void pullGlobalStats(std::vector<GpuStatsGlobalInfo>* outStats);
private:
// Dump global stats
@@ -52,9 +54,9 @@
// GpuStats access should be guarded by mLock.
std::mutex mLock;
// Key is driver version code.
- std::unordered_map<uint64_t, GpuStatsGlobalAtom> mGlobalStats;
+ std::unordered_map<uint64_t, GpuStatsGlobalInfo> mGlobalStats;
// Key is <app package name>+<driver version code>.
- std::unordered_map<std::string, GpuStatsAppAtom> mAppStats;
+ std::unordered_map<std::string, GpuStatsAppInfo> mAppStats;
};
} // namespace android
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index 20699c9..1651057 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -29,20 +29,20 @@
static NotifyMotionArgs generateBasicMotionArgs() {
// Create a basic motion event for testing
- constexpr size_t pointerCount = 1;
- PointerProperties properties[pointerCount];
- properties[0].id = 0;
- properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ PointerProperties properties;
+ properties.id = 0;
+ properties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
- PointerCoords coords[pointerCount];
- coords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 1);
- coords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
+ PointerCoords coords;
+ coords.clear();
+ coords.setAxisValue(AMOTION_EVENT_AXIS_X, 1);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
static constexpr nsecs_t downTime = 2;
NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/,
AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN,
0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/,
- 0/*pointerCount*/, properties, coords, 0/*xPrecision*/, 0/*yPrecision*/,
+ 1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/,
downTime, {}/*videoFrames*/);
return motionArgs;
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 9bf499b..ac1d492 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -23,7 +23,6 @@
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.1",
- "android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
@@ -57,7 +56,6 @@
"libui",
"libinput",
"libutils",
- "libutilscallstack",
"libSurfaceFlingerProperties",
],
static_libs: [
@@ -189,7 +187,6 @@
"android.frameworks.displayservice@1.0",
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
- "android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"libbinder",
@@ -244,13 +241,15 @@
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.1",
- "android.hardware.configstore@1.2",
+ "android.hardware.graphics.common@1.2",
"libhidlbase",
"libhidltransport",
"libhwbinder",
+ "libui",
"libutils",
],
export_shared_lib_headers: [
+ "android.hardware.graphics.common@1.2",
"libhidlbase",
"libhidltransport",
"libhwbinder",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 6badc73..7884362 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -163,9 +163,6 @@
layer.source.buffer.buffer = mActiveBuffer;
layer.source.buffer.isOpaque = isOpaque(s);
layer.source.buffer.fence = mActiveBufferFence;
- layer.source.buffer.cacheHint = useCachedBufferForClientComposition()
- ? renderengine::Buffer::CachingHint::USE_CACHE
- : renderengine::Buffer::CachingHint::NO_CACHE;
layer.source.buffer.textureName = mTextureName;
layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
layer.source.buffer.isY410BT2020 = isHdrY410();
@@ -242,7 +239,8 @@
void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata) {
+ int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) {
RETURN_IF_NO_HWC_LAYER(displayDevice);
// Apply this display's projection's viewport to the visible region
@@ -294,10 +292,10 @@
setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
}
- ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
- error = hwcLayer->setDataspace(mCurrentDataSpace);
+ ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+ error = hwcLayer->setDataspace(dataspace);
if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
to_string(error).c_str(), static_cast<int32_t>(error));
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index c48146f..8149cba 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -81,7 +81,8 @@
bool isHdrY410() const override;
void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+ const Rect& viewport, int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) override;
bool onPreComposition(nsecs_t refreshStartTime) override;
bool onPostComposition(const std::optional<DisplayId>& displayId,
@@ -161,10 +162,6 @@
bool mRefreshPending{false};
- // Returns true if, when drawing the active buffer during gpu compositon, we
- // should use a cached buffer or not.
- virtual bool useCachedBufferForClientComposition() const = 0;
-
// prepareClientLayer - constructs a RenderEngine layer for GPU composition.
bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform, Region& clearRegion,
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 6866e5c..cc78ece 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -178,7 +178,8 @@
return;
}
- auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer : mCurrentTextureBuffer;
+ auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
+ : mCurrentTextureBuffer->graphicBuffer();
auto err = addReleaseFence(slot, buffer, fence);
if (err != OK) {
BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
@@ -214,9 +215,9 @@
}
// If item->mGraphicBuffer is not null, this buffer has not been acquired
- // before.
+ // before, so we need to clean up old references.
if (item->mGraphicBuffer != nullptr) {
- mImages[item->mSlot] = nullptr;
+ mImages[item->mSlot] = std::make_shared<Image>(item->mGraphicBuffer, mRE);
}
return NO_ERROR;
@@ -229,18 +230,21 @@
int slot = item.mSlot;
BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
- mCurrentTextureBuffer != nullptr ? mCurrentTextureBuffer->handle : 0, slot,
- mSlots[slot].mGraphicBuffer->handle);
+ (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr)
+ ? mCurrentTextureBuffer->graphicBuffer()->handle
+ : 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<GraphicBuffer> nextTextureBuffer = mSlots[slot].mGraphicBuffer;
+ std::shared_ptr<Image> nextTextureBuffer = mImages[slot];
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
if (pendingRelease == nullptr) {
- status_t status = releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer);
+ status_t status =
+ releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->graphicBuffer());
if (status < NO_ERROR) {
BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
status);
@@ -249,7 +253,7 @@
}
} else {
pendingRelease->currentTexture = mCurrentTexture;
- pendingRelease->graphicBuffer = mCurrentTextureBuffer;
+ pendingRelease->graphicBuffer = mCurrentTextureBuffer->graphicBuffer();
pendingRelease->isPending = true;
}
}
@@ -257,8 +261,6 @@
// Update the BufferLayerConsumer state.
mCurrentTexture = slot;
mCurrentTextureBuffer = nextTextureBuffer;
- mCurrentTextureBufferStaleForGpu = false;
- mCurrentTextureImageFreed = nullptr;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
@@ -280,7 +282,12 @@
status_t BufferLayerConsumer::bindTextureImageLocked() {
ATRACE_CALL();
- return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer, mCurrentFence, false);
+ if (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr) {
+ return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer->graphicBuffer(),
+ mCurrentFence);
+ }
+
+ return NO_INIT;
}
void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
@@ -308,12 +315,15 @@
void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
BLC_LOGV("computeCurrentTransformMatrixLocked");
- if (mCurrentTextureBuffer == nullptr) {
+ if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->graphicBuffer() == nullptr) {
BLC_LOGD("computeCurrentTransformMatrixLocked: "
"mCurrentTextureBuffer is nullptr");
}
- GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, mCurrentTextureBuffer, mCurrentCrop,
- mCurrentTransform, mFilteringEnabled);
+ GLConsumer::computeTransformMatrix(mCurrentTransformMatrix,
+ mCurrentTextureBuffer == nullptr
+ ? nullptr
+ : mCurrentTextureBuffer->graphicBuffer(),
+ mCurrentCrop, mCurrentTransform, mFilteringEnabled);
}
nsecs_t BufferLayerConsumer::getTimestamp() {
@@ -365,16 +375,7 @@
*outFence = mCurrentFence;
}
- return mCurrentTextureBuffer;
-}
-
-bool BufferLayerConsumer::getAndSetCurrentBufferCacheHint() {
- Mutex::Autolock lock(mMutex);
- bool useCache = mCurrentTextureBufferStaleForGpu;
- // Set the staleness bit here, as this function is only called during a
- // client composition path.
- mCurrentTextureBufferStaleForGpu = true;
- return useCache;
+ return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer->graphicBuffer();
}
Rect BufferLayerConsumer::getCurrentCrop() const {
@@ -432,10 +433,8 @@
BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
- mCurrentTextureImageFreed = std::move(mImages[slotIndex]);
- } else {
- mImages[slotIndex] = nullptr;
}
+ mImages[slotIndex] = nullptr;
ConsumerBase::freeBufferLocked(slotIndex);
}
@@ -474,7 +473,10 @@
void BufferLayerConsumer::abandonLocked() {
BLC_LOGV("abandonLocked");
- mCurrentTextureBuffer.clear();
+ mCurrentTextureBuffer = nullptr;
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ mImages[i] = nullptr;
+ }
ConsumerBase::abandonLocked();
}
@@ -492,4 +494,11 @@
ConsumerBase::dumpLocked(result, prefix);
}
+BufferLayerConsumer::Image::~Image() {
+ if (mGraphicBuffer != nullptr) {
+ ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId());
+ mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId());
+ }
+}
+
}; // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index e2a6d2e..32ccfbb 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -149,11 +149,6 @@
// for use with bilinear filtering.
void setFilteringEnabled(bool enabled);
- // Sets mCurrentTextureBufferStaleForGpu to true to indicate that the
- // buffer is now "stale" for GPU composition, and returns the old staleness
- // bit as a caching hint.
- bool getAndSetCurrentBufferCacheHint();
-
// getCurrentBuffer returns the buffer associated with the current image.
// When outSlot is not nullptr, the current buffer slot index is also
// returned. Simiarly, when outFence is not nullptr, the current output
@@ -218,6 +213,22 @@
status_t bindTextureImageLocked();
private:
+ // Utility class for managing GraphicBuffer references into renderengine
+ class Image {
+ public:
+ Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine)
+ : mGraphicBuffer(graphicBuffer), mRE(engine) {}
+ virtual ~Image();
+ const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
+
+ private:
+ // mGraphicBuffer is the buffer that was used to create this image.
+ sp<GraphicBuffer> mGraphicBuffer;
+ // Back-reference into renderengine to initiate cleanup.
+ renderengine::RenderEngine& mRE;
+ DISALLOW_COPY_AND_ASSIGN(Image);
+ };
+
// freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in
// that slot. Otherwise it has no effect.
@@ -248,14 +259,10 @@
// consume buffers as hardware textures.
static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
- // mCurrentTextureImage is the buffer containing the current texture. It's
+ // mCurrentTextureBuffer is the buffer containing 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<GraphicBuffer> mCurrentTextureBuffer;
-
- // True if the buffer was used for the previous client composition frame,
- // and false otherwise.
- bool mCurrentTextureBufferStaleForGpu;
+ std::shared_ptr<Image> mCurrentTextureBuffer;
// mCurrentCrop is the crop rectangle that applies to the current texture.
// It gets set each time updateTexImage is called.
@@ -333,16 +340,8 @@
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
int mCurrentTexture;
- // Cached image used for rendering the current texture through GPU
- // composition, which contains the cached image after freeBufferLocked is
- // called on the current buffer. Whenever latchBuffer is called, this is
- // expected to be cleared. Then, if bindTexImage is called before the next
- // buffer is acquired, then this image is bound.
- std::unique_ptr<renderengine::Image> mCurrentTextureImageFreed;
-
- // Cached images used for rendering the current texture through GPU
- // composition.
- std::unique_ptr<renderengine::Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
+ // Shadow buffer cache for cleaning up renderengine references.
+ std::shared_ptr<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
// A release that is pending on the receipt of a new release fence from
// presentDisplay
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 18b0d58..e4179ee 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -342,10 +342,6 @@
return NO_ERROR;
}
-bool BufferQueueLayer::useCachedBufferForClientComposition() const {
- return mConsumer->getAndSetCurrentBufferCacheHint();
-}
-
status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mConsumer->getFrameNumber();
@@ -396,10 +392,9 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
- if (mFlinger->mUse90Hz && mFlinger->mUseSmart90ForVideo) {
- // Report the requested present time to the Scheduler, if the feature is turned on.
- mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp,
- item.mIsAutoTimestamp, mName.c_str());
+ if (mFlinger->mUseSmart90ForVideo) {
+ // Report mApi ID for each layer.
+ mFlinger->mScheduler->addNativeWindowApi(item.mApi);
}
Mutex::Autolock lock(mQueueItemLock);
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index fbb8c14..a2aad17 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -62,9 +62,6 @@
public:
bool fenceHasSignaled() const override;
-protected:
- bool useCachedBufferForClientComposition() const override;
-
private:
nsecs_t getDesiredPresentTime() override;
std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index a6c090c..b2383ad 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -48,7 +48,12 @@
mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
}
-BufferStateLayer::~BufferStateLayer() = default;
+BufferStateLayer::~BufferStateLayer() {
+ if (mActiveBuffer != nullptr) {
+ auto& engine(mFlinger->getRenderEngine());
+ engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
+ }
+}
// -----------------------------------------------------------------------
// Interface implementation for Layer
@@ -468,7 +473,7 @@
const State& s(getDrawingState());
auto& engine(mFlinger->getRenderEngine());
- return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence, false);
+ return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence);
}
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
@@ -542,6 +547,11 @@
return BAD_VALUE;
}
+ if (mActiveBuffer != nullptr) {
+ // todo: get this to work with BufferStateLayerCache
+ auto& engine(mFlinger->getRenderEngine());
+ engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
+ }
mActiveBuffer = s.buffer;
mActiveBufferFence = s.acquireFence;
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
@@ -551,11 +561,6 @@
return NO_ERROR;
}
-bool BufferStateLayer::useCachedBufferForClientComposition() const {
- // TODO: Store a proper staleness bit to support EGLImage caching.
- return false;
-}
-
status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
// TODO(marissaw): support frame history events
mCurrentFrameNumber = mFrameNumber;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 0b03f49..97662e8 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -96,9 +96,6 @@
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
-protected:
- bool useCachedBufferForClientComposition() const override;
-
private:
nsecs_t getDesiredPresentTime() override;
std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 2aeece7..a2692bc 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -81,7 +81,8 @@
void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
const ui::Transform& transform, const Rect& viewport,
- int32_t /* supportedPerFrameMetadata */) {
+ int32_t /* supportedPerFrameMetadata */,
+ const ui::Dataspace targetDataspace) {
RETURN_IF_NO_HWC_LAYER(display);
Region visible = transform.transform(visibleRegion.intersect(viewport));
@@ -101,9 +102,10 @@
setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
- error = hwcLayer->setDataspace(mCurrentDataSpace);
+ const ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+ error = hwcLayer->setDataspace(dataspace);
if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
to_string(error).c_str(), static_cast<int32_t>(error));
}
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 9786419..9a72b40 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -36,7 +36,8 @@
bool setColor(const half3& color) override;
void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+ const Rect& viewport, int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) override;
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index 3b4f6e4..02d7890 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -49,8 +49,8 @@
sp<GraphicBuffer>* outBuffer);
protected:
- int getSlot(const sp<GraphicBuffer>& buffer);
- int getLeastRecentlyUsedSlot();
+ bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot);
+ uint32_t getLeastRecentlyUsedSlot();
uint64_t getCounter();
private:
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index 8177c7f..8613210 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -24,29 +24,36 @@
std::fill(std::begin(mBuffers), std::end(mBuffers),
std::pair<uint64_t, wp<GraphicBuffer>>(0, nullptr));
}
-int HwcBufferCache::getSlot(const sp<GraphicBuffer>& buffer) {
+bool HwcBufferCache::getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
// search for cached buffer first
for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- if (mBuffers[i].second == buffer) {
- return i;
+ // Weak pointers in the cache may have had their object destroyed.
+ // Comparisons between weak pointers will accurately reflect this case,
+ // but comparisons between weak and strong may not. Thus, we create a weak
+ // pointer from strong pointer buffer
+ wp<GraphicBuffer> weakCopy(buffer);
+ if (mBuffers[i].second == weakCopy) {
+ *outSlot = i;
+ return true;
}
}
// use the least-recently used slot
- return getLeastRecentlyUsedSlot();
+ *outSlot = getLeastRecentlyUsedSlot();
+ return false;
}
-int HwcBufferCache::getLeastRecentlyUsedSlot() {
+uint32_t HwcBufferCache::getLeastRecentlyUsedSlot() {
auto iter = std::min_element(std::begin(mBuffers), std::end(mBuffers));
return std::distance(std::begin(mBuffers), iter);
}
void HwcBufferCache::getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
sp<GraphicBuffer>* outBuffer) {
- *outSlot = getSlot(buffer);
+ bool cached = getSlot(buffer, outSlot);
auto& [currentCounter, currentBuffer] = mBuffers[*outSlot];
- if (currentBuffer == buffer) {
+ if (cached) {
// already cached in HWC, skip sending the buffer
*outBuffer = nullptr;
currentCounter = getCounter();
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
index d4bbf6d..ac04cb3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -28,8 +28,10 @@
sp<GraphicBuffer>* outBuffer) {
HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer);
}
- int getSlot(const sp<GraphicBuffer>& buffer) { return HwcBufferCache::getSlot(buffer); }
- int getLeastRecentlyUsedSlot() { return HwcBufferCache::getLeastRecentlyUsedSlot(); }
+ bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
+ return HwcBufferCache::getSlot(buffer, outSlot);
+ }
+ uint32_t getLeastRecentlyUsedSlot() { return HwcBufferCache::getLeastRecentlyUsedSlot(); }
};
class HwcBufferCacheTest : public testing::Test {
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 738f4b6..7927fa9 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -40,6 +40,6 @@
}
void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
- const Rect&, int32_t) {}
+ const Rect&, int32_t, const ui::Dataspace) {}
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index c7cfdcd..7222a3e 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -34,7 +34,8 @@
bool canReceiveInput() const override;
void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata) override;
+ const Rect& viewport, int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) override;
bool isCreatedFromMainThread() const override { return true; }
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index bca0abc..910a527 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -143,8 +143,8 @@
return error;
}
- auto display = std::make_unique<impl::Display>(*mComposer.get(), mPowerAdvisor, mCapabilities,
- displayId, DisplayType::Virtual);
+ auto display = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities, displayId,
+ DisplayType::Virtual);
display->setConnected(true);
*outDisplay = display.get();
mDisplays.emplace(displayId, std::move(display));
@@ -182,8 +182,8 @@
return;
}
- auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mPowerAdvisor,
- mCapabilities, displayId, displayType);
+ auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities,
+ displayId, displayType);
newDisplay->setConnected(true);
mDisplays.emplace(displayId, std::move(newDisplay));
} else if (connection == Connection::Disconnected) {
@@ -254,11 +254,10 @@
}
namespace impl {
-Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
+Display::Display(android::Hwc2::Composer& composer,
const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
DisplayType type)
: mComposer(composer),
- mPowerAdvisor(advisor),
mCapabilities(capabilities),
mId(id),
mIsConnected(false),
@@ -636,12 +635,6 @@
Error Display::setColorMode(ColorMode mode, RenderIntent renderIntent)
{
- // When the color mode is switched to DISPLAY_P3, we want to boost the GPU frequency
- // so that GPU composition can finish in time. When color mode is switched from
- // DISPLAY_P3, we want to reset GPU frequency.
- const bool expensiveRenderingExpected = (mode == ColorMode::DISPLAY_P3);
- mPowerAdvisor.setExpensiveRenderingExpected(mId, expensiveRenderingExpected);
-
auto intError = mComposer.setColorMode(mId, mode, renderIntent);
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 70358a0..f96614f 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -37,8 +37,6 @@
#include <unordered_set>
#include <vector>
-#include "PowerAdvisor.h"
-
namespace android {
struct DisplayedFrameStats;
class Fence;
@@ -125,7 +123,6 @@
std::unique_ptr<android::Hwc2::Composer> mComposer;
std::unordered_set<Capability> mCapabilities;
std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
- android::Hwc2::impl::PowerAdvisor mPowerAdvisor;
bool mRegisteredCallback = false;
};
@@ -273,9 +270,8 @@
class Display : public HWC2::Display {
public:
- Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
- const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
- DisplayType type);
+ Display(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
+ hwc2_display_t id, DisplayType type);
~Display() override;
// Required by HWC2
@@ -352,7 +348,6 @@
// this HWC2::Display, so these references are guaranteed to be valid for
// the lifetime of this object.
android::Hwc2::Composer& mComposer;
- android::Hwc2::PowerAdvisor& mPowerAdvisor;
const std::unordered_set<Capability>& mCapabilities;
hwc2_display_t mId;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 12bbae2..039db73 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -38,7 +38,7 @@
PowerAdvisor::PowerAdvisor() = default;
-void PowerAdvisor::setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) {
+void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
if (expected) {
mExpensiveDisplays.insert(displayId);
} else {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 573a1a9..5aa1f22 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -22,10 +22,12 @@
#undef HWC2_INCLUDE_STRINGIFICATION
#undef HWC2_USE_CPP11
+#include <unordered_set>
+
#include <android/hardware/power/1.3/IPower.h>
#include <utils/StrongPointer.h>
-#include <unordered_set>
+#include "DisplayIdentification.h"
namespace android {
namespace Hwc2 {
@@ -34,7 +36,7 @@
public:
virtual ~PowerAdvisor();
- virtual void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) = 0;
+ virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
};
namespace impl {
@@ -48,12 +50,12 @@
PowerAdvisor();
~PowerAdvisor() override;
- void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) override;
+ void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
private:
sp<V1_3::IPower> getPowerHal();
- std::unordered_set<hwc2_display_t> mExpensiveDisplays;
+ std::unordered_set<DisplayId> mExpensiveDisplays;
bool mNotifiedExpensiveRendering = false;
bool mReconnectPowerHal = false;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a6adeb3..5c3fb05 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -103,6 +103,7 @@
mCurrentState.cornerRadius = 0.0f;
mCurrentState.api = -1;
mCurrentState.hasColorTransform = false;
+ mCurrentState.colorSpaceAgnostic = false;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -147,7 +148,7 @@
strongRelative->removeZOrderRelative(this);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
- mCurrentState.zOrderRelativeOf = nullptr;
+ setZOrderRelativeOf(nullptr);
}
// Since we are no longer reachable from CurrentState SurfaceFlinger
@@ -1071,13 +1072,6 @@
mNeedsFiltering = (!getActiveTransform(c).preserveRects() || type >= ui::Transform::SCALE);
}
- // If the layer is hidden, signal and clear out all local sync points so
- // that transactions for layers depending on this layer's frames becoming
- // visible are not blocked
- if (c.flags & layer_state_t::eLayerHidden) {
- clearSyncPoints();
- }
-
if (mCurrentState.inputInfoChanged) {
flags |= eInputInfoChanged;
mCurrentState.inputInfoChanged = false;
@@ -1164,7 +1158,7 @@
if (strongRelative != nullptr) {
strongRelative->removeZOrderRelative(this);
}
- mCurrentState.zOrderRelativeOf = nullptr;
+ setZOrderRelativeOf(nullptr);
}
setTransactionFlags(eTransactionNeeded);
return true;
@@ -1184,6 +1178,13 @@
setTransactionFlags(eTransactionNeeded);
}
+void Layer::setZOrderRelativeOf(const wp<Layer>& relativeOf) {
+ mCurrentState.zOrderRelativeOf = relativeOf;
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+}
+
bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
sp<Handle> handle = static_cast<Handle*>(relativeToHandle.get());
if (handle == nullptr) {
@@ -1207,7 +1208,7 @@
if (oldZOrderRelativeOf != nullptr) {
oldZOrderRelativeOf->removeZOrderRelative(this);
}
- mCurrentState.zOrderRelativeOf = relative;
+ setZOrderRelativeOf(relative);
relative->addZOrderRelative(this);
setTransactionFlags(eTransactionNeeded);
@@ -1355,6 +1356,17 @@
return true;
}
+bool Layer::setColorSpaceAgnostic(const bool agnostic) {
+ if (mCurrentState.colorSpaceAgnostic == agnostic) {
+ return false;
+ }
+ mCurrentState.sequence++;
+ mCurrentState.colorSpaceAgnostic = agnostic;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
uint32_t Layer::getLayerStack() const {
auto p = mDrawingParent.promote();
if (p == nullptr) {
@@ -1764,18 +1776,6 @@
mCurrentParent = layer;
}
-void Layer::clearSyncPoints() {
- for (const auto& child : mCurrentChildren) {
- child->clearSyncPoints();
- }
-
- Mutex::Autolock lock(mLocalSyncPointMutex);
- for (auto& point : mLocalSyncPoints) {
- point->setFrameAvailable();
- }
- mLocalSyncPoints.clear();
-}
-
int32_t Layer::getZ() const {
return mDrawingState.z;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 046482c..1afb917 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -210,6 +210,7 @@
// The deque of callback handles for this frame. The back of the deque contains the most
// recent callback handle.
std::deque<sp<CallbackHandle>> callbackHandles;
+ bool colorSpaceAgnostic;
};
explicit Layer(const LayerCreationArgs& args);
@@ -297,6 +298,7 @@
virtual bool setColorTransform(const mat4& matrix);
virtual mat4 getColorTransform() const;
virtual bool hasColorTransform() const;
+ virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
// Used only to set BufferStateLayer state
virtual bool setTransform(uint32_t /*transform*/) { return false; };
@@ -315,6 +317,7 @@
return false;
};
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
+ virtual bool setColorSpaceAgnostic(const bool agnostic);
ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
@@ -450,7 +453,8 @@
bool getForceClientComposition(const sp<DisplayDevice>& display);
virtual void setPerFrameData(const sp<const DisplayDevice>& display,
const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata) = 0;
+ int32_t supportedPerFrameMetadata,
+ const ui::Dataspace targetDataspace) = 0;
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
@@ -750,8 +754,6 @@
virtual bool applyPendingStates(State* stateToCommit);
virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
- void clearSyncPoints();
-
// Returns mCurrentScaling mode (originating from the
// Client) or mOverrideScalingMode mode (originating from
// the Surface Controller) if set.
@@ -899,6 +901,8 @@
// Layer bounds in screen space.
FloatRect mScreenBounds;
+
+ void setZOrderRelativeOf(const wp<Layer>& relativeOf);
};
} // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 2d6d33c..04e8796 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -92,12 +92,10 @@
void LayerProtoHelper::writeToProto(const ui::Transform& transform,
TransformProto* transformProto) {
- const uint32_t type = transform.getType();
+ const uint32_t type = transform.getType() | (transform.getOrientation() << 8);
transformProto->set_type(type);
- if (type &
- (ui::Transform::SCALE | ui::Transform::ROTATE | ui::Transform::TRANSLATE |
- ui::Transform::UNKNOWN)) {
+ if (type & (ui::Transform::SCALE | ui::Transform::UNKNOWN)) {
transformProto->set_dsdx(transform[0][0]);
transformProto->set_dtdx(transform[0][1]);
transformProto->set_dsdy(transform[1][0]);
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index bd8548c..4f0b3bb 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -21,27 +21,168 @@
#include "RegionSamplingThread.h"
+#include <cutils/properties.h>
#include <gui/IRegionSamplingListener.h>
#include <utils/Trace.h>
+#include <string>
#include "DisplayDevice.h"
#include "Layer.h"
#include "SurfaceFlinger.h"
namespace android {
+using namespace std::chrono_literals;
template <typename T>
struct SpHash {
size_t operator()(const sp<T>& p) const { return std::hash<T*>()(p.get()); }
};
-RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger) : mFlinger(flinger) {
- std::lock_guard threadLock(mThreadMutex);
- mThread = std::thread([this]() { threadMain(); });
- pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
+constexpr auto lumaSamplingStepTag = "LumaSamplingStep";
+enum class samplingStep {
+ noWorkNeeded,
+ idleTimerWaiting,
+ waitForZeroPhase,
+ waitForSamplePhase,
+ sample
+};
+
+constexpr auto defaultRegionSamplingOffset = -3ms;
+constexpr auto defaultRegionSamplingPeriod = 100ms;
+constexpr auto defaultRegionSamplingTimerTimeout = 100ms;
+// TODO: (b/127403193) duration to string conversion could probably be constexpr
+template <typename Rep, typename Per>
+inline std::string toNsString(std::chrono::duration<Rep, Per> t) {
+ return std::to_string(std::chrono::duration_cast<std::chrono::nanoseconds>(t).count());
}
+RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() {
+ char value[PROPERTY_VALUE_MAX] = {};
+
+ property_get("debug.sf.region_sampling_offset_ns", value,
+ toNsString(defaultRegionSamplingOffset).c_str());
+ int const samplingOffsetNsRaw = atoi(value);
+
+ property_get("debug.sf.region_sampling_period_ns", value,
+ toNsString(defaultRegionSamplingPeriod).c_str());
+ int const samplingPeriodNsRaw = atoi(value);
+
+ property_get("debug.sf.region_sampling_timer_timeout_ns", value,
+ toNsString(defaultRegionSamplingTimerTimeout).c_str());
+ int const samplingTimerTimeoutNsRaw = atoi(value);
+
+ if ((samplingPeriodNsRaw < 0) || (samplingTimerTimeoutNsRaw < 0)) {
+ ALOGW("User-specified sampling tuning options nonsensical. Using defaults");
+ mSamplingOffset = defaultRegionSamplingOffset;
+ mSamplingPeriod = defaultRegionSamplingPeriod;
+ mSamplingTimerTimeout = defaultRegionSamplingTimerTimeout;
+ } else {
+ mSamplingOffset = std::chrono::nanoseconds(samplingOffsetNsRaw);
+ mSamplingPeriod = std::chrono::nanoseconds(samplingPeriodNsRaw);
+ mSamplingTimerTimeout = std::chrono::nanoseconds(samplingTimerTimeoutNsRaw);
+ }
+}
+
+struct SamplingOffsetCallback : DispSync::Callback {
+ SamplingOffsetCallback(RegionSamplingThread& samplingThread, Scheduler& scheduler,
+ std::chrono::nanoseconds targetSamplingOffset)
+ : mRegionSamplingThread(samplingThread),
+ mScheduler(scheduler),
+ mTargetSamplingOffset(targetSamplingOffset) {}
+
+ ~SamplingOffsetCallback() { stopVsyncListener(); }
+
+ SamplingOffsetCallback(const SamplingOffsetCallback&) = delete;
+ SamplingOffsetCallback& operator=(const SamplingOffsetCallback&) = delete;
+
+ void startVsyncListener() {
+ std::lock_guard lock(mMutex);
+ if (mVsyncListening) return;
+
+ mPhaseIntervalSetting = Phase::ZERO;
+ mScheduler.withPrimaryDispSync([this](android::DispSync& sync) {
+ sync.addEventListener("SamplingThreadDispSyncListener", 0, this);
+ });
+ mVsyncListening = true;
+ }
+
+ void stopVsyncListener() {
+ std::lock_guard lock(mMutex);
+ stopVsyncListenerLocked();
+ }
+
+private:
+ void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ {
+ if (!mVsyncListening) return;
+
+ mScheduler.withPrimaryDispSync(
+ [this](android::DispSync& sync) { sync.removeEventListener(this); });
+ mVsyncListening = false;
+ }
+
+ void onDispSyncEvent(nsecs_t /* when */) final {
+ std::unique_lock<decltype(mMutex)> lock(mMutex);
+
+ if (mPhaseIntervalSetting == Phase::ZERO) {
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase));
+ mPhaseIntervalSetting = Phase::SAMPLING;
+ mScheduler.withPrimaryDispSync([this](android::DispSync& sync) {
+ sync.changePhaseOffset(this, mTargetSamplingOffset.count());
+ });
+ return;
+ }
+
+ if (mPhaseIntervalSetting == Phase::SAMPLING) {
+ mPhaseIntervalSetting = Phase::ZERO;
+ mScheduler.withPrimaryDispSync(
+ [this](android::DispSync& sync) { sync.changePhaseOffset(this, 0); });
+ stopVsyncListenerLocked();
+ lock.unlock();
+ mRegionSamplingThread.notifySamplingOffset();
+ return;
+ }
+ }
+
+ RegionSamplingThread& mRegionSamplingThread;
+ Scheduler& mScheduler;
+ const std::chrono::nanoseconds mTargetSamplingOffset;
+ mutable std::mutex mMutex;
+ enum class Phase {
+ ZERO,
+ SAMPLING
+ } mPhaseIntervalSetting /*GUARDED_BY(mMutex) macro doesnt work with unique_lock?*/
+ = Phase::ZERO;
+ bool mVsyncListening /*GUARDED_BY(mMutex)*/ = false;
+};
+
+RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler,
+ const TimingTunables& tunables)
+ : mFlinger(flinger),
+ mScheduler(scheduler),
+ mTunables(tunables),
+ mIdleTimer(std::chrono::duration_cast<std::chrono::milliseconds>(
+ mTunables.mSamplingTimerTimeout),
+ [] {}, [this] { checkForStaleLuma(); }),
+ mPhaseCallback(std::make_unique<SamplingOffsetCallback>(*this, mScheduler,
+ tunables.mSamplingOffset)),
+ lastSampleTime(0ns) {
+ {
+ std::lock_guard threadLock(mThreadMutex);
+ mThread = std::thread([this]() { threadMain(); });
+ pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
+ }
+ mIdleTimer.start();
+}
+
+RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler)
+ : RegionSamplingThread(flinger, scheduler,
+ TimingTunables{defaultRegionSamplingOffset,
+ defaultRegionSamplingPeriod,
+ defaultRegionSamplingTimerTimeout}) {}
+
RegionSamplingThread::~RegionSamplingThread() {
+ mIdleTimer.stop();
+
{
std::lock_guard lock(mMutex);
mRunning = false;
@@ -71,8 +212,41 @@
mDescriptors.erase(wp<IBinder>(IInterface::asBinder(listener)));
}
-void RegionSamplingThread::sampleNow() {
+void RegionSamplingThread::checkForStaleLuma() {
std::lock_guard lock(mMutex);
+
+ if (mDiscardedFrames) {
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForZeroPhase));
+ mDiscardedFrames = false;
+ mPhaseCallback->startVsyncListener();
+ }
+}
+
+void RegionSamplingThread::notifyNewContent() {
+ doSample();
+}
+
+void RegionSamplingThread::notifySamplingOffset() {
+ doSample();
+}
+
+void RegionSamplingThread::doSample() {
+ std::lock_guard lock(mMutex);
+ auto now = std::chrono::nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+ if (lastSampleTime + mTunables.mSamplingPeriod > now) {
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::idleTimerWaiting));
+ mDiscardedFrames = true;
+ return;
+ }
+
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::sample));
+
+ mDiscardedFrames = false;
+ lastSampleTime = now;
+
+ mIdleTimer.reset();
+ mPhaseCallback->stopVsyncListener();
+
mSampleRequested = true;
mCondition.notify_one();
}
@@ -238,6 +412,7 @@
for (size_t d = 0; d < activeDescriptors.size(); ++d) {
activeDescriptors[d].listener->onSampleCollected(lumas[d]);
}
+ ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded));
}
void RegionSamplingThread::threadMain() {
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index ab06513..d4e57bf 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -16,6 +16,7 @@
#pragma once
+#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>
@@ -25,17 +26,42 @@
#include <binder/IBinder.h>
#include <ui/Rect.h>
#include <utils/StrongPointer.h>
+#include "Scheduler/IdleTimer.h"
namespace android {
class GraphicBuffer;
class IRegionSamplingListener;
class Layer;
+class Scheduler;
class SurfaceFlinger;
+struct SamplingOffsetCallback;
class RegionSamplingThread : public IBinder::DeathRecipient {
public:
- explicit RegionSamplingThread(SurfaceFlinger& flinger);
+ struct TimingTunables {
+ // debug.sf.sampling_offset_ns
+ // When asynchronously collecting sample, the offset, from zero phase in the vsync timeline
+ // at which the sampling should start.
+ std::chrono::nanoseconds mSamplingOffset;
+ // debug.sf.sampling_period_ns
+ // This is the maximum amount of time the luma recieving client
+ // should have to wait for a new luma value after a frame is updated. The inverse of this is
+ // roughly the sampling rate. Sampling system rounds up sub-vsync sampling period to vsync
+ // period.
+ std::chrono::nanoseconds mSamplingPeriod;
+ // debug.sf.sampling_timer_timeout_ns
+ // This is the interval at which the luma sampling system will check that the luma clients
+ // have up to date information. It defaults to the mSamplingPeriod.
+ std::chrono::nanoseconds mSamplingTimerTimeout;
+ };
+ struct EnvironmentTimingTunables : TimingTunables {
+ EnvironmentTimingTunables();
+ };
+ explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler,
+ const TimingTunables& tunables);
+ explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler);
+
~RegionSamplingThread();
// Add a listener to receive luma notifications. The luma reported via listener will
@@ -44,8 +70,13 @@
const sp<IRegionSamplingListener>& listener);
// Remove the listener to stop receiving median luma notifications.
void removeListener(const sp<IRegionSamplingListener>& listener);
- // Instruct the thread to perform a median luma sampling on the layers.
- void sampleNow();
+
+ // Notifies sampling engine that new content is available. This will trigger a sampling
+ // pass at some point in the future.
+ void notifyNewContent();
+
+ // Notifies the sampling engine that it has a good timing window in which to sample.
+ void notifySamplingOffset();
private:
struct Descriptor {
@@ -63,12 +94,19 @@
const sp<GraphicBuffer>& buffer, const Point& leftTop,
const std::vector<RegionSamplingThread::Descriptor>& descriptors);
+ void doSample();
void binderDied(const wp<IBinder>& who) override;
+ void checkForStaleLuma();
void captureSample() REQUIRES(mMutex);
void threadMain();
SurfaceFlinger& mFlinger;
+ Scheduler& mScheduler;
+ const TimingTunables mTunables;
+ scheduler::IdleTimer mIdleTimer;
+
+ std::unique_ptr<SamplingOffsetCallback> const mPhaseCallback;
std::mutex mThreadMutex;
std::thread mThread GUARDED_BY(mThreadMutex);
@@ -79,6 +117,8 @@
bool mSampleRequested GUARDED_BY(mMutex) = false;
std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mMutex);
+ std::chrono::nanoseconds lastSampleTime GUARDED_BY(mMutex);
+ bool mDiscardedFrames GUARDED_BY(mMutex) = false;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 665179e..5178836 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -43,6 +43,7 @@
namespace android {
DispSync::~DispSync() = default;
+DispSync::Callback::~Callback() = default;
namespace impl {
@@ -75,9 +76,18 @@
void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
if (mTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
- mPeriod = period;
+
mPhase = phase;
mReferenceTime = referenceTime;
+ if (mPeriod != period && mReferenceTime != 0) {
+ // Inflate the reference time to be the most recent predicted
+ // vsync before the current time.
+ const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t baseTime = now - mReferenceTime;
+ const nsecs_t numOldPeriods = baseTime / mPeriod;
+ mReferenceTime = mReferenceTime + (numOldPeriods)*mPeriod;
+ }
+ mPeriod = period;
if (mTraceDetailedInfo) {
ATRACE_INT64("DispSync:Period", mPeriod);
ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
@@ -428,8 +438,16 @@
void DispSync::resetLocked() {
mPhase = 0;
- mReferenceTime = 0;
+ const size_t lastSampleIdx = (mFirstResyncSample + mNumResyncSamples - 1) % MAX_RESYNC_SAMPLES;
+ // Keep the most recent sample, when we resync to hardware we'll overwrite this
+ // with a more accurate signal
+ if (mResyncSamples[lastSampleIdx] != 0) {
+ mReferenceTime = mResyncSamples[lastSampleIdx];
+ }
mModelUpdated = false;
+ for (size_t i = 0; i < MAX_RESYNC_SAMPLES; i++) {
+ mResyncSamples[i] = 0;
+ }
mNumResyncSamples = 0;
mFirstResyncSample = 0;
mNumResyncSamplesSincePresent = 0;
@@ -529,7 +547,6 @@
Mutex::Autolock lock(mMutex);
mPeriod = period;
mPhase = 0;
- mReferenceTime = 0;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 4a90f10..6f3bd00 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DISPSYNC_H
-#define ANDROID_DISPSYNC_H
+#pragma once
#include <stddef.h>
@@ -35,10 +34,16 @@
public:
class Callback {
public:
- virtual ~Callback() = default;
+ Callback() = default;
+ virtual ~Callback();
virtual void onDispSyncEvent(nsecs_t when) = 0;
+
+ protected:
+ Callback(Callback const&) = delete;
+ Callback& operator=(Callback const&) = delete;
};
+ DispSync() = default;
virtual ~DispSync();
virtual void reset() = 0;
@@ -57,6 +62,10 @@
virtual nsecs_t expectedPresentTime() = 0;
virtual void dump(std::string& result) const = 0;
+
+protected:
+ DispSync(DispSync const&) = delete;
+ DispSync& operator=(DispSync const&) = delete;
};
namespace impl {
@@ -204,7 +213,7 @@
// These member variables are the state used during the resynchronization
// process to store information about the hardware vsync event times used
// to compute the model.
- nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES];
+ nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES] = {0};
size_t mFirstResyncSample;
size_t mNumResyncSamples;
int mNumResyncSamplesSincePresent;
@@ -239,5 +248,3 @@
} // namespace impl
} // namespace android
-
-#endif // ANDROID_DISPSYNC_H
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index ab1f460..7e2b03d 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -76,13 +76,13 @@
mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
- : highFpsLateAppOffsetNs,
+ : highFpsLateSfOffsetNs,
highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
- : highFpsLateSfOffsetNs};
+ : highFpsLateAppOffsetNs};
mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
- : highFpsLateAppOffsetNs,
+ : highFpsLateSfOffsetNs,
highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
- : highFpsLateSfOffsetNs};
+ : highFpsLateAppOffsetNs};
mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 026f7c7..cbcc031 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -28,7 +28,7 @@
namespace scheduler {
/**
- * This class is used to encapsulate configuration for refresh rates. It holds infomation
+ * This class is used to encapsulate configuration for refresh rates. It holds information
* about available refresh rates on the device, and the mapping between the numbers and human
* readable names.
*/
@@ -40,8 +40,6 @@
enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
struct RefreshRate {
- // Type of the refresh rate.
- RefreshRateType type;
// This config ID corresponds to the position of the config in the vector that is stored
// on the device.
int configId;
@@ -59,13 +57,16 @@
}
~RefreshRateConfigs() = default;
- const std::vector<RefreshRate>& getRefreshRates() { return mRefreshRates; }
+ const std::unordered_map<RefreshRateType, RefreshRate>& getRefreshRates() {
+ return mRefreshRates;
+ }
+ const RefreshRate& getRefreshRate(RefreshRateType type) { return mRefreshRates[type]; }
private:
void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
// This is the rate that HWC encapsulates right now when the device is in DOZE mode.
- mRefreshRates.push_back(
- RefreshRate{RefreshRateType::POWER_SAVING, SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
+ mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
+ RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
if (configs.size() < 1) {
ALOGE("Device does not have valid configs. Config size is 0.");
@@ -88,9 +89,10 @@
nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
- mRefreshRates.push_back(
- RefreshRate{RefreshRateType::DEFAULT, configIdToVsyncPeriod[0].first,
- base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
+ mRefreshRates.emplace(RefreshRateType::DEFAULT,
+ RefreshRate{configIdToVsyncPeriod[0].first,
+ base::StringPrintf("%2.ffps", fps),
+ static_cast<uint32_t>(fps)});
}
if (configs.size() < 2) {
@@ -102,13 +104,14 @@
vsyncPeriod = configIdToVsyncPeriod[1].second;
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
- mRefreshRates.push_back(
- RefreshRate{RefreshRateType::PERFORMANCE, configIdToVsyncPeriod[1].first,
- base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
+ mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
+ RefreshRate{configIdToVsyncPeriod[1].first,
+ base::StringPrintf("%2.ffps", fps),
+ static_cast<uint32_t>(fps)});
}
}
- std::vector<RefreshRate> mRefreshRates;
+ std::unordered_map<RefreshRateType, RefreshRate> mRefreshRates;
};
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index dcb2988..2491081 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -41,10 +41,9 @@
static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
public:
- explicit RefreshRateStats(
- const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
- const std::shared_ptr<TimeStats>& timeStats)
- : mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)),
+ explicit RefreshRateStats(const std::shared_ptr<RefreshRateConfigs>& refreshRateConfigs,
+ const std::shared_ptr<TimeStats>& timeStats)
+ : mRefreshRateConfigs(refreshRateConfigs),
mTimeStats(timeStats),
mPreviousRecordedTime(systemTime()) {}
~RefreshRateStats() = default;
@@ -84,7 +83,7 @@
flushTime();
std::unordered_map<std::string, int64_t> totalTime;
- for (auto config : mRefreshRateConfigs->getRefreshRates()) {
+ for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) {
int64_t totalTimeForConfig = 0;
if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
totalTimeForConfig = mConfigModesTotalTime.at(config.configId);
@@ -124,7 +123,7 @@
mPreviousRecordedTime = currentTime;
mConfigModesTotalTime[mode] += timeElapsedMs;
- for (const auto& config : mRefreshRateConfigs->getRefreshRates()) {
+ for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) {
if (config.configId == mode) {
mTimeStats->recordRefreshRate(config.fps, timeElapsed);
}
@@ -143,7 +142,7 @@
}
// Keeps information about refresh rate configs that device has.
- std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+ std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs;
// Aggregate refresh rate statistics for telemetry.
std::shared_ptr<TimeStats> mTimeStats;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 990318a..0063c8a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -26,9 +26,9 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
-#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
+#include <system/window.h>
#include <ui/DisplayStatInfo.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -68,9 +68,14 @@
mPrimaryDispSync = std::move(primaryDispSync);
mEventControlThread = std::make_unique<impl::EventControlThread>(function);
+ mSetIdleTimerMs = set_idle_timer_ms(0);
+
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.set_idle_timer_ms", value, "0");
- mSetIdleTimerMs = atoi(value);
+ int int_value = atoi(value);
+ if (int_value) {
+ mSetIdleTimerMs = atoi(value);
+ }
if (mSetIdleTimerMs > 0) {
mIdleTimer =
@@ -292,31 +297,39 @@
mPrimaryDispSync->dump(result);
}
-void Scheduler::addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
- const std::string layerName) {
- // This is V1 logic. It calculates the average FPS based on the timestamp frequency
- // regardless of which layer the timestamp came from.
- // For now, the averages and FPS are recorded in the systrace.
- determineTimestampAverage(isAutoTimestamp, framePresentTime);
-
- // This is V2 logic. It calculates the average and median timestamp difference based on the
- // individual layer history. The results are recorded in the systrace.
- determineLayerTimestampStats(layerName, framePresentTime);
+void Scheduler::addNativeWindowApi(int apiId) {
+ std::lock_guard<std::mutex> lock(mWindowApiHistoryLock);
+ mWindowApiHistory[mApiHistoryCounter] = apiId;
+ mApiHistoryCounter++;
+ mApiHistoryCounter = mApiHistoryCounter % scheduler::ARRAY_SIZE;
}
-void Scheduler::incrementFrameCounter() {
- std::lock_guard<std::mutex> lock(mLayerHistoryLock);
- mLayerHistory.incrementCounter();
+void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) {
+ fn(*mPrimaryDispSync);
}
-void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback) {
+void Scheduler::updateFpsBasedOnNativeWindowApi() {
+ int mode;
+ {
+ std::lock_guard<std::mutex> lock(mWindowApiHistoryLock);
+ mode = scheduler::calculate_mode(mWindowApiHistory);
+ }
+ ATRACE_INT("NativeWindowApiMode", mode);
+
+ if (mode == NATIVE_WINDOW_API_MEDIA) {
+ // TODO(b/127365162): These callback names are not accurate anymore. Update.
+ mediaChangeRefreshRate(MediaFeatureState::MEDIA_PLAYING);
+ ATRACE_INT("DetectedVideo", 1);
+ } else {
+ mediaChangeRefreshRate(MediaFeatureState::MEDIA_OFF);
+ ATRACE_INT("DetectedVideo", 0);
+ }
+}
+
+void Scheduler::setChangeRefreshRateCallback(
+ const ChangeRefreshRateCallback& changeRefreshRateCallback) {
std::lock_guard<std::mutex> lock(mCallbackLock);
- mExpiredTimerCallback = expiredTimerCallback;
-}
-
-void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- mResetTimerCallback = resetTimerCallback;
+ mChangeRefreshRateCallback = changeRefreshRateCallback;
}
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
@@ -328,85 +341,6 @@
}
}
-void Scheduler::determineLayerTimestampStats(const std::string layerName,
- const nsecs_t framePresentTime) {
- std::vector<int64_t> differencesMs;
- std::string differencesText = "";
- {
- std::lock_guard<std::mutex> lock(mLayerHistoryLock);
- mLayerHistory.insert(layerName, framePresentTime);
-
- // Traverse through the layer history, and determine the differences in present times.
- nsecs_t newestPresentTime = framePresentTime;
- for (int i = 1; i < mLayerHistory.getSize(); i++) {
- std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
- for (auto layer : layers) {
- if (layer.first != layerName) {
- continue;
- }
- int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
- // Dismiss noise.
- if (differenceMs > 10 && differenceMs < 60) {
- differencesMs.push_back(differenceMs);
- }
- IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
- newestPresentTime = layer.second;
- }
- }
- }
- ALOGV("Layer %s timestamp intervals: %s", layerName.c_str(), differencesText.c_str());
-
- if (!differencesMs.empty()) {
- // Mean/Average is a good indicator for when 24fps videos are playing, because the frames
- // come in 33, and 49 ms intervals with occasional 41ms.
- const int64_t meanMs = scheduler::calculate_mean(differencesMs);
- const auto tagMean = "TimestampMean_" + layerName;
- ATRACE_INT(tagMean.c_str(), meanMs);
-
- // Mode and median are good indicators for 30 and 60 fps videos, because the majority of
- // frames come in 16, or 33 ms intervals.
- const auto tagMedian = "TimestampMedian_" + layerName;
- ATRACE_INT(tagMedian.c_str(), scheduler::calculate_median(&differencesMs));
-
- const auto tagMode = "TimestampMode_" + layerName;
- ATRACE_INT(tagMode.c_str(), scheduler::calculate_mode(differencesMs));
- }
-}
-
-void Scheduler::determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime) {
- ATRACE_INT("AutoTimestamp", isAutoTimestamp);
-
- // Video does not have timestamp automatically set, so we discard timestamps that are
- // coming in from other sources for now.
- if (isAutoTimestamp) {
- return;
- }
- int64_t differenceMs = (framePresentTime - mPreviousFrameTimestamp) / 1000000;
- mPreviousFrameTimestamp = framePresentTime;
-
- if (differenceMs < 10 || differenceMs > 100) {
- // Dismiss noise.
- return;
- }
- ATRACE_INT("TimestampDiff", differenceMs);
-
- mTimeDifferences[mCounter % scheduler::ARRAY_SIZE] = differenceMs;
- mCounter++;
- int64_t mean = scheduler::calculate_mean(mTimeDifferences);
- ATRACE_INT("AutoTimestampMean", mean);
-
- // TODO(b/113612090): This are current numbers from trial and error while running videos
- // from YouTube at 24, 30, and 60 fps.
- if (mean > 14 && mean < 18) {
- ATRACE_INT("MediaFPS", 60);
- } else if (mean > 31 && mean < 34) {
- ATRACE_INT("MediaFPS", 30);
- return;
- } else if (mean > 39 && mean < 42) {
- ATRACE_INT("MediaFPS", 24);
- }
-}
-
void Scheduler::resetIdleTimer() {
if (mIdleTimer) {
mIdleTimer->reset();
@@ -414,19 +348,15 @@
}
void Scheduler::resetTimerCallback() {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mResetTimerCallback) {
- mResetTimerCallback();
- ATRACE_INT("ExpiredIdleTimer", 0);
- }
+ // We do not notify the applications about config changes when idle timer is reset.
+ timerChangeRefreshRate(IdleTimerState::RESET);
+ ATRACE_INT("ExpiredIdleTimer", 0);
}
void Scheduler::expiredTimerCallback() {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mExpiredTimerCallback) {
- mExpiredTimerCallback();
- ATRACE_INT("ExpiredIdleTimer", 1);
- }
+ // We do not notify the applications about config changes when idle timer expires.
+ timerChangeRefreshRate(IdleTimerState::EXPIRED);
+ ATRACE_INT("ExpiredIdleTimer", 1);
}
std::string Scheduler::doDump() {
@@ -435,4 +365,46 @@
return stream.str();
}
+void Scheduler::mediaChangeRefreshRate(MediaFeatureState mediaFeatureState) {
+ // Default playback for media is DEFAULT when media is on.
+ RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
+ ConfigEvent configEvent = ConfigEvent::None;
+
+ {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ mCurrentMediaFeatureState = mediaFeatureState;
+ // Only switch to PERFORMANCE if idle timer was reset, when turning
+ // media off. If the timer is IDLE, stay at DEFAULT.
+ if (mediaFeatureState == MediaFeatureState::MEDIA_OFF &&
+ mCurrentIdleTimerState == IdleTimerState::RESET) {
+ refreshRateType = RefreshRateType::PERFORMANCE;
+ }
+ }
+ changeRefreshRate(refreshRateType, configEvent);
+}
+
+void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) {
+ RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
+ ConfigEvent configEvent = ConfigEvent::None;
+
+ {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ mCurrentIdleTimerState = idleTimerState;
+ // Only switch to PERFOMANCE if the idle timer was reset, and media is
+ // not playing. Otherwise, stay at DEFAULT.
+ if (idleTimerState == IdleTimerState::RESET &&
+ mCurrentMediaFeatureState == MediaFeatureState::MEDIA_OFF) {
+ refreshRateType = RefreshRateType::PERFORMANCE;
+ }
+ }
+ changeRefreshRate(refreshRateType, configEvent);
+}
+
+void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ if (mChangeRefreshRateCallback) {
+ mChangeRefreshRateCallback(refreshRateType, configEvent);
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 7f113e7..73896d5 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <functional>
#include <memory>
#include <ui/DisplayStatInfo.h>
@@ -28,6 +29,7 @@
#include "IdleTimer.h"
#include "InjectVSyncSource.h"
#include "LayerHistory.h"
+#include "RefreshRateConfigs.h"
#include "SchedulerUtils.h"
namespace android {
@@ -36,9 +38,19 @@
class Scheduler {
public:
- using ExpiredIdleTimerCallback = std::function<void()>;
+ // Enum to keep track of whether we trigger event to notify choreographer of config changes.
+ enum class ConfigEvent { None, Changed };
+
+ // logical or operator with the semantics of at least one of the events is Changed
+ friend ConfigEvent operator|(const ConfigEvent& first, const ConfigEvent& second) {
+ if (first == ConfigEvent::Changed) return ConfigEvent::Changed;
+ if (second == ConfigEvent::Changed) return ConfigEvent::Changed;
+ return ConfigEvent::None;
+ }
+
+ using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+ using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>;
using GetVsyncPeriod = std::function<nsecs_t()>;
- using ResetIdleTimerCallback = std::function<void()>;
// Enum to indicate whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
@@ -93,6 +105,9 @@
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
+ // Provides access to the DispSync object for the primary display.
+ void withPrimaryDispSync(std::function<void(DispSync&)> const& fn);
+
sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle);
// Should be called when receiving a hotplug event.
@@ -130,15 +145,16 @@
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
nsecs_t expectedPresentTime();
- // Adds the present time for given layer to the history of present times.
- void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
- const std::string layerName);
- // Increments counter in the layer history to indicate that SF has started a new frame.
- void incrementFrameCounter();
- // Callback that gets invoked once the idle timer expires.
- void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
- // Callback that gets invoked once the idle timer is reset.
- void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
+ // apiId indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer.
+ // TODO(b/123956502): Remove this call with V1 go/content-fps-detection-in-scheduler.
+ void addNativeWindowApi(int apiId);
+ // Updates FPS based on the most occured request for Native Window API.
+ void updateFpsBasedOnNativeWindowApi();
+ // Callback that gets invoked when Scheduler wants to change the refresh rate.
+ void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback);
+
+ // Returns whether idle timer is enabled or not
+ bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; }
// Returns relevant information about Scheduler for dumpsys purposes.
std::string doDump();
@@ -153,17 +169,16 @@
private:
friend class TestableScheduler;
+ // In order to make sure that the features don't override themselves, we need a state machine
+ // to keep track which feature requested the config change.
+ enum class MediaFeatureState { MEDIA_PLAYING, MEDIA_OFF };
+ enum class IdleTimerState { EXPIRED, RESET };
+
// Creates a connection on the given EventThread and forwards the given callbacks.
sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
- // Collects the statistical mean (average) and median between timestamp
- // intervals for each frame for each layer.
- void determineLayerTimestampStats(const std::string layerName, const nsecs_t framePresentTime);
- // Collects the average difference between timestamps for each frame regardless
- // of which layer the timestamp came from.
- void determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime);
// Function that resets the idle timer.
void resetIdleTimer();
// Function that is called when the timer resets.
@@ -172,6 +187,12 @@
void expiredTimerCallback();
// Sets vsync period.
void setVsyncPeriod(const nsecs_t period);
+ // Media feature's function to change the refresh rate.
+ void mediaChangeRefreshRate(MediaFeatureState mediaFeatureState);
+ // Idle timer feature's function to change the refresh rate.
+ void timerChangeRefreshRate(IdleTimerState idleTimerState);
+ // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters.
+ void changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent);
// If fences from sync Framework are supported.
const bool mHasSyncFramework;
@@ -205,10 +226,13 @@
std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
size_t mCounter = 0;
- // DetermineLayerTimestampStats is called from BufferQueueLayer::onFrameAvailable which
- // can run on any thread, and cause failure.
- std::mutex mLayerHistoryLock;
- LayerHistory mLayerHistory GUARDED_BY(mLayerHistoryLock);
+ // The following few fields follow native window api bits that come with buffers. If there are
+ // more buffers with NATIVE_WINDOW_API_MEDIA we render at 60Hz, otherwise we render at 90Hz.
+ // There is not dependency on timestamp for V0.
+ // TODO(b/123956502): Remove this when more robust logic for content fps detection is developed.
+ std::mutex mWindowApiHistoryLock;
+ std::array<int, scheduler::ARRAY_SIZE> mWindowApiHistory GUARDED_BY(mWindowApiHistoryLock);
+ int64_t mApiHistoryCounter = 0;
// Timer that records time between requests for next vsync. If the time is higher than a given
// interval, a callback is fired. Set this variable to >0 to use this feature.
@@ -216,8 +240,14 @@
std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
std::mutex mCallbackLock;
- ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
- ExpiredIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
+ ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
+
+ // In order to make sure that the features don't override themselves, we need a state machine
+ // to keep track which feature requested the config change.
+ std::mutex mFeatureStateLock;
+ MediaFeatureState mCurrentMediaFeatureState GUARDED_BY(mFeatureStateLock) =
+ MediaFeatureState::MEDIA_OFF;
+ IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
index 191022d..fb5414f 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
@@ -34,23 +34,5 @@
return v->at(n);
}
-int64_t calculate_mode(const std::vector<int64_t>& v) {
- if (v.empty()) {
- return 0;
- }
-
- // Create a map with all the counts for the indivicual values in the vector.
- std::unordered_map<int64_t, int64_t> counts;
- for (int64_t value : v) {
- counts[value]++;
- }
-
- // Sort the map, and return the number with the highest count. If two numbers have
- // the same count, first one is returned.
- using ValueType = const decltype(counts)::value_type&;
- const auto compareCounts = [](ValueType l, ValueType r) { return l.second <= r.second; };
- return std::max_element(counts.begin(), counts.end(), compareCounts)->first;
-}
-
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index edd23de..9e6e8c7 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -18,6 +18,7 @@
#include <cinttypes>
#include <numeric>
+#include <unordered_map>
#include <vector>
namespace android {
@@ -45,7 +46,24 @@
int64_t calculate_median(std::vector<int64_t>* v);
// Calculates the statistical mode in the vector. Return 0 if the vector is empty.
-int64_t calculate_mode(const std::vector<int64_t>& v);
+template <typename T>
+auto calculate_mode(const T& v) {
+ if (v.empty()) {
+ return 0;
+ }
+
+ // Create a map with all the counts for the indivicual values in the vector.
+ std::unordered_map<int64_t, int> counts;
+ for (int64_t value : v) {
+ counts[value]++;
+ }
+
+ // Sort the map, and return the number with the highest count. If two numbers have
+ // the same count, first one is returned.
+ using ValueType = const decltype(counts)::value_type&;
+ const auto compareCounts = [](ValueType l, ValueType r) { return l.second <= r.second; };
+ return static_cast<int>(std::max_element(counts.begin(), counts.end(), compareCounts)->first);
+}
} // namespace scheduler
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4d5a527..1af2096 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -62,7 +62,6 @@
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
#include <ui/UiConfig.h>
-#include <utils/CallStack.h>
#include <utils/StopWatch.h>
#include <utils/String16.h>
#include <utils/String8.h>
@@ -110,7 +109,6 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
-#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
#include <configstore/Utils.h>
@@ -203,9 +201,6 @@
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
const String16 sDump("android.permission.DUMP");
-constexpr float kDefaultRefreshRate = 60.f;
-constexpr float kPerformanceRefreshRate = 90.f;
-
// ---------------------------------------------------------------------------
int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
bool SurfaceFlinger::useHwcForRgbToYuv;
@@ -375,11 +370,13 @@
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
- property_get("debug.sf.use_90Hz", value, "0");
- mUse90Hz = atoi(value);
-
+ mUseSmart90ForVideo = use_smart_90_for_video(false);
property_get("debug.sf.use_smart_90_for_video", value, "0");
- mUseSmart90ForVideo = atoi(value);
+
+ int int_value = atoi(value);
+ if (int_value) {
+ mUseSmart90ForVideo = true;
+ }
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
@@ -568,19 +565,17 @@
readPersistentProperties();
mBootStage = BootStage::FINISHED;
- // TODO(b/122905403): Once the display policy is completely integrated, this flag should go
- // away and it should be controlled by flipping the switch in setting. The switch in
- // settings should only be available to P19 devices, if they are opted into 90Hz fishfood.
- // The boot must be complete before we can set the active config.
+ // set the refresh rate according to the policy
+ const auto displayId = getInternalDisplayIdLocked();
+ LOG_ALWAYS_FATAL_IF(!displayId);
- if (mUse90Hz) {
- mPhaseOffsets->setRefreshRateType(
- scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
- setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
+ const auto performanceRefreshRate =
+ mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
+
+ if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
} else {
- mPhaseOffsets->setRefreshRateType(
- scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
- setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None);
+ setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
}
}));
}
@@ -638,6 +633,10 @@
mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
mSfConnectionHandle.get());
+ mRegionSamplingThread =
+ new RegionSamplingThread(*this, *mScheduler,
+ RegionSamplingThread::EnvironmentTimingTunables());
+
// Get a RenderEngine for the given display / config (can't fail)
int32_t renderEngineFeature = 0;
renderEngineFeature |= (useColorManagement ?
@@ -704,19 +703,18 @@
ALOGE("Run StartPropertySetThread failed!");
}
- if (mUse90Hz) {
- mScheduler->setExpiredIdleTimerCallback([this] {
- Mutex::Autolock lock(mStateLock);
- setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None);
- });
- mScheduler->setResetIdleTimerCallback([this] {
- Mutex::Autolock lock(mStateLock);
- setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
- });
+ if (mScheduler->isIdleTimerEnabled()) {
+ mScheduler->setChangeRefreshRateCallback(
+ [this](RefreshRateType type, Scheduler::ConfigEvent event) {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(type, event);
+ });
}
- mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
- *display->getId()),
- mTimeStats);
+ mRefreshRateConfigs[*display->getId()] = std::make_shared<scheduler::RefreshRateConfigs>(
+ getHwComposer().getConfigs(*display->getId()));
+ mRefreshRateStats =
+ std::make_unique<scheduler::RefreshRateStats>(mRefreshRateConfigs[*display->getId()],
+ mTimeStats);
ALOGV("Done initializing");
}
@@ -920,17 +918,9 @@
}
void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
- ConfigEvent event) {
+ Scheduler::ConfigEvent event) {
ATRACE_CALL();
- Vector<DisplayInfo> configs;
- // Lock is acquired by setRefreshRateTo.
- getDisplayConfigsLocked(displayToken, &configs);
- if (mode < 0 || mode >= static_cast<int>(configs.size())) {
- ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
- return;
- }
-
// Lock is acquired by setRefreshRateTo.
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
@@ -949,9 +939,11 @@
}
// Don't check against the current mode yet. Worst case we set the desired
- // config twice.
+ // config twice. However event generation config might have changed so we need to update it
+ // accordingly
std::lock_guard<std::mutex> lock(mActiveConfigLock);
- mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, event};
+ const Scheduler::ConfigEvent desiredConfig = mDesiredActiveConfig.event | event;
+ mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, desiredConfig};
if (!mDesiredActiveConfigChanged) {
// This is the first time we set the desired
@@ -983,8 +975,10 @@
display->setActiveConfig(mUpcomingActiveConfig.configId);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
- if (mUpcomingActiveConfig.event != ConfigEvent::None) {
+ if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
mUpcomingActiveConfig.configId);
}
@@ -992,15 +986,6 @@
bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
- // we may be in the process of changing the active state
- if (mWaitForNextInvalidate) {
- mWaitForNextInvalidate = false;
-
- repaintEverythingForHWC();
- // We do not want to give another frame to HWC while we are transitioning.
- return true;
- }
-
if (mCheckPendingFence) {
if (mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled)) {
@@ -1052,7 +1037,6 @@
getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId);
// we need to submit an empty frame to HWC to start the process
- mWaitForNextInvalidate = true;
mCheckPendingFence = true;
return false;
@@ -1309,7 +1293,7 @@
status_t SurfaceFlinger::addRegionSamplingListener(const Rect& samplingArea,
const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) {
- if (!listener) {
+ if (!listener || samplingArea == Rect::INVALID_RECT) {
return BAD_VALUE;
}
mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener);
@@ -1317,6 +1301,9 @@
}
status_t SurfaceFlinger::removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+ if (!listener) {
+ return BAD_VALUE;
+ }
mRegionSamplingThread->removeListener(listener);
return NO_ERROR;
}
@@ -1422,57 +1409,30 @@
return mAllowedConfigs[displayId]->isConfigAllowed(config);
}
-void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, ConfigEvent event) {
- mPhaseOffsets->setRefreshRateType(refreshRate);
-
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
-
+void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::ConfigEvent event) {
if (mBootStage != BootStage::FINISHED) {
return;
}
-
- // TODO(b/113612090): There should be a message queue flush here. Because this esentially
- // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
- // manner, once the setActiveConfig is synchronous, and is executed at a known time in a
- // refresh cycle.
+ ATRACE_CALL();
// Don't do any updating if the current fps is the same as the new one.
- const nsecs_t currentVsyncPeriod = getVsyncPeriod();
- if (currentVsyncPeriod == 0) {
- return;
- }
-
- // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
- // floating numbers.
- const float currentFps = 1e9 / currentVsyncPeriod;
- const float newFps = refreshRate == RefreshRateType::PERFORMANCE ? kPerformanceRefreshRate
- : kDefaultRefreshRate;
- if (std::abs(currentFps - newFps) <= 1) {
- return;
- }
-
const auto displayId = getInternalDisplayIdLocked();
LOG_ALWAYS_FATAL_IF(!displayId);
+ const auto displayToken = getInternalDisplayTokenLocked();
- auto configs = getHwComposer().getConfigs(*displayId);
- for (int i = 0; i < configs.size(); i++) {
- if (!isConfigAllowed(*displayId, i)) {
- ALOGV("Skipping config %d as it is not part of allowed configs", i);
- continue;
- }
-
- const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
- if (vsyncPeriod == 0) {
- continue;
- }
- const float fps = 1e9 / vsyncPeriod;
- // TODO(b/113612090): There should be a better way at determining which config
- // has the right refresh rate.
- if (std::abs(fps - newFps) <= 1) {
- setDesiredActiveConfig(getInternalDisplayTokenLocked(), i, event);
- }
+ auto desiredConfigId = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate).configId;
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (desiredConfigId == display->getActiveConfig()) {
+ return;
}
+
+ if (!isConfigAllowed(*displayId, desiredConfigId)) {
+ ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
+ return;
+ }
+
+ mPhaseOffsets->setRefreshRateType(refreshRate);
+ setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
}
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -1616,15 +1576,16 @@
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
+ if (mUseSmart90ForVideo) {
+ // This call is made each time SF wakes up and creates a new frame. It is part
+ // of video detection feature.
+ mScheduler->updateFpsBasedOnNativeWindowApi();
+ }
+
if (performSetActiveConfig()) {
break;
}
- if (mUse90Hz && mUseSmart90ForVideo) {
- // This call is made each time SF wakes up and creates a new frame. It is part
- // of video detection feature.
- mScheduler->incrementFrameCounter();
- }
bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled);
bool hwcFrameMissed = !mHadClientComposition && frameMissed;
@@ -1786,6 +1747,13 @@
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
}
+ Dataspace targetDataspace = Dataspace::UNKNOWN;
+ if (useColorManagement) {
+ ColorMode colorMode;
+ RenderIntent renderIntent;
+ pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
+ display->setColorMode(colorMode, targetDataspace, renderIntent);
+ }
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
layer->forceClientComposition(displayDevice);
@@ -1817,15 +1785,7 @@
const auto& displayState = display->getState();
layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
- displayDevice->getSupportedPerFrameMetadata());
- }
-
- if (useColorManagement) {
- ColorMode colorMode;
- Dataspace dataSpace;
- RenderIntent renderIntent;
- pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
- display->setColorMode(colorMode, dataSpace, renderIntent);
+ displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
}
}
@@ -1968,78 +1928,22 @@
getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
-// debug patch for b/119477596 - add stack guards to catch stack
-// corruptions and disable clang optimizations.
-// The code below is temporary and planned to be removed once stack
-// corruptions are found.
-#pragma clang optimize off
-class StackGuard {
-public:
- StackGuard(const char* name, const char* func, int line) {
- guarders.reserve(MIN_CAPACITY);
- guarders.push_back({this, name, func, line});
- validate();
- }
- ~StackGuard() {
- for (auto i = guarders.end() - 1; i >= guarders.begin(); --i) {
- if (i->guard == this) {
- guarders.erase(i);
- break;
- }
- }
- }
-
- static void validate() {
- for (const auto& guard : guarders) {
- if (guard.guard->cookie != COOKIE_VALUE) {
- ALOGE("%s:%d: Stack corruption detected at %s", guard.func, guard.line, guard.name);
- CallStack stack(LOG_TAG);
- abort();
- }
- }
- }
-
-private:
- uint64_t cookie = COOKIE_VALUE;
- static constexpr uint64_t COOKIE_VALUE = 0xc0febebedeadbeef;
- static constexpr size_t MIN_CAPACITY = 16;
-
- struct GuarderElement {
- StackGuard* guard;
- const char* name;
- const char* func;
- int line;
- };
-
- static std::vector<GuarderElement> guarders;
-};
-std::vector<StackGuard::GuarderElement> StackGuard::guarders;
-
-#define DEFINE_STACK_GUARD(__n) StackGuard __n##StackGuard(#__n, __FUNCTION__, __LINE__);
-
-#define ASSERT_ON_STACK_GUARD() StackGuard::validate();
void SurfaceFlinger::postComposition()
{
- DEFINE_STACK_GUARD(begin);
ATRACE_CALL();
ALOGV("postComposition");
// Release any buffers which were replaced this frame
nsecs_t dequeueReadyTime = systemTime();
- DEFINE_STACK_GUARD(dequeueReadyTime);
for (auto& layer : mLayersWithQueuedFrames) {
layer->releasePendingBuffer(dequeueReadyTime);
}
- ASSERT_ON_STACK_GUARD();
// |mStateLock| not needed as we are on the main thread
const auto displayDevice = getDefaultDisplayDeviceLocked();
- DEFINE_STACK_GUARD(displayDevice);
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- DEFINE_STACK_GUARD(glCompositionDoneFenceTime);
-
if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
@@ -2050,52 +1954,37 @@
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
- ASSERT_ON_STACK_GUARD();
-
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId())
: Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
- DEFINE_STACK_GUARD(presentFenceTime);
getBE().mDisplayTimeline.push(presentFenceTime);
DisplayStatInfo stats;
- DEFINE_STACK_GUARD(stats);
mScheduler->getDisplayStatInfo(&stats);
- ASSERT_ON_STACK_GUARD();
-
// We use the mRefreshStartTime which might be sampled a little later than
// when we started doing work for this frame, but that should be okay
// since updateCompositorTiming has snapping logic.
updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
CompositorTiming compositorTiming;
- DEFINE_STACK_GUARD(compositorTiming);
-
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
- DEFINE_STACK_GUARD(lock);
compositorTiming = getBE().mCompositorTiming;
-
- ASSERT_ON_STACK_GUARD();
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool frameLatched =
layer->onPostComposition(displayDevice->getId(), glCompositionDoneFenceTime,
presentFenceTime, compositorTiming);
- DEFINE_STACK_GUARD(frameLatched);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
layer->getOccupancyHistory(false));
}
- ASSERT_ON_STACK_GUARD();
});
if (presentFenceTime->isValid()) {
- ASSERT_ON_STACK_GUARD();
mScheduler->addPresentFence(presentFenceTime);
- ASSERT_ON_STACK_GUARD();
}
if (!hasSyncFramework) {
@@ -2105,92 +1994,67 @@
}
}
- ASSERT_ON_STACK_GUARD();
-
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
-
- ASSERT_ON_STACK_GUARD();
} else if (displayDevice && getHwComposer().isConnected(*displayDevice->getId())) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t presentTime =
getHwComposer().getRefreshTimestamp(*displayDevice->getId());
- DEFINE_STACK_GUARD(presentTime);
-
mAnimFrameTracker.setActualPresentTime(presentTime);
- ASSERT_ON_STACK_GUARD();
}
mAnimFrameTracker.advanceFrame();
}
- ASSERT_ON_STACK_GUARD();
-
mTimeStats->incrementTotalFrames();
if (mHadClientComposition) {
mTimeStats->incrementClientCompositionFrames();
}
- ASSERT_ON_STACK_GUARD();
-
mTimeStats->setPresentFenceGlobal(presentFenceTime);
- ASSERT_ON_STACK_GUARD();
-
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
!displayDevice->isPoweredOn()) {
return;
}
nsecs_t currentTime = systemTime();
- DEFINE_STACK_GUARD(currentTime);
if (mHasPoweredOff) {
mHasPoweredOff = false;
} else {
nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
- DEFINE_STACK_GUARD(elapsedTime);
size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
- DEFINE_STACK_GUARD(numPeriods);
if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
getBE().mFrameBuckets[numPeriods] += elapsedTime;
} else {
getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime;
}
getBE().mTotalTime += elapsedTime;
-
- ASSERT_ON_STACK_GUARD();
}
getBE().mLastSwapTime = currentTime;
- ASSERT_ON_STACK_GUARD();
{
std::lock_guard lock(mTexturePoolMutex);
- DEFINE_STACK_GUARD(lock);
const size_t refillCount = mTexturePoolSize - mTexturePool.size();
- DEFINE_STACK_GUARD(refillCount);
if (refillCount > 0) {
const size_t offset = mTexturePool.size();
mTexturePool.resize(mTexturePoolSize);
getRenderEngine().genTextures(refillCount, mTexturePool.data() + offset);
ATRACE_INT("TexturePoolSize", mTexturePool.size());
}
- ASSERT_ON_STACK_GUARD();
}
mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
mTransactionCompletedThread.sendCallbacks();
- if (mLumaSampling) {
- mRegionSamplingThread->sampleNow();
+ if (mLumaSampling && mRegionSamplingThread) {
+ mRegionSamplingThread->notifyNewContent();
}
-
- ASSERT_ON_STACK_GUARD();
}
-#pragma clang optimize on // b/119477596
void SurfaceFlinger::computeLayerBounds() {
for (const auto& pair : mDisplays) {
@@ -3457,6 +3321,16 @@
// Perform some cleanup steps if we used client composition.
if (hasClientComposition) {
clientCompositionDisplay.clearRegion = clearRegion;
+
+ // We boost GPU frequency here because there will be color spaces conversion
+ // and it's expensive. We boost the GPU frequency so that GPU composition can
+ // finish in time. We must reset GPU frequency afterwards, because high frequency
+ // consumes extra battery.
+ const bool expensiveRenderingExpected =
+ clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3;
+ if (expensiveRenderingExpected && displayId) {
+ mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true);
+ }
if (!debugRegion.isEmpty()) {
Region::const_iterator it = debugRegion.begin();
Region::const_iterator end = debugRegion.end();
@@ -3472,6 +3346,9 @@
}
renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
buf->getNativeBuffer(), std::move(fd), readyFence);
+ if (expensiveRenderingExpected && displayId) {
+ mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
+ }
}
return true;
}
@@ -3999,6 +3876,11 @@
if (what & layer_state_t::eMetadataChanged) {
if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eColorSpaceAgnosticChanged) {
+ if (layer->setColorSpaceAgnostic(s.colorSpaceAgnostic)) {
+ flags |= eTraversalNeeded;
+ }
+ }
std::vector<sp<CallbackHandle>> callbackHandles;
if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
mTransactionCompletedThread.run();
@@ -4502,7 +4384,7 @@
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriod());
- StringAppendF(&result, "Scheduler enabled. 90Hz feature: %s\n", mUse90Hz ? "on" : "off");
+ StringAppendF(&result, "Scheduler enabled.");
StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n",
mUseSmart90ForVideo ? "on" : "off");
mScheduler->dump(mAppConnectionHandle, result);
@@ -4856,6 +4738,7 @@
*/
result.append("\nScheduler state:\n");
result.append(mScheduler->doDump() + "\n");
+ StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off");
result.append(mRefreshRateStats->doDump() + "\n");
}
@@ -5757,21 +5640,28 @@
// make sure that the current config is still allowed
int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId);
if (!isConfigAllowed(*displayId, currentConfigIndex)) {
- // TODO(b/122906558): stop querying HWC for the available configs and instead use the cached
- // configs queried on boot
- auto configs = getHwComposer().getConfigs(*displayId);
-
- for (int i = 0; i < configs.size(); i++) {
- if (isConfigAllowed(*displayId, i)) {
+ for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) {
+ if (isConfigAllowed(*displayId, config.configId)) {
// TODO: we switch to the first allowed config. In the future
// we may want to enhance this logic to pick a similar config
// to the current one
- ALOGV("Old config is not allowed - switching to config %d", i);
- setDesiredActiveConfig(displayToken, i, ConfigEvent::Changed);
+ ALOGV("Old config is not allowed - switching to config %d", config.configId);
+ setDesiredActiveConfig(displayToken, config.configId,
+ Scheduler::ConfigEvent::Changed);
break;
}
}
}
+
+ // If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT,
+ // there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed.
+ if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) {
+ const auto performanceRefreshRate =
+ mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
+ if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed);
+ }
+ }
}
status_t SurfaceFlinger::setAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8f80175..6a456f5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -53,6 +53,7 @@
#include "DisplayDevice.h"
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
#include "Effects/Daltonizer.h"
#include "FrameTracker.h"
#include "LayerStats.h"
@@ -521,13 +522,11 @@
void signalLayerUpdate();
void signalRefresh();
- enum class ConfigEvent { None, Changed };
-
// called on the main thread in response to initializeDisplays()
void onInitializeDisplays() REQUIRES(mStateLock);
// Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
- void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode, ConfigEvent event)
- REQUIRES(mStateLock);
+ void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
+ Scheduler::ConfigEvent event) REQUIRES(mStateLock);
// Once HWC has returned the present fence, this sets the active config and a new refresh
// rate in SF. It also triggers HWC vsync.
void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -808,8 +807,8 @@
// Sets the refresh rate by switching active configs, if they are available for
// the desired refresh rate.
- void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType, ConfigEvent event)
- REQUIRES(mStateLock);
+ void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType,
+ Scheduler::ConfigEvent event) REQUIRES(mStateLock);
bool isConfigAllowed(const DisplayId& displayId, int32_t config);
@@ -1012,9 +1011,6 @@
TransactionCompletedThread mTransactionCompletedThread;
- bool mLumaSampling = true;
- sp<RegionSamplingThread> mRegionSamplingThread = new RegionSamplingThread(*this);
-
// Restrict layers to use two buffers in their bufferqueues.
bool mLayerTripleBufferingDisabled = false;
@@ -1101,13 +1097,15 @@
/* ------------------------------------------------------------------------
* Scheduler
*/
- bool mUse90Hz = false;
bool mUseSmart90ForVideo = false;
std::unique_ptr<Scheduler> mScheduler;
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+ std::unordered_map<DisplayId, std::shared_ptr<scheduler::RefreshRateConfigs>>
+ mRefreshRateConfigs;
+
std::mutex mAllowedConfigsLock;
std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
GUARDED_BY(mAllowedConfigsLock);
@@ -1115,7 +1113,7 @@
struct ActiveConfigInfo {
int configId;
sp<IBinder> displayToken;
- ConfigEvent event;
+ Scheduler::ConfigEvent event;
bool operator!=(const ActiveConfigInfo& other) const {
if (configId != other.configId) {
@@ -1134,20 +1132,22 @@
// below flags are set by main thread only
bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false;
- bool mWaitForNextInvalidate = false;
bool mCheckPendingFence = false;
/* ------------------------------------------------------------------------ */
+ bool mLumaSampling = true;
+ sp<RegionSamplingThread> mRegionSamplingThread;
+
sp<IInputFlinger> mInputFlinger;
InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
// Should only be accessed by the main thread.
InputWindowCommands mInputWindowCommands;
-
ui::DisplayPrimaries mInternalDisplayPrimaries;
sp<SetInputWindowsListener> mSetInputWindowsListener;
bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
+ Hwc2::impl::PowerAdvisor mPowerAdvisor;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index e676d20..e130511 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -4,7 +4,6 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
-#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <cstdlib>
@@ -16,9 +15,9 @@
namespace sysprop {
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
-using ::android::hardware::configstore::V1_2::DisplayPrimaries;
-using ::android::hardware::graphics::common::V1_2::Dataspace;
-using ::android::hardware::graphics::common::V1_2::PixelFormat;
+using android::hardware::graphics::common::V1_2::Dataspace;
+using android::hardware::graphics::common::V1_2::PixelFormat;
+using android::ui::DisplayPrimaries;
int64_t vsync_event_phase_offset_ns(int64_t defaultValue) {
auto temp = SurfaceFlingerProperties::vsync_event_phase_offset_ns();
@@ -167,33 +166,15 @@
auto tmpuseColorManagement = SurfaceFlingerProperties::use_color_management();
auto tmpHasHDRDisplay = SurfaceFlingerProperties::has_HDR_display();
auto tmpHasWideColorDisplay = SurfaceFlingerProperties::has_wide_color_display();
- if (tmpuseColorManagement.has_value() && tmpHasHDRDisplay.has_value() &&
- tmpHasWideColorDisplay.has_value()) {
- return *tmpuseColorManagement || *tmpHasHDRDisplay || *tmpHasWideColorDisplay;
- }
- auto surfaceFlingerConfigsServiceV1_2 = ISurfaceFlingerConfigs::getService();
- if (surfaceFlingerConfigsServiceV1_2) {
- return getBool<V1_2::ISurfaceFlingerConfigs,
- &V1_2::ISurfaceFlingerConfigs::useColorManagement>(defaultValue);
- }
- return defaultValue;
-}
-auto getCompositionPreference(sp<V1_2::ISurfaceFlingerConfigs> configsServiceV1_2) {
- Dataspace defaultCompositionDataspace = Dataspace::V0_SRGB;
- PixelFormat defaultCompositionPixelFormat = PixelFormat::RGBA_8888;
- Dataspace wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
- PixelFormat wideColorGamutCompositionPixelFormat = PixelFormat::RGBA_8888;
- configsServiceV1_2->getCompositionPreference(
- [&](auto tmpDefaultDataspace, auto tmpDefaultPixelFormat,
- auto tmpWideColorGamutDataspace, auto tmpWideColorGamutPixelFormat) {
- defaultCompositionDataspace = tmpDefaultDataspace;
- defaultCompositionPixelFormat = tmpDefaultPixelFormat;
- wideColorGamutCompositionDataspace = tmpWideColorGamutDataspace;
- wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat;
- });
- return std::tuple(defaultCompositionDataspace, defaultCompositionPixelFormat,
- wideColorGamutCompositionDataspace, wideColorGamutCompositionPixelFormat);
+ auto tmpuseColorManagementVal = tmpuseColorManagement.has_value() ? *tmpuseColorManagement :
+ defaultValue;
+ auto tmpHasHDRDisplayVal = tmpHasHDRDisplay.has_value() ? *tmpHasHDRDisplay :
+ defaultValue;
+ auto tmpHasWideColorDisplayVal = tmpHasWideColorDisplay.has_value() ? *tmpHasWideColorDisplay :
+ defaultValue;
+
+ return tmpuseColorManagementVal || tmpHasHDRDisplayVal || tmpHasWideColorDisplayVal;
}
int64_t default_composition_dataspace(Dataspace defaultValue) {
@@ -201,10 +182,6 @@
if (temp.has_value()) {
return *temp;
}
- auto configsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (configsServiceV1_2) {
- return static_cast<int64_t>(get<0>(getCompositionPreference(configsServiceV1_2)));
- }
return static_cast<int64_t>(defaultValue);
}
@@ -213,10 +190,6 @@
if (temp.has_value()) {
return *temp;
}
- auto configsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (configsServiceV1_2) {
- return static_cast<int32_t>(get<1>(getCompositionPreference(configsServiceV1_2)));
- }
return static_cast<int32_t>(defaultValue);
}
@@ -225,10 +198,6 @@
if (temp.has_value()) {
return *temp;
}
- auto configsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (configsServiceV1_2) {
- return static_cast<int64_t>(get<2>(getCompositionPreference(configsServiceV1_2)));
- }
return static_cast<int64_t>(defaultValue);
}
@@ -237,13 +206,25 @@
if (temp.has_value()) {
return *temp;
}
- auto configsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (configsServiceV1_2) {
- return static_cast<int32_t>(get<3>(getCompositionPreference(configsServiceV1_2)));
- }
return static_cast<int32_t>(defaultValue);
}
+int32_t set_idle_timer_ms(int32_t defaultValue) {
+ auto temp = SurfaceFlingerProperties::set_idle_timer_ms();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
+bool use_smart_90_for_video(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::use_smart_90_for_video();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
#define DISPLAY_PRIMARY_SIZE 3
constexpr float kSrgbRedX = 0.4123f;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index c86880e..6f90117 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -3,8 +3,9 @@
#define SURFACEFLINGERPROPERTIES_H_
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
-#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
+#include <android/hardware/graphics/common/1.2/types.h>
#include <sysprop/SurfaceFlingerProperties.sysprop.h>
+#include <ui/ConfigStoreTypes.h>
#include <cstdint>
#include <optional>
@@ -54,7 +55,11 @@
int32_t wcg_composition_pixel_format(
android::hardware::graphics::common::V1_2::PixelFormat defaultValue);
-android::hardware::configstore::V1_2::DisplayPrimaries getDisplayNativePrimaries();
+int32_t set_idle_timer_ms(int32_t defaultValue);
+
+bool use_smart_90_for_video(bool defaultValue);
+
+android::ui::DisplayPrimaries getDisplayNativePrimaries();
} // namespace sysprop
} // namespace android
#endif // SURFACEFLINGERPROPERTIES_H_
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 429636b..fe6dc93 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -286,3 +286,24 @@
access: Readonly
prop_name: "ro.surface_flinger.display_primary_white"
}
+
+# setIdleTimerMs indicates what is considered a timeout in milliseconds for Scheduler. This value is
+# used by the Scheduler to trigger inactivity callbacks that will switch the display to a lower
+# refresh rate. Setting this property to 0 means there is no timer.
+prop {
+ api_name: "set_idle_timer_ms"
+ type: Integer
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.set_idle_timer_ms"
+}
+
+# useSmart90ForVideo indicates whether Scheduler should detect content FPS, and try to adjust the
+# screen refresh rate based on that.
+prop {
+ api_name: "use_smart_90_for_video"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.use_smart_90_for_video"
+}
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 91999ae..be862c9 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*"
+ "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*"
}
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 34cdff7..319e01c 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -198,12 +198,15 @@
class ScreenCapture : public RefBase {
public:
static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
+ captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
+ }
+
+ static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
const auto sf = ComposerService::getComposerService();
- const auto token = sf->getInternalDisplayToken();
SurfaceComposerClient::Transaction().apply(true);
sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(token, &outBuffer, Rect(), 0, 0, false));
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false));
*sc = std::make_unique<ScreenCapture>(outBuffer);
}
@@ -482,6 +485,12 @@
return screenshot;
}
+ void asTransaction(const std::function<void(Transaction&)>& exec) {
+ Transaction t;
+ exec(t);
+ t.apply(true);
+ }
+
static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
static BufferGenerator bufferGenerator;
return bufferGenerator.get(outBuffer, outFence);
@@ -4086,11 +4095,6 @@
fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
}
- void asTransaction(const std::function<void(Transaction&)>& exec) {
- Transaction t;
- exec(t);
- t.apply(true);
- }
sp<SurfaceControl> mBGSurfaceControl;
sp<SurfaceControl> mFGSurfaceControl;
@@ -5421,4 +5425,102 @@
}
}
+class MultiDisplayLayerBoundsTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
+ SurfaceComposerClient::getDisplayInfo(mMainDisplay, &mMainDisplayInfo);
+
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&mProducer, &consumer);
+ consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setDefaultBufferSize(mMainDisplayInfo.w, mMainDisplayInfo.h);
+ }
+
+ virtual void TearDown() {
+ SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
+ LayerTransactionTest::TearDown();
+ mColorLayer = 0;
+ }
+
+ void createDisplay(const Rect& layerStackRect, uint32_t layerStack) {
+ mVirtualDisplay =
+ SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
+ asTransaction([&](Transaction& t) {
+ t.setDisplaySurface(mVirtualDisplay, mProducer);
+ t.setDisplayLayerStack(mVirtualDisplay, layerStack);
+ t.setDisplayProjection(mVirtualDisplay, mMainDisplayInfo.orientation, layerStackRect,
+ Rect(mMainDisplayInfo.w, mMainDisplayInfo.h));
+ });
+ }
+
+ void createColorLayer(uint32_t layerStack) {
+ mColorLayer =
+ createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ ASSERT_TRUE(mColorLayer != nullptr);
+ ASSERT_TRUE(mColorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setLayerStack(mColorLayer, layerStack);
+ t.setCrop_legacy(mColorLayer, Rect(0, 0, 30, 40));
+ t.setLayer(mColorLayer, INT32_MAX - 2);
+ t.setColor(mColorLayer,
+ half3{mExpectedColor.r / 255.0f, mExpectedColor.g / 255.0f,
+ mExpectedColor.b / 255.0f});
+ t.show(mColorLayer);
+ });
+ }
+
+ DisplayInfo mMainDisplayInfo;
+ sp<IBinder> mMainDisplay;
+ sp<IBinder> mVirtualDisplay;
+ sp<IGraphicBufferProducer> mProducer;
+ sp<SurfaceControl> mColorLayer;
+ Color mExpectedColor = {63, 63, 195, 255};
+};
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
+ createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 1 /* layerStack */);
+ createColorLayer(1 /* layerStack */);
+
+ asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+ // Verify color layer does not render on main display.
+ std::unique_ptr<ScreenCapture> sc;
+ ScreenCapture::captureScreen(&sc, mMainDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), {0, 0, 0, 255});
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+ // Verify color layer renders correctly on virtual display.
+ ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 0});
+}
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) {
+ // Create a display and set its layer stack to the main display's layer stack so
+ // the contents of the main display are mirrored on to the virtual display.
+
+ // Assumption here is that the new mirrored display has the same viewport as the
+ // primary display that it is mirroring.
+ createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 0 /* layerStack */);
+ createColorLayer(0 /* layerStack */);
+
+ asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+ // Verify color layer renders correctly on main display and it is mirrored on the
+ // virtual display.
+ std::unique_ptr<ScreenCapture> sc;
+ ScreenCapture::captureScreen(&sc, mMainDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+ ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 6deec29..30ae764 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -592,8 +592,6 @@
renderengine::LayerSettings layer = layerSettings.back();
EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
- EXPECT_EQ(renderengine::Buffer::CachingHint::NO_CACHE,
- layer.source.buffer.cacheHint);
EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 1487d47..9bf29a2 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1926,6 +1926,10 @@
EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID))
.WillOnce(Return(Error::NONE));
EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+
+ // Cleanup
+ mFlinger.mutableCurrentState().displays.removeItem(displayToken);
+ mFlinger.mutableDrawingState().displays.removeItem(displayToken);
}
TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 3d887ea..4342dc9 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -45,6 +45,7 @@
std::unique_ptr<RefreshRateStats> mRefreshRateStats;
std::shared_ptr<android::mock::TimeStats> mTimeStats;
+ std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs;
};
RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -61,7 +62,8 @@
void RefreshRateStatsTest::init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs) {
mTimeStats = std::make_shared<android::mock::TimeStats>();
- mRefreshRateStats = std::make_unique<RefreshRateStats>(configs, mTimeStats);
+ mRefreshRateConfigs = std::make_shared<RefreshRateConfigs>(configs);
+ mRefreshRateStats = std::make_unique<RefreshRateStats>(mRefreshRateConfigs, mTimeStats);
}
namespace {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d61973e..13059e8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -324,6 +324,7 @@
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
+ auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
@@ -340,6 +341,8 @@
// still be referenced by something despite our best efforts to destroy
// it after each test is done.
mutableDisplays().clear();
+ mutableCurrentState().displays.clear();
+ mutableDrawingState().displays.clear();
mutableEventQueue().reset();
mutableInterceptor().reset();
mutableScheduler().reset();
@@ -352,18 +355,11 @@
* Wrapper classes for Read-write access to private data to set up
* preconditions and assert post-conditions.
*/
- class FakePowerAdvisor : public Hwc2::PowerAdvisor {
- public:
- FakePowerAdvisor() = default;
- ~FakePowerAdvisor() override = default;
- void setExpensiveRenderingExpected(hwc2_display_t, bool) override {}
- };
-
struct HWC2Display : public HWC2::impl::Display {
- HWC2Display(Hwc2::Composer& composer, Hwc2::PowerAdvisor& advisor,
+ HWC2Display(Hwc2::Composer& composer,
const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
HWC2::DisplayType type)
- : HWC2::impl::Display(composer, advisor, capabilities, id, type) {}
+ : HWC2::impl::Display(composer, capabilities, id, type) {}
~HWC2Display() {
// Prevents a call to disable vsyncs.
mType = HWC2::DisplayType::Invalid;
@@ -427,14 +423,7 @@
return *this;
}
- auto& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
- mPowerAdvisor = powerAdvisor;
- return *this;
- }
-
void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
- static FakePowerAdvisor defaultPowerAdvisor;
- if (mPowerAdvisor == nullptr) mPowerAdvisor = &defaultPowerAdvisor;
static const std::unordered_set<HWC2::Capability> defaultCapabilities;
if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
@@ -442,8 +431,8 @@
// not refer to an instance owned by FakeHwcDisplayInjector. This
// class has temporary lifetime, while the constructed HWC2::Display
// is much longer lived.
- auto display = std::make_unique<HWC2Display>(*composer, *mPowerAdvisor, *mCapabilities,
- mHwcDisplayId, mHwcDisplayType);
+ auto display = std::make_unique<HWC2Display>(*composer, *mCapabilities, mHwcDisplayId,
+ mHwcDisplayType);
auto config = HWC2::Display::Config::Builder(*display, mActiveConfig);
config.setWidth(mWidth);
@@ -478,7 +467,6 @@
int32_t mDpiY = DEFAULT_DPI;
int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
- Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
};
class FakeDisplayDeviceInjector {
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index dc6d83b..7c65f95 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -29,7 +29,7 @@
PowerAdvisor();
~PowerAdvisor() override;
- MOCK_METHOD2(setExpensiveRenderingExpected, void(hwc2_display_t displayId, bool expected));
+ MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
};
} // namespace mock