Merge "SF: Make screenshot surface async" into nyc-mr1-dev
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index f4044b2..d406179 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -99,30 +99,47 @@
return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
}
+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid,
+ const char* pkgname, const char* seinfo) {
+ if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << path;
+ return -1;
+ }
+ if (selinux_android_setfilecon(path.c_str(), pkgname, seinfo, uid) < 0) {
+ PLOG(ERROR) << "Failed to setfilecon " << path;
+ return -1;
+ }
+ return 0;
+}
+
+static int prepare_app_dir(const std::string& parent, const char* name, mode_t target_mode,
+ uid_t uid, const char* pkgname, const char* seinfo) {
+ return prepare_app_dir(StringPrintf("%s/%s", parent.c_str(), name), target_mode, uid, pkgname,
+ seinfo);
+}
+
int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
appid_t appid, const char* seinfo, int target_sdk_version) {
uid_t uid = multiuser_get_uid(userid, appid);
- int target_mode = target_sdk_version >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
+ mode_t target_mode = target_sdk_version >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
- if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
- PLOG(ERROR) << "Failed to prepare " << path;
+ if (prepare_app_dir(path, target_mode, uid, pkgname, seinfo) ||
+ prepare_app_dir(path, "cache", 0771, uid, pkgname, seinfo) ||
+ prepare_app_dir(path, "code_cache", 0771, uid, pkgname, seinfo)) {
return -1;
}
- if (selinux_android_setfilecon(path.c_str(), pkgname, seinfo, uid) < 0) {
- PLOG(ERROR) << "Failed to setfilecon " << path;
+
+ // Remember inode numbers of cache directories so that we can clear
+ // contents while CE storage is locked
+ if (write_path_inode(path, "cache", kXattrInodeCache) ||
+ write_path_inode(path, "code_cache", kXattrInodeCodeCache)) {
return -1;
}
}
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid, userid, pkgname);
- if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) == -1) {
- PLOG(ERROR) << "Failed to prepare " << path;
- // TODO: include result once 25796509 is fixed
- return 0;
- }
- if (selinux_android_setfilecon(path.c_str(), pkgname, seinfo, uid) < 0) {
- PLOG(ERROR) << "Failed to setfilecon " << path;
+ if (prepare_app_dir(path, target_mode, uid, pkgname, seinfo)) {
// TODO: include result once 25796509 is fixed
return 0;
}
@@ -266,24 +283,29 @@
int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
ino_t ce_data_inode) {
- std::string suffix = "";
- bool only_cache = false;
- if (flags & FLAG_CLEAR_CACHE_ONLY) {
- suffix = CACHE_DIR_POSTFIX;
- only_cache = true;
- } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
- suffix = CODE_CACHE_DIR_POSTFIX;
- only_cache = true;
- }
-
int res = 0;
if (flags & FLAG_STORAGE_CE) {
- auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode) + suffix;
+ auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode);
+ if (flags & FLAG_CLEAR_CACHE_ONLY) {
+ path = read_path_inode(path, "cache", kXattrInodeCache);
+ } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+ path = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
+ }
if (access(path.c_str(), F_OK) == 0) {
res |= delete_dir_contents(path);
}
}
if (flags & FLAG_STORAGE_DE) {
+ std::string suffix = "";
+ bool only_cache = false;
+ if (flags & FLAG_CLEAR_CACHE_ONLY) {
+ suffix = CACHE_DIR_POSTFIX;
+ only_cache = true;
+ } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+ suffix = CODE_CACHE_DIR_POSTFIX;
+ only_cache = true;
+ }
+
auto path = create_data_user_de_package_path(uuid, userid, pkgname) + suffix;
if (access(path.c_str(), F_OK) == 0) {
// TODO: include result once 25796509 is fixed
@@ -627,14 +649,9 @@
}
int get_app_data_inode(const char *uuid, const char *pkgname, int userid, int flags, ino_t *inode) {
- struct stat buf;
- memset(&buf, 0, sizeof(buf));
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
- if (stat(path.c_str(), &buf) == 0) {
- *inode = buf.st_ino;
- return 0;
- }
+ return get_path_inode(path, inode);
}
return -1;
}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index c838993..674f760 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
+#include <sys/xattr.h>
#if defined(__APPLE__)
#include <sys/mount.h>
@@ -39,7 +40,9 @@
#ifndef LOG_TAG
#define LOG_TAG "installd"
#endif
+
#define CACHE_NOISY(x) //x
+#define DEBUG_XATTRS 0
using android::base::StringPrintf;
@@ -105,10 +108,12 @@
while ((ent = readdir(dir))) {
if (ent->d_ino == ce_data_inode) {
auto resolved = StringPrintf("%s/%s", user_path.c_str(), ent->d_name);
+#if DEBUG_XATTRS
if (resolved != fallback) {
LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
<< " instead of " << fallback;
}
+#endif
closedir(dir);
return resolved;
}
@@ -551,7 +556,7 @@
if (res == NULL) {
return NULL;
}
- CACHE_NOISY(ALOGI("Allocated large cache mem block: %p size %d", res, len));
+ CACHE_NOISY(ALOGI("Allocated large cache mem block: %p size %zu", res, len));
// Link it into our list of blocks, not disrupting the current one.
if (cache->memBlocks == NULL) {
*(void**)res = NULL;
@@ -576,7 +581,7 @@
cache->curMemBlockEnd = newBlock + CACHE_BLOCK_SIZE;
nextPos = res + len;
}
- CACHE_NOISY(ALOGI("cache_malloc: ret %p size %d, block=%p, nextPos=%p",
+ CACHE_NOISY(ALOGI("cache_malloc: ret %p size %zu, block=%p, nextPos=%p",
res, len, cache->memBlocks, nextPos));
cache->curMemBlockAvail = nextPos;
return res;
@@ -654,7 +659,7 @@
cache->availFiles = newAvail;
cache->files = newFiles;
}
- CACHE_NOISY(ALOGI("Setting file %p at position %d in array %p", file,
+ CACHE_NOISY(ALOGI("Setting file %p at position %zd in array %p", file,
cache->numFiles, cache->files));
cache->files[cache->numFiles] = file;
cache->numFiles++;
@@ -779,6 +784,99 @@
return 0;
}
+int get_path_inode(const std::string& path, ino_t *inode) {
+ struct stat buf;
+ memset(&buf, 0, sizeof(buf));
+ if (stat(path.c_str(), &buf) != 0) {
+ PLOG(WARNING) << "Failed to stat " << path;
+ return -1;
+ } else {
+ *inode = buf.st_ino;
+ return 0;
+ }
+}
+
+/**
+ * Write the inode of a specific child file into the given xattr on the
+ * parent directory. This allows you to find the child later, even if its
+ * name is encrypted.
+ */
+int write_path_inode(const std::string& parent, const char* name, const char* inode_xattr) {
+ ino_t inode = 0;
+ uint64_t inode_raw = 0;
+ auto path = StringPrintf("%s/%s", parent.c_str(), name);
+
+ if (get_path_inode(path, &inode) != 0) {
+ // Path probably doesn't exist yet; ignore
+ return 0;
+ }
+
+ // Check to see if already set correctly
+ if (getxattr(parent.c_str(), inode_xattr, &inode_raw, sizeof(inode_raw)) == sizeof(inode_raw)) {
+ if (inode_raw == inode) {
+ // Already set correctly; skip writing
+ return 0;
+ } else {
+ PLOG(WARNING) << "Mismatched inode value; found " << inode
+ << " on disk but marked value was " << inode_raw << "; overwriting";
+ }
+ }
+
+ inode_raw = inode;
+ if (setxattr(parent.c_str(), inode_xattr, &inode_raw, sizeof(inode_raw), 0) != 0 && errno != EOPNOTSUPP) {
+ PLOG(ERROR) << "Failed to write xattr " << inode_xattr << " at " << parent;
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Read the inode of a specific child file from the given xattr on the
+ * parent directory. Returns a currently valid path for that child, which
+ * might have an encrypted name.
+ */
+std::string read_path_inode(const std::string& parent, const char* name, const char* inode_xattr) {
+ ino_t inode = 0;
+ uint64_t inode_raw = 0;
+ auto fallback = StringPrintf("%s/%s", parent.c_str(), name);
+
+ // Lookup the inode value written earlier
+ if (getxattr(parent.c_str(), inode_xattr, &inode_raw, sizeof(inode_raw)) == sizeof(inode_raw)) {
+ inode = inode_raw;
+ }
+
+ // For testing purposes, rely on the inode when defined; this could be
+ // optimized to use access() in the future.
+ if (inode != 0) {
+ DIR* dir = opendir(parent.c_str());
+ if (dir == nullptr) {
+ PLOG(ERROR) << "Failed to opendir " << parent;
+ return fallback;
+ }
+
+ struct dirent* ent;
+ while ((ent = readdir(dir))) {
+ if (ent->d_ino == inode) {
+ auto resolved = StringPrintf("%s/%s", parent.c_str(), ent->d_name);
+#if DEBUG_XATTRS
+ if (resolved != fallback) {
+ LOG(DEBUG) << "Resolved path " << resolved << " for inode " << inode
+ << " instead of " << fallback;
+ }
+#endif
+ closedir(dir);
+ return resolved;
+ }
+ }
+ LOG(WARNING) << "Failed to resolve inode " << inode << "; using " << fallback;
+ closedir(dir);
+ return fallback;
+ } else {
+ return fallback;
+ }
+}
+
void add_cache_files(cache_t* cache, const std::string& data_path) {
DIR *d;
struct dirent *de;
@@ -796,7 +894,6 @@
if (de->d_type == DT_DIR) {
DIR* subdir;
const char *name = de->d_name;
- char* pathpos;
/* always skip "." and ".." */
if (name[0] == '.') {
@@ -804,16 +901,9 @@
if ((name[1] == '.') && (name[2] == 0)) continue;
}
- strcpy(dirname, basepath);
- pathpos = dirname + strlen(dirname);
- if ((*(pathpos-1)) != '/') {
- *pathpos = '/';
- pathpos++;
- *pathpos = 0;
- }
-
- // TODO: also try searching using xattr when CE is locked
- snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s/cache", name);
+ auto parent = StringPrintf("%s/%s", basepath, name);
+ auto resolved = read_path_inode(parent, "cache", kXattrInodeCache);
+ strcpy(dirname, resolved.c_str());
CACHE_NOISY(ALOGI("Adding cache files from dir: %s\n", dirname));
subdir = opendir(dirname);
@@ -931,16 +1021,16 @@
{
CACHE_NOISY(size_t i;)
- CACHE_NOISY(ALOGI("clear_cache_files: %d dirs, %d files\n", cache->numDirs, cache->numFiles));
+ CACHE_NOISY(ALOGI("clear_cache_files: %zu dirs, %zu files\n", cache->numDirs, cache->numFiles));
CACHE_NOISY(
for (i=0; i<cache->numDirs; i++) {
cache_dir_t* dir = cache->dirs[i];
- ALOGI("dir #%d: %p %s parent=%p\n", i, dir, dir->name, dir->parent);
+ ALOGI("dir #%zu: %p %s parent=%p\n", i, dir, dir->name, dir->parent);
})
CACHE_NOISY(
for (i=0; i<cache->numFiles; i++) {
cache_file_t* file = cache->files[i];
- ALOGI("file #%d: %p %s time=%d dir=%p\n", i, file, file->name,
+ ALOGI("file #%zu: %p %s time=%d dir=%p\n", i, file, file->name,
(int)file->modTime, file->dir);
})
void* block = cache->memBlocks;
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 60df356..8123e9b 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -62,6 +62,9 @@
int8_t* curMemBlockEnd;
} cache_t;
+constexpr const char* kXattrInodeCache = "user.inode_cache";
+constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
+
int create_pkg_path(char path[PKG_PATH_MAX],
const char *pkgname,
const char *postfix,
@@ -118,6 +121,11 @@
cache_t* start_cache_collection();
+int get_path_inode(const std::string& path, ino_t *inode);
+
+int write_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
+std::string read_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
+
void add_cache_files(cache_t* cache, const std::string& data_path);
void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size);
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index af26721..74a4123 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -137,6 +137,12 @@
* should be used */
virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0;
+ virtual status_t getDisplayColorModes(const sp<IBinder>& display,
+ Vector<android_color_mode_t>* outColorModes) = 0;
+ virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) = 0;
+ virtual status_t setActiveColorMode(const sp<IBinder>& display,
+ android_color_mode_t colorMode) = 0;
+
/* Capture the specified screen. requires READ_FRAME_BUFFER permission
* This function will fail if there is a secure window on screen.
*/
@@ -193,6 +199,9 @@
SET_POWER_MODE,
GET_DISPLAY_STATS,
GET_HDR_CAPABILITIES,
+ GET_DISPLAY_COLOR_MODES,
+ GET_ACTIVE_COLOR_MODE,
+ SET_ACTIVE_COLOR_MODE,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 95e8b70..b8ee331 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -83,6 +83,16 @@
// returned by getDisplayInfo
static status_t setActiveConfig(const sp<IBinder>& display, int id);
+ // Gets the list of supported color modes for the given display
+ static status_t getDisplayColorModes(const sp<IBinder>& display,
+ Vector<android_color_mode_t>* outColorModes);
+
+ // Gets the active color mode for the given display
+ static android_color_mode_t getActiveColorMode(const sp<IBinder>& display);
+
+ // Sets the active color mode for the given display
+ static status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode);
+
/* Triggers screen on/off or low power mode and waits for it to complete */
static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h
index 99a7622..88dd585 100644
--- a/include/media/openmax/OMX_Core.h
+++ b/include/media/openmax/OMX_Core.h
@@ -516,6 +516,9 @@
* but must signal the event no more than 40ms after the first frame in the batch. The frames
* must be ordered by system timestamp inside and across batches.
*
+ * The component shall signal the render-timestamp of the very first frame (as well as the
+ * first frame after each flush) unbatched (with nData1 set to 1) within 5 msec.
+ *
* If component is doing frame-rate conversion, it must signal the render time of each
* converted frame, and must interpolate media timestamps for in-between frames.
*
@@ -753,15 +756,21 @@
When the command is "OMX_CommandStateSet" the component will queue a
state transition to the new state idenfied in nParam.
+ The component shall transition from executing to loaded state within 500 msec.
+
When the command is "OMX_CommandFlush", to flush a port's buffer queues,
the command will force the component to return all buffers NOT CURRENTLY
BEING PROCESSED to the application, in the order in which the buffers
were received.
+ The component shall finish flusing each port within 5 msec.
+
When the command is "OMX_CommandPortDisable" or
"OMX_CommandPortEnable", the component's port (given by the value of
nParam) will be stopped or restarted.
+ The component shall finish disabling/reenabling each port within 5 msec.
+
When the command "OMX_CommandMarkBuffer" is used to mark a buffer, the
pCmdData will point to a OMX_MARKTYPE structure containing the component
handle of the component to examine the buffer chain for the mark. nParam1
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
index ad73ee7..799944f 100644
--- a/include/ui/DisplayInfo.h
+++ b/include/ui/DisplayInfo.h
@@ -36,7 +36,6 @@
bool secure;
nsecs_t appVsyncOffset;
nsecs_t presentationDeadline;
- int colorTransform;
};
/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index a8b4fa8..f0b0ada 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -32,6 +32,8 @@
#include <private/gui/LayerState.h>
+#include <system/graphics.h>
+
#include <ui/DisplayInfo.h>
#include <ui/DisplayStatInfo.h>
#include <ui/HdrCapabilities.h>
@@ -269,6 +271,82 @@
return reply.readInt32();
}
+ virtual status_t getDisplayColorModes(const sp<IBinder>& display,
+ Vector<android_color_mode_t>* outColorModes) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("getDisplayColorModes failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("getDisplayColorModes failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_COLOR_MODES, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getDisplayColorModes failed to transact: %d", result);
+ return result;
+ }
+ result = static_cast<status_t>(reply.readInt32());
+ if (result == NO_ERROR) {
+ size_t numModes = reply.readUint32();
+ outColorModes->clear();
+ outColorModes->resize(numModes);
+ for (size_t i = 0; i < numModes; ++i) {
+ outColorModes->replaceAt(static_cast<android_color_mode_t>(reply.readInt32()), i);
+ }
+ }
+ return result;
+ }
+
+ virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result);
+ return static_cast<android_color_mode_t>(result);
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result);
+ return static_cast<android_color_mode_t>(result);
+ }
+ result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getActiveColorMode failed to transact: %d", result);
+ return static_cast<android_color_mode_t>(result);
+ }
+ return static_cast<android_color_mode_t>(reply.readInt32());
+ }
+
+ virtual status_t setActiveColorMode(const sp<IBinder>& display,
+ android_color_mode_t colorMode) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("setActiveColorMode failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = data.writeInt32(colorMode);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveColorMode failed to writeInt32: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_COLOR_MODE, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveColorMode failed to transact: %d", result);
+ return result;
+ }
+ return static_cast<status_t>(reply.readInt32());
+ }
+
virtual status_t clearAnimationFrameStats() {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -469,6 +547,56 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case GET_DISPLAY_COLOR_MODES: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ Vector<android_color_mode_t> colorModes;
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("getDisplayColorModes failed to readStrongBinder: %d", result);
+ return result;
+ }
+ result = getDisplayColorModes(display, &colorModes);
+ reply->writeInt32(result);
+ if (result == NO_ERROR) {
+ reply->writeUint32(static_cast<uint32_t>(colorModes.size()));
+ for (size_t i = 0; i < colorModes.size(); ++i) {
+ reply->writeInt32(colorModes[i]);
+ }
+ }
+ return NO_ERROR;
+ }
+ case GET_ACTIVE_COLOR_MODE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("getActiveColorMode failed to readStrongBinder: %d", result);
+ return result;
+ }
+ android_color_mode_t colorMode = getActiveColorMode(display);
+ result = reply->writeInt32(static_cast<int32_t>(colorMode));
+ return result;
+ }
+ case SET_ACTIVE_COLOR_MODE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("getActiveColorMode failed to readStrongBinder: %d", result);
+ return result;
+ }
+ int32_t colorModeInt = 0;
+ result = data.readInt32(&colorModeInt);
+ if (result != NO_ERROR) {
+ ALOGE("setActiveColorMode failed to readInt32: %d", result);
+ return result;
+ }
+ result = setActiveColorMode(display,
+ static_cast<android_color_mode_t>(colorModeInt));
+ result = reply->writeInt32(result);
+ return result;
+ }
case CLEAR_ANIMATION_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
status_t result = clearAnimationFrameStats();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 26b2209..3df5f74 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -29,6 +29,8 @@
#include <binder/IMemory.h>
#include <binder/IServiceManager.h>
+#include <system/graphics.h>
+
#include <ui/DisplayInfo.h>
#include <gui/CpuConsumer.h>
@@ -771,6 +773,20 @@
return ComposerService::getComposerService()->setActiveConfig(display, id);
}
+status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
+ Vector<android_color_mode_t>* outColorModes) {
+ return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
+}
+
+android_color_mode_t SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
+ return ComposerService::getComposerService()->getActiveColorMode(display);
+}
+
+status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display,
+ android_color_mode_t colorMode) {
+ return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
+}
+
void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token,
int mode) {
ComposerService::getComposerService()->setPowerMode(token, mode);
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index ac37990..ee152bf 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -795,6 +795,11 @@
return NO_MEMORY;
}
+ if (numRects > (UINT32_MAX / sizeof(Rect))) {
+ android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0);
+ return NO_MEMORY;
+ }
+
Region result;
result.mStorage.clear();
for (size_t r = 0; r < numRects; ++r) {
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 7a0cce4..fcb9357 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -54,6 +54,8 @@
// Implementation is incomplete and untested.
#define ENABLE_EGL_KHR_GL_COLORSPACE 0
+#define ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS 0
+
// ----------------------------------------------------------------------------
namespace android {
@@ -84,7 +86,9 @@
"EGL_KHR_swap_buffers_with_damage "
"EGL_ANDROID_create_native_client_buffer "
"EGL_ANDROID_front_buffer_auto_refresh "
+#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
"EGL_ANDROID_get_frame_timestamps "
+#endif
;
extern char const * const gExtensionString =
"EGL_KHR_image " // mandatory
@@ -1212,10 +1216,12 @@
setError(EGL_BAD_SURFACE, EGL_FALSE);
}
+#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
if (attribute == EGL_TIMESTAMPS_ANDROID) {
s->enableTimestamps = value;
return EGL_TRUE;
}
+#endif
if (s->cnx->egl.eglSurfaceAttrib) {
return s->cnx->egl.eglSurfaceAttrib(
@@ -2036,6 +2042,7 @@
}
switch (timestamp) {
+#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
case EGL_QUEUE_TIME_ANDROID:
case EGL_RENDERING_COMPLETE_TIME_ANDROID:
case EGL_COMPOSITION_START_TIME_ANDROID:
@@ -2043,6 +2050,7 @@
case EGL_DISPLAY_RETIRE_TIME_ANDROID:
case EGL_READS_DONE_TIME_ANDROID:
return EGL_TRUE;
+#endif
default:
return EGL_FALSE;
}
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a67b3ff..5c2c0ad 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -415,6 +415,17 @@
}
// ----------------------------------------------------------------------------
+#ifdef USE_HWC2
+void DisplayDevice::setActiveColorMode(android_color_mode_t mode) {
+ mActiveColorMode = mode;
+}
+
+android_color_mode_t DisplayDevice::getActiveColorMode() const {
+ return mActiveColorMode;
+}
+#endif
+
+// ----------------------------------------------------------------------------
void DisplayDevice::setLayerStack(uint32_t stack) {
mLayerStack = stack;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index dd9b104..105e980 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -182,6 +182,11 @@
void setPowerMode(int mode);
bool isDisplayOn() const;
+#ifdef USE_HWC2
+ android_color_mode_t getActiveColorMode() const;
+ void setActiveColorMode(android_color_mode_t mode);
+#endif
+
/* ------------------------------------------------------------------------
* Display active config management.
*/
@@ -252,6 +257,10 @@
int mPowerMode;
// Current active config
int mActiveConfig;
+#ifdef USE_HWC2
+ // current active color mode
+ android_color_mode_t mActiveColorMode;
+#endif
};
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index ed8cc08..4fe3cfd 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -149,7 +149,12 @@
}
for (auto element : mDisplays) {
- auto display = element.second;
+ auto display = element.second.lock();
+ if (!display) {
+ ALOGE("~Device: Found a display (%" PRId64 " that has already been"
+ " destroyed", element.first);
+ continue;
+ }
DisplayType displayType = HWC2::DisplayType::Invalid;
auto error = display->getType(&displayType);
@@ -208,6 +213,10 @@
ALOGI("Created virtual display");
*format = static_cast<android_pixel_format_t>(intFormat);
*outDisplay = getDisplayById(displayId);
+ if (!*outDisplay) {
+ ALOGE("Failed to get display by id");
+ return Error::BadDisplay;
+ }
(*outDisplay)->setVirtual();
return Error::None;
}
@@ -289,7 +298,10 @@
std::shared_ptr<Display> Device::getDisplayById(hwc2_display_t id) {
if (mDisplays.count(id) != 0) {
- return mDisplays.at(id);
+ auto strongDisplay = mDisplays[id].lock();
+ ALOGE_IF(!strongDisplay, "Display %" PRId64 " is in mDisplays but is no"
+ " longer alive", id);
+ return strongDisplay;
}
auto display = std::make_shared<Display>(*this, id);
@@ -305,9 +317,12 @@
"Capability size has changed");
uint32_t numCapabilities = 0;
mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, nullptr);
- mCapabilities.resize(numCapabilities);
- auto asInt = reinterpret_cast<int32_t*>(mCapabilities.data());
+ std::vector<Capability> capabilities(numCapabilities);
+ auto asInt = reinterpret_cast<int32_t*>(capabilities.data());
mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, asInt);
+ for (auto capability : capabilities) {
+ mCapabilities.emplace(capability);
+ }
}
bool Device::hasCapability(HWC2::Capability capability) const
@@ -430,6 +445,7 @@
auto error = static_cast<Error>(intError);
ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:"
" %s (%d)", display, to_string(error).c_str(), intError);
+ mDisplays.erase(display);
}
// Display methods
@@ -565,7 +581,7 @@
return Error::None;
}
-Error Display::getColorModes(std::vector<int32_t>* outModes) const
+Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const
{
uint32_t numModes = 0;
int32_t intError = mDevice.mGetColorModes(mDevice.mHwcDevice, mId,
@@ -583,7 +599,10 @@
return error;
}
- std::swap(*outModes, modes);
+ outModes->resize(numModes);
+ for (size_t i = 0; i < numModes; i++) {
+ (*outModes)[i] = static_cast<android_color_mode_t>(modes[i]);
+ }
return Error::None;
}
@@ -789,7 +808,7 @@
return static_cast<Error>(intError);
}
-Error Display::setColorMode(int32_t mode)
+Error Display::setColorMode(android_color_mode_t mode)
{
int32_t intError = mDevice.mSetColorMode(mDevice.mHwcDevice, mId, mode);
return static_cast<Error>(intError);
@@ -810,6 +829,7 @@
auto handle = buffer->getNativeBuffer()->handle;
int32_t intError = mDevice.mSetOutputBuffer(mDevice.mHwcDevice, mId, handle,
fenceFd);
+ close(fenceFd);
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 8ab61e9..fb04af8 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -33,6 +33,7 @@
#include <functional>
#include <string>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
namespace android {
@@ -66,7 +67,7 @@
std::string dump() const;
- const std::vector<Capability>& getCapabilities() const {
+ const std::unordered_set<Capability>& getCapabilities() const {
return mCapabilities;
};
@@ -88,7 +89,8 @@
// Other Device methods
// This will create a Display if one is not found, but it will not be marked
- // as connected
+ // as connected. This Display may be null if the display has been torn down
+ // but has not been removed from the map yet.
std::shared_ptr<Display> getDisplayById(hwc2_display_t id);
bool hasCapability(HWC2::Capability capability) const;
@@ -180,8 +182,8 @@
HWC2_PFN_SET_LAYER_VISIBLE_REGION mSetLayerVisibleRegion;
HWC2_PFN_SET_LAYER_Z_ORDER mSetLayerZOrder;
- std::vector<Capability> mCapabilities;
- std::unordered_map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+ std::unordered_set<Capability> mCapabilities;
+ std::unordered_map<hwc2_display_t, std::weak_ptr<Display>> mDisplays;
HotplugCallback mHotplug;
std::vector<std::pair<std::shared_ptr<Display>, Connection>>
@@ -280,7 +282,7 @@
[[clang::warn_unused_result]] Error getChangedCompositionTypes(
std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes);
[[clang::warn_unused_result]] Error getColorModes(
- std::vector<int32_t>* outModes) const;
+ std::vector<android_color_mode_t>* outModes) const;
// Doesn't call into the HWC2 device, so no errors are possible
std::vector<std::shared_ptr<const Config>> getConfigs() const;
@@ -305,7 +307,7 @@
buffer_handle_t target,
const android::sp<android::Fence>& acquireFence,
android_dataspace_t dataspace);
- [[clang::warn_unused_result]] Error setColorMode(int32_t mode);
+ [[clang::warn_unused_result]] Error setColorMode(android_color_mode_t mode);
[[clang::warn_unused_result]] Error setColorTransform(
const android::mat4& matrix, android_color_transform_t hint);
[[clang::warn_unused_result]] Error setOutputBuffer(
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
index e739ef4..8bcee39 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
@@ -75,7 +75,7 @@
using namespace HWC2;
-static constexpr Attribute ColorTransform = static_cast<Attribute>(6);
+static constexpr Attribute ColorMode = static_cast<Attribute>(6);
namespace android {
@@ -268,9 +268,7 @@
&Display::setClientTarget, buffer_handle_t, int32_t,
int32_t, hwc_region_t>);
case FunctionDescriptor::SetColorMode:
- return asFP<HWC2_PFN_SET_COLOR_MODE>(
- displayHook<decltype(&Display::setColorMode),
- &Display::setColorMode, int32_t>);
+ return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook);
case FunctionDescriptor::SetColorTransform:
return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook);
case FunctionDescriptor::SetOutputBuffer:
@@ -894,7 +892,7 @@
return Error::None;
}
-Error HWC2On1Adapter::Display::setColorMode(int32_t mode)
+Error HWC2On1Adapter::Display::setColorMode(android_color_mode_t mode)
{
std::unique_lock<std::recursive_mutex> lock (mStateMutex);
@@ -1198,11 +1196,14 @@
newConfig->setAttribute(Attribute::DpiY,
values[attributeMap[HWC_DISPLAY_DPI_Y]]);
if (hasColor) {
- newConfig->setAttribute(ColorTransform,
+ // In HWC1, color modes are referred to as color transforms. To avoid confusion with
+ // the HWC2 concept of color transforms, we internally refer to them as color modes for
+ // both HWC1 and 2.
+ newConfig->setAttribute(ColorMode,
values[attributeMap[HWC_DISPLAY_COLOR_TRANSFORM]]);
}
- // We can only do this after attempting to read the color transform
+ // We can only do this after attempting to read the color mode
newConfig->setHwc1Id(hwc1ConfigId);
for (auto& existingConfig : mConfigs) {
@@ -1678,8 +1679,8 @@
void HWC2On1Adapter::Display::Config::setHwc1Id(uint32_t id)
{
- int32_t colorTransform = getAttribute(ColorTransform);
- mHwc1Ids.emplace(colorTransform, id);
+ android_color_mode_t colorMode = static_cast<android_color_mode_t>(getAttribute(ColorMode));
+ mHwc1Ids.emplace(colorMode, id);
}
bool HWC2On1Adapter::Display::Config::hasHwc1Id(uint32_t id) const
@@ -1692,18 +1693,20 @@
return false;
}
-int32_t HWC2On1Adapter::Display::Config::getColorModeForHwc1Id(
- uint32_t id) const
+Error HWC2On1Adapter::Display::Config::getColorModeForHwc1Id(
+ uint32_t id, android_color_mode_t* outMode) const
{
for (const auto& idPair : mHwc1Ids) {
if (id == idPair.second) {
- return idPair.first;
+ *outMode = idPair.first;
+ return Error::None;
}
}
- return -1;
+ ALOGE("Unable to find color mode for HWC ID %" PRIu32 " on config %u", id, mId);
+ return Error::BadParameter;
}
-Error HWC2On1Adapter::Display::Config::getHwc1IdForColorMode(int32_t mode,
+Error HWC2On1Adapter::Display::Config::getHwc1IdForColorMode(android_color_mode_t mode,
uint32_t* outId) const
{
for (const auto& idPair : mHwc1Ids) {
@@ -1726,25 +1729,26 @@
return false;
}
}
- int32_t otherColorTransform = other.getAttribute(ColorTransform);
- if (mHwc1Ids.count(otherColorTransform) != 0) {
+ android_color_mode_t otherColorMode =
+ static_cast<android_color_mode_t>(other.getAttribute(ColorMode));
+ if (mHwc1Ids.count(otherColorMode) != 0) {
ALOGE("Attempted to merge two configs (%u and %u) which appear to be "
- "identical", mHwc1Ids.at(otherColorTransform),
- other.mHwc1Ids.at(otherColorTransform));
+ "identical", mHwc1Ids.at(otherColorMode),
+ other.mHwc1Ids.at(otherColorMode));
return false;
}
- mHwc1Ids.emplace(otherColorTransform,
- other.mHwc1Ids.at(otherColorTransform));
+ mHwc1Ids.emplace(otherColorMode,
+ other.mHwc1Ids.at(otherColorMode));
return true;
}
-std::set<int32_t> HWC2On1Adapter::Display::Config::getColorTransforms() const
+std::set<android_color_mode_t> HWC2On1Adapter::Display::Config::getColorModes() const
{
- std::set<int32_t> colorTransforms;
+ std::set<android_color_mode_t> colorModes;
for (const auto& idPair : mHwc1Ids) {
- colorTransforms.emplace(idPair.first);
+ colorModes.emplace(idPair.first);
}
- return colorTransforms;
+ return colorModes;
}
std::string HWC2On1Adapter::Display::Config::toString(bool splitLine) const
@@ -1787,15 +1791,15 @@
for (const auto& id : mHwc1Ids) {
- int32_t colorTransform = id.first;
+ android_color_mode_t colorMode = id.first;
uint32_t hwc1Id = id.second;
std::memset(buffer, 0, BUFFER_SIZE);
- if (colorTransform == mDisplay.mActiveColorMode) {
+ if (colorMode == mDisplay.mActiveColorMode) {
writtenBytes = snprintf(buffer, BUFFER_SIZE, " [%u/%d]", hwc1Id,
- colorTransform);
+ colorMode);
} else {
writtenBytes = snprintf(buffer, BUFFER_SIZE, " %u/%d", hwc1Id,
- colorTransform);
+ colorMode);
}
output.append(buffer, writtenBytes);
}
@@ -1814,10 +1818,10 @@
void HWC2On1Adapter::Display::populateColorModes()
{
- mColorModes = mConfigs[0]->getColorTransforms();
+ mColorModes = mConfigs[0]->getColorModes();
for (const auto& config : mConfigs) {
- std::set<int32_t> intersection;
- auto configModes = config->getColorTransforms();
+ std::set<android_color_mode_t> intersection;
+ auto configModes = config->getColorModes();
std::set_intersection(mColorModes.cbegin(), mColorModes.cend(),
configModes.cbegin(), configModes.cend(),
std::inserter(intersection, intersection.begin()));
@@ -1830,7 +1834,7 @@
if (mDevice.mHwc1Device->getActiveConfig == nullptr) {
ALOGV("getActiveConfig is null, choosing config 0");
mActiveConfig = mConfigs[0];
- mActiveColorMode = -1;
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
return;
}
@@ -1842,7 +1846,13 @@
ALOGV("Setting active config to %d for HWC1 config %u",
config->getId(), activeConfig);
mActiveConfig = config;
- mActiveColorMode = config->getColorModeForHwc1Id(activeConfig);
+ if (config->getColorModeForHwc1Id(activeConfig, &mActiveColorMode) != Error::None) {
+ // This should never happen since we checked for the config's presence before
+ // setting it as active.
+ ALOGE("Unable to find color mode for active HWC1 config %d",
+ config->getId());
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ }
break;
}
}
@@ -1850,7 +1860,7 @@
ALOGV("Unable to find active HWC1 config %u, defaulting to "
"config 0", activeConfig);
mActiveConfig = mConfigs[0];
- mActiveColorMode = -1;
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
}
}
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
index dc7c355..bdacc73 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
@@ -213,7 +213,7 @@
HWC2::Error setClientTarget(buffer_handle_t target,
int32_t acquireFence, int32_t dataspace,
hwc_region_t damage);
- HWC2::Error setColorMode(int32_t mode);
+ HWC2::Error setColorMode(android_color_mode_t mode);
HWC2::Error setColorTransform(android_color_transform_t hint);
HWC2::Error setOutputBuffer(buffer_handle_t buffer,
int32_t releaseFence);
@@ -258,8 +258,9 @@
void setHwc1Id(uint32_t id);
bool hasHwc1Id(uint32_t id) const;
- int32_t getColorModeForHwc1Id(uint32_t id) const;
- HWC2::Error getHwc1IdForColorMode(int32_t mode,
+ HWC2::Error getColorModeForHwc1Id(uint32_t id,
+ android_color_mode_t *outMode) const;
+ HWC2::Error getHwc1IdForColorMode(android_color_mode_t mode,
uint32_t* outId) const;
void setId(hwc2_config_t id) { mId = id; }
@@ -269,7 +270,7 @@
// mode. Returns whether the merge was successful
bool merge(const Config& other);
- std::set<int32_t> getColorTransforms() const;
+ std::set<android_color_mode_t> getColorModes() const;
// splitLine divides the output into two lines suitable for
// dumpsys SurfaceFlinger
@@ -281,7 +282,7 @@
std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
// Maps from color transform to HWC1 config ID
- std::unordered_map<int32_t, uint32_t> mHwc1Ids;
+ std::unordered_map<android_color_mode_t, uint32_t> mHwc1Ids;
};
class Changes {
@@ -378,8 +379,8 @@
std::vector<std::shared_ptr<Config>> mConfigs;
std::shared_ptr<const Config> mActiveConfig;
- std::set<int32_t> mColorModes;
- int32_t mActiveColorMode;
+ std::set<android_color_mode_t> mColorModes;
+ android_color_mode_t mActiveColorMode;
std::string mName;
HWC2::DisplayType mType;
HWC2::PowerMode mPowerMode;
@@ -432,6 +433,12 @@
hint);
}
+ static int32_t setColorModeHook(hwc2_device_t* device,
+ hwc2_display_t display, int32_t /*android_color_mode_t*/ intMode) {
+ auto mode = static_cast<android_color_mode_t>(intMode);
+ return callDisplayFunction(device, display, &Display::setColorMode, mode);
+ }
+
static int32_t setPowerModeHook(hwc2_device_t* device,
hwc2_display_t display, int32_t intMode) {
auto mode = static_cast<HWC2::PowerMode>(intMode);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 133e5f1..c87ba72 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -144,6 +144,11 @@
mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
}
+bool HWComposer::hasCapability(HWC2::Capability capability) const
+{
+ return mHwcDevice->getCapabilities().count(capability) > 0;
+}
+
bool HWComposer::isValidDisplay(int32_t displayId) const {
return static_cast<size_t>(displayId) < mDisplayData.size() &&
mDisplayData[displayId].hwcDisplay;
@@ -359,8 +364,8 @@
return config;
}
-std::vector<int32_t> HWComposer::getColorModes(int32_t displayId) const {
- std::vector<int32_t> modes;
+std::vector<android_color_mode_t> HWComposer::getColorModes(int32_t displayId) const {
+ std::vector<android_color_mode_t> modes;
if (!isValidDisplay(displayId)) {
ALOGE("getColorModes: Attempted to access invalid display %d",
@@ -374,12 +379,31 @@
if (error != HWC2::Error::None) {
ALOGE("getColorModes failed for display %d: %s (%d)", displayId,
to_string(error).c_str(), static_cast<int32_t>(error));
- return std::vector<int32_t>();
+ return std::vector<android_color_mode_t>();
}
return modes;
}
+status_t HWComposer::setActiveColorMode(int32_t displayId, android_color_mode_t mode) {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("setActiveColorMode: Display %d is not valid", displayId);
+ return BAD_INDEX;
+ }
+
+ auto& displayData = mDisplayData[displayId];
+ auto error = displayData.hwcDisplay->setColorMode(mode);
+ if (error != HWC2::Error::None) {
+ ALOGE("setActiveConfig: Failed to set color mode %d on display %d: "
+ "%s (%d)", mode, displayId, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
void HWComposer::setVsyncEnabled(int32_t disp, HWC2::Vsync enabled) {
if (disp < 0 || disp >= HWC_DISPLAY_VIRTUAL) {
ALOGD("setVsyncEnabled: Ignoring for virtual display %d", disp);
@@ -443,6 +467,10 @@
Mutex::Autolock _l(mDisplayLock);
auto displayId = displayDevice.getHwcDisplayId();
+ if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ ALOGV("Skipping HWComposer prepare for non-HWC display");
+ return NO_ERROR;
+ }
if (!isValidDisplay(displayId)) {
return BAD_INDEX;
}
@@ -536,6 +564,11 @@
}
bool HWComposer::hasDeviceComposition(int32_t displayId) const {
+ if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ // Displays without a corresponding HWC display are never composed by
+ // the device
+ return false;
+ }
if (!isValidDisplay(displayId)) {
ALOGE("hasDeviceComposition: Invalid display %d", displayId);
return false;
@@ -544,6 +577,11 @@
}
bool HWComposer::hasClientComposition(int32_t displayId) const {
+ if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ // Displays without a corresponding HWC display are always composed by
+ // the client
+ return true;
+ }
if (!isValidDisplay(displayId)) {
ALOGE("hasClientComposition: Invalid display %d", displayId);
return true;
@@ -692,6 +730,28 @@
return NO_ERROR;
}
+status_t HWComposer::setColorTransform(int32_t displayId,
+ const mat4& transform) {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("setColorTransform: Display %d is not valid", displayId);
+ return BAD_INDEX;
+ }
+
+ auto& displayData = mDisplayData[displayId];
+ bool isIdentity = transform == mat4();
+ auto error = displayData.hwcDisplay->setColorTransform(transform,
+ isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY :
+ HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX);
+ if (error != HWC2::Error::None) {
+ ALOGE("setColorTransform: Failed to set transform on display %d: "
+ "%s (%d)", displayId, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
void HWComposer::disconnectDisplay(int displayId) {
LOG_ALWAYS_FATAL_IF(displayId < 0);
auto& displayData = mDisplayData[displayId];
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index aa233df..41671f6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -81,6 +81,8 @@
void setEventHandler(EventHandler* handler);
+ bool hasCapability(HWC2::Capability capability) const;
+
// Attempts to allocate a virtual display. If the virtual display is created
// on the HWC device, outId will contain its HWC ID.
status_t allocateVirtualDisplay(uint32_t width, uint32_t height,
@@ -104,6 +106,9 @@
// set active config
status_t setActiveConfig(int32_t displayId, size_t configId);
+ // Sets a color transform to be applied to the result of composition
+ status_t setColorTransform(int32_t displayId, const mat4& transform);
+
// reset state when an external, non-virtual display is disconnected
void disconnectDisplay(int32_t displayId);
@@ -149,7 +154,9 @@
std::shared_ptr<const HWC2::Display::Config>
getActiveConfig(int32_t displayId) const;
- std::vector<int32_t> getColorModes(int32_t displayId) const;
+ std::vector<android_color_mode_t> getColorModes(int32_t displayId) const;
+
+ status_t setActiveColorMode(int32_t displayId, android_color_mode_t mode);
// for debugging ----------------------------------------------------------
void dump(String8& out) const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
index 4afd8a2..ef41658 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -42,6 +42,8 @@
#include <cutils/log.h>
#include <cutils/properties.h>
+#include <system/graphics.h>
+
#include "HWComposer.h"
#include "../Layer.h" // needed only for debugging
@@ -403,7 +405,7 @@
config.ydpi = values[i] / 1000.0f;
break;
case HWC_DISPLAY_COLOR_TRANSFORM:
- config.colorTransform = values[i];
+ config.colorMode = static_cast<android_color_mode_t>(values[i]);
break;
default:
ALOG_ASSERT(false, "unknown display attribute[%zu] %#x",
@@ -519,6 +521,11 @@
return mDisplayData[disp].configs[currentConfig].refresh;
}
+android_color_mode_t HWComposer::getColorMode(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].colorMode;
+}
+
const Vector<HWComposer::DisplayConfig>& HWComposer::getConfigs(int disp) const {
return mDisplayData[disp].configs;
}
@@ -1182,10 +1189,10 @@
for (size_t c = 0; c < disp.configs.size(); ++c) {
const DisplayConfig& config(disp.configs[c]);
result.appendFormat(" %s%zd: %ux%u, xdpi=%f, ydpi=%f"
- ", refresh=%" PRId64 ", colorTransform=%d\n",
+ ", refresh=%" PRId64 ", colorMode=%d\n",
c == disp.currentConfig ? "* " : "", c,
config.width, config.height, config.xdpi, config.ydpi,
- config.refresh, config.colorTransform);
+ config.refresh, config.colorMode);
}
if (disp.list) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
index c861817..170e382 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -22,6 +22,8 @@
#include <hardware/hwcomposer_defs.h>
+#include <system/graphics.h>
+
#include <ui/Fence.h>
#include <utils/BitSet.h>
@@ -257,7 +259,15 @@
float xdpi;
float ydpi;
nsecs_t refresh;
- int colorTransform;
+ android_color_mode_t colorMode;
+ bool operator==(const DisplayConfig& rhs) const {
+ return width == rhs.width &&
+ height == rhs.height &&
+ xdpi == rhs.xdpi &&
+ ydpi == rhs.ydpi &&
+ refresh == rhs.refresh &&
+ colorMode == rhs.colorMode;
+ }
};
// Query display parameters. Pass in a display index (e.g.
@@ -274,6 +284,7 @@
float getDpiX(int disp) const;
float getDpiY(int disp) const;
nsecs_t getRefreshPeriod(int disp) const;
+ android_color_mode_t getColorMode(int disp) const;
const Vector<DisplayConfig>& getConfigs(int disp) const;
size_t getCurrentConfig(int disp) const;
diff --git a/services/surfaceflinger/Effects/Daltonizer.cpp b/services/surfaceflinger/Effects/Daltonizer.cpp
index feb8936..a104e8f 100644
--- a/services/surfaceflinger/Effects/Daltonizer.cpp
+++ b/services/surfaceflinger/Effects/Daltonizer.cpp
@@ -19,21 +19,14 @@
namespace android {
-Daltonizer::Daltonizer() :
- mType(deuteranomaly), mMode(simulation), mDirty(true) {
-}
-
-Daltonizer::~Daltonizer() {
-}
-
-void Daltonizer::setType(Daltonizer::ColorBlindnessTypes type) {
+void Daltonizer::setType(ColorBlindnessType type) {
if (type != mType) {
mDirty = true;
mType = type;
}
}
-void Daltonizer::setMode(Daltonizer::Mode mode) {
+void Daltonizer::setMode(ColorBlindnessMode mode) {
if (mode != mMode) {
mDirty = true;
mMode = mode;
@@ -49,6 +42,11 @@
}
void Daltonizer::update() {
+ if (mType == ColorBlindnessType::None) {
+ mColorTransform = mat4();
+ return;
+ }
+
// converts a linear RGB color to the XYZ space
const mat4 rgb2xyz( 0.4124, 0.2126, 0.0193, 0,
0.3576, 0.7152, 0.1192, 0,
@@ -149,24 +147,25 @@
mat4 correction(0);
switch (mType) {
- case protanopia:
- case protanomaly:
+ case ColorBlindnessType::Protanomaly:
simulation = lms2lmsp;
- if (mMode == Daltonizer::correction)
+ if (mMode == ColorBlindnessMode::Correction)
correction = errp;
break;
- case deuteranopia:
- case deuteranomaly:
+ case ColorBlindnessType::Deuteranomaly:
simulation = lms2lmsd;
- if (mMode == Daltonizer::correction)
+ if (mMode == ColorBlindnessMode::Correction)
correction = errd;
break;
- case tritanopia:
- case tritanomaly:
+ case ColorBlindnessType::Tritanomaly:
simulation = lms2lmst;
- if (mMode == Daltonizer::correction)
+ if (mMode == ColorBlindnessMode::Correction)
correction = errt;
break;
+ case ColorBlindnessType::None:
+ // We already caught this at the beginning of the method, but the
+ // compiler doesn't know that
+ break;
}
mColorTransform = lms2rgb *
diff --git a/services/surfaceflinger/Effects/Daltonizer.h b/services/surfaceflinger/Effects/Daltonizer.h
index e816437..d21b155 100644
--- a/services/surfaceflinger/Effects/Daltonizer.h
+++ b/services/surfaceflinger/Effects/Daltonizer.h
@@ -21,27 +21,22 @@
namespace android {
+enum class ColorBlindnessType {
+ None, // Disables the Daltonizer
+ Protanomaly, // L (red) cone deficient
+ Deuteranomaly, // M (green) cone deficient (most common)
+ Tritanomaly // S (blue) cone deficient
+};
+
+enum class ColorBlindnessMode {
+ Simulation,
+ Correction
+};
+
class Daltonizer {
public:
- enum ColorBlindnessTypes {
- protanopia, // L (red) cone missing
- deuteranopia, // M (green) cone missing
- tritanopia, // S (blue) cone missing
- protanomaly, // L (red) cone deficient
- deuteranomaly, // M (green) cone deficient (most common)
- tritanomaly // S (blue) cone deficient
- };
-
- enum Mode {
- simulation,
- correction
- };
-
- Daltonizer();
- ~Daltonizer();
-
- void setType(ColorBlindnessTypes type);
- void setMode(Mode mode);
+ void setType(ColorBlindnessType type);
+ void setMode(ColorBlindnessMode mode);
// returns the color transform to apply in the shader
const mat4& operator()();
@@ -49,9 +44,9 @@
private:
void update();
- ColorBlindnessTypes mType;
- Mode mMode;
- bool mDirty;
+ ColorBlindnessType mType = ColorBlindnessType::None;
+ ColorBlindnessMode mMode = ColorBlindnessMode::Simulation;
+ bool mDirty = true;
mat4 mColorTransform;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 548b048..4d04072 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -51,6 +51,8 @@
#include "RenderEngine/RenderEngine.h"
+#include <mutex>
+
#define DEBUG_RESIZE 0
namespace android {
@@ -1056,8 +1058,13 @@
}
HWC2::Composition Layer::getCompositionType(int32_t hwcId) const {
+ if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+ // If we're querying the composition type for a display that does not
+ // have a HWC counterpart, then it will always be Client
+ return HWC2::Composition::Client;
+ }
if (mHwcLayers.count(hwcId) == 0) {
- ALOGE("getCompositionType called without a valid HWC layer");
+ ALOGE("getCompositionType called with an invalid HWC layer");
return HWC2::Composition::Invalid;
}
return mHwcLayers.at(hwcId).compositionType;
@@ -1091,6 +1098,20 @@
return static_cast<uint32_t>(producerStickyTransform);
}
+bool Layer::latchUnsignaledBuffers() {
+ static bool propertyLoaded = false;
+ static bool latch = false;
+ static std::mutex mutex;
+ std::lock_guard<std::mutex> lock(mutex);
+ if (!propertyLoaded) {
+ char value[PROPERTY_VALUE_MAX] = {};
+ property_get("debug.sf.latch_unsignaled", value, "0");
+ latch = atoi(value);
+ propertyLoaded = true;
+ }
+ return latch;
+}
+
uint64_t Layer::getHeadFrameNumber() const {
Mutex::Autolock lock(mQueueItemLock);
if (!mQueueItems.empty()) {
@@ -1102,6 +1123,10 @@
bool Layer::headFenceHasSignaled() const {
#ifdef USE_HWC2
+ if (latchUnsignaledBuffers()) {
+ return true;
+ }
+
Mutex::Autolock lock(mQueueItemLock);
if (mQueueItems.empty()) {
return true;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 78a8427..c070539 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -465,6 +465,9 @@
// Temporary - Used only for LEGACY camera mode.
uint32_t getProducerStickyTransform() const;
+ // Loads the corresponding system property once per process
+ static bool latchUnsignaledBuffers();
+
// -----------------------------------------------------------------------
class SyncPoint
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e5d5ebe..e2bd19f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -152,7 +152,6 @@
mPrimaryDispSync("PrimaryDispSync"),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
- mDaltonize(false),
mHasColorMatrix(false),
mHasPoweredOff(false),
mFrameBuckets(),
@@ -180,6 +179,10 @@
}
ALOGI_IF(mDebugRegion, "showupdates enabled");
ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
+
+ property_get("debug.sf.disable_backpressure", value, "0");
+ mPropagateBackpressure = !atoi(value);
+ ALOGI_IF(!mPropagateBackpressure, "Disabling backpressure propagation");
}
void SurfaceFlinger::onFirstRef()
@@ -632,18 +635,7 @@
// All non-virtual displays are currently considered secure.
info.secure = true;
- // DisplayManager expects each color mode to be its own display
- // info record.
- std::vector<int32_t> modes = getHwComposer().getColorModes(type);
-
- if (modes.size() == 0) {
- info.colorTransform = 0;
- configs->push_back(info);
- }
- for (int32_t mode : modes) {
- info.colorTransform = mode;
- configs->push_back(info);
- }
+ configs->push_back(info);
}
return NO_ERROR;
@@ -705,6 +697,7 @@
if (mMode < 0 || mMode >= static_cast<int>(configs.size())) {
ALOGE("Attempt to set active config = %d for display with %zu configs",
mMode, configs.size());
+ return true;
}
sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
if (hw == NULL) {
@@ -723,6 +716,101 @@
postMessageSync(msg);
return NO_ERROR;
}
+status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
+ Vector<android_color_mode_t>* outColorModes) {
+ if ((outColorModes == nullptr) || (display.get() == nullptr)) {
+ return BAD_VALUE;
+ }
+
+ if (!display.get()) {
+ return NAME_NOT_FOUND;
+ }
+
+ int32_t type = NAME_NOT_FOUND;
+ for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
+ if (display == mBuiltinDisplays[i]) {
+ type = i;
+ break;
+ }
+ }
+
+ if (type < 0) {
+ return type;
+ }
+
+ std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type);
+ outColorModes->clear();
+ std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
+
+ return NO_ERROR;
+}
+
+android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
+ sp<DisplayDevice> device(getDisplayDevice(display));
+ if (device != nullptr) {
+ return device->getActiveColorMode();
+ }
+ return static_cast<android_color_mode_t>(BAD_VALUE);
+}
+
+void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
+ android_color_mode_t mode) {
+ ALOGD("Set active color mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
+ this);
+ int32_t type = hw->getDisplayType();
+ android_color_mode_t currentMode = hw->getActiveColorMode();
+
+ if (mode == currentMode) {
+ ALOGD("Screen type=%d is already in color mode=%d", hw->getDisplayType(), mode);
+ return;
+ }
+
+ if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ ALOGW("Trying to set config for virtual display");
+ return;
+ }
+
+ hw->setActiveColorMode(mode);
+ getHwComposer().setActiveColorMode(type, mode);
+}
+
+
+status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
+ android_color_mode_t colorMode) {
+ class MessageSetActiveColorMode: public MessageBase {
+ SurfaceFlinger& mFlinger;
+ sp<IBinder> mDisplay;
+ android_color_mode_t mMode;
+ public:
+ MessageSetActiveColorMode(SurfaceFlinger& flinger, const sp<IBinder>& disp,
+ android_color_mode_t mode) :
+ mFlinger(flinger), mDisplay(disp) { mMode = mode; }
+ virtual bool handler() {
+ Vector<android_color_mode_t> modes;
+ mFlinger.getDisplayColorModes(mDisplay, &modes);
+ bool exists = std::find(std::begin(modes), std::end(modes), mMode) != std::end(modes);
+ if (mMode < 0 || !exists) {
+ ALOGE("Attempt to set invalid active color mode = %d for display %p", mMode,
+ mDisplay.get());
+ return true;
+ }
+ sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
+ if (hw == nullptr) {
+ ALOGE("Attempt to set active color mode = %d for null display %p",
+ mMode, mDisplay.get());
+ } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
+ ALOGW("Attempt to set active color mode= %d for virtual display",
+ mMode);
+ } else {
+ mFlinger.setActiveColorModeInternal(hw, mMode);
+ }
+ return true;
+ }
+ };
+ sp<MessageBase> msg = new MessageSetActiveColorMode(*this, display, colorMode);
+ postMessageSync(msg);
+ return NO_ERROR;
+}
status_t SurfaceFlinger::clearAnimationFrameStats() {
Mutex::Autolock _l(mStateLock);
@@ -925,7 +1013,7 @@
mPreviousPresentFence != Fence::NO_FENCE &&
mPreviousPresentFence->getSignalTime() == INT64_MAX;
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
- if (frameMissed) {
+ if (mPropagateBackpressure && frameMissed) {
signalLayerUpdate();
break;
}
@@ -975,7 +1063,13 @@
postComposition(refreshStartTime);
mPreviousPresentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY);
- mHadClientComposition = mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY);
+
+ mHadClientComposition = false;
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
+ mHadClientComposition = mHadClientComposition ||
+ mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
+ }
// Release any buffers which were replaced this frame
for (auto& layer : mLayersWithQueuedFrames) {
@@ -1224,8 +1318,7 @@
}
layer->setGeometry(displayDevice);
- if (mDebugDisableHWC || mDebugRegion || mDaltonize ||
- mHasColorMatrix) {
+ if (mDebugDisableHWC || mDebugRegion) {
layer->forceClientComposition(hwcId);
}
}
@@ -1233,6 +1326,9 @@
}
}
+
+ mat4 colorMatrix = mColorMatrix * mDaltonizer();
+
// Set the per-frame data
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
auto& displayDevice = mDisplays[displayId];
@@ -1240,11 +1336,18 @@
if (hwcId < 0) {
continue;
}
+ if (colorMatrix != mPreviousColorMatrix) {
+ status_t result = mHwc->setColorTransform(hwcId, colorMatrix);
+ ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
+ "display %zd: %d", displayId, result);
+ }
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
layer->setPerFrameData(displayDevice);
}
}
+ mPreviousColorMatrix = colorMatrix;
+
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
auto& displayDevice = mDisplays[displayId];
if (!displayDevice->isDisplayOn()) {
@@ -1926,18 +2029,7 @@
}
}
- if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) {
- if (!doComposeSurfaces(hw, dirtyRegion)) return;
- } else {
- RenderEngine& engine(getRenderEngine());
- mat4 colorMatrix = mColorMatrix;
- if (mDaltonize) {
- colorMatrix = colorMatrix * mDaltonizer();
- }
- mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
- doComposeSurfaces(hw, dirtyRegion);
- engine.setupColorTransform(oldMatrix);
- }
+ if (!doComposeSurfaces(hw, dirtyRegion)) return;
// update the swap region and clear the dirty region
hw->swapRegion.orSelf(dirtyRegion);
@@ -1952,6 +2044,15 @@
ALOGV("doComposeSurfaces");
const auto hwcId = displayDevice->getHwcDisplayId();
+
+ mat4 oldColorMatrix;
+ const bool applyColorMatrix = !mHwc->hasDeviceComposition(hwcId) &&
+ !mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform);
+ if (applyColorMatrix) {
+ mat4 colorMatrix = mColorMatrix * mDaltonizer();
+ oldColorMatrix = getRenderEngine().setupColorTransform(colorMatrix);
+ }
+
bool hasClientComposition = mHwc->hasClientComposition(hwcId);
if (hasClientComposition) {
ALOGV("hasClientComposition");
@@ -2069,6 +2170,10 @@
}
}
+ if (applyColorMatrix) {
+ getRenderEngine().setupColorTransform(oldColorMatrix);
+ }
+
// disable scissor at the end of the frame
mRenderEngine->disableScissor();
return true;
@@ -2944,8 +3049,7 @@
colorizer.bold(result);
result.append("h/w composer state:\n");
colorizer.reset(result);
- bool hwcDisabled = mDebugDisableHWC || mDebugRegion || mDaltonize ||
- mHasColorMatrix;
+ bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
result.appendFormat(" h/w composer %s\n",
hwcDisabled ? "disabled" : "enabled");
hwc.dump(result);
@@ -3100,16 +3204,24 @@
// daltonize
n = data.readInt32();
switch (n % 10) {
- case 1: mDaltonizer.setType(Daltonizer::protanomaly); break;
- case 2: mDaltonizer.setType(Daltonizer::deuteranomaly); break;
- case 3: mDaltonizer.setType(Daltonizer::tritanomaly); break;
+ case 1:
+ mDaltonizer.setType(ColorBlindnessType::Protanomaly);
+ break;
+ case 2:
+ mDaltonizer.setType(ColorBlindnessType::Deuteranomaly);
+ break;
+ case 3:
+ mDaltonizer.setType(ColorBlindnessType::Tritanomaly);
+ break;
+ default:
+ mDaltonizer.setType(ColorBlindnessType::None);
+ break;
}
if (n >= 10) {
- mDaltonizer.setMode(Daltonizer::correction);
+ mDaltonizer.setMode(ColorBlindnessMode::Correction);
} else {
- mDaltonizer.setMode(Daltonizer::simulation);
+ mDaltonizer.setMode(ColorBlindnessMode::Simulation);
}
- mDaltonize = n > 0;
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
@@ -3117,15 +3229,14 @@
case 1015: {
// apply a color matrix
n = data.readInt32();
- mHasColorMatrix = n ? 1 : 0;
if (n) {
// color matrix is sent as mat3 matrix followed by vec3
// offset, then packed into a mat4 where the last row is
// the offset and extra values are 0
for (size_t i = 0 ; i < 4; i++) {
- for (size_t j = 0; j < 4; j++) {
- mColorMatrix[i][j] = data.readFloat();
- }
+ for (size_t j = 0; j < 4; j++) {
+ mColorMatrix[i][j] = data.readFloat();
+ }
}
} else {
mColorMatrix = mat4();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0df39a4..f50f9e7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -46,6 +46,8 @@
#include <hardware/hwcomposer_defs.h>
+#include <system/graphics.h>
+
#include <private/gui/LayerState.h>
#include "Barrier.h"
@@ -222,6 +224,10 @@
virtual status_t getDisplayConfigs(const sp<IBinder>& display,
Vector<DisplayInfo>* configs);
virtual int getActiveConfig(const sp<IBinder>& display);
+ virtual status_t getDisplayColorModes(const sp<IBinder>& display,
+ Vector<android_color_mode_t>* configs);
+ virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display);
+ virtual status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode);
virtual void setPowerMode(const sp<IBinder>& display, int mode);
virtual status_t setActiveConfig(const sp<IBinder>& display, int id);
virtual status_t clearAnimationFrameStats();
@@ -260,6 +266,9 @@
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode);
+ // Called on the main thread in response to setActiveColorMode()
+ void setActiveColorModeInternal(const sp<DisplayDevice>& hw, android_color_mode_t colorMode);
+
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -368,6 +377,16 @@
return mDisplays.valueFor(dpy);
}
+ int32_t getDisplayType(const sp<IBinder>& display) {
+ if (!display.get()) return NAME_NOT_FOUND;
+ for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
+ if (display == mBuiltinDisplays[i]) {
+ return i;
+ }
+ }
+ return NAME_NOT_FOUND;
+ }
+
// mark a region of a layer stack dirty. this updates the dirty
// region of all screens presenting this layer stack.
void invalidateLayerStack(uint32_t layerStack, const Region& dirty);
@@ -507,6 +526,9 @@
bool mBootFinished;
bool mForceFullDamage;
FenceTracker mFenceTracker;
+#ifdef USE_HWC2
+ bool mPropagateBackpressure = true;
+#endif
// these are thread safe
mutable MessageQueue mEventQueue;
@@ -527,8 +549,11 @@
*/
Daltonizer mDaltonizer;
+#ifndef USE_HWC2
bool mDaltonize;
+#endif
+ mat4 mPreviousColorMatrix;
mat4 mColorMatrix;
bool mHasColorMatrix;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 69fb8c5..6fe2358 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -59,6 +59,8 @@
#include <private/android_filesystem_config.h>
#include <private/gui/SyncFeatures.h>
+#include <set>
+
#include "Client.h"
#include "clz.h"
#include "Colorizer.h"
@@ -574,20 +576,8 @@
return BAD_VALUE;
}
- if (!display.get())
- return NAME_NOT_FOUND;
-
- int32_t type = NAME_NOT_FOUND;
- for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- if (display == mBuiltinDisplays[i]) {
- type = i;
- break;
- }
- }
-
- if (type < 0) {
- return type;
- }
+ int32_t type = getDisplayType(display);
+ if (type < 0) return type;
// TODO: Not sure if display density should handled by SF any longer
class Density {
@@ -649,7 +639,6 @@
info.ydpi = ydpi;
info.fps = float(1e9 / hwConfig.refresh);
info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
- info.colorTransform = hwConfig.colorTransform;
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -750,6 +739,55 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
+ Vector<android_color_mode_t>* outColorModes) {
+ if (outColorModes == nullptr || display.get() == nullptr) {
+ return BAD_VALUE;
+ }
+
+ int32_t type = getDisplayType(display);
+ if (type < 0) return type;
+
+ std::set<android_color_mode_t> colorModes;
+ for (const HWComposer::DisplayConfig& hwConfig : getHwComposer().getConfigs(type)) {
+ colorModes.insert(hwConfig.colorMode);
+ }
+
+ outColorModes->clear();
+ std::copy(colorModes.cbegin(), colorModes.cend(), std::back_inserter(*outColorModes));
+
+ return NO_ERROR;
+}
+
+android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
+ if (display.get() == nullptr) return static_cast<android_color_mode_t>(BAD_VALUE);
+
+ int32_t type = getDisplayType(display);
+ if (type < 0) return static_cast<android_color_mode_t>(type);
+
+ return getHwComposer().getColorMode(type);
+}
+
+status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
+ android_color_mode_t colorMode) {
+ if (display.get() == nullptr || colorMode < 0) {
+ return BAD_VALUE;
+ }
+
+ int32_t type = getDisplayType(display);
+ if (type < 0) return type;
+ const Vector<HWComposer::DisplayConfig>& hwConfigs = getHwComposer().getConfigs(type);
+ HWComposer::DisplayConfig desiredConfig = hwConfigs[getHwComposer().getCurrentConfig(type)];
+ desiredConfig.colorMode = colorMode;
+ for (size_t c = 0; c < hwConfigs.size(); ++c) {
+ const HWComposer::DisplayConfig config = hwConfigs[c];
+ if (config == desiredConfig) {
+ return setActiveConfig(display, c);
+ }
+ }
+ return BAD_VALUE;
+}
+
status_t SurfaceFlinger::clearAnimationFrameStats() {
Mutex::Autolock _l(mStateLock);
mAnimFrameTracker.clearStats();
@@ -3080,14 +3118,20 @@
// daltonize
n = data.readInt32();
switch (n % 10) {
- case 1: mDaltonizer.setType(Daltonizer::protanomaly); break;
- case 2: mDaltonizer.setType(Daltonizer::deuteranomaly); break;
- case 3: mDaltonizer.setType(Daltonizer::tritanomaly); break;
+ case 1:
+ mDaltonizer.setType(ColorBlindnessType::Protanomaly);
+ break;
+ case 2:
+ mDaltonizer.setType(ColorBlindnessType::Deuteranomaly);
+ break;
+ case 3:
+ mDaltonizer.setType(ColorBlindnessType::Tritanomaly);
+ break;
}
if (n >= 10) {
- mDaltonizer.setMode(Daltonizer::correction);
+ mDaltonizer.setMode(ColorBlindnessMode::Correction);
} else {
- mDaltonizer.setMode(Daltonizer::simulation);
+ mDaltonizer.setMode(ColorBlindnessMode::Simulation);
}
mDaltonize = n > 0;
invalidateHwcGeometry();