Merge "[SurfaceFlinger] Accept data space and pixel format to take screenshot."
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index cd0fbd4..16abc1e 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -4,6 +4,7 @@
[Builtin Hooks Options]
# Only turn on clang-format check for the following subfolders.
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+ libs/graphicsenv/
libs/gui/
libs/ui/
libs/vr/
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index e897482..19c2830 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -224,6 +224,11 @@
{ "pagecache", "Page cache", 0, {
{ REQ, "events/filemap/enable" },
} },
+ { "memory", "Memory", 0, {
+ { OPT, "events/kmem/rss_stat/enable" },
+ { OPT, "events/kmem/ion_heap_grow/enable" },
+ { OPT, "events/kmem/ion_heap_shrink/enable" },
+ } },
};
struct TracingVendorCategory {
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index e185cbe..9aa1075 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -121,7 +121,6 @@
"kill",
"librank",
"logcat",
- "logcompressor",
"lsmod",
"lsof",
"netstat",
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 2470a1d..e4990b0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -805,7 +805,7 @@
PLOG(WARNING) << "Failed to chmod " << p->fts_path;
}
}
- // Intentional fall through to also set GID
+ [[fallthrough]]; // also set GID
case FTS_F:
if (chown(p->fts_path, -1, expected) != 0) {
PLOG(WARNING) << "Failed to chown " << p->fts_path;
@@ -1442,7 +1442,7 @@
&& !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
p->fts_number = 1;
}
- // Fall through to count the directory
+ [[fallthrough]]; // to count the directory
case FTS_DEFAULT:
case FTS_F:
case FTS_SL:
@@ -1857,13 +1857,14 @@
}
}
}
- // Fall through to always count against total
+ [[fallthrough]]; // always count against total
case FTS_D:
// Ignore data belonging to specific apps
p->fts_number = p->fts_parent->fts_number;
if (p->fts_level == 1 && !strcmp(p->fts_name, "Android")) {
p->fts_number = 1;
}
+ [[fallthrough]]; // always count against total
case FTS_DEFAULT:
case FTS_SL:
case FTS_SLNONE:
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 28c7658..b2e7047 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -322,21 +322,8 @@
return false;
}
const char* isa = parameters_.instruction_set;
-
- // Check whether the file exists where expected.
std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
std::string isa_path = dalvik_cache + "/" + isa;
- std::string art_path = isa_path + "/system@framework@boot.art";
- std::string oat_path = isa_path + "/system@framework@boot.oat";
- bool cleared = false;
- if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
- // Files exist, assume everything is alright if not forced. Otherwise clean up.
- if (!force) {
- return true;
- }
- ClearDirectory(isa_path);
- cleared = true;
- }
// Reset umask in otapreopt, so that we control the the access for the files we create.
umask(0);
@@ -355,17 +342,34 @@
}
}
- // Prepare to create.
+ // Check whether we have files in /data.
+ // TODO: check that the files are correct wrt/ jars.
+ std::string art_path = isa_path + "/system@framework@boot.art";
+ std::string oat_path = isa_path + "/system@framework@boot.oat";
+ bool cleared = false;
+ if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
+ // Files exist, assume everything is alright if not forced. Otherwise clean up.
+ if (!force) {
+ return true;
+ }
+ ClearDirectory(isa_path);
+ cleared = true;
+ }
+
+ // Check whether we have an image in /system.
+ // TODO: check that the files are correct wrt/ jars.
+ std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
+ if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
+ // Note: we ignore |force| here.
+ return true;
+ }
+
+
if (!cleared) {
ClearDirectory(isa_path);
}
- std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
- if (access(preopted_boot_art_path.c_str(), F_OK) != 0) {
- // No preopted boot image. Try to compile.
- return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
- }
- return true;
+ return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
}
static bool CreatePath(const std::string& path) {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 48f9eb4..6b9cf0d 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -974,7 +974,7 @@
if (chmod(p->fts_path, target_mode) != 0) {
PLOG(WARNING) << "Failed to chmod " << p->fts_path;
}
- // Intentional fall through to also set GID
+ [[fallthrough]]; // to also set GID
case FTS_F:
if (chown(p->fts_path, -1, gid) != 0) {
PLOG(WARNING) << "Failed to chown " << p->fts_path;
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index d776682..79cd6b5 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -274,6 +274,7 @@
// Note that we ignore the strict_policy and don't propagate it
// further (since we do no outbound RPCs anyway).
strict_policy = bio_get_uint32(msg);
+ bio_get_uint32(msg); // Ignore worksource header.
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index 8c3ff74..7f5177b 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -94,7 +94,8 @@
* int fd = ASharedMemory_create("memory", 128);
*
* // By default it has PROT_READ | PROT_WRITE | PROT_EXEC.
- * char *buffer = (char *) mmap(NULL, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ * size_t memSize = ASharedMemory_getSize(fd);
+ * char *buffer = (char *) mmap(NULL, memSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
*
* strcpy(buffer, "This is an example."); // trivially initialize content
*
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index f052bcb..7a47724 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -109,6 +109,10 @@
"BC_DEAD_BINDER_DONE"
};
+// The work source represents the UID of the process we should attribute the transaction to.
+// We use -1 to specify that the work source was not set using #setWorkSource.
+static const int kUnsetWorkSource = -1;
+
static const char* getReturnString(uint32_t cmd)
{
size_t idx = cmd & 0xff;
@@ -383,6 +387,25 @@
return mStrictModePolicy;
}
+uid_t IPCThreadState::setWorkSource(uid_t uid)
+{
+ uid_t returnValue = mWorkSource;
+ mWorkSource = uid;
+ return returnValue;
+}
+
+uid_t IPCThreadState::getWorkSource() const
+{
+ return mWorkSource;
+}
+
+uid_t IPCThreadState::clearWorkSource()
+{
+ uid_t returnValue = mWorkSource;
+ mWorkSource = kUnsetWorkSource;
+ return returnValue;
+}
+
void IPCThreadState::setLastTransactionBinderFlags(int32_t flags)
{
mLastTransactionBinderFlags = flags;
@@ -736,6 +759,7 @@
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
+ mWorkSource(kUnsetWorkSource),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 87c9842..bc1a71c 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -601,6 +601,7 @@
{
writeInt32(IPCThreadState::self()->getStrictModePolicy() |
STRICT_MODE_PENALTY_GATHER);
+ writeInt32(IPCThreadState::self()->getWorkSource());
// currently the interface identification token is just its name as a string
return writeString16(interface);
}
@@ -613,6 +614,7 @@
bool Parcel::enforceInterface(const String16& interface,
IPCThreadState* threadState) const
{
+ // StrictModePolicy.
int32_t strictPolicy = readInt32();
if (threadState == nullptr) {
threadState = IPCThreadState::self();
@@ -627,6 +629,10 @@
} else {
threadState->setStrictModePolicy(strictPolicy);
}
+ // WorkSource.
+ int32_t workSource = readInt32();
+ threadState->setWorkSource(workSource);
+ // Interface descriptor.
const String16 str(readString16());
if (str == interface) {
return true;
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 40b51ad..5888e14 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -47,6 +47,13 @@
void setStrictModePolicy(int32_t policy);
int32_t getStrictModePolicy() const;
+ // See Binder#setThreadWorkSource in Binder.java.
+ uid_t setWorkSource(uid_t uid);
+ // See Binder#getThreadWorkSource in Binder.java.
+ uid_t getWorkSource() const;
+ // See Binder#clearThreadWorkSource in Binder.java.
+ uid_t clearWorkSource();
+
void setLastTransactionBinderFlags(int32_t flags);
int32_t getLastTransactionBinderFlags() const;
@@ -155,6 +162,9 @@
status_t mLastError;
pid_t mCallingPid;
uid_t mCallingUid;
+ // The UID of the process who is responsible for this transaction.
+ // This is used for resource attribution.
+ int32_t mWorkSource;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
IPCThreadStateBase *mIPCThreadStateBase;
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 1a9018a..e37c388 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -42,8 +42,8 @@
/**
* analog using std::shared_ptr for internally held refcount
*
- * ref must be called at least one time during the lifetime of this object. The recommended way to construct
- * this object is with SharedRefBase::make.
+ * ref must be called at least one time during the lifetime of this object. The recommended way to
+ * construct this object is with SharedRefBase::make.
*/
class SharedRefBase {
public:
@@ -77,7 +77,7 @@
/**
* Convenience method for making an object directly with a reference.
*/
- template<class T, class... Args>
+ template <class T, class... Args>
static std::shared_ptr<T> make(Args&&... args) {
T* t = new T(std::forward<Args>(args)...);
return t->template ref<T>();
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 0e97b50..d36b3c0 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -51,6 +51,99 @@
void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29);
/**
+ * This is called to allocate an array with a given length. If allocation fails, null should be
+ * returned.
+ */
+typedef void* (*AParcel_arrayReallocator)(void* vectorData, size_t length);
+
+// @START-PRIMITIVE-VECTOR-GETTERS
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * This will never be called for an empty array.
+ */
+typedef int32_t* (*AParcel_int32ArrayGetter)(void* arrayData);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * This will never be called for an empty array.
+ */
+typedef uint32_t* (*AParcel_uint32ArrayGetter)(void* arrayData);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * This will never be called for an empty array.
+ */
+typedef int64_t* (*AParcel_int64ArrayGetter)(void* arrayData);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * This will never be called for an empty array.
+ */
+typedef uint64_t* (*AParcel_uint64ArrayGetter)(void* arrayData);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * This will never be called for an empty array.
+ */
+typedef float* (*AParcel_floatArrayGetter)(void* arrayData);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * This will never be called for an empty array.
+ */
+typedef double* (*AParcel_doubleArrayGetter)(void* arrayData);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * This will never be called for an empty array.
+ */
+typedef bool (*AParcel_boolArrayGetter)(const void* arrayData, size_t index);
+
+/**
+ * This is called to set an underlying value in an arrayData object at index.
+ */
+typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool value);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * This will never be called for an empty array.
+ */
+typedef char16_t* (*AParcel_charArrayGetter)(void* arrayData);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * This will never be called for an empty array.
+ */
+typedef int8_t* (*AParcel_byteArrayGetter)(void* arrayData);
+
+// @END-PRIMITIVE-VECTOR-GETTERS
+
+/**
+ * This is called to allocate a buffer
+ *
+ * The length here includes the space required to insert a '\0' for a properly formed c-str. If the
+ * buffer returned from this function is retStr, it will be filled by AParcel_readString with the
+ * data from the remote process, and it will be filled such that retStr[length] == '\0'.
+ *
+ * If allocation fails, null should be returned.
+ */
+typedef void* (*AParcel_stringReallocator)(void* stringData, size_t length);
+
+/**
+ * This is called to get the buffer from a stringData object.
+ */
+typedef char* (*AParcel_stringGetter)(void* stringData);
+
+/**
* Writes an AIBinder to the next location in a non-null parcel. Can be null.
*/
binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29);
@@ -95,22 +188,6 @@
__INTRODUCED_IN(29);
/**
- * This is called to allocate a buffer
- *
- * The length here includes the space required to insert a '\0' for a properly formed c-str. If the
- * buffer returned from this function is retStr, it will be filled by AParcel_readString with the
- * data from the remote process, and it will be filled such that retStr[length] == '\0'.
- *
- * If allocation fails, null should be returned.
- */
-typedef void* (*AParcel_string_reallocator)(void* stringData, size_t length);
-
-/**
- * This is called to get the buffer from a stringData object.
- */
-typedef char* (*AParcel_string_getter)(void* stringData);
-
-/**
* Reads and allocates string value from the next location in a non-null parcel.
*
* Data is passed to the string allocator once the string size is known. This data should be used to
@@ -121,11 +198,11 @@
* If this function returns a success, the buffer returned by allocator when passed stringData will
* contain a null-terminated c-str read from the binder.
*/
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator,
- AParcel_string_getter getter, void** stringData)
+binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator,
+ AParcel_stringGetter getter, void** stringData)
__INTRODUCED_IN(29);
-// @START
+// @START-PRIMITIVE-READ-WRITE
/**
* Writes int32_t value to the next location in a non-null parcel.
*/
@@ -216,7 +293,125 @@
*/
binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODUCED_IN(29);
-// @END
+/**
+ * Writes an array of int32_t to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of uint32_t to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of int64_t to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of uint64_t to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of float to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of double to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of bool to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData,
+ AParcel_boolArrayGetter getter, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of char16_t to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of int8_t to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of int32_t from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_int32ArrayGetter getter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of uint32_t from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_uint32ArrayGetter getter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of int64_t from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_int64ArrayGetter getter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of uint64_t from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_uint64ArrayGetter getter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of float from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_floatArrayGetter getter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of double from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_doubleArrayGetter getter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of bool from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_boolArraySetter setter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of char16_t from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_charArrayGetter getter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of int8_t from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_byteArrayGetter getter) __INTRODUCED_IN(29);
+
+// @END-PRIMITIVE-READ-WRITE
#endif //__ANDROID_API__ >= __ANDROID_API_Q__
__END_DECLS
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index d3e6cae..faeb78f 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -31,14 +31,246 @@
#ifdef __cplusplus
#include <string>
+#include <vector>
namespace ndk {
/**
+ * This resizes a std::vector of some underlying type to the given length.
+ */
+template <typename T>
+static inline void* AParcel_stdVectorReallocator(void* vectorData, size_t length) {
+ std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
+ if (length > vec->max_size()) return nullptr;
+
+ vec->resize(length);
+ return vec;
+}
+
+/**
+ * This retrieves the underlying contiguous vector from a corresponding vectorData.
+ */
+template <typename T>
+static inline T* AParcel_stdVectorGetter(void* vectorData) {
+ std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
+ return vec->data();
+}
+
+/**
+ * This retrieves the underlying value in a vector which may not be contiguous at index from a
+ * corresponding vectorData.
+ */
+template <typename T>
+static inline T AParcel_stdVectorGetter(const void* vectorData, size_t index) {
+ const std::vector<T>* vec = static_cast<const std::vector<T>*>(vectorData);
+ return (*vec)[index];
+}
+
+/**
+ * This sets the underlying value in a corresponding vectorData which may not be contiguous at
+ * index.
+ */
+template <typename T>
+static inline void AParcel_stdVectorSetter(void* vectorData, size_t index, T value) {
+ std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
+ (*vec)[index] = value;
+}
+
+/**
+ * Writes a vector to the next location in a non-null parcel.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<T>& vec);
+
+/**
+ * Reads a vector to the next location in a non-null parcel.
+ */
+template <typename T>
+static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<T>* vec);
+
+// @START
+/**
+ * Writes a vector of int32_t to the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_writeVector<int32_t>(AParcel* parcel,
+ const std::vector<int32_t>& vec) {
+ return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Reads a vector of int32_t from the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_readVector<int32_t>(const AParcel* parcel,
+ std::vector<int32_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readInt32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int32_t>,
+ AParcel_stdVectorGetter<int32_t>);
+}
+
+/**
+ * Writes a vector of uint32_t to the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_writeVector<uint32_t>(AParcel* parcel,
+ const std::vector<uint32_t>& vec) {
+ return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Reads a vector of uint32_t from the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_readVector<uint32_t>(const AParcel* parcel,
+ std::vector<uint32_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readUint32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint32_t>,
+ AParcel_stdVectorGetter<uint32_t>);
+}
+
+/**
+ * Writes a vector of int64_t to the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_writeVector<int64_t>(AParcel* parcel,
+ const std::vector<int64_t>& vec) {
+ return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Reads a vector of int64_t from the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_readVector<int64_t>(const AParcel* parcel,
+ std::vector<int64_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readInt64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int64_t>,
+ AParcel_stdVectorGetter<int64_t>);
+}
+
+/**
+ * Writes a vector of uint64_t to the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_writeVector<uint64_t>(AParcel* parcel,
+ const std::vector<uint64_t>& vec) {
+ return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Reads a vector of uint64_t from the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_readVector<uint64_t>(const AParcel* parcel,
+ std::vector<uint64_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readUint64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint64_t>,
+ AParcel_stdVectorGetter<uint64_t>);
+}
+
+/**
+ * Writes a vector of float to the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_writeVector<float>(AParcel* parcel, const std::vector<float>& vec) {
+ return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Reads a vector of float from the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_readVector<float>(const AParcel* parcel, std::vector<float>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readFloatArray(parcel, &vectorData, &AParcel_stdVectorReallocator<float>,
+ AParcel_stdVectorGetter<float>);
+}
+
+/**
+ * Writes a vector of double to the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_writeVector<double>(AParcel* parcel,
+ const std::vector<double>& vec) {
+ return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Reads a vector of double from the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_readVector<double>(const AParcel* parcel, std::vector<double>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readDoubleArray(parcel, &vectorData, &AParcel_stdVectorReallocator<double>,
+ AParcel_stdVectorGetter<double>);
+}
+
+/**
+ * Writes a vector of bool to the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_writeVector<bool>(AParcel* parcel, const std::vector<bool>& vec) {
+ return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec),
+ AParcel_stdVectorGetter<bool>, vec.size());
+}
+
+/**
+ * Reads a vector of bool from the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_readVector<bool>(const AParcel* parcel, std::vector<bool>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readBoolArray(parcel, &vectorData, &AParcel_stdVectorReallocator<bool>,
+ AParcel_stdVectorSetter<bool>);
+}
+
+/**
+ * Writes a vector of char16_t to the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_writeVector<char16_t>(AParcel* parcel,
+ const std::vector<char16_t>& vec) {
+ return AParcel_writeCharArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Reads a vector of char16_t from the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_readVector<char16_t>(const AParcel* parcel,
+ std::vector<char16_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readCharArray(parcel, &vectorData, &AParcel_stdVectorReallocator<char16_t>,
+ AParcel_stdVectorGetter<char16_t>);
+}
+
+/**
+ * Writes a vector of int8_t to the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_writeVector<int8_t>(AParcel* parcel,
+ const std::vector<int8_t>& vec) {
+ return AParcel_writeByteArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Reads a vector of int8_t from the next location in a non-null parcel.
+ */
+template <>
+inline binder_status_t AParcel_readVector<int8_t>(const AParcel* parcel, std::vector<int8_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readByteArray(parcel, &vectorData, &AParcel_stdVectorReallocator<int8_t>,
+ AParcel_stdVectorGetter<int8_t>);
+}
+
+// @END
+
+/**
* Takes a std::string and reallocates it to the specified length. For use with AParcel_readString.
* See use below in AParcel_readString.
*/
-static inline void* AParcel_std_string_reallocator(void* stringData, size_t length) {
+static inline void* AParcel_stdStringReallocator(void* stringData, size_t length) {
std::string* str = static_cast<std::string*>(stringData);
str->resize(length - 1);
return stringData;
@@ -47,7 +279,7 @@
/**
* Takes a std::string and returns the inner char*.
*/
-static inline char* AParcel_std_string_getter(void* stringData) {
+static inline char* AParcel_stdStringGetter(void* stringData) {
std::string* str = static_cast<std::string*>(stringData);
return &(*str)[0];
}
@@ -64,10 +296,31 @@
*/
static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) {
void* stringData = static_cast<void*>(str);
- return AParcel_readString(parcel, AParcel_std_string_reallocator, AParcel_std_string_getter,
+ return AParcel_readString(parcel, AParcel_stdStringReallocator, AParcel_stdStringGetter,
&stringData);
}
+template <typename T>
+static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) {
+ if (vec.size() > INT32_MAX) {
+ return STATUS_BAD_VALUE;
+ }
+
+ return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size()));
+}
+
+template <typename T>
+static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) {
+ int32_t size;
+ binder_status_t err = AParcel_readInt32(parcel, &size);
+
+ if (err != STATUS_OK) return err;
+ if (size < 0) return STATUS_UNEXPECTED_NULL;
+
+ vec->resize(static_cast<size_t>(size));
+ return STATUS_OK;
+}
+
} // namespace ndk
#endif // __cplusplus
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 2a1bff1..f84814f 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -24,30 +24,48 @@
AIBinder_Weak_promote;
AParcel_delete;
AParcel_readBool;
+ AParcel_readBoolArray;
AParcel_readByte;
+ AParcel_readByteArray;
AParcel_readChar;
+ AParcel_readCharArray;
AParcel_readDouble;
+ AParcel_readDoubleArray;
AParcel_readFloat;
+ AParcel_readFloatArray;
AParcel_readInt32;
+ AParcel_readInt32Array;
AParcel_readInt64;
+ AParcel_readInt64Array;
AParcel_readNullableStrongBinder;
AParcel_readStatusHeader;
AParcel_readString;
AParcel_readStrongBinder;
AParcel_readUint32;
+ AParcel_readUint32Array;
AParcel_readUint64;
+ AParcel_readUint64Array;
AParcel_writeBool;
+ AParcel_writeBoolArray;
AParcel_writeByte;
+ AParcel_writeByteArray;
AParcel_writeChar;
+ AParcel_writeCharArray;
AParcel_writeDouble;
+ AParcel_writeDoubleArray;
AParcel_writeFloat;
+ AParcel_writeFloatArray;
AParcel_writeInt32;
+ AParcel_writeInt32Array;
AParcel_writeInt64;
+ AParcel_writeInt64Array;
AParcel_writeStatusHeader;
AParcel_writeString;
AParcel_writeStrongBinder;
AParcel_writeUint32;
+ AParcel_writeUint32Array;
AParcel_writeUint64;
+ AParcel_writeUint64Array;
AStatus_delete;
AStatus_fromExceptionCode;
AStatus_fromExceptionCodeWithMessage;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 3e03e90..29094db 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -31,6 +31,163 @@
using ::android::sp;
using ::android::status_t;
+template <typename T>
+using ContiguousArrayGetter = T* (*)(void* arrayData);
+template <typename T>
+using ArrayGetter = T (*)(const void* arrayData, size_t index);
+template <typename T>
+using ArraySetter = void (*)(void* arrayData, size_t index, T value);
+
+template <typename T>
+binder_status_t WriteArray(AParcel* parcel, const T* array, size_t length) {
+ if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
+
+ Parcel* rawParcel = parcel->get();
+
+ status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
+ if (status != STATUS_OK) return PruneStatusT(status);
+
+ int32_t size = 0;
+ if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY;
+
+ void* const data = rawParcel->writeInplace(size);
+ if (data == nullptr) return STATUS_NO_MEMORY;
+
+ memcpy(data, array, size);
+
+ return STATUS_OK;
+}
+
+// Each element in a char16_t array is converted to an int32_t (not packed).
+template <>
+binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, size_t length) {
+ if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
+
+ Parcel* rawParcel = parcel->get();
+
+ status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
+ if (status != STATUS_OK) return PruneStatusT(status);
+
+ int32_t size = 0;
+ if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY;
+
+ for (int32_t i = 0; i < length; i++) {
+ status = rawParcel->writeChar(array[i]);
+
+ if (status != STATUS_OK) return PruneStatusT(status);
+ }
+
+ return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t ReadArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator, ContiguousArrayGetter<T> getter) {
+ const Parcel* rawParcel = parcel->get();
+
+ int32_t length;
+ status_t status = rawParcel->readInt32(&length);
+
+ if (status != STATUS_OK) return PruneStatusT(status);
+ if (length < 0) return STATUS_UNEXPECTED_NULL;
+
+ *arrayData = reallocator(*arrayData, length);
+ if (*arrayData == nullptr) return STATUS_NO_MEMORY;
+
+ if (length == 0) return STATUS_OK;
+
+ T* array = getter(*arrayData);
+ if (array == nullptr) return STATUS_NO_MEMORY;
+
+ int32_t size = 0;
+ if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY;
+
+ const void* data = rawParcel->readInplace(size);
+ if (data == nullptr) return STATUS_NO_MEMORY;
+
+ memcpy(array, data, size);
+
+ return STATUS_OK;
+}
+
+// Each element in a char16_t array is converted to an int32_t (not packed)
+template <>
+binder_status_t ReadArray<char16_t>(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ ContiguousArrayGetter<char16_t> getter) {
+ const Parcel* rawParcel = parcel->get();
+
+ int32_t length;
+ status_t status = rawParcel->readInt32(&length);
+
+ if (status != STATUS_OK) return PruneStatusT(status);
+ if (length < 0) return STATUS_UNEXPECTED_NULL;
+
+ *arrayData = reallocator(*arrayData, length);
+ if (*arrayData == nullptr) return STATUS_NO_MEMORY;
+
+ if (length == 0) return STATUS_OK;
+
+ char16_t* array = getter(*arrayData);
+ if (array == nullptr) return STATUS_NO_MEMORY;
+
+ int32_t size = 0;
+ if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY;
+
+ for (int32_t i = 0; i < length; i++) {
+ status = rawParcel->readChar(array + i);
+
+ if (status != STATUS_OK) return PruneStatusT(status);
+ }
+
+ return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t WriteArray(AParcel* parcel, const void* arrayData, ArrayGetter<T> getter,
+ size_t length, status_t (Parcel::*write)(T)) {
+ if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
+
+ Parcel* rawParcel = parcel->get();
+
+ status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
+ if (status != STATUS_OK) return PruneStatusT(status);
+
+ for (size_t i = 0; i < length; i++) {
+ status = (rawParcel->*write)(getter(arrayData, i));
+
+ if (status != STATUS_OK) return PruneStatusT(status);
+ }
+
+ return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t ReadArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator, ArraySetter<T> setter,
+ status_t (Parcel::*read)(T*) const) {
+ const Parcel* rawParcel = parcel->get();
+
+ int32_t length;
+ status_t status = rawParcel->readInt32(&length);
+
+ if (status != STATUS_OK) return PruneStatusT(status);
+ if (length < 0) return STATUS_UNEXPECTED_NULL;
+
+ *arrayData = reallocator(*arrayData, length);
+ if (*arrayData == nullptr) return STATUS_NO_MEMORY;
+
+ for (size_t i = 0; i < length; i++) {
+ T readTarget;
+ status = (rawParcel->*read)(&readTarget);
+ if (status != STATUS_OK) return PruneStatusT(status);
+
+ setter(*arrayData, i, readTarget);
+ }
+
+ return STATUS_OK;
+}
+
void AParcel_delete(AParcel* parcel) {
delete parcel;
}
@@ -98,8 +255,8 @@
return STATUS_OK;
}
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator,
- AParcel_string_getter getter, void** stringData) {
+binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator,
+ AParcel_stringGetter getter, void** stringData) {
size_t len16;
const char16_t* str16 = parcel->get()->readString16Inplace(&len16);
@@ -122,10 +279,15 @@
}
*stringData = reallocator(*stringData, len8);
+
+ if (*stringData == nullptr) {
+ return STATUS_NO_MEMORY;
+ }
+
char* str8 = getter(*stringData);
if (str8 == nullptr) {
- LOG(WARNING) << __func__ << ": AParcel_string_allocator failed to allocate.";
+ LOG(WARNING) << __func__ << ": AParcel_stringReallocator failed to allocate.";
return STATUS_NO_MEMORY;
}
@@ -227,4 +389,95 @@
return PruneStatusT(status);
}
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length) {
+ return WriteArray<int32_t>(parcel, value, length);
+}
+
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length) {
+ return WriteArray<uint32_t>(parcel, value, length);
+}
+
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length) {
+ return WriteArray<int64_t>(parcel, value, length);
+}
+
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length) {
+ return WriteArray<uint64_t>(parcel, value, length);
+}
+
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length) {
+ return WriteArray<float>(parcel, value, length);
+}
+
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length) {
+ return WriteArray<double>(parcel, value, length);
+}
+
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData,
+ AParcel_boolArrayGetter getter, size_t length) {
+ return WriteArray<bool>(parcel, arrayData, getter, length, &Parcel::writeBool);
+}
+
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length) {
+ return WriteArray<char16_t>(parcel, value, length);
+}
+
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length) {
+ return WriteArray<int8_t>(parcel, value, length);
+}
+
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_int32ArrayGetter getter) {
+ return ReadArray<int32_t>(parcel, arrayData, reallocator, getter);
+}
+
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_uint32ArrayGetter getter) {
+ return ReadArray<uint32_t>(parcel, arrayData, reallocator, getter);
+}
+
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_int64ArrayGetter getter) {
+ return ReadArray<int64_t>(parcel, arrayData, reallocator, getter);
+}
+
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_uint64ArrayGetter getter) {
+ return ReadArray<uint64_t>(parcel, arrayData, reallocator, getter);
+}
+
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_floatArrayGetter getter) {
+ return ReadArray<float>(parcel, arrayData, reallocator, getter);
+}
+
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_doubleArrayGetter getter) {
+ return ReadArray<double>(parcel, arrayData, reallocator, getter);
+}
+
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_boolArraySetter setter) {
+ return ReadArray<bool>(parcel, arrayData, reallocator, setter, &Parcel::readBool);
+}
+
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_charArrayGetter getter) {
+ return ReadArray<char16_t>(parcel, arrayData, reallocator, getter);
+}
+
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData,
+ AParcel_arrayReallocator reallocator,
+ AParcel_byteArrayGetter getter) {
+ return ReadArray<int8_t>(parcel, arrayData, reallocator, getter);
+}
+
// @END
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index bbd3e5d..45f8d06 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -30,13 +30,15 @@
("Byte", "int8_t"),
]
-def replaceFileTags(path, content):
+non_contiguously_addressable = {"Bool"}
+
+def replaceFileTags(path, content, start_tag, end_tag):
print("Updating", path)
with open(path, "r+") as f:
lines = f.readlines()
- start = lines.index("// @START\n")
- end = lines.index("// @END\n")
+ start = lines.index("// @" + start_tag + "\n")
+ end = lines.index("// @" + end_tag + "\n")
if end <= start or start < 0 or end < 0:
print("Failed to find tags in", path)
@@ -59,8 +61,10 @@
print("Updating auto-generated code")
+ pre_header = ""
header = ""
source = ""
+ cpp_helper = ""
for pretty, cpp in data_types:
header += "/**\n"
@@ -82,8 +86,97 @@
source += " return PruneStatusT(status);\n"
source += "}\n\n"
- replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header)
- replaceFileTags(ROOT + "parcel.cpp", source)
+ for pretty, cpp in data_types:
+ nca = pretty in non_contiguously_addressable
+
+ arg_type = "const " + cpp + "* value"
+ if nca: arg_type = "const void* arrayData, AParcel_" + pretty.lower() + "ArrayGetter getter"
+ args = "value, length"
+ if nca: args = "arrayData, getter, length, &Parcel::write" + pretty
+
+ header += "/**\n"
+ header += " * Writes an array of " + cpp + " to the next location in a non-null parcel.\n"
+ header += " */\n"
+ header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) __INTRODUCED_IN(29);\n\n"
+ source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) {\n"
+ source += " return WriteArray<" + cpp + ">(parcel, " + args + ");\n";
+ source += "}\n\n"
+
+ for pretty, cpp in data_types:
+ nca = pretty in non_contiguously_addressable
+
+ extra_getter_args = ""
+ if nca: extra_getter_args = ", size_t index"
+ getter_return = cpp + "*"
+ if nca: getter_return = cpp
+ getter_array_data = "void* arrayData"
+ if nca: getter_array_data = "const void* arrayData"
+
+ getter_type = "AParcel_" + pretty.lower() + "ArrayGetter"
+ setter_type = "AParcel_" + pretty.lower() + "ArraySetter"
+
+ pre_header += "/**\n"
+ pre_header += " * This is called to get the underlying data from an arrayData object.\n"
+ pre_header += " *\n"
+ pre_header += " * This will never be called for an empty array.\n"
+ pre_header += " */\n"
+ pre_header += "typedef " + getter_return + " (*" + getter_type + ")(" + getter_array_data + extra_getter_args + ");\n\n"
+
+ if nca:
+ pre_header += "/**\n"
+ pre_header += " * This is called to set an underlying value in an arrayData object at index.\n"
+ pre_header += " */\n"
+ pre_header += "typedef void (*" + setter_type + ")(void* arrayData, size_t index, " + cpp + " value);\n\n"
+
+ read_using = "getter"
+ if nca: read_using = "setter"
+ read_type = getter_type
+ if nca: read_type = setter_type
+
+ arguments = ["const AParcel* parcel"]
+ arguments += ["void** arrayData"]
+ arguments += ["AParcel_arrayReallocator reallocator"]
+ arguments += [read_type + " " + read_using]
+ arguments = ", ".join(arguments)
+
+ header += "/**\n"
+ header += " * Reads an array of " + cpp + " from the next location in a non-null parcel.\n"
+ header += " */\n"
+ header += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") __INTRODUCED_IN(29);\n\n"
+ source += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") {\n"
+ additional_args = ""
+ if nca: additional_args = ", &Parcel::read" + pretty
+ source += " return ReadArray<" + cpp + ">(parcel, arrayData, reallocator, " + read_using + additional_args + ");\n";
+ source += "}\n\n"
+
+ cpp_helper += "/**\n"
+ cpp_helper += " * Writes a vector of " + cpp + " to the next location in a non-null parcel.\n"
+ cpp_helper += " */\n"
+ cpp_helper += "template<>\n"
+ cpp_helper += "inline binder_status_t AParcel_writeVector<" + cpp + ">(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n"
+ write_args = "vec.data()"
+ if nca: write_args = "static_cast<const void*>(&vec), AParcel_stdVectorGetter<" + cpp + ">"
+ cpp_helper += " return AParcel_write" + pretty + "Array(parcel, " + write_args + ", vec.size());\n"
+ cpp_helper += "}\n\n"
+
+ cpp_helper += "/**\n"
+ cpp_helper += " * Reads a vector of " + cpp + " from the next location in a non-null parcel.\n"
+ cpp_helper += " */\n"
+ cpp_helper += "template<>\n"
+ cpp_helper += "inline binder_status_t AParcel_readVector<" + cpp + ">(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
+ cpp_helper += " void* vectorData = static_cast<void*>(vec);\n"
+ read_args = []
+ read_args += ["parcel"]
+ read_args += ["&vectorData"]
+ read_args += ["&AParcel_stdVectorReallocator<" + cpp + ">"]
+ read_args += ["AParcel_stdVector" + read_using.capitalize() + "<" + cpp + ">"]
+ cpp_helper += " return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n"
+ cpp_helper += "}\n\n"
+
+ replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", pre_header, "START-PRIMITIVE-VECTOR-GETTERS", "END-PRIMITIVE-VECTOR-GETTERS")
+ replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header, "START-PRIMITIVE-READ-WRITE", "END-PRIMITIVE-READ-WRITE")
+ replaceFileTags(ROOT + "parcel.cpp", source, "START", "END")
+ replaceFileTags(ROOT + "include_ndk/android/binder_parcel_utils.h", cpp_helper, "START", "END")
print("Updating DONE.")
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 22bf1e5..6945cac 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -134,3 +134,4 @@
#include <android/binder_auto_utils.h>
#include <android/binder_interface_utils.h>
+#include <android/binder_parcel_utils.h>
diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh
index 49b4730..9a4577f 100755
--- a/libs/binder/ndk/update.sh
+++ b/libs/binder/ndk/update.sh
@@ -18,6 +18,6 @@
set -ex
# This script makes sure that the source code is in sync with the various scripts
-./scripts/init_map.sh > libbinder_ndk.map.txt
./scripts/gen_parcel_helper.py
./scripts/format.sh
+./scripts/init_map.sh > libbinder_ndk.map.txt
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 73c2eba..7bcfffd 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -71,6 +71,7 @@
BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION,
BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
+ BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION,
};
pid_t start_server_process(int arg2, bool usePoll = false)
@@ -938,6 +939,43 @@
EXPECT_EQ(NO_ERROR, ret);
}
+TEST_F(BinderLibTest, WorkSourceUnsetByDefault)
+{
+ status_t ret;
+ Parcel data, reply;
+ data.writeInterfaceToken(binderLibTestServiceName);
+ ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+ EXPECT_EQ(-1, reply.readInt32());
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceSet)
+{
+ status_t ret;
+ Parcel data, reply;
+ uid_t previousWorkSource = IPCThreadState::self()->setWorkSource(100);
+ data.writeInterfaceToken(binderLibTestServiceName);
+ ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+ EXPECT_EQ(100, reply.readInt32());
+ EXPECT_EQ(-1, previousWorkSource);
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceCleared)
+{
+ status_t ret;
+ Parcel data, reply;
+
+ IPCThreadState::self()->setWorkSource(100);
+ uid_t previousWorkSource = IPCThreadState::self()->clearWorkSource();
+ data.writeInterfaceToken(binderLibTestServiceName);
+ ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+
+ EXPECT_EQ(-1, reply.readInt32());
+ EXPECT_EQ(100, previousWorkSource);
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
class BinderLibTestService : public BBinder
{
public:
@@ -1236,6 +1274,11 @@
}
return NO_ERROR;
}
+ case BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION: {
+ data.enforceInterface(binderLibTestServiceName);
+ reply->writeInt32(IPCThreadState::self()->getWorkSource());
+ return NO_ERROR;
+ }
default:
return UNKNOWN_TRANSACTION;
};
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 3328ad7..024d72b 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -68,7 +68,9 @@
}
void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
- const std::string appPref, bool developerOptIn) {
+ const std::string appPref, bool developerOptIn,
+ const int rulesFd, const long rulesOffset,
+ const long rulesLength) {
if (!mAnglePath.empty()) {
ALOGV("ignoring attempt to change ANGLE path from '%s' to '%s'", mAnglePath.c_str(),
path.c_str());
@@ -94,6 +96,13 @@
}
mAngleDeveloperOptIn = developerOptIn;
+
+ ALOGV("setting ANGLE rules file descriptor to '%i'", rulesFd);
+ mAngleRulesFd = rulesFd;
+ ALOGV("setting ANGLE rules offset to '%li'", rulesOffset);
+ mAngleRulesOffset = rulesOffset;
+ ALOGV("setting ANGLE rules length to '%li'", rulesLength);
+ mAngleRulesLength = rulesLength;
}
void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
@@ -124,6 +133,18 @@
return mAngleAppPref.c_str();
}
+int GraphicsEnv::getAngleRulesFd() {
+ return mAngleRulesFd;
+}
+
+long GraphicsEnv::getAngleRulesOffset() {
+ return mAngleRulesOffset;
+}
+
+long GraphicsEnv::getAngleRulesLength() {
+ return mAngleRulesLength;
+}
+
const std::string GraphicsEnv::getLayerPaths(){
return mLayerPaths;
}
@@ -146,7 +167,7 @@
auto sphalNamespace = android_get_exported_namespace("sphal");
if (!sphalNamespace) return;
mDriverNamespace = android_create_namespace("gfx driver",
- nullptr, // ld_library_path
+ mDriverPath.c_str(), // ld_library_path
mDriverPath.c_str(), // default_library_path
ANDROID_NAMESPACE_TYPE_SHARED |
ANDROID_NAMESPACE_TYPE_ISOLATED,
@@ -192,6 +213,15 @@
const char* android_getAngleAppPref() {
return android::GraphicsEnv::getInstance().getAngleAppPref();
}
+int android_getAngleRulesFd() {
+ return android::GraphicsEnv::getInstance().getAngleRulesFd();
+}
+long android_getAngleRulesOffset() {
+ return android::GraphicsEnv::getInstance().getAngleRulesOffset();
+}
+long android_getAngleRulesLength() {
+ return android::GraphicsEnv::getInstance().getAngleRulesLength();
+}
const char* android_getLayerPaths() {
return android::GraphicsEnv::getInstance().getLayerPaths().c_str();
}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 1783429..404823a 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -45,11 +45,15 @@
// in the search path must have a '!' after the zip filename, e.g.
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
void setAngleInfo(const std::string path, const std::string appName, const std::string appPref,
- bool devOptIn);
+ bool devOptIn, const int rulesFd, const long rulesOffset,
+ const long rulesLength);
android_namespace_t* getAngleNamespace();
const char* getAngleAppName();
const char* getAngleAppPref();
bool getAngleDeveloperOptIn();
+ int getAngleRulesFd();
+ long getAngleRulesOffset();
+ long getAngleRulesLength();
void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
NativeLoaderNamespace* getAppNamespace();
@@ -66,6 +70,9 @@
std::string mAngleAppName;
std::string mAngleAppPref;
bool mAngleDeveloperOptIn;
+ int mAngleRulesFd;
+ long mAngleRulesOffset;
+ long mAngleRulesLength;
std::string mDebugLayers;
std::string mLayerPaths;
android_namespace_t* mDriverNamespace = nullptr;
@@ -92,6 +99,9 @@
const char* android_getAngleAppName();
const char* android_getAngleAppPref();
bool android_getAngleDeveloperOptIn();
+ int android_getAngleRulesFd();
+ long android_getAngleRulesOffset();
+ long android_getAngleRulesLength();
const char* android_getLayerPaths();
const char* android_getDebugLayers();
}
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index 3dac037..1a7c2d3 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -400,19 +400,8 @@
ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
return BAD_VALUE;
}
- auto detached_buffer = BufferHubBuffer::Import(std::move(detached_handle->handle()));
- if (detached_buffer == nullptr) {
- ALOGE("attachBuffer: BufferHubBuffer cannot be NULL.");
- return BAD_VALUE;
- }
- auto status_or_handle = detached_buffer->Promote();
- if (!status_or_handle.ok()) {
- ALOGE("attachBuffer: Failed to promote a BufferHubBuffer into a BufferProducer, error=%d.",
- status_or_handle.error());
- return BAD_VALUE;
- }
std::shared_ptr<BufferProducer> buffer_producer =
- BufferProducer::Import(status_or_handle.take());
+ BufferProducer::Import(std::move(detached_handle->handle()));
if (buffer_producer == nullptr) {
ALOGE("attachBuffer: Failed to import BufferProducer.");
return BAD_VALUE;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 7b35409..0a0c8ca 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -78,7 +78,7 @@
shared_libs: [
"android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.configstore@1.0",
@@ -97,7 +97,7 @@
],
export_shared_lib_headers: [
- "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
],
static_libs: [
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 606386c..44a947e 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -41,7 +41,6 @@
#include <poll.h>
-using android::dvr::BufferHubMetadata;
using android::dvr::BufferTraits;
using android::dvr::DetachedBufferRPC;
using android::dvr::NativeHandleWrapper;
@@ -160,7 +159,7 @@
// If all imports succeed, replace the previous buffer and id.
mId = bufferId;
- mBfferStateBit = bufferTraits.buffer_state_bit();
+ mBufferStateBit = bufferTraits.buffer_state_bit();
// TODO(b/112012161) Set up shared fences.
ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
@@ -175,26 +174,6 @@
return poll(&p, 1, timeoutMs);
}
-Status<LocalChannelHandle> BufferHubBuffer::Promote() {
- ATRACE_CALL();
-
- // TODO(b/112338294) remove after migrate producer buffer to binder
- ALOGW("BufferHubBuffer::Promote: not supported operation during migration");
- return {};
-
- ALOGD("BufferHubBuffer::Promote: id=%d.", mId);
-
- auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Promote>();
- if (statusOrHandle.ok()) {
- // Invalidate the buffer.
- mBufferHandle = {};
- } else {
- ALOGE("BufferHubBuffer::Promote: Failed to promote buffer (id=%d): %s.", mId,
- statusOrHandle.GetErrorMessage().c_str());
- }
- return statusOrHandle;
-}
-
Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
ATRACE_CALL();
ALOGD("BufferHubBuffer::Duplicate: id=%d.", mId);
diff --git a/libs/ui/BufferHubMetadata.cpp b/libs/ui/BufferHubMetadata.cpp
index b0c4510..1e08ed1 100644
--- a/libs/ui/BufferHubMetadata.cpp
+++ b/libs/ui/BufferHubMetadata.cpp
@@ -22,7 +22,6 @@
#include <ui/BufferHubMetadata.h>
namespace android {
-namespace dvr {
namespace {
@@ -30,8 +29,8 @@
} // namespace
-using BufferHubDefs::kMetadataHeaderSize;
-using BufferHubDefs::MetadataHeader;
+using dvr::BufferHubDefs::kMetadataHeaderSize;
+using dvr::BufferHubDefs::MetadataHeader;
/* static */
BufferHubMetadata BufferHubMetadata::Create(size_t userMetadataSize) {
@@ -101,5 +100,4 @@
}
}
-} // namespace dvr
} // namespace android
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 61df02d..ee06d93 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -234,6 +234,9 @@
case ColorMode::BT2020:
return std::string("ColorMode::BT2020");
+ case ColorMode::DISPLAY_BT2020:
+ return std::string("ColorMode::DISPLAY_BT2020");
+
case ColorMode::BT2100_PQ:
return std::string("ColorMode::BT2100_PQ");
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index e8ae244..cefe5b3 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -88,7 +88,7 @@
// A state mask which is unique to a buffer hub client among all its siblings sharing the same
// concrete graphic buffer.
- uint64_t buffer_state_bit() const { return mBfferStateBit; }
+ uint64_t buffer_state_bit() const { return mBufferStateBit; }
size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
@@ -112,11 +112,6 @@
// Polls the fd for |timeoutMs| milliseconds (-1 for infinity).
int Poll(int timeoutMs);
- // Promotes a BufferHubBuffer to become a ProducerBuffer. Once promoted the BufferHubBuffer
- // channel will be closed automatically on successful IPC return. Further IPCs towards this
- // channel will return error.
- pdx::Status<pdx::LocalChannelHandle> Promote();
-
// Creates a BufferHubBuffer client from an existing one. The new client will
// share the same underlying gralloc buffer and ashmem region for metadata.
pdx::Status<pdx::LocalChannelHandle> Duplicate();
@@ -130,15 +125,15 @@
int ImportGraphicBuffer();
// Global id for the buffer that is consistent across processes.
- int mId;
- uint64_t mBfferStateBit;
+ int mId = -1;
+ uint64_t mBufferStateBit = 0;
// Wrapps the gralloc buffer handle of this buffer.
dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;
// An ashmem-based metadata object. The same shared memory are mapped to the
// bufferhubd daemon and all buffer clients.
- dvr::BufferHubMetadata mMetadata;
+ BufferHubMetadata mMetadata;
// PDX backend.
BufferHubClient mClient;
diff --git a/libs/ui/include/ui/BufferHubMetadata.h b/libs/ui/include/ui/BufferHubMetadata.h
index 46adc6a..94a9000 100644
--- a/libs/ui/include/ui/BufferHubMetadata.h
+++ b/libs/ui/include/ui/BufferHubMetadata.h
@@ -38,7 +38,6 @@
#pragma clang diagnostic pop
namespace android {
-namespace dvr {
class BufferHubMetadata {
public:
@@ -83,24 +82,25 @@
bool IsValid() const { return mAshmemHandle.IsValid() && mMetadataHeader != nullptr; }
size_t user_metadata_size() const { return mUserMetadataSize; }
- size_t metadata_size() const { return mUserMetadataSize + BufferHubDefs::kMetadataHeaderSize; }
+ size_t metadata_size() const {
+ return mUserMetadataSize + dvr::BufferHubDefs::kMetadataHeaderSize;
+ }
const pdx::LocalHandle& ashmem_handle() const { return mAshmemHandle; }
- BufferHubDefs::MetadataHeader* metadata_header() { return mMetadataHeader; }
+ dvr::BufferHubDefs::MetadataHeader* metadata_header() { return mMetadataHeader; }
private:
BufferHubMetadata(size_t userMetadataSize, pdx::LocalHandle ashmemHandle,
- BufferHubDefs::MetadataHeader* metadataHeader);
+ dvr::BufferHubDefs::MetadataHeader* metadataHeader);
BufferHubMetadata(const BufferHubMetadata&) = delete;
void operator=(const BufferHubMetadata&) = delete;
size_t mUserMetadataSize = 0;
pdx::LocalHandle mAshmemHandle;
- BufferHubDefs::MetadataHeader* mMetadataHeader = nullptr;
+ dvr::BufferHubDefs::MetadataHeader* mMetadataHeader = nullptr;
};
-} // namespace dvr
} // namespace android
#endif // ANDROID_BUFFER_HUB_METADATA_H_
diff --git a/libs/ui/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
index 6a7479a..4cd9a0b 100644
--- a/libs/ui/include/ui/FloatRect.h
+++ b/libs/ui/include/ui/FloatRect.h
@@ -28,7 +28,7 @@
float getHeight() const { return bottom - top; }
FloatRect intersect(const FloatRect& other) const {
- return {
+ FloatRect intersection = {
// Inline to avoid tromping on other min/max defines or adding a
// dependency on STL
(left > other.left) ? left : other.left,
@@ -36,6 +36,10 @@
(right < other.right) ? right : other.right,
(bottom < other.bottom) ? bottom : other.bottom
};
+ if (intersection.getWidth() < 0 || intersection.getHeight() < 0) {
+ return {0, 0, 0, 0};
+ }
+ return intersection;
}
float left = 0.0f;
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index 0fa819d..1d53ac8 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
#include <system/graphics.h>
// android::ui::* in this header file will alias different types as
@@ -25,10 +26,10 @@
namespace ui {
using android::hardware::graphics::common::V1_0::Hdr;
-using android::hardware::graphics::common::V1_1::ColorMode;
-using android::hardware::graphics::common::V1_1::Dataspace;
using android::hardware::graphics::common::V1_1::PixelFormat;
using android::hardware::graphics::common::V1_1::RenderIntent;
+using android::hardware::graphics::common::V1_2::ColorMode;
+using android::hardware::graphics::common::V1_2::Dataspace;
} // namespace ui
} // namespace android
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 6e73960..228d202 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -36,6 +36,14 @@
}
cc_test {
+ name: "BufferHubBuffer_test",
+ header_libs: ["libbufferhub_headers", "libdvr_headers"],
+ shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+ srcs: ["BufferHubBuffer_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+}
+
+cc_test {
name: "BufferHubMetadata_test",
header_libs: ["libbufferhub_headers", "libdvr_headers"],
shared_libs: ["libpdx_default_transport", "libui", "libutils"],
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
new file mode 100644
index 0000000..be06ad2
--- /dev/null
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferHubBufferTest"
+
+#include <gtest/gtest.h>
+#include <ui/BufferHubBuffer.h>
+
+namespace android {
+
+namespace {
+
+const int kWidth = 640;
+const int kHeight = 480;
+const int kLayerCount = 1;
+const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+const int kUsage = 0;
+const size_t kUserMetadataSize = 0;
+
+} // namespace
+
+using BufferHubBufferTest = ::testing::Test;
+
+using dvr::BufferHubDefs::IsBufferGained;
+using dvr::BufferHubDefs::kMetadataHeaderSize;
+using dvr::BufferHubDefs::kProducerStateBit;
+using pdx::LocalChannelHandle;
+
+TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
+ // Buffer Creation will fail: BLOB format requires height to be 1.
+ auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
+ /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, kUserMetadataSize);
+
+ EXPECT_FALSE(b1->IsConnected());
+ EXPECT_FALSE(b1->IsValid());
+
+ // Buffer Creation will fail: user metadata size too large.
+ auto b2 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ /*userMetadataSize=*/std::numeric_limits<size_t>::max());
+
+ EXPECT_FALSE(b2->IsConnected());
+ EXPECT_FALSE(b2->IsValid());
+
+ // Buffer Creation will fail: user metadata size too large.
+ const size_t userMetadataSize = std::numeric_limits<size_t>::max() - kMetadataHeaderSize;
+ auto b3 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ userMetadataSize);
+
+ EXPECT_FALSE(b3->IsConnected());
+ EXPECT_FALSE(b3->IsValid());
+}
+
+TEST_F(BufferHubBufferTest, CreateBufferHubBuffer) {
+ auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ kUserMetadataSize);
+ EXPECT_TRUE(b1->IsConnected());
+ EXPECT_TRUE(b1->IsValid());
+ EXPECT_NE(b1->id(), 0);
+}
+
+TEST_F(BufferHubBufferTest, DuplicateBufferHubBuffer) {
+ auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ kUserMetadataSize);
+ int id1 = b1->id();
+ EXPECT_TRUE(b1->IsValid());
+ EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
+
+ auto statusOrHandle = b1->Duplicate();
+ EXPECT_TRUE(statusOrHandle);
+
+ // The detached buffer should still be valid.
+ EXPECT_TRUE(b1->IsConnected());
+ EXPECT_TRUE(b1->IsValid());
+
+ // Gets the channel handle for the duplicated buffer.
+ LocalChannelHandle h2 = statusOrHandle.take();
+ EXPECT_TRUE(h2.valid());
+
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
+ EXPECT_FALSE(h2.valid());
+ ASSERT_TRUE(b2 != nullptr);
+ EXPECT_TRUE(b2->IsValid());
+ EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
+
+ int id2 = b2->id();
+
+ // These two buffer instances are based on the same physical buffer under the
+ // hood, so they should share the same id.
+ EXPECT_EQ(id1, id2);
+ // We use buffer_state_bit() to tell those two instances apart.
+ EXPECT_NE(b1->buffer_state_bit(), b2->buffer_state_bit());
+ EXPECT_NE(b1->buffer_state_bit(), 0ULL);
+ EXPECT_NE(b2->buffer_state_bit(), 0ULL);
+ EXPECT_NE(b1->buffer_state_bit(), kProducerStateBit);
+ EXPECT_NE(b2->buffer_state_bit(), kProducerStateBit);
+
+ // Both buffer instances should be in gained state.
+ EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
+ EXPECT_TRUE(IsBufferGained(b2->buffer_state()));
+
+ // TODO(b/112338294): rewrite test after migration
+ return;
+}
+
+} // namespace android
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index ba5cfcd..43ac79e 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -22,6 +22,7 @@
"buffer_hub_base.cpp",
"buffer_hub_rpc.cpp",
"consumer_buffer.cpp",
+ "buffer_client_impl.cpp",
"ion_buffer.cpp",
"producer_buffer.cpp",
]
diff --git a/libs/vr/libbufferhub/buffer_client_impl.cpp b/libs/vr/libbufferhub/buffer_client_impl.cpp
new file mode 100644
index 0000000..6bef98a
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_client_impl.cpp
@@ -0,0 +1,55 @@
+#include <log/log.h>
+#include <private/dvr/IBufferClient.h>
+
+namespace android {
+namespace dvr {
+
+class BpBufferClient : public BpInterface<IBufferClient> {
+ public:
+ explicit BpBufferClient(const sp<IBinder>& impl)
+ : BpInterface<IBufferClient>(impl) {}
+
+ bool isValid() override;
+};
+
+IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient");
+
+// Transaction code
+enum {
+ IS_VALID = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+bool BpBufferClient::isValid() {
+ Parcel data, reply;
+ status_t ret =
+ data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor());
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferClient::isValid: failed to write into parcel; errno=%d",
+ ret);
+ return false;
+ }
+
+ ret = remote()->transact(IS_VALID, data, &reply);
+ if (ret == NO_ERROR) {
+ return reply.readBool();
+ } else {
+ ALOGE("BpBufferClient::isValid: failed to transact; errno=%d", ret);
+ return false;
+ }
+}
+
+status_t BnBufferClient::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ switch (code) {
+ case IS_VALID: {
+ CHECK_INTERFACE(IBufferClient, data, reply);
+ return reply->writeBool(isValid());
+ } break;
+ default:
+ // Should not reach except binder defined transactions such as dumpsys
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace dvr
+} // namespace android
\ No newline at end of file
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index b477f1a..4d98dfc 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -214,13 +214,12 @@
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
- uint64_t context;
LocalHandle fence;
// The producer buffer starts in gained state.
// Acquire, release, and gain in gained state should fail.
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
EXPECT_EQ(-EALREADY, p->Gain(&fence));
@@ -233,10 +232,10 @@
EXPECT_EQ(-EBUSY, p->Gain(&fence));
// Acquire in posted state should succeed.
- EXPECT_LE(0, c->Acquire(&fence, &context));
+ EXPECT_LE(0, c->Acquire(&fence));
// Acquire, post, and gain in acquired state should fail.
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
EXPECT_EQ(-EBUSY, p->Gain(&fence));
@@ -246,14 +245,14 @@
// Release, acquire, and post in released state should fail.
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
// Gain in released state should succeed.
EXPECT_EQ(0, p->Gain(&fence));
// Acquire, release, and gain in gained state should fail.
- EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence));
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
EXPECT_EQ(-EALREADY, p->Gain(&fence));
}
@@ -491,7 +490,7 @@
EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
LocalHandle fence;
Metadata m2 = {};
- EXPECT_EQ(0, c->Acquire(&fence, &m2));
+ EXPECT_EQ(0, c->Acquire(&fence, &m2, sizeof(m2)));
EXPECT_EQ(m.field1, m2.field1);
EXPECT_EQ(m.field2, m2.field2);
EXPECT_EQ(0, c->Release(LocalHandle()));
@@ -552,11 +551,11 @@
// It is illegal to acquire metadata larger than originally requested during
// buffer allocation.
- EXPECT_NE(0, c->Acquire(&fence, &e));
+ EXPECT_NE(0, c->Acquire(&fence, &e, sizeof(e)));
// It is ok to acquire metadata smaller than originally requested during
// buffer allocation.
- EXPECT_EQ(0, c->Acquire(&fence, &sequence));
+ EXPECT_EQ(0, c->Acquire(&fence, &sequence, sizeof(sequence)));
EXPECT_EQ(m.field1, sequence);
}
@@ -829,43 +828,7 @@
EXPECT_NE(b1->id(), 0);
}
-TEST_F(LibBufferHubTest, TestPromoteBufferHubBuffer) {
- // TODO(b/112338294) rewrite test after migration
- return;
-
- auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
- kUsage, kUserMetadataSize);
- int b1_id = b1->id();
- EXPECT_TRUE(b1->IsValid());
-
- auto status_or_handle = b1->Promote();
- EXPECT_TRUE(status_or_handle);
-
- // The detached buffer should have hangup.
- EXPECT_GT(RETRY_EINTR(b1->Poll(kPollTimeoutMs)), 0);
- auto status_or_int = b1->GetEventMask(POLLHUP);
- EXPECT_TRUE(status_or_int.ok());
- EXPECT_EQ(status_or_int.get(), POLLHUP);
-
- // The buffer client is still considered as connected but invalid.
- EXPECT_TRUE(b1->IsConnected());
- EXPECT_FALSE(b1->IsValid());
-
- // Gets the channel handle for the producer.
- LocalChannelHandle h1 = status_or_handle.take();
- EXPECT_TRUE(h1.valid());
-
- std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Import(std::move(h1));
- EXPECT_FALSE(h1.valid());
- ASSERT_TRUE(p1 != nullptr);
- int p1_id = p1->id();
-
- // A newly promoted ProducerBuffer should inherit the same buffer id.
- EXPECT_EQ(b1_id, p1_id);
- EXPECT_TRUE(IsBufferGained(p1->buffer_state()));
-}
-
-TEST_F(LibBufferHubTest, TestDetachThenPromote) {
+TEST_F(LibBufferHubTest, TestDetach) {
// TODO(b/112338294) rewrite test after migration
return;
@@ -887,26 +850,6 @@
EXPECT_TRUE(b1->IsValid());
int b1_id = b1->id();
EXPECT_EQ(b1_id, p1_id);
-
- // Promote the detached buffer.
- status_or_handle = b1->Promote();
- // The buffer client is still considered as connected but invalid.
- EXPECT_TRUE(b1->IsConnected());
- EXPECT_FALSE(b1->IsValid());
- EXPECT_TRUE(status_or_handle.ok());
-
- // Gets the channel handle for the producer.
- LocalChannelHandle h2 = status_or_handle.take();
- EXPECT_TRUE(h2.valid());
-
- std::unique_ptr<ProducerBuffer> p2 = ProducerBuffer::Import(std::move(h2));
- EXPECT_FALSE(h2.valid());
- ASSERT_TRUE(p2 != nullptr);
- int p2_id = p2->id();
-
- // A newly promoted ProducerBuffer should inherit the same buffer id.
- EXPECT_EQ(b1_id, p2_id);
- EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
}
TEST_F(LibBufferHubTest, TestDuplicateBufferHubBuffer) {
@@ -951,10 +894,4 @@
// TODO(b/112338294) rewrite test after migration
return;
-
- // Promote the detached buffer should fail as b1 is no longer the exclusive
- // owner of the buffer..
- status_or_handle = b1->Promote();
- EXPECT_FALSE(status_or_handle.ok());
- EXPECT_EQ(status_or_handle.error(), EINVAL);
}
diff --git a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
new file mode 100644
index 0000000..03f2d95
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
@@ -0,0 +1,29 @@
+#ifndef ANDROID_DVR_IBUFFERCLIENT_H
+#define ANDROID_DVR_IBUFFERCLIENT_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+namespace dvr {
+
+// Interface for acessing BufferHubBuffer remotely.
+class IBufferClient : public IInterface {
+ public:
+ DECLARE_META_INTERFACE(BufferClient);
+
+ // Checks if the buffer node is valid.
+ virtual bool isValid() = 0;
+};
+
+// BnInterface for IBufferClient. Should only be created in bufferhub service.
+class BnBufferClient : public BnInterface<IBufferClient> {
+ public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_IBUFFERCLIENT_H
\ No newline at end of file
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 6d28d41..49f9c3e 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -191,11 +191,6 @@
// Imports the given channel handle to a DetachedBuffer, taking ownership.
kOpImport,
- // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the
- // DetachedBuffer channel will be closed automatically on successful IPC
- // return. Further IPCs towards this channel will return error.
- kOpPromote,
-
// Creates a DetachedBuffer client from an existing one. The new client will
// share the same underlying gralloc buffer and ashmem region for metadata.
kOpDuplicate,
@@ -212,10 +207,9 @@
uint32_t format, uint64_t usage,
size_t user_metadata_size));
PDX_REMOTE_METHOD(Import, kOpImport, BufferTraits<LocalHandle>(Void));
- PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
- PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
+ PDX_REMOTE_API(API, Create, Import, Duplicate);
};
} // namespace dvr
diff --git a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
index 2044c53..7349779 100644
--- a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
@@ -45,15 +45,6 @@
// Returns zero on success, or a negative errno code otherwise.
int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
- // Attempt to retrieve a post event from buffer hub. If successful,
- // |ready_fence| is set to a fence to wait on until the buffer is ready. This
- // call will only succeed after the fd is signaled. This returns zero or a
- // negative unix error code.
- template <typename Meta>
- int Acquire(LocalHandle* ready_fence, Meta* meta) {
- return Acquire(ready_fence, meta, sizeof(*meta));
- }
-
// Asynchronously acquires a bufer.
int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h b/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h
index 3086982..ae70b77 100644
--- a/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h
+++ b/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h
@@ -40,7 +40,7 @@
bool IsValid() const { return ints_.size() != 0 || fds_.size() != 0; }
// Duplicate a native handle from the wrapper.
- const native_handle_t* DuplicateHandle() const {
+ native_handle_t* DuplicateHandle() const {
if (!IsValid()) {
return nullptr;
}
@@ -58,7 +58,7 @@
}
// Takes the native handle out of the wrapper.
- const native_handle_t* TakeHandle() {
+ native_handle_t* TakeHandle() {
if (!IsValid()) {
return nullptr;
}
@@ -70,8 +70,8 @@
NativeHandleWrapper(const NativeHandleWrapper&) = delete;
void operator=(const NativeHandleWrapper&) = delete;
- static const native_handle_t* FromFdsAndInts(std::vector<FileHandleType> fds,
- std::vector<int> ints) {
+ static native_handle_t* FromFdsAndInts(std::vector<FileHandleType> fds,
+ std::vector<int> ints) {
native_handle_t* handle = native_handle_create(fds.size(), ints.size());
if (!handle) {
ALOGE("NativeHandleWrapper::TakeHandle: Failed to create new handle.");
diff --git a/opengl/include/EGL/egl.h b/opengl/include/EGL/egl.h
index 93a3965..c9e8b7c 100644
--- a/opengl/include/EGL/egl.h
+++ b/opengl/include/EGL/egl.h
@@ -33,12 +33,12 @@
** used to make the header, and the header can be found at
** http://www.khronos.org/registry/egl
**
-** Khronos $Git commit SHA1: a732b061e7 $ on $Git commit date: 2017-06-17 23:27:53 +0100 $
+** Khronos $Git commit SHA1: bae3518c48 $ on $Git commit date: 2018-05-17 10:56:57 -0700 $
*/
#include <EGL/eglplatform.h>
-/* Generated on date 20170627 */
+/* Generated on date 20180517 */
/* Generated C header for:
* API: egl
@@ -235,10 +235,66 @@
EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);
#endif /* EGL_VERSION_1_4 */
-/* This version of Android does not yet support EGL 1.5, but the following
- * portion of EGL 1.5 is included in order to support portions of "eglext.h".
- */
+#ifndef EGL_VERSION_1_5
+#define EGL_VERSION_1_5 1
+typedef void *EGLSync;
typedef intptr_t EGLAttrib;
+typedef khronos_utime_nanoseconds_t EGLTime;
+typedef void *EGLImage;
+#define EGL_CONTEXT_MAJOR_VERSION 0x3098
+#define EGL_CONTEXT_MINOR_VERSION 0x30FB
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
+#define EGL_NO_RESET_NOTIFICATION 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
+#define EGL_OPENGL_ES3_BIT 0x00000040
+#define EGL_CL_EVENT_HANDLE 0x309C
+#define EGL_SYNC_CL_EVENT 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
+#define EGL_SYNC_TYPE 0x30F7
+#define EGL_SYNC_STATUS 0x30F1
+#define EGL_SYNC_CONDITION 0x30F8
+#define EGL_SIGNALED 0x30F2
+#define EGL_UNSIGNALED 0x30F3
+#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
+#define EGL_FOREVER 0xFFFFFFFFFFFFFFFFull
+#define EGL_TIMEOUT_EXPIRED 0x30F5
+#define EGL_CONDITION_SATISFIED 0x30F6
+#define EGL_NO_SYNC EGL_CAST(EGLSync,0)
+#define EGL_SYNC_FENCE 0x30F9
+#define EGL_GL_COLORSPACE 0x309D
+#define EGL_GL_COLORSPACE_SRGB 0x3089
+#define EGL_GL_COLORSPACE_LINEAR 0x308A
+#define EGL_GL_RENDERBUFFER 0x30B9
+#define EGL_GL_TEXTURE_2D 0x30B1
+#define EGL_GL_TEXTURE_LEVEL 0x30BC
+#define EGL_GL_TEXTURE_3D 0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
+#define EGL_IMAGE_PRESERVED 0x30D2
+#define EGL_NO_IMAGE EGL_CAST(EGLImage,0)
+EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
+EGLAPI EGLImage EGLAPIENTRY eglCreateImage (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImage (EGLDisplay dpy, EGLImage image);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags);
+#endif /* EGL_VERSION_1_5 */
#ifdef __cplusplus
}
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 0fd91eb..ad4ffd7 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -33,12 +33,12 @@
** used to make the header, and the header can be found at
** http://www.khronos.org/registry/egl
**
-** Khronos $Git commit SHA1: feaaeb19e1 $ on $Git commit date: 2018-02-26 20:49:02 -0800 $
+** Khronos $Git commit SHA1: bae3518c48 $ on $Git commit date: 2018-05-17 10:56:57 -0700 $
*/
#include <EGL/eglplatform.h>
-#define EGL_EGLEXT_VERSION 20180228
+#define EGL_EGLEXT_VERSION 20180517
/* Generated C header for:
* API: egl
@@ -618,6 +618,16 @@
#define EGL_EXT_client_extensions 1
#endif /* EGL_EXT_client_extensions */
+#ifndef EGL_EXT_client_sync
+#define EGL_EXT_client_sync 1
+#define EGL_SYNC_CLIENT_EXT 0x3364
+#define EGL_SYNC_CLIENT_SIGNAL_EXT 0x3365
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCLIENTSIGNALSYNCEXTPROC) (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglClientSignalSyncEXT (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_EXT_client_sync */
+
#ifndef EGL_EXT_compositor
#define EGL_EXT_compositor 1
#define EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT 0x3460
@@ -903,6 +913,14 @@
#endif
#endif /* EGL_EXT_swap_buffers_with_damage */
+#ifndef EGL_EXT_sync_reuse
+#define EGL_EXT_sync_reuse 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNSIGNALSYNCEXTPROC) (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglUnsignalSyncEXT (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_EXT_sync_reuse */
+
#ifndef EGL_EXT_yuv_surface
#define EGL_EXT_yuv_surface 1
#define EGL_YUV_ORDER_EXT 0x3301
@@ -1147,6 +1165,14 @@
#define EGL_STREAM_FIFO_SYNCHRONOUS_NV 0x3336
#endif /* EGL_NV_stream_fifo_synchronous */
+#ifndef EGL_NV_stream_flush
+#define EGL_NV_stream_flush 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMFLUSHNVPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamFlushNV (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_NV_stream_flush */
+
#ifndef EGL_NV_stream_frame_limits
#define EGL_NV_stream_frame_limits 1
#define EGL_PRODUCER_MAX_FRAME_HINT_NV 0x3337
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
index c77c333..0bc2cb9 100644
--- a/opengl/include/EGL/eglplatform.h
+++ b/opengl/include/EGL/eglplatform.h
@@ -77,12 +77,24 @@
typedef HBITMAP EGLNativePixmapType;
typedef HWND EGLNativeWindowType;
-#elif defined(__APPLE__) || defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
typedef int EGLNativeDisplayType;
typedef void *EGLNativeWindowType;
typedef void *EGLNativePixmapType;
+#elif defined(WL_EGL_PLATFORM)
+
+typedef struct wl_display *EGLNativeDisplayType;
+typedef struct wl_egl_pixmap *EGLNativePixmapType;
+typedef struct wl_egl_window *EGLNativeWindowType;
+
+#elif defined(__GBM__)
+
+typedef struct gbm_device *EGLNativeDisplayType;
+typedef struct gbm_bo *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
#elif defined(__ANDROID__) || defined(ANDROID)
struct ANativeWindow;
@@ -92,7 +104,13 @@
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
typedef void* EGLNativeDisplayType;
-#elif defined(__unix__)
+#elif defined(USE_OZONE)
+
+typedef intptr_t EGLNativeDisplayType;
+typedef intptr_t EGLNativeWindowType;
+typedef intptr_t EGLNativePixmapType;
+
+#elif defined(__unix__) || defined(USE_X11)
/* X11 (tentative) */
#include <X11/Xlib.h>
@@ -102,6 +120,20 @@
typedef Pixmap EGLNativePixmapType;
typedef Window EGLNativeWindowType;
+#elif defined(__APPLE__)
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativeWindowType;
+typedef void *EGLNativePixmapType;
+
+#elif defined(__HAIKU__)
+
+#include <kernel/image.h>
+
+typedef void *EGLNativeDisplayType;
+typedef khronos_uintptr_t EGLNativePixmapType;
+typedef khronos_uintptr_t EGLNativeWindowType;
+
#else
#error "Platform not recognized"
#endif
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index 1d5def5..8bb7e83 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -181,7 +181,7 @@
case GL_FOG:
case GL_DEPTH_TEST:
ogles_invalidate_perspective(c);
- // fall-through...
+ [[fallthrough]];
case GL_BLEND:
case GL_SCISSOR_TEST:
case GL_ALPHA_TEST:
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index aae8e05..4c5f3e9 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -401,14 +401,14 @@
switch (format) {
case GL_PALETTE4_RGB8_OES:
indexBits = 4;
- /* FALLTHROUGH */
+ [[fallthrough]];
case GL_PALETTE8_RGB8_OES:
entrySize = 3;
break;
case GL_PALETTE4_RGBA8_OES:
indexBits = 4;
- /* FALLTHROUGH */
+ [[fallthrough]];
case GL_PALETTE8_RGBA8_OES:
entrySize = 4;
break;
@@ -417,7 +417,7 @@
case GL_PALETTE4_RGBA4_OES:
case GL_PALETTE4_RGB5_A1_OES:
indexBits = 4;
- /* FALLTHROUGH */
+ [[fallthrough]];
case GL_PALETTE8_R5_G6_B5_OES:
case GL_PALETTE8_RGBA4_OES:
case GL_PALETTE8_RGB5_A1_OES:
@@ -446,14 +446,14 @@
switch (format) {
case GL_PALETTE4_RGB8_OES:
indexBits = 4;
- /* FALLTHROUGH */
+ [[fallthrough]];
case GL_PALETTE8_RGB8_OES:
entrySize = 3;
break;
case GL_PALETTE4_RGBA8_OES:
indexBits = 4;
- /* FALLTHROUGH */
+ [[fallthrough]];
case GL_PALETTE8_RGBA8_OES:
entrySize = 4;
break;
@@ -462,7 +462,7 @@
case GL_PALETTE4_RGBA4_OES:
case GL_PALETTE4_RGB5_A1_OES:
indexBits = 4;
- /* FALLTHROUGH */
+ [[fallthrough]];
case GL_PALETTE8_R5_G6_B5_OES:
case GL_PALETTE8_RGBA4_OES:
case GL_PALETTE8_RGB5_A1_OES:
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 31712fc..a7fea33 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -51,6 +51,14 @@
typedef bool (*fpANGLEUseForApplication)(const char* appName, const char* deviceMfr,
const char* deviceModel, ANGLEPreference developerOption,
ANGLEPreference appPreference);
+
+ // TODO(ianelliott@): Get this from an ANGLE header:
+ typedef bool (*fpANGLEGetUtilityAPI)(unsigned int* versionToUse);
+
+ // TODO(ianelliott@): Get this from an ANGLE header:
+ typedef bool (*fpAndroidUseANGLEForApplication)(int fd, long offset, long length,
+ const char* appName, const char* deviceMfr,
+ const char* deviceModel);
}
// ----------------------------------------------------------------------------
@@ -511,7 +519,7 @@
return ANGLE_NO_PREFERENCE;
}
-static void* load_angle(const char* kind, egl_connection_t* cnx) {
+static void* load_angle(const char* kind, android_namespace_t* ns, egl_connection_t* cnx) {
// Only attempt to load ANGLE libs
if (strcmp(kind, "EGL") != 0 && strcmp(kind, "GLESv2") != 0 && strcmp(kind, "GLESv1_CM") != 0)
return nullptr;
@@ -520,10 +528,12 @@
std::string name;
char prop[PROPERTY_VALUE_MAX];
- android_namespace_t* ns = android_getAngleNamespace();
const char* app_name = android_getAngleAppName();
const char* app_pref = android_getAngleAppPref();
bool developer_opt_in = android_getAngleDeveloperOptIn();
+ const int rules_fd = android_getAngleRulesFd();
+ const long rules_offset = android_getAngleRulesOffset();
+ const long rules_length = android_getAngleRulesLength();
// Determine whether or not to use ANGLE:
ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
@@ -539,21 +549,58 @@
char model[PROPERTY_VALUE_MAX];
property_get("ro.product.manufacturer", manufacturer, "UNSET");
property_get("ro.product.model", model, "UNSET");
- ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
- so = load_angle_from_namespace("feature_support", ns);
+ // Check if ANGLE is enabled. Workaround for b/118375731
+ // We suspect that loading & unloading a library somehow corrupts
+ // the process.
+ property_get("debug.angle.enable", prop, "0");
+ if (atoi(prop)) {
+ so = load_angle_from_namespace("feature_support", ns);
+ }
if (so) {
ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
- fpANGLEUseForApplication fp =
- (fpANGLEUseForApplication)dlsym(so, "ANGLEUseForApplication");
- if (fp) {
- use_angle = (fp)(app_name_str.c_str(), manufacturer, model, developer_option,
- app_preference);
- ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
+ bool use_version0_API = false;
+ bool use_version1_API = false;
+ fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
+ (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
+ if (ANGLEGetUtilityAPI) {
+ unsigned int versionToUse = 1;
+ if ((ANGLEGetUtilityAPI)(&versionToUse)) {
+ if (versionToUse == 1) {
+ use_version1_API = true;
+ } else {
+ use_version0_API = true;
+ }
+ }
} else {
- ALOGW("Cannot find ANGLEUseForApplication in library");
+ use_version0_API = true;
}
-
+ if (use_version1_API) {
+ // Use the new version 1 API to determine if the
+ // application should use the ANGLE or the native driver.
+ fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
+ (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
+ if (AndroidUseANGLEForApplication) {
+ use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
+ rules_length, app_name_str.c_str(),
+ manufacturer, model);
+ } else {
+ ALOGW("Cannot find AndroidUseANGLEForApplication in library");
+ }
+ } else if (use_version0_API) {
+ // Use the old version 0 API to determine if the
+ // application should use the ANGLE or the native driver.
+ fpANGLEUseForApplication ANGLEUseForApplication =
+ (fpANGLEUseForApplication)dlsym(so, "ANGLEUseForApplication");
+ if (ANGLEUseForApplication) {
+ ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
+ use_angle = (ANGLEUseForApplication)(app_name_str.c_str(), manufacturer, model,
+ developer_option, app_preference);
+ ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
+ } else {
+ ALOGW("Cannot find ANGLEUseForApplication in library");
+ }
+ }
ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
dlclose(so);
so = nullptr;
@@ -620,7 +667,10 @@
ATRACE_CALL();
void* dso = nullptr;
- dso = load_angle(kind, cnx);
+ android_namespace_t* ns = android_getAngleNamespace();
+ if (ns) {
+ dso = load_angle(kind, ns, cnx);
+ }
#ifndef __ANDROID_VNDK__
if (!dso) {
android_namespace_t* ns = android_getDriverNamespace();
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index e3c708d..29a966d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -52,6 +52,21 @@
return cnx->platform.eglGetDisplay(display);
}
+EGLDisplay eglGetPlatformDisplay(EGLenum platform, EGLNativeDisplayType display,
+ const EGLAttrib* attrib_list) {
+ ATRACE_CALL();
+ clearError();
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
+ // Call down the chain, which usually points directly to the impl
+ // but may also be routed through layers
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglGetPlatformDisplay(platform, display, attrib_list);
+}
+
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
clearError();
@@ -97,6 +112,14 @@
return cnx->platform.eglCreateWindowSurface(dpy, config, window, attrib_list);
}
+EGLSurface eglCreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void* native_window,
+ const EGLAttrib* attrib_list) {
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglCreatePlatformWindowSurface(dpy, config, native_window, attrib_list);
+}
+
EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap,
const EGLint* attrib_list) {
clearError();
@@ -105,6 +128,14 @@
return cnx->platform.eglCreatePixmapSurface(dpy, config, pixmap, attrib_list);
}
+EGLSurface eglCreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap,
+ const EGLAttrib* attrib_list) {
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglCreatePlatformPixmapSurface(dpy, config, native_pixmap, attrib_list);
+}
+
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) {
clearError();
@@ -352,6 +383,14 @@
return cnx->platform.eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list);
}
+EGLImage eglCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer,
+ const EGLAttrib* attrib_list) {
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglCreateImage(dpy, ctx, target, buffer, attrib_list);
+}
+
EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) {
clearError();
@@ -359,6 +398,24 @@
return cnx->platform.eglDestroyImageKHR(dpy, img);
}
+EGLBoolean eglDestroyImage(EGLDisplay dpy, EGLImageKHR img) {
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglDestroyImage(dpy, img);
+}
+
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 5
+// ----------------------------------------------------------------------------
+
+EGLSyncKHR eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list) {
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglCreateSync(dpy, type, attrib_list);
+}
+
EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) {
clearError();
@@ -366,6 +423,13 @@
return cnx->platform.eglCreateSyncKHR(dpy, type, attrib_list);
}
+EGLBoolean eglDestroySync(EGLDisplay dpy, EGLSyncKHR sync) {
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglDestroySync(dpy, sync);
+}
+
EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) {
clearError();
@@ -380,6 +444,13 @@
return cnx->platform.eglSignalSyncKHR(dpy, sync, mode);
}
+EGLint eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTimeKHR timeout) {
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglClientWaitSyncKHR(dpy, sync, flags, timeout);
+}
+
EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) {
clearError();
@@ -387,6 +458,13 @@
return cnx->platform.eglClientWaitSyncKHR(dpy, sync, flags, timeout);
}
+EGLBoolean eglGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value) {
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglGetSyncAttrib(dpy, sync, attribute, value);
+}
+
EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint* value) {
clearError();
@@ -490,6 +568,12 @@
return cnx->platform.eglWaitSyncKHR(dpy, sync, flags);
}
+EGLBoolean eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) {
+ clearError();
+ egl_connection_t* const cnx = &gEGLImpl;
+ return cnx->platform.eglWaitSync(dpy, sync, flags);
+}
+
EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) {
clearError();
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index d452a6c..476b304 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -46,7 +46,8 @@
// ----------------------------------------------------------------------------
static char const * const sVendorString = "Android";
-static char const * const sVersionString = "1.4 Android META-EGL";
+static char const* const sVersionString14 = "1.4 Android META-EGL";
+static char const* const sVersionString15 = "1.5 Android META-EGL";
static char const * const sClientApiString = "OpenGL_ES";
extern char const * const gBuiltinExtensionString;
@@ -119,14 +120,15 @@
return false;
}
-EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
+EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp,
+ const EGLAttrib* attrib_list) {
if (uintptr_t(disp) >= NUM_DISPLAYS)
return nullptr;
- return sDisplay[uintptr_t(disp)].getDisplay(disp);
+ return sDisplay[uintptr_t(disp)].getPlatformDisplay(disp, attrib_list);
}
-static void addAnglePlatformAttributes(egl_connection_t* const cnx, const EGLAttrib* attrib_list,
+static bool addAnglePlatformAttributes(egl_connection_t* const cnx, const EGLAttrib* attrib_list,
std::vector<EGLAttrib>& attrs) {
intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
@@ -153,24 +155,29 @@
}
}
- cnx->angleBackend = angleBackendDefault;
-
// Allow debug property to override application's
char prop[PROPERTY_VALUE_MAX];
property_get("debug.angle.backend", prop, "0");
switch (atoi(prop)) {
case 1:
ALOGV("addAnglePlatformAttributes: Requesting OpenGLES back-end");
- cnx->angleBackend = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
+ angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
break;
case 2:
ALOGV("addAnglePlatformAttributes: Requesting Vulkan back-end");
- cnx->angleBackend = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+ angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
break;
default:
break;
}
+ if (cnx->angleBackend == 0) {
+ // Haven't been initialized yet, so set it.
+ cnx->angleBackend = angleBackendDefault;
+ } else if (cnx->angleBackend != angleBackendDefault) {
+ return false;
+ }
+
attrs.reserve(4 * 2);
attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
@@ -198,6 +205,8 @@
}
attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
attrs.push_back(EGL_FALSE);
+
+ return true;
}
// Initialize function ptrs for ANGLE PlatformMethods struct, used for systrace
@@ -237,24 +246,30 @@
return true;
}
-static EGLDisplay getDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx) {
+static EGLDisplay getPlatformDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx,
+ const EGLAttrib* attrib_list, EGLint* error) {
EGLDisplay dpy = EGL_NO_DISPLAY;
+ *error = EGL_NONE;
- // Locally define this until EGL 1.5 is supported
- typedef EGLDisplay (*PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform, void* native_display,
- const EGLAttrib* attrib_list);
-
- PFNEGLGETPLATFORMDISPLAYPROC eglGetPlatformDisplay =
- reinterpret_cast<PFNEGLGETPLATFORMDISPLAYPROC>(
- cnx->egl.eglGetProcAddress("eglGetPlatformDisplay"));
-
- if (eglGetPlatformDisplay) {
+ if (cnx->egl.eglGetPlatformDisplay) {
std::vector<EGLAttrib> attrs;
- addAnglePlatformAttributes(cnx, nullptr, attrs);
+ if (attrib_list) {
+ for (const EGLAttrib* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
+ attrs.push_back(attr[0]);
+ attrs.push_back(attr[1]);
+ }
+ }
+
+ if (!addAnglePlatformAttributes(cnx, attrib_list, attrs)) {
+ ALOGE("eglGetDisplay(%p) failed: Mismatch display request", display);
+ *error = EGL_BAD_PARAMETER;
+ return EGL_NO_DISPLAY;
+ }
attrs.push_back(EGL_NONE);
- dpy = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
- reinterpret_cast<void*>(EGL_DEFAULT_DISPLAY), attrs.data());
+ dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
+ reinterpret_cast<void*>(EGL_DEFAULT_DISPLAY),
+ attrs.data());
if (dpy == EGL_NO_DISPLAY) {
ALOGE("eglGetPlatformDisplay failed!");
} else {
@@ -270,8 +285,8 @@
return dpy;
}
-EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
-
+EGLDisplay egl_display_t::getPlatformDisplay(EGLNativeDisplayType display,
+ const EGLAttrib* attrib_list) {
std::lock_guard<std::mutex> _l(lock);
ATRACE_CALL();
@@ -283,10 +298,24 @@
EGLDisplay dpy = EGL_NO_DISPLAY;
if (cnx->useAngle) {
- dpy = getDisplayAngle(display, cnx);
+ EGLint error;
+ dpy = getPlatformDisplayAngle(display, cnx, attrib_list, &error);
+ if (error != EGL_NONE) {
+ return setError(error, dpy);
+ }
}
if (dpy == EGL_NO_DISPLAY) {
- dpy = cnx->egl.eglGetDisplay(display);
+ // NOTE: eglGetPlatformDisplay with a empty attribute list
+ // behaves the same as eglGetDisplay
+ if (cnx->egl.eglGetPlatformDisplay) {
+ dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANDROID_KHR, display,
+ attrib_list);
+ } else {
+ if (attrib_list) {
+ ALOGW("getPlatformDisplay: unexpected attribute list, attributes ignored");
+ }
+ dpy = cnx->egl.eglGetDisplay(display);
+ }
}
disp.dpy = dpy;
@@ -305,13 +334,20 @@
std::unique_lock<std::mutex> _l(refLock);
refs++;
if (refs > 1) {
- if (major != nullptr)
- *major = VERSION_MAJOR;
- if (minor != nullptr)
- *minor = VERSION_MINOR;
+ // We don't know what to report until we know what the
+ // driver supports. Make sure we are initialized before
+ // returning the version info.
while(!eglIsInitialized) {
refCond.wait(_l);
}
+ egl_connection_t* const cnx = &gEGLImpl;
+
+ // TODO: If device doesn't provide 1.4 or 1.5 then we'll be
+ // changing the behavior from the past where we always advertise
+ // version 1.4. May need to check that revision is valid
+ // before using cnx->major & cnx->minor
+ if (major != nullptr) *major = cnx->major;
+ if (minor != nullptr) *minor = cnx->minor;
return EGL_TRUE;
}
while(eglIsInitialized) {
@@ -358,7 +394,52 @@
// the query strings are per-display
mVendorString = sVendorString;
- mVersionString = sVersionString;
+ mVersionString.clear();
+ cnx->driverVersion = EGL_MAKE_VERSION(1, 4, 0);
+ if ((cnx->major == 1) && (cnx->minor == 5)) {
+ mVersionString = sVersionString15;
+ cnx->driverVersion = EGL_MAKE_VERSION(1, 5, 0);
+ } else if ((cnx->major == 1) && (cnx->minor == 4)) {
+ mVersionString = sVersionString14;
+ // Extensions needed for an EGL 1.4 implementation to be
+ // able to support EGL 1.5 functionality
+ std::vector<const char*> egl15extensions = {
+ "EGL_EXT_client_extensions",
+ // "EGL_EXT_platform_base", // implemented by EGL runtime
+ "EGL_KHR_image_base",
+ "EGL_KHR_fence_sync",
+ "EGL_KHR_wait_sync",
+ "EGL_KHR_create_context",
+ "EGL_EXT_create_context_robustness",
+ "EGL_KHR_gl_colorspace",
+ "EGL_ANDROID_native_fence_sync",
+ };
+ bool extensionsFound = true;
+ for (const auto& name : egl15extensions) {
+ extensionsFound &= findExtension(disp.queryString.extensions, name);
+ ALOGV("Extension %s: %s", name,
+ findExtension(disp.queryString.extensions, name) ? "Found" : "Missing");
+ }
+ // NOTE: From the spec:
+ // Creation of fence sync objects requires support from the bound
+ // client API, and will not succeed unless the client API satisfies:
+ // client API is OpenGL ES, and either the OpenGL ES version is 3.0
+ // or greater, or the GL_OES_EGL_sync extension is supported.
+ // We don't have a way to check the GL_EXTENSIONS string at this
+ // point in the code, assume that GL_OES_EGL_sync is supported
+ // because EGL_KHR_fence_sync is supported (as verified above).
+ if (extensionsFound) {
+ // Have everything needed to emulate EGL 1.5 so report EGL 1.5
+ // to the application.
+ mVersionString = sVersionString15;
+ cnx->major = 1;
+ cnx->minor = 5;
+ }
+ }
+ if (mVersionString.empty()) {
+ ALOGW("Unexpected driver version: %d.%d, want 1.4 or 1.5", cnx->major, cnx->minor);
+ mVersionString = sVersionString14;
+ }
mClientApiString = sClientApiString;
mExtensionString = gBuiltinExtensionString;
@@ -419,10 +500,12 @@
traceGpuCompletion = true;
}
- if (major != nullptr)
- *major = VERSION_MAJOR;
- if (minor != nullptr)
- *minor = VERSION_MINOR;
+ // TODO: If device doesn't provide 1.4 or 1.5 then we'll be
+ // changing the behavior from the past where we always advertise
+ // version 1.4. May need to check that revision is valid
+ // before using cnx->major & cnx->minor
+ if (major != nullptr) *major = cnx->major;
+ if (minor != nullptr) *minor = cnx->minor;
}
{ // scope for refLock
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index f764028..36856b7 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -49,6 +49,7 @@
class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
static egl_display_t sDisplay[NUM_DISPLAYS];
EGLDisplay getDisplay(EGLNativeDisplayType display);
+ EGLDisplay getPlatformDisplay(EGLNativeDisplayType display, const EGLAttrib* attrib_list);
void loseCurrentImpl(egl_context_t * cur_c);
public:
@@ -72,7 +73,7 @@
bool getObject(egl_object_t* object) const;
static egl_display_t* get(EGLDisplay dpy);
- static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
+ static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp, const EGLAttrib* attrib_list);
EGLBoolean makeCurrent(egl_context_t* c, egl_context_t* cur_c,
EGLSurface draw, EGLSurface read, EGLContext ctx,
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index b587a16..2921d51 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -44,6 +44,18 @@
/* EGL 1.4 */
+/* EGL 1.5 */
+EGL_ENTRY(EGLImage, eglCreateImage, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLAttrib *)
+EGL_ENTRY(EGLBoolean, eglDestroyImage, EGLDisplay, EGLImage)
+EGL_ENTRY(EGLDisplay, eglGetPlatformDisplay, EGLenum, void *, const EGLAttrib *)
+EGL_ENTRY(EGLSurface, eglCreatePlatformWindowSurface, EGLDisplay, EGLConfig, void *, const EGLAttrib *)
+EGL_ENTRY(EGLSurface, eglCreatePlatformPixmapSurface, EGLDisplay, EGLConfig, void *, const EGLAttrib *)
+EGL_ENTRY(EGLSyncKHR, eglCreateSync, EGLDisplay, EGLenum, const EGLAttrib *)
+EGL_ENTRY(EGLBoolean, eglDestroySync, EGLDisplay, EGLSync)
+EGL_ENTRY(EGLint, eglClientWaitSync, EGLDisplay, EGLSync, EGLint, EGLTimeKHR)
+EGL_ENTRY(EGLBoolean, eglGetSyncAttrib, EGLDisplay, EGLSync, EGLint, EGLAttrib *)
+EGL_ENTRY(EGLBoolean, eglWaitSync, EGLDisplay, EGLSync, EGLint)
+
/* EGL_EGLEXT_VERSION 3 */
EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint *)
@@ -75,6 +87,10 @@
EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR, EGLDisplay, EGLNativeFileDescriptorKHR)
EGL_ENTRY(EGLint, eglWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint)
+/* EGL_EGLEXT_VERSION 20170627 */
+EGL_ENTRY(EGLSurface, eglCreatePlatformWindowSurfaceEXT, EGLDisplay, EGLConfig, void *, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePlatformPixmapSurfaceEXT, EGLDisplay, EGLConfig, void *, const EGLint *)
+
/* ANDROID extensions */
EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint)
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 0d69a65..1daa4d2 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -135,6 +135,11 @@
"EGL_IMG_context_priority "
"EGL_KHR_no_config_context "
;
+
+char const * const gClientExtensionString =
+ "EGL_EXT_client_extensions "
+ "EGL_KHR_platform_android "
+ "EGL_ANGLE_platform_angle";
// clang-format on
// extensions not exposed to applications but used by the ANDROID system
@@ -279,17 +284,31 @@
// ----------------------------------------------------------------------------
-EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display)
-{
+static EGLDisplay eglGetPlatformDisplayTmpl(EGLenum platform, EGLNativeDisplayType display,
+ const EGLAttrib* attrib_list) {
+ if (platform != EGL_PLATFORM_ANDROID_KHR) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
uintptr_t index = reinterpret_cast<uintptr_t>(display);
if (index >= NUM_DISPLAYS) {
return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
}
- EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
+ EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display, attrib_list);
return dpy;
}
+EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display) {
+ return eglGetPlatformDisplayTmpl(EGL_PLATFORM_ANDROID_KHR, display, nullptr);
+}
+
+EGLDisplay eglGetPlatformDisplayImpl(EGLenum platform, void* native_display,
+ const EGLAttrib* attrib_list) {
+ return eglGetPlatformDisplayTmpl(platform, static_cast<EGLNativeDisplayType>(native_display),
+ attrib_list);
+}
+
// ----------------------------------------------------------------------------
// Initialization
// ----------------------------------------------------------------------------
@@ -526,22 +545,22 @@
// Cleans up color space related parameters that the driver does not understand.
// If there is no color space attribute in attrib_list, colorSpace is left
// unmodified.
-static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window,
- android_pixel_format format, const EGLint* attrib_list,
- EGLint* colorSpace,
- std::vector<EGLint>* strippedAttribList) {
- for (const EGLint* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
+template <typename AttrType>
+static EGLBoolean processAttributes(egl_display_ptr dp, ANativeWindow* window,
+ android_pixel_format format, const AttrType* attrib_list,
+ EGLint* colorSpace, std::vector<AttrType>* strippedAttribList) {
+ for (const AttrType* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
bool copyAttribute = true;
if (attr[0] == EGL_GL_COLORSPACE_KHR) {
// Fail immediately if the driver doesn't have color space support at all.
if (!dp->hasColorSpaceSupport) return false;
- *colorSpace = attr[1];
+ *colorSpace = static_cast<EGLint>(attr[1]);
// Strip the attribute if the driver doesn't understand it.
copyAttribute = false;
std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format);
for (auto driverColorSpace : driverColorSpaces) {
- if (attr[1] == driverColorSpace) {
+ if (static_cast<EGLint>(attr[1]) == driverColorSpace) {
copyAttribute = true;
break;
}
@@ -598,6 +617,16 @@
return true;
}
+// Note: This only works for existing GLenum's that are all 32bits.
+// If you have 64bit attributes (e.g. pointers) you shouldn't be calling this.
+void convertAttribs(const EGLAttrib* attribList, std::vector<EGLint>& newList) {
+ for (const EGLAttrib* attr = attribList; attr && attr[0] != EGL_NONE; attr += 2) {
+ newList.push_back(static_cast<EGLint>(attr[0]));
+ newList.push_back(static_cast<EGLint>(attr[1]));
+ }
+ newList.push_back(EGL_NONE);
+}
+
// Gets the native pixel format corrsponding to the passed EGLConfig.
void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config,
android_pixel_format* format) {
@@ -685,124 +714,161 @@
return EGL_TRUE;
}
-EGLSurface eglCreateWindowSurfaceImpl( EGLDisplay dpy, EGLConfig config,
- NativeWindowType window,
- const EGLint *attrib_list)
-{
- const EGLint *origAttribList = attrib_list;
+template <typename AttrType, typename CreateFuncType>
+EGLSurface eglCreateWindowSurfaceTmpl(egl_display_ptr dp, egl_connection_t* cnx, EGLConfig config,
+ ANativeWindow* window, const AttrType* attrib_list,
+ CreateFuncType createWindowSurfaceFunc) {
+ const AttrType* origAttribList = attrib_list;
- egl_connection_t* cnx = nullptr;
- egl_display_ptr dp = validate_display_connection(dpy, cnx);
- if (dp) {
- if (!window) {
+ if (!window) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
+ int value = 0;
+ window->query(window, NATIVE_WINDOW_IS_VALID, &value);
+ if (!value) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
+ // NOTE: When using Vulkan backend, the Vulkan runtime makes all the
+ // native_window_* calls, so don't do them here.
+ if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ if (result < 0) {
+ ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
+ "failed (%#x) (already connected to another API?)",
+ window, result);
+ return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+ }
+
+ EGLDisplay iDpy = dp->disp.dpy;
+ android_pixel_format format;
+ getNativePixelFormat(iDpy, cnx, config, &format);
+
+ // now select correct colorspace and dataspace based on user's attribute list
+ EGLint colorSpace = EGL_UNKNOWN;
+ std::vector<AttrType> strippedAttribList;
+ if (!processAttributes<AttrType>(dp, window, format, attrib_list, &colorSpace,
+ &strippedAttribList)) {
+ ALOGE("error invalid colorspace: %d", colorSpace);
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ attrib_list = strippedAttribList.data();
+
+ if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ int err = native_window_set_buffers_format(window, format);
+ if (err != 0) {
+ ALOGE("error setting native window pixel format: %s (%d)", strerror(-err), err);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
}
- int value = 0;
- window->query(window, NATIVE_WINDOW_IS_VALID, &value);
- if (!value) {
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
-
- // NOTE: When using Vulkan backend, the Vulkan runtime makes all the
- // native_window_* calls, so don't do them here.
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
- int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
- if (result < 0) {
- ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
- "failed (%#x) (already connected to another API?)",
- window, result);
- return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- }
- }
-
- EGLDisplay iDpy = dp->disp.dpy;
- android_pixel_format format;
- getNativePixelFormat(iDpy, cnx, config, &format);
-
- // now select correct colorspace and dataspace based on user's attribute list
- EGLint colorSpace = EGL_UNKNOWN;
- std::vector<EGLint> strippedAttribList;
- if (!processAttributes(dp, window, format, attrib_list, &colorSpace,
- &strippedAttribList)) {
- ALOGE("error invalid colorspace: %d", colorSpace);
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
- }
- attrib_list = strippedAttribList.data();
-
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
- int err = native_window_set_buffers_format(window, format);
+ android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
+ if (dataSpace != HAL_DATASPACE_UNKNOWN) {
+ err = native_window_set_buffers_data_space(window, dataSpace);
if (err != 0) {
- ALOGE("error setting native window pixel format: %s (%d)",
- strerror(-err), err);
+ ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err);
native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
}
+ }
+ }
- android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
- if (dataSpace != HAL_DATASPACE_UNKNOWN) {
- err = native_window_set_buffers_data_space(window, dataSpace);
- if (err != 0) {
- ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err),
- err);
- native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
+ // the EGL spec requires that a new EGLSurface default to swap interval
+ // 1, so explicitly set that on the window here.
+ window->setSwapInterval(window, 1);
+
+ EGLSurface surface = createWindowSurfaceFunc(iDpy, config, window, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s = new egl_surface_t(dp.get(), config, window, surface,
+ getReportedColorSpace(colorSpace), cnx);
+ return s;
+ }
+
+ // EGLSurface creation failed
+ if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ native_window_set_buffers_format(window, 0);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ }
+ return EGL_NO_SURFACE;
+}
+
+typedef EGLSurface(EGLAPIENTRYP PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config,
+ NativeWindowType window,
+ const EGLint* attrib_list);
+typedef EGLSurface(EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEPROC)(
+ EGLDisplay dpy, EGLConfig config, void* native_window, const EGLAttrib* attrib_list);
+
+EGLSurface eglCreateWindowSurfaceImpl(EGLDisplay dpy, EGLConfig config, NativeWindowType window,
+ const EGLint* attrib_list) {
+ egl_connection_t* cnx = NULL;
+ egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ if (dp) {
+ return eglCreateWindowSurfaceTmpl<
+ EGLint, PFNEGLCREATEWINDOWSURFACEPROC>(dp, cnx, config, window, attrib_list,
+ cnx->egl.eglCreateWindowSurface);
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePlatformWindowSurfaceImpl(EGLDisplay dpy, EGLConfig config, void* native_window,
+ const EGLAttrib* attrib_list) {
+ egl_connection_t* cnx = NULL;
+ egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ if (dp) {
+ if (cnx->driverVersion >= EGL_MAKE_VERSION(1, 5, 0)) {
+ if (cnx->egl.eglCreatePlatformWindowSurface) {
+ return eglCreateWindowSurfaceTmpl<EGLAttrib, PFNEGLCREATEPLATFORMWINDOWSURFACEPROC>(
+ dp, cnx, config, static_cast<ANativeWindow*>(native_window), attrib_list,
+ cnx->egl.eglCreatePlatformWindowSurface);
}
+ // driver doesn't support native function, return EGL_BAD_DISPLAY
+ ALOGE("Driver indicates EGL 1.5 support, but does not have "
+ "eglCreatePlatformWindowSurface");
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
}
- // the EGL spec requires that a new EGLSurface default to swap interval
- // 1, so explicitly set that on the window here.
- ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
- anw->setSwapInterval(anw, 1);
-
- EGLSurface surface = cnx->egl.eglCreateWindowSurface(
- iDpy, config, window, attrib_list);
- if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s =
- new egl_surface_t(dp.get(), config, window, surface,
- getReportedColorSpace(colorSpace), cnx);
- return s;
- }
-
- // EGLSurface creation failed
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
- native_window_set_buffers_format(window, 0);
- native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ std::vector<EGLint> convertedAttribs;
+ convertAttribs(attrib_list, convertedAttribs);
+ if (cnx->egl.eglCreatePlatformWindowSurfaceEXT) {
+ return eglCreateWindowSurfaceTmpl<EGLint, PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC>(
+ dp, cnx, config, static_cast<ANativeWindow*>(native_window),
+ convertedAttribs.data(), cnx->egl.eglCreatePlatformWindowSurfaceEXT);
+ } else {
+ return eglCreateWindowSurfaceTmpl<
+ EGLint, PFNEGLCREATEWINDOWSURFACEPROC>(dp, cnx, config,
+ static_cast<ANativeWindow*>(
+ native_window),
+ convertedAttribs.data(),
+ cnx->egl.eglCreateWindowSurface);
}
}
return EGL_NO_SURFACE;
}
-EGLSurface eglCreatePixmapSurfaceImpl( EGLDisplay dpy, EGLConfig config,
- NativePixmapType pixmap,
- const EGLint *attrib_list)
-{
+EGLSurface eglCreatePlatformPixmapSurfaceImpl(EGLDisplay dpy, EGLConfig /*config*/,
+ void* /*native_pixmap*/,
+ const EGLAttrib* /*attrib_list*/) {
+ // Per EGL_KHR_platform_android:
+ // It is not valid to call eglCreatePlatformPixmapSurface with a <dpy> that
+ // belongs to the Android platform. Any such call fails and generates
+ // an EGL_BAD_PARAMETER error.
+
+ egl_connection_t* cnx = NULL;
+ egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ if (dp) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePixmapSurfaceImpl(EGLDisplay dpy, EGLConfig /*config*/,
+ NativePixmapType /*pixmap*/, const EGLint* /*attrib_list*/) {
egl_connection_t* cnx = nullptr;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
- EGLDisplay iDpy = dp->disp.dpy;
- android_pixel_format format;
- getNativePixelFormat(iDpy, cnx, config, &format);
-
- // now select a corresponding sRGB format if needed
- EGLint colorSpace = EGL_UNKNOWN;
- std::vector<EGLint> strippedAttribList;
- if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
- &strippedAttribList)) {
- ALOGE("error invalid colorspace: %d", colorSpace);
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
- }
- attrib_list = strippedAttribList.data();
-
- EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
- dp->disp.dpy, config, pixmap, attrib_list);
- if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s =
- new egl_surface_t(dp.get(), config, nullptr, surface,
- getReportedColorSpace(colorSpace), cnx);
- return s;
- }
+ return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
}
return EGL_NO_SURFACE;
}
@@ -1392,15 +1458,10 @@
const char* eglQueryStringImpl(EGLDisplay dpy, EGLint name)
{
- // Generate an error quietly when client extensions (as defined by
- // EGL_EXT_client_extensions) are queried. We do not want to rely on
- // validate_display to generate the error as validate_display would log
- // the error, which can be misleading.
- //
- // If we want to support EGL_EXT_client_extensions later, we can return
- // the client extension string here instead.
- if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
- return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)nullptr);
+ if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) {
+ // Return list of client extensions
+ return gClientExtensionString;
+ }
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return (const char *) nullptr;
@@ -1641,113 +1702,256 @@
return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
-EGLImageKHR eglCreateImageKHRImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target,
- EGLClientBuffer buffer, const EGLint *attrib_list)
-{
+// Note: EGLImageKHR and EGLImage are the same thing so no need
+// to templatize that.
+template <typename AttrType, typename FuncType>
+EGLImageKHR eglCreateImageTmpl(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const AttrType* attrib_list,
+ FuncType eglCreateImageFunc) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_NO_IMAGE_KHR;
ContextRef _c(dp.get(), ctx);
- egl_context_t * const c = _c.get();
+ egl_context_t* const c = _c.get();
EGLImageKHR result = EGL_NO_IMAGE_KHR;
egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglCreateImageKHR) {
- result = cnx->egl.eglCreateImageKHR(
- dp->disp.dpy,
- c ? c->context : EGL_NO_CONTEXT,
- target, buffer, attrib_list);
+ if (cnx->dso && eglCreateImageFunc) {
+ result = eglCreateImageFunc(dp->disp.dpy, c ? c->context : EGL_NO_CONTEXT, target, buffer,
+ attrib_list);
}
return result;
}
-EGLBoolean eglDestroyImageKHRImpl(EGLDisplay dpy, EGLImageKHR img)
-{
+typedef EGLImage(EGLAPIENTRYP PFNEGLCREATEIMAGE)(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer,
+ const EGLAttrib* attrib_list);
+
+EGLImageKHR eglCreateImageKHRImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint* attrib_list) {
+ return eglCreateImageTmpl<EGLint, PFNEGLCREATEIMAGEKHRPROC>(dpy, ctx, target, buffer,
+ attrib_list,
+ gEGLImpl.egl.eglCreateImageKHR);
+}
+
+EGLImage eglCreateImageImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer,
+ const EGLAttrib* attrib_list) {
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->driverVersion >= EGL_MAKE_VERSION(1, 5, 0)) {
+ if (cnx->egl.eglCreateImage) {
+ return eglCreateImageTmpl<EGLAttrib, PFNEGLCREATEIMAGE>(dpy, ctx, target, buffer,
+ attrib_list,
+ cnx->egl.eglCreateImage);
+ }
+ // driver doesn't support native function, return EGL_BAD_DISPLAY
+ ALOGE("Driver indicates EGL 1.5 support, but does not have eglCreateImage");
+ return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE);
+ }
+
+ std::vector<EGLint> convertedAttribs;
+ convertAttribs(attrib_list, convertedAttribs);
+ return eglCreateImageTmpl<EGLint, PFNEGLCREATEIMAGEKHRPROC>(dpy, ctx, target, buffer,
+ convertedAttribs.data(),
+ gEGLImpl.egl.eglCreateImageKHR);
+}
+
+EGLBoolean eglDestroyImageTmpl(EGLDisplay dpy, EGLImageKHR img,
+ PFNEGLDESTROYIMAGEKHRPROC destroyImageFunc) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
- result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
+ if (cnx->dso && destroyImageFunc) {
+ result = destroyImageFunc(dp->disp.dpy, img);
}
return result;
}
+EGLBoolean eglDestroyImageKHRImpl(EGLDisplay dpy, EGLImageKHR img) {
+ return eglDestroyImageTmpl(dpy, img, gEGLImpl.egl.eglDestroyImageKHR);
+}
+
+EGLBoolean eglDestroyImageImpl(EGLDisplay dpy, EGLImageKHR img) {
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->driverVersion >= EGL_MAKE_VERSION(1, 5, 0)) {
+ if (cnx->egl.eglDestroyImage) {
+ return eglDestroyImageTmpl(dpy, img, gEGLImpl.egl.eglDestroyImage);
+ }
+ // driver doesn't support native function, return EGL_BAD_DISPLAY
+ ALOGE("Driver indicates EGL 1.5 support, but does not have eglDestroyImage");
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ return eglDestroyImageTmpl(dpy, img, gEGLImpl.egl.eglDestroyImageKHR);
+}
+
// ----------------------------------------------------------------------------
// EGL_EGLEXT_VERSION 5
// ----------------------------------------------------------------------------
-
-EGLSyncKHR eglCreateSyncKHRImpl(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
-{
+// NOTE: EGLSyncKHR and EGLSync are identical, no need to templatize
+template <typename AttrType, typename FuncType>
+EGLSyncKHR eglCreateSyncTmpl(EGLDisplay dpy, EGLenum type, const AttrType* attrib_list,
+ FuncType eglCreateSyncFunc) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_NO_SYNC_KHR;
- EGLSyncKHR result = EGL_NO_SYNC_KHR;
egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
- result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
+ EGLSyncKHR result = EGL_NO_SYNC_KHR;
+ if (cnx->dso && eglCreateSyncFunc) {
+ result = eglCreateSyncFunc(dp->disp.dpy, type, attrib_list);
}
return result;
}
-EGLBoolean eglDestroySyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync)
-{
+typedef EGLSurface(EGLAPIENTRYP PFNEGLCREATESYNC)(EGLDisplay dpy, EGLenum type,
+ const EGLAttrib* attrib_list);
+
+EGLSyncKHR eglCreateSyncKHRImpl(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) {
+ return eglCreateSyncTmpl<EGLint, PFNEGLCREATESYNCKHRPROC>(dpy, type, attrib_list,
+ gEGLImpl.egl.eglCreateSyncKHR);
+}
+
+EGLSync eglCreateSyncImpl(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list) {
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->driverVersion >= EGL_MAKE_VERSION(1, 5, 0)) {
+ if (cnx->egl.eglCreateSync) {
+ return eglCreateSyncTmpl<EGLAttrib, PFNEGLCREATESYNC>(dpy, type, attrib_list,
+ cnx->egl.eglCreateSync);
+ }
+ // driver doesn't support native function, return EGL_BAD_DISPLAY
+ ALOGE("Driver indicates EGL 1.5 support, but does not have eglCreateSync");
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SYNC);
+ }
+
+ std::vector<EGLint> convertedAttribs;
+ convertAttribs(attrib_list, convertedAttribs);
+ return eglCreateSyncTmpl<EGLint, PFNEGLCREATESYNCKHRPROC>(dpy, type, convertedAttribs.data(),
+ cnx->egl.eglCreateSyncKHR);
+}
+
+EGLBoolean eglDestroySyncTmpl(EGLDisplay dpy, EGLSyncKHR sync,
+ PFNEGLDESTROYSYNCKHRPROC eglDestroySyncFunc) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
- result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
+ if (cnx->dso && eglDestroySyncFunc) {
+ result = eglDestroySyncFunc(dp->disp.dpy, sync);
}
return result;
}
+EGLBoolean eglDestroySyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync) {
+ return eglDestroySyncTmpl(dpy, sync, gEGLImpl.egl.eglDestroySyncKHR);
+}
+
+EGLBoolean eglDestroySyncImpl(EGLDisplay dpy, EGLSyncKHR sync) {
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->driverVersion >= EGL_MAKE_VERSION(1, 5, 0)) {
+ if (cnx->egl.eglDestroySync) {
+ return eglDestroySyncTmpl(dpy, sync, cnx->egl.eglDestroySync);
+ }
+ ALOGE("Driver indicates EGL 1.5 support, but does not have eglDestroySync");
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ return eglDestroySyncTmpl(dpy, sync, cnx->egl.eglDestroySyncKHR);
+}
+
EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglSignalSyncKHR) {
- result = cnx->egl.eglSignalSyncKHR(
- dp->disp.dpy, sync, mode);
+ if (cnx->dso && gEGLImpl.egl.eglSignalSyncKHR) {
+ result = gEGLImpl.egl.eglSignalSyncKHR(dp->disp.dpy, sync, mode);
}
return result;
}
-EGLint eglClientWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync,
- EGLint flags, EGLTimeKHR timeout)
-{
+EGLint eglClientWaitSyncTmpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout,
+ PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncFunc) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
EGLint result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
- result = cnx->egl.eglClientWaitSyncKHR(
- dp->disp.dpy, sync, flags, timeout);
+ if (cnx->dso && eglClientWaitSyncFunc) {
+ result = eglClientWaitSyncFunc(dp->disp.dpy, sync, flags, timeout);
}
return result;
}
-EGLBoolean eglGetSyncAttribKHRImpl(EGLDisplay dpy, EGLSyncKHR sync,
- EGLint attribute, EGLint *value)
-{
+EGLint eglClientWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) {
+ egl_connection_t* const cnx = &gEGLImpl;
+ return eglClientWaitSyncTmpl(dpy, sync, flags, timeout, cnx->egl.eglClientWaitSyncKHR);
+}
+
+EGLint eglClientWaitSyncImpl(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTimeKHR timeout) {
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->driverVersion >= EGL_MAKE_VERSION(1, 5, 0)) {
+ if (cnx->egl.eglClientWaitSync) {
+ return eglClientWaitSyncTmpl(dpy, sync, flags, timeout, cnx->egl.eglClientWaitSync);
+ }
+ ALOGE("Driver indicates EGL 1.5 support, but does not have eglClientWaitSync");
+ return setError(EGL_BAD_DISPLAY, (EGLint)EGL_FALSE);
+ }
+
+ return eglClientWaitSyncTmpl(dpy, sync, flags, timeout, cnx->egl.eglClientWaitSyncKHR);
+}
+
+template <typename AttrType, typename FuncType>
+EGLBoolean eglGetSyncAttribTmpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, AttrType* value,
+ FuncType eglGetSyncAttribFunc) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
- result = cnx->egl.eglGetSyncAttribKHR(
- dp->disp.dpy, sync, attribute, value);
+ if (cnx->dso && eglGetSyncAttribFunc) {
+ result = eglGetSyncAttribFunc(dp->disp.dpy, sync, attribute, value);
}
return result;
}
+typedef EGLBoolean(EGLAPIENTRYP PFNEGLGETSYNCATTRIB)(EGLDisplay dpy, EGLSync sync, EGLint attribute,
+ EGLAttrib* value);
+
+EGLBoolean eglGetSyncAttribImpl(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value) {
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->driverVersion >= EGL_MAKE_VERSION(1, 5, 0)) {
+ if (cnx->egl.eglGetSyncAttrib) {
+ return eglGetSyncAttribTmpl<EGLAttrib, PFNEGLGETSYNCATTRIB>(dpy, sync, attribute, value,
+ cnx->egl.eglGetSyncAttrib);
+ }
+ ALOGE("Driver indicates EGL 1.5 support, but does not have eglGetSyncAttrib");
+ return setError(EGL_BAD_DISPLAY, (EGLint)EGL_FALSE);
+ }
+
+ // Fallback to KHR, ask for EGLint attribute and cast back to EGLAttrib
+ EGLint attribValue;
+ EGLBoolean ret =
+ eglGetSyncAttribTmpl<EGLint, PFNEGLGETSYNCATTRIBKHRPROC>(dpy, sync, attribute,
+ &attribValue,
+ gEGLImpl.egl
+ .eglGetSyncAttribKHR);
+ if (ret) {
+ *value = static_cast<EGLAttrib>(attribValue);
+ }
+ return ret;
+}
+
+EGLBoolean eglGetSyncAttribKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute,
+ EGLint* value) {
+ return eglGetSyncAttribTmpl<EGLint, PFNEGLGETSYNCATTRIBKHRPROC>(dpy, sync, attribute, value,
+ gEGLImpl.egl
+ .eglGetSyncAttribKHR);
+}
+
EGLStreamKHR eglCreateStreamKHRImpl(EGLDisplay dpy, const EGLint *attrib_list)
{
const egl_display_ptr dp = validate_display(dpy);
@@ -1934,17 +2138,43 @@
// EGL_EGLEXT_VERSION 15
// ----------------------------------------------------------------------------
-EGLint eglWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) {
+// Need to template function type because return type is different
+template <typename ReturnType, typename FuncType>
+ReturnType eglWaitSyncTmpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags,
+ FuncType eglWaitSyncFunc) {
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- EGLint result = EGL_FALSE;
+ ReturnType result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglWaitSyncKHR) {
- result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags);
+ if (cnx->dso && eglWaitSyncFunc) {
+ result = eglWaitSyncFunc(dp->disp.dpy, sync, flags);
}
return result;
}
+typedef EGLBoolean(EGLAPIENTRYP PFNEGLWAITSYNC)(EGLDisplay dpy, EGLSync sync, EGLint flags);
+
+EGLint eglWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) {
+ egl_connection_t* const cnx = &gEGLImpl;
+ return eglWaitSyncTmpl<EGLint, PFNEGLWAITSYNCKHRPROC>(dpy, sync, flags,
+ cnx->egl.eglWaitSyncKHR);
+}
+
+EGLBoolean eglWaitSyncImpl(EGLDisplay dpy, EGLSync sync, EGLint flags) {
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->driverVersion >= EGL_MAKE_VERSION(1, 5, 0)) {
+ if (cnx->egl.eglWaitSync) {
+ return eglWaitSyncTmpl<EGLBoolean, PFNEGLWAITSYNC>(dpy, sync, flags,
+ cnx->egl.eglWaitSync);
+ }
+ return setError(EGL_BAD_DISPLAY, (EGLint)EGL_FALSE);
+ }
+
+ return static_cast<EGLBoolean>(
+ eglWaitSyncTmpl<EGLint, PFNEGLWAITSYNCKHRPROC>(dpy, sync, flags,
+ cnx->egl.eglWaitSyncKHR));
+}
+
// ----------------------------------------------------------------------------
// ANDROID extensions
// ----------------------------------------------------------------------------
@@ -2371,7 +2601,9 @@
};
static const implementation_map_t sPlatformImplMap[] = {
+ // clang-format off
{ "eglGetDisplay", (EGLFuncPointer)&eglGetDisplayImpl },
+ { "eglGetPlatformDisplay", (EGLFuncPointer)&eglGetPlatformDisplayImpl },
{ "eglInitialize", (EGLFuncPointer)&eglInitializeImpl },
{ "eglTerminate", (EGLFuncPointer)&eglTerminateImpl },
{ "eglGetConfigs", (EGLFuncPointer)&eglGetConfigsImpl },
@@ -2379,6 +2611,8 @@
{ "eglGetConfigAttrib", (EGLFuncPointer)&eglGetConfigAttribImpl },
{ "eglCreateWindowSurface", (EGLFuncPointer)&eglCreateWindowSurfaceImpl },
{ "eglCreatePixmapSurface", (EGLFuncPointer)&eglCreatePixmapSurfaceImpl },
+ { "eglCreatePlatformWindowSurface", (EGLFuncPointer)&eglCreatePlatformWindowSurfaceImpl },
+ { "eglCreatePlatformPixmapSurface", (EGLFuncPointer)&eglCreatePlatformPixmapSurfaceImpl },
{ "eglCreatePbufferSurface", (EGLFuncPointer)&eglCreatePbufferSurfaceImpl },
{ "eglDestroySurface", (EGLFuncPointer)&eglDestroySurfaceImpl },
{ "eglQuerySurface", (EGLFuncPointer)&eglQuerySurfaceImpl },
@@ -2412,6 +2646,12 @@
{ "eglUnlockSurfaceKHR", (EGLFuncPointer)&eglUnlockSurfaceKHRImpl },
{ "eglCreateImageKHR", (EGLFuncPointer)&eglCreateImageKHRImpl },
{ "eglDestroyImageKHR", (EGLFuncPointer)&eglDestroyImageKHRImpl },
+ { "eglCreateImage", (EGLFuncPointer)&eglCreateImageImpl },
+ { "eglDestroyImage", (EGLFuncPointer)&eglDestroyImageImpl },
+ { "eglCreateSync", (EGLFuncPointer)&eglCreateSyncImpl },
+ { "eglDestroySync", (EGLFuncPointer)&eglDestroySyncImpl },
+ { "eglClientWaitSync", (EGLFuncPointer)&eglClientWaitSyncImpl },
+ { "eglGetSyncAttrib", (EGLFuncPointer)&eglGetSyncAttribImpl },
{ "eglCreateSyncKHR", (EGLFuncPointer)&eglCreateSyncKHRImpl },
{ "eglDestroySyncKHR", (EGLFuncPointer)&eglDestroySyncKHRImpl },
{ "eglSignalSyncKHR", (EGLFuncPointer)&eglSignalSyncKHRImpl },
@@ -2429,6 +2669,7 @@
{ "eglStreamConsumerReleaseKHR", (EGLFuncPointer)&eglStreamConsumerReleaseKHRImpl },
{ "eglGetStreamFileDescriptorKHR", (EGLFuncPointer)&eglGetStreamFileDescriptorKHRImpl },
{ "eglCreateStreamFromFileDescriptorKHR", (EGLFuncPointer)&eglCreateStreamFromFileDescriptorKHRImpl },
+ { "eglWaitSync", (EGLFuncPointer)&eglWaitSyncImpl },
{ "eglWaitSyncKHR", (EGLFuncPointer)&eglWaitSyncKHRImpl },
{ "eglDupNativeFenceFDANDROID", (EGLFuncPointer)&eglDupNativeFenceFDANDROIDImpl },
{ "eglPresentationTimeANDROID", (EGLFuncPointer)&eglPresentationTimeANDROIDImpl },
@@ -2447,6 +2688,7 @@
{ "glGetFloatv", (EGLFuncPointer)&glGetFloatvImpl },
{ "glGetIntegerv", (EGLFuncPointer)&glGetIntegervImpl },
{ "glGetInteger64v", (EGLFuncPointer)&glGetInteger64vImpl },
+ // clang-format on
};
EGLFuncPointer FindPlatformImplAddr(const char* name)
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 77654b0..7c710d5 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -24,6 +24,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 4
+#define EGL_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))
// ----------------------------------------------------------------------------
namespace android {
@@ -36,6 +37,7 @@
extern char const * const platform_names[];
+// clang-format off
struct egl_connection_t {
enum {
GLESv1_INDEX = 0,
@@ -64,6 +66,7 @@
gl_hooks_t * hooks[2];
EGLint major;
EGLint minor;
+ EGLint driverVersion;
egl_t egl;
// Functions implemented or redirected by platform libraries
@@ -77,6 +80,7 @@
EGLint angleBackend;
void* vendorEGL;
};
+// clang-format on
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/platform_entries.in b/opengl/libs/platform_entries.in
index b28f6cc..4673411 100644
--- a/opengl/libs/platform_entries.in
+++ b/opengl/libs/platform_entries.in
@@ -1,11 +1,14 @@
EGL_ENTRY(EGLDisplay, eglGetDisplay, EGLNativeDisplayType)
+EGL_ENTRY(EGLDisplay, eglGetPlatformDisplay, EGLenum, EGLNativeDisplayType, const EGLAttrib*)
EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint*, EGLConfig*, EGLint, EGLint*)
EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint*)
EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint*)
+EGL_ENTRY(EGLSurface, eglCreatePlatformWindowSurface, EGLDisplay, EGLConfig, void*, const EGLAttrib*)
EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint*)
+EGL_ENTRY(EGLSurface, eglCreatePlatformPixmapSurface, EGLDisplay, EGLConfig, void*, const EGLAttrib*)
EGL_ENTRY(EGLSurface, eglCreatePbufferSurface, EGLDisplay, EGLConfig, const EGLint*)
EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface)
EGL_ENTRY(EGLBoolean, eglQuerySurface, EGLDisplay, EGLSurface, EGLint, EGLint*)
@@ -37,8 +40,14 @@
EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint*)
EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint*)
EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLImage, eglCreateImage, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLAttrib*)
+EGL_ENTRY(EGLBoolean, eglDestroyImage, EGLDisplay, EGLImage)
EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint*)
EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
+EGL_ENTRY(EGLSync, eglCreateSync, EGLDisplay, EGLenum, const EGLAttrib*)
+EGL_ENTRY(EGLBoolean, eglDestroySync, EGLDisplay, EGLSync)
+EGL_ENTRY(EGLint, eglClientWaitSync, EGLDisplay, EGLSync, EGLint, EGLTimeKHR)
+EGL_ENTRY(EGLBoolean, eglGetSyncAttrib, EGLDisplay, EGLSyncKHR, EGLint, EGLAttrib*)
EGL_ENTRY(EGLSyncKHR, eglCreateSyncKHR, EGLDisplay, EGLenum, const EGLint*)
EGL_ENTRY(EGLBoolean, eglDestroySyncKHR, EGLDisplay, EGLSyncKHR)
EGL_ENTRY(EGLBoolean, eglSignalSyncKHR, EGLDisplay, EGLSyncKHR, EGLenum)
@@ -56,6 +65,7 @@
EGL_ENTRY(EGLBoolean, eglStreamConsumerReleaseKHR, EGLDisplay, EGLStreamKHR)
EGL_ENTRY(EGLNativeFileDescriptorKHR, eglGetStreamFileDescriptorKHR, EGLDisplay, EGLStreamKHR)
EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR, EGLDisplay, EGLNativeFileDescriptorKHR)
+EGL_ENTRY(EGLint, eglWaitSync, EGLDisplay, EGLSync, EGLint)
EGL_ENTRY(EGLint, eglWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint)
EGL_ENTRY(EGLint, eglDupNativeFenceFDANDROID, EGLDisplay, EGLSyncKHR)
EGL_ENTRY(EGLBoolean, eglPresentationTimeANDROID, EGLDisplay, EGLSurface, EGLnsecsANDROID)
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index f9e96ea..9fa58e2 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -93,6 +93,7 @@
pushd out > /dev/null
mkdir classes
javac -d classes android/opengl/EGL14.java \
+ android/opengl/EGL15.java \
android/opengl/EGLExt.java \
com/google/android/gles_jni/GLImpl.java \
javax/microedition/khronos/opengles/GL10.java \
@@ -155,13 +156,13 @@
compareGenerated ../../../../base/opengl/java/javax/microedition/khronos/opengles generated/javax/microedition/khronos/opengles $x
done
-for x in EGL14 EGLExt GLES10 GLES10Ext GLES11 GLES11Ext GLES20 GLES30 GLES31 GLES31Ext GLES32
+for x in EGL14 EGL15 EGLExt GLES10 GLES10Ext GLES11 GLES11Ext GLES20 GLES30 GLES31 GLES31Ext GLES32
do
compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java
compareGenerated ../../../../base/core/jni generated/C android_opengl_${x}.cpp
done
-for x in EGLConfig EGLContext EGLDisplay EGLObjectHandle EGLSurface
+for x in EGLConfig EGLContext EGLDisplay EGLObjectHandle EGLSurface EGLImage EGLSync
do
compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java
done
diff --git a/opengl/tools/glgen/specs/egl/EGL15.spec b/opengl/tools/glgen/specs/egl/EGL15.spec
new file mode 100644
index 0000000..e0aad30
--- /dev/null
+++ b/opengl/tools/glgen/specs/egl/EGL15.spec
@@ -0,0 +1,14 @@
+EGLSync eglCreateSync ( EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list )
+EGLBoolean eglDestroySync ( EGLDisplay dpy, EGLSync sync )
+EGLint eglClientWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout )
+EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value )
+// NOTE: native_display isn't actually an EGLAttrib. Using EGLAttrib
+// so that the generate creates mostly correct code (do not want a buffer)
+// have to manually change cast to (void *) in generated code that calls
+// the native function.
+EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list )
+EGLSurface eglCreatePlatformWindowSurface ( EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list )
+EGLSurface eglCreatePlatformPixmapSurface ( EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list )
+EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags )
+EGLImage eglCreateImage ( EGLDisplay dpy, EGLContext context, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list )
+EGLBoolean eglDestroyImage ( EGLDisplay dpy, EGLImage image )
diff --git a/opengl/tools/glgen/specs/egl/checks.spec b/opengl/tools/glgen/specs/egl/checks.spec
index ae531ee..e2bae48 100644
--- a/opengl/tools/glgen/specs/egl/checks.spec
+++ b/opengl/tools/glgen/specs/egl/checks.spec
@@ -11,3 +11,5 @@
//STUB function: eglCreatePbufferFromClientBuffer nullAllowed attrib_list sentinel attrib_list EGL_NONE
eglCreateContext sentinel attrib_list EGL_NONE
eglQueryContext check value 1
+//unsupported: eglCreatePlatformPixmapSurface nullAllowed attrib_list sentinel attrib_list EGL_NONE
+eglCreatePlatformPixmapSurface unsupported
diff --git a/opengl/tools/glgen/src/CType.java b/opengl/tools/glgen/src/CType.java
index aba98af..b1f8e05 100644
--- a/opengl/tools/glgen/src/CType.java
+++ b/opengl/tools/glgen/src/CType.java
@@ -57,7 +57,9 @@
if(baseType.equals("EGLContext")
|| baseType.equals("EGLConfig")
|| baseType.equals("EGLSurface")
- || baseType.equals("EGLDisplay")) {
+ || baseType.equals("EGLDisplay")
+ || baseType.equals("EGLImage")
+ || baseType.equals("EGLSync")) {
return true;
}
return false;
diff --git a/opengl/tools/glgen/src/GenerateEGL.java b/opengl/tools/glgen/src/GenerateEGL.java
index 2ef3970..57958c6 100644
--- a/opengl/tools/glgen/src/GenerateEGL.java
+++ b/opengl/tools/glgen/src/GenerateEGL.java
@@ -84,7 +84,7 @@
ParameterChecker checker = new ParameterChecker(checksReader);
- for(String suffix: new String[] {"EGL14", "EGLExt"}) {
+ for(String suffix: new String[] {"EGL14", "EGL15", "EGLExt"}) {
BufferedReader specReader = new BufferedReader(new FileReader(
"specs/egl/" + suffix + ".spec"));
String egljFilename = "android/opengl/" + suffix + ".java";
diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java
index 7f08503..0b4401a 100644
--- a/opengl/tools/glgen/src/JType.java
+++ b/opengl/tools/glgen/src/JType.java
@@ -60,12 +60,16 @@
typeMapping.put(new CType("EGLNativeDisplayType"), new JType("long"));
typeMapping.put(new CType("EGLClientBuffer"), new JType("long"));
typeMapping.put(new CType("EGLnsecsANDROID"), new JType("long"));
+ typeMapping.put(new CType("EGLAttrib"), new JType("long"));
+ typeMapping.put(new CType("EGLTime"), new JType("long"));
// EGL nonprimitive types
typeMapping.put(new CType("EGLConfig"), new JType("EGLConfig", true, false));
typeMapping.put(new CType("EGLContext"), new JType("EGLContext", true, false));
typeMapping.put(new CType("EGLDisplay"), new JType("EGLDisplay", true, false));
typeMapping.put(new CType("EGLSurface"), new JType("EGLSurface", true, false));
+ typeMapping.put(new CType("EGLImage"), new JType("EGLImage", true, false));
+ typeMapping.put(new CType("EGLSync"), new JType("EGLSync", true, false));
// Untyped pointers map to untyped Buffers
@@ -139,6 +143,8 @@
arrayTypeMapping.put(new CType("EGLint", true, true), new JType("int", false, true));
arrayTypeMapping.put(new CType("EGLConfig", false, true), new JType("EGLConfig", true, true));
arrayTypeMapping.put(new CType("EGLConfig", true, true), new JType("EGLConfig", true, true));
+ arrayTypeMapping.put(new CType("EGLAttrib", false, true), new JType("long", false, true));
+ arrayTypeMapping.put(new CType("EGLAttrib", true, true), new JType("long", false, true));
}
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index e8691bb..6697189 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -103,6 +103,12 @@
if (cfunc.hasEGLHandleArg()) {
return;
}
+ // eglGetPlatformDisplay does not have any EGLHandleArgs
+ // but we do not want to create IOBuffers of this, so
+ // exit
+ if (cfunc.getName().equals("eglGetPlatformDisplay")) {
+ return;
+ }
}
jfunc = JFunc.convert(cfunc, false);
diff --git a/opengl/tools/glgen/static/egl/EGLImage.java b/opengl/tools/glgen/static/egl/EGLImage.java
new file mode 100644
index 0000000..731ce72
--- /dev/null
+++ b/opengl/tools/glgen/static/egl/EGLImage.java
@@ -0,0 +1,37 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.opengl;
+
+/**
+ * Wrapper class for native EGLImage objects.
+ *
+ */
+public class EGLImage extends EGLObjectHandle {
+ private EGLImage(long handle) {
+ super(handle);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof EGLImage)) return false;
+
+ EGLImage that = (EGLImage) o;
+ return getNativeHandle() == that.getNativeHandle();
+ }
+}
diff --git a/opengl/tools/glgen/static/egl/EGLSync.java b/opengl/tools/glgen/static/egl/EGLSync.java
new file mode 100644
index 0000000..472f9e7
--- /dev/null
+++ b/opengl/tools/glgen/static/egl/EGLSync.java
@@ -0,0 +1,37 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.opengl;
+
+/**
+ * Wrapper class for native EGLSync objects.
+ *
+ */
+public class EGLSync extends EGLObjectHandle {
+ private EGLSync(long handle) {
+ super(handle);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof EGLSync)) return false;
+
+ EGLSync that = (EGLSync) o;
+ return getNativeHandle() == that.getNativeHandle();
+ }
+}
diff --git a/opengl/tools/glgen/stubs/egl/EGL15Header.java-if b/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
new file mode 100644
index 0000000..7409d93
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
@@ -0,0 +1,76 @@
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.opengl;
+
+/**
+ * EGL 1.5
+ *
+ */
+public class EGL15 {
+
+ public static final int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 0x00000001;
+ public static final int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 0x00000002;
+ public static final int EGL_OPENGL_ES3_BIT = 0x00000040;
+ public static final int EGL_SYNC_FLUSH_COMMANDS_BIT = 0x0001;
+ public static final int EGL_GL_COLORSPACE_SRGB = 0x3089;
+ public static final int EGL_GL_COLORSPACE_LINEAR = 0x308A;
+ public static final int EGL_CONTEXT_MAJOR_VERSION = 0x3098;
+ public static final int EGL_CL_EVENT_HANDLE = 0x309C;
+ public static final int EGL_GL_COLORSPACE = 0x309D;
+ public static final int EGL_GL_TEXTURE_2D = 0x30B1;
+ public static final int EGL_GL_TEXTURE_3D = 0x30B2;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x30B3;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x30B4;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x30B5;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x30B6;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x30B7;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x30B8;
+ public static final int EGL_GL_RENDERBUFFER = 0x30B9;
+ public static final int EGL_GL_TEXTURE_LEVEL = 0x30BC;
+ public static final int EGL_GL_TEXTURE_ZOFFSET = 0x30BD;
+ public static final int EGL_IMAGE_PRESERVED = 0x30D2;
+ public static final int EGL_SYNC_PRIOR_COMMANDS_COMPLETE = 0x30F0;
+ public static final int EGL_SYNC_STATUS = 0x30F1;
+ public static final int EGL_SIGNALED = 0x30F2;
+ public static final int EGL_UNSIGNALED = 0x30F3;
+ public static final int EGL_TIMEOUT_EXPIRED = 0x30F5;
+ public static final int EGL_CONDITION_SATISFIED = 0x30F6;
+ public static final int EGL_SYNC_TYPE = 0x30F7;
+ public static final int EGL_SYNC_CONDITION = 0x30F8;
+ public static final int EGL_SYNC_FENCE = 0x30F9;
+ public static final int EGL_CONTEXT_MINOR_VERSION = 0x30FB;
+ public static final int EGL_CONTEXT_OPENGL_PROFILE_MASK = 0x30FD;
+ public static final int EGL_SYNC_CL_EVENT = 0x30FE;
+ public static final int EGL_SYNC_CL_EVENT_COMPLETE = 0x30FF;
+ public static final int EGL_CONTEXT_OPENGL_DEBUG = 0x31B0;
+ public static final int EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE = 0x31B1;
+ public static final int EGL_CONTEXT_OPENGL_ROBUST_ACCESS = 0x31B2;
+ public static final int EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY = 0x31BD;
+ public static final int EGL_NO_RESET_NOTIFICATION = 0x31BE;
+ public static final int EGL_LOSE_CONTEXT_ON_RESET = 0x31BF;
+ public static final int EGL_PLATFORM_ANDROID_KHR = 0x3141;
+ public static final long EGL_FOREVER = 0xFFFFFFFFFFFFFFFFL;
+ public static final EGLImage EGL_NO_IMAGE = null;
+ public static final EGLSync EGL_NO_SYNC = null;
+ public static final EGLContext EGL_NO_CONTEXT = null;
+ public static final EGLDisplay EGL_NO_DISPLAY = null;
+ public static final EGLSurface EGL_NO_SURFACE = null;
+
+ native private static void _nativeClassInit();
+ static {
+ _nativeClassInit();
+ }
diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
new file mode 100644
index 0000000..70b46f7
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
@@ -0,0 +1,205 @@
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <nativehelper/JNIHelp.h>
+#include <utils/misc.h>
+#include "jni.h"
+
+#include <EGL/egl.h>
+#include <assert.h>
+
+#include <ui/ANativeObjectBase.h>
+
+static int initialized = 0;
+
+// classes from EGL 1.4
+static jclass egldisplayClass;
+static jclass eglsurfaceClass;
+static jclass eglconfigClass;
+static jclass eglcontextClass;
+static jclass bufferClass;
+static jclass nioAccessClass;
+
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+
+static jmethodID egldisplayGetHandleID;
+static jmethodID eglconfigGetHandleID;
+static jmethodID eglcontextGetHandleID;
+static jmethodID eglsurfaceGetHandleID;
+
+static jmethodID egldisplayConstructor;
+static jmethodID eglcontextConstructor;
+static jmethodID eglsurfaceConstructor;
+static jmethodID eglconfigConstructor;
+
+static jobject eglNoContextObject;
+static jobject eglNoDisplayObject;
+static jobject eglNoSurfaceObject;
+
+// classes from EGL 1.5
+static jclass eglimageClass;
+static jclass eglsyncClass;
+
+static jmethodID eglimageGetHandleID;
+static jmethodID eglsyncGetHandleID;
+
+static jmethodID eglimageConstructor;
+static jmethodID eglsyncConstructor;
+
+static jobject eglNoImageObject;
+static jobject eglNoSyncObject;
+
+/* Cache method IDs each time the class is loaded. */
+
+static void nativeClassInit(JNIEnv *_env, jclass glImplClass) {
+ // EGL 1.4 Init
+ jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
+ eglconfigClass = (jclass)_env->NewGlobalRef(eglconfigClassLocal);
+ jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
+ eglcontextClass = (jclass)_env->NewGlobalRef(eglcontextClassLocal);
+ jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
+ egldisplayClass = (jclass)_env->NewGlobalRef(egldisplayClassLocal);
+ jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
+ eglsurfaceClass = (jclass)_env->NewGlobalRef(eglsurfaceClassLocal);
+
+ eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
+ eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
+ egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
+ eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
+
+ eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
+ eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
+ egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
+ eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
+
+ jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor,
+ reinterpret_cast<jlong>(EGL_NO_CONTEXT));
+ eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
+ jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor,
+ reinterpret_cast<jlong>(EGL_NO_DISPLAY));
+ eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
+ jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor,
+ reinterpret_cast<jlong>(EGL_NO_SURFACE));
+ eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
+
+ jclass eglClass = _env->FindClass("android/opengl/EGL15");
+ jfieldID noContextFieldID =
+ _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
+ _env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject);
+
+ jfieldID noDisplayFieldID =
+ _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
+ _env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject);
+
+ jfieldID noSurfaceFieldID =
+ _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
+ _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject);
+
+ // EGL 1.5 init
+ jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+ nioAccessClass = (jclass)_env->NewGlobalRef(nioAccessClassLocal);
+
+ jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+ bufferClass = (jclass)_env->NewGlobalRef(bufferClassLocal);
+
+ getBasePointerID =
+ _env->GetStaticMethodID(nioAccessClass, "getBasePointer", "(Ljava/nio/Buffer;)J");
+ getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, "getBaseArray",
+ "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+ getBaseArrayOffsetID =
+ _env->GetStaticMethodID(nioAccessClass, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+ positionID = _env->GetFieldID(bufferClass, "position", "I");
+ limitID = _env->GetFieldID(bufferClass, "limit", "I");
+ elementSizeShiftID = _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+
+ jclass eglimageClassLocal = _env->FindClass("android/opengl/EGLImage");
+ eglimageClass = (jclass)_env->NewGlobalRef(eglimageClassLocal);
+ jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
+ eglsyncClass = (jclass)_env->NewGlobalRef(eglsyncClassLocal);
+
+ eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
+ eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
+
+ eglimageConstructor = _env->GetMethodID(eglimageClass, "<init>", "(J)V");
+ eglsyncConstructor = _env->GetMethodID(eglsyncClass, "<init>", "(J)V");
+
+ jfieldID noImageFieldID =
+ _env->GetStaticFieldID(eglClass, "EGL_NO_IMAGE", "Landroid/opengl/EGLImage;");
+ _env->SetStaticObjectField(eglClass, noImageFieldID, eglNoImageObject);
+
+ jfieldID noSyncFieldID =
+ _env->GetStaticFieldID(eglClass, "EGL_NO_SYNC", "Landroid/opengl/EGLSync;");
+ _env->SetStaticObjectField(eglClass, noSyncFieldID, eglNoSyncObject);
+}
+
+static void *getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining,
+ jint *offset) {
+ jint position;
+ jint limit;
+ jint elementSizeShift;
+ jlong pointer;
+
+ position = _env->GetIntField(buffer, positionID);
+ limit = _env->GetIntField(buffer, limitID);
+ elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+ *remaining = (limit - position) << elementSizeShift;
+ pointer = _env->CallStaticLongMethod(nioAccessClass, getBasePointerID, buffer);
+ if (pointer != 0L) {
+ *array = NULL;
+ return reinterpret_cast<void *>(pointer);
+ }
+ eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
+ eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
+
+ *array = (jarray)_env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer);
+ *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer);
+
+ return NULL;
+}
+
+static void releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) {
+ _env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT);
+}
+
+static void *fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
+ if (obj == NULL) {
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "Object is set to null.");
+ }
+
+ jlong handle = _env->CallLongMethod(obj, mid);
+ return reinterpret_cast<void *>(handle);
+}
+
+static jobject toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void *handle) {
+ if (cls == eglimageClass && (EGLImage)handle == EGL_NO_IMAGE) {
+ return eglNoImageObject;
+ }
+
+ return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
+}
+
+// --------------------------------------------------------------------------
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
new file mode 100644
index 0000000..fd44498
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
@@ -0,0 +1,46 @@
+/* EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglGetPlatformDisplay
+ (JNIEnv *_env, jobject _this, jint platform, jlong native_display, jlongArray attrib_list_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ EGLDisplay _returnValue = (EGLDisplay) 0;
+ EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+ jint _remaining;
+ EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+ if (!attrib_list_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "attrib_list == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+ attrib_list_base = (EGLAttrib *)
+ _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+ attrib_list = attrib_list_base + offset;
+
+ _returnValue = eglGetPlatformDisplay(
+ (EGLenum)platform,
+ (void *)native_display,
+ (EGLAttrib *)attrib_list
+ );
+
+exit:
+ if (attrib_list_base) {
+ _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
+}
+
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.java b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.java
new file mode 100644
index 0000000..28945e8
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.java
@@ -0,0 +1,9 @@
+ // C function EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list )
+
+ public static native EGLDisplay eglGetPlatformDisplay(
+ int platform,
+ long native_display,
+ long[] attrib_list,
+ int offset
+ );
+
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.nativeReg b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.nativeReg
new file mode 100644
index 0000000..8a309bf
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.nativeReg
@@ -0,0 +1 @@
+{"eglGetPlatformDisplay", "(IJ[JI)Landroid/opengl/EGLDisplay;", (void *) android_eglGetPlatformDisplay },
diff --git a/opengl/tools/glgen2/registry/egl.xml b/opengl/tools/glgen2/registry/egl.xml
index e422e96..26771e1 100644
--- a/opengl/tools/glgen2/registry/egl.xml
+++ b/opengl/tools/glgen2/registry/egl.xml
@@ -801,7 +801,9 @@
<enum value="0x3361" name="EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT"/>
<enum value="0x3362" name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/>
<enum value="0x3363" name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/>
- <unused start="0x3364" end="0x339F"/>
+ <enum value="0x3364" name="EGL_SYNC_CLIENT_EXT"/>
+ <enum value="0x3365" name="EGL_SYNC_CLIENT_SIGNAL_EXT"/>
+ <unused start="0x3366" end="0x339F"/>
</enums>
<enums namespace="EGL" start="0x33A0" end="0x33AF" vendor="ANGLE" comment="Reserved for Shannon Woods (Bug 13175)">
@@ -887,6 +889,10 @@
<enum value="0x3471" name="EGL_IMPORT_IMPLICIT_SYNC_EXT"/>
<enum value="0x3472" name="EGL_IMPORT_EXPLICIT_SYNC_EXT"/>
</enums>
+ <enums namespace="EGL" start="0x3480" end="0x348F" vendor="ANGLE" comment="Reserved for Courtney Goeltzenleuchter - ANGLE (gitlab EGL bug 7)">
+ <enum value="0x3480" name="EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE"/>
+ <unused start="0x3481" end="0x348F"/>
+ </enums>
<!-- Please remember that new enumerant allocations must be obtained by
request to the Khronos API registrar (see comments at the top of this
@@ -897,8 +903,8 @@
<!-- Reservable for future use. To generate a new range, allocate multiples
of 16 starting at the lowest available point in this block. -->
- <enums namespace="EGL" start="0x3480" end="0x3FFF" vendor="KHR" comment="Reserved for future use">
- <unused start="0x3480" end="0x3FFF"/>
+ <enums namespace="EGL" start="0x3490" end="0x3FFF" vendor="KHR" comment="Reserved for future use">
+ <unused start="0x3490" end="0x3FFF"/>
</enums>
<enums namespace="EGL" start="0x8F70" end="0x8F7F" vendor="HI" comment="For Mark Callow, Khronos bug 4055. Shared with GL.">
@@ -930,6 +936,12 @@
<param><ptype>EGLint</ptype> *<name>num_config</name></param>
</command>
<command>
+ <proto><ptype>EGLBoolean</ptype> <name>eglClientSignalSyncEXT</name></proto>
+ <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+ <param><ptype>EGLSync</ptype> <name>sync</name></param>
+ <param>const <ptype>EGLAttrib</ptype> *<name>attrib_list</name></param>
+ </command>
+ <command>
<proto><ptype>EGLint</ptype> <name>eglClientWaitSync</name></proto>
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
<param><ptype>EGLSync</ptype> <name>sync</name></param>
@@ -1647,6 +1659,11 @@
<param>const <ptype>EGLAttrib</ptype> *<name>attrib_list</name></param>
</command>
<command>
+ <proto><ptype>EGLBoolean</ptype> <name>eglStreamFlushNV</name></proto>
+ <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+ <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
+ </command>
+ <command>
<proto><ptype>EGLBoolean</ptype> <name>eglSurfaceAttrib</name></proto>
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
<param><ptype>EGLSurface</ptype> <name>surface</name></param>
@@ -1701,6 +1718,12 @@
<param><ptype>EGLSurface</ptype> <name>surface</name></param>
</command>
<command>
+ <proto><ptype>EGLBoolean</ptype> <name>eglUnsignalSyncEXT</name></proto>
+ <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+ <param><ptype>EGLSync</ptype> <name>sync</name></param>
+ <param>const <ptype>EGLAttrib</ptype> *<name>attrib_list</name></param>
+ </command>
+ <command>
<proto><ptype>EGLBoolean</ptype> <name>eglWaitClient</name></proto>
</command>
<command>
@@ -2146,6 +2169,13 @@
</require>
</extension>
<extension name="EGL_EXT_client_extensions" supported="egl"/>
+ <extension name="EGL_EXT_client_sync" supported="egl">
+ <require>
+ <enum name="EGL_SYNC_CLIENT_EXT"/>
+ <enum name="EGL_SYNC_CLIENT_SIGNAL_EXT"/>
+ <command name="eglClientSignalSyncEXT"/>
+ </require>
+ </extension>
<extension name="EGL_EXT_create_context_robustness" supported="egl">
<require>
<enum name="EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT"/>
@@ -2371,6 +2401,11 @@
<command name="eglSwapBuffersWithDamageEXT"/>
</require>
</extension>
+ <extension name="EGL_EXT_sync_reuse" supported="egl">
+ <require>
+ <command name="eglUnsignalSyncEXT"/>
+ </require>
+ </extension>
<extension name="EGL_EXT_yuv_surface" supported="egl">
<require>
<enum name="EGL_YUV_ORDER_EXT"/>
@@ -2932,6 +2967,11 @@
<enum name="EGL_STREAM_FIFO_SYNCHRONOUS_NV"/>
</require>
</extension>
+ <extension name="EGL_NV_stream_flush" supported="egl">
+ <require>
+ <command name="eglStreamFlushNV"/>
+ </require>
+ </extension>
<extension name="EGL_NV_stream_frame_limits" supported="egl">
<require>
<enum name="EGL_PRODUCER_MAX_FRAME_HINT_NV"/>
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 9a65452..622a623 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -41,6 +41,8 @@
"-Wall",
"-Wextra",
"-Werror",
+ // Allow implicit fallthroughs in InputReader.cpp until they are fixed.
+ "-Wno-error=implicit-fallthrough",
"-Wno-unused-parameter",
// TODO: Move inputflinger to its own process and mark it hidden
//-fvisibility=hidden
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 38104c4..2cad986 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -852,7 +852,8 @@
return true;
}
- addMonitoringTargetsLocked(inputTargets);
+ // Add monitor channels from event's or focused display.
+ addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
@@ -919,7 +920,8 @@
return true;
}
- addMonitoringTargetsLocked(inputTargets);
+ // Add monitor channels from event's or focused display.
+ addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
// Dispatch the motion.
if (conflictingPointerActions) {
@@ -1665,17 +1667,29 @@
target.pointerIds = pointerIds;
}
-void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets) {
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- inputTargets.push();
+void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets,
+ int32_t displayId) {
+ std::unordered_map<int32_t, Vector<sp<InputChannel>>>::const_iterator it =
+ mMonitoringChannelsByDisplay.find(displayId);
- InputTarget& target = inputTargets.editTop();
- target.inputChannel = mMonitoringChannels[i];
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- target.xOffset = 0;
- target.yOffset = 0;
- target.pointerIds.clear();
- target.scaleFactor = 1.0f;
+ if (it != mMonitoringChannelsByDisplay.end()) {
+ const Vector<sp<InputChannel>>& monitoringChannels = it->second;
+ const size_t numChannels = monitoringChannels.size();
+ for (size_t i = 0; i < numChannels; i++) {
+ inputTargets.push();
+
+ InputTarget& target = inputTargets.editTop();
+ target.inputChannel = monitoringChannels[i];
+ target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.xOffset = 0;
+ target.yOffset = 0;
+ target.pointerIds.clear();
+ target.scaleFactor = 1.0f;
+ }
+ } else {
+ // If there is no monitor channel registered or all monitor channel unregistered,
+ // the display can't detect the extra system gesture by a copy of input events.
+ ALOGW("There is no monitor channel found in display=%" PRId32, displayId);
}
}
@@ -2294,8 +2308,12 @@
void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
const CancelationOptions& options) {
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- synthesizeCancelationEventsForInputChannelLocked(mMonitoringChannels[i], options);
+ for (auto& it : mMonitoringChannelsByDisplay) {
+ const Vector<sp<InputChannel>>& monitoringChannels = it.second;
+ const size_t numChannels = monitoringChannels.size();
+ for (size_t i = 0; i < numChannels; i++) {
+ synthesizeCancelationEventsForInputChannelLocked(monitoringChannels[i], options);
+ }
}
}
@@ -3486,12 +3504,16 @@
dump += INDENT "Displays: <none>\n";
}
- if (!mMonitoringChannels.isEmpty()) {
- dump += INDENT "MonitoringChannels:\n";
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- const sp<InputChannel>& channel = mMonitoringChannels[i];
- dump += StringPrintf(INDENT2 "%zu: '%s'\n", i, channel->getName().c_str());
- }
+ if (!mMonitoringChannelsByDisplay.empty()) {
+ for (auto& it : mMonitoringChannelsByDisplay) {
+ const Vector<sp<InputChannel>>& monitoringChannels = it.second;
+ dump += INDENT "MonitoringChannels in Display %d:\n";
+ const size_t numChannels = monitoringChannels.size();
+ for (size_t i = 0; i < numChannels; i++) {
+ const sp<InputChannel>& channel = monitoringChannels[i];
+ dump += StringPrintf(INDENT2 "%zu: '%s'\n", i, channel->getName().c_str());
+ }
+ }
} else {
dump += INDENT "MonitoringChannels: <none>\n";
}
@@ -3609,10 +3631,10 @@
}
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
+ const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId) {
#if DEBUG_REGISTRATION
- ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().c_str(),
- toString(monitor));
+ ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32,
+ inputChannel->getName().c_str(), displayId);
#endif
{ // acquire lock
@@ -3624,13 +3646,20 @@
return BAD_VALUE;
}
+ // If InputWindowHandle is null and displayId is not ADISPLAY_ID_NONE,
+ // treat inputChannel as monitor channel for displayId.
+ bool monitor = inputWindowHandle == nullptr && displayId != ADISPLAY_ID_NONE;
+
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
+ // Store monitor channel by displayId.
if (monitor) {
- mMonitoringChannels.push(inputChannel);
+ Vector<sp<InputChannel>>& monitoringChannels =
+ mMonitoringChannelsByDisplay[displayId];
+ monitoringChannels.push(inputChannel);
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
@@ -3687,11 +3716,21 @@
}
void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
- for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- if (mMonitoringChannels[i] == inputChannel) {
- mMonitoringChannels.removeAt(i);
- break;
- }
+ for (auto it = mMonitoringChannelsByDisplay.begin();
+ it != mMonitoringChannelsByDisplay.end(); ) {
+ Vector<sp<InputChannel>>& monitoringChannels = it->second;
+ const size_t numChannels = monitoringChannels.size();
+ for (size_t i = 0; i < numChannels; i++) {
+ if (monitoringChannels[i] == inputChannel) {
+ monitoringChannels.removeAt(i);
+ break;
+ }
+ }
+ if (monitoringChannels.empty()) {
+ it = mMonitoringChannelsByDisplay.erase(it);
+ } else {
+ ++it;
+ }
}
}
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index aedad2f..5efb2fa 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -346,13 +346,19 @@
virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
const sp<InputChannel>& toChannel) = 0;
- /* Registers or unregister input channels that may be used as targets for input events.
- * If monitor is true, the channel will receive a copy of all input events.
+ /* Registers input channels that may be used as targets for input events.
+ * If inputWindowHandle is null, and displayId is not ADISPLAY_ID_NONE,
+ * the channel will receive a copy of all input events form the specific displayId.
*
- * These methods may be called on any thread (usually by the input manager).
+ * This method may be called on any thread (usually by the input manager).
*/
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor) = 0;
+ const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId) = 0;
+
+ /* Unregister input channels that will no longer receive input events.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
};
@@ -407,7 +413,7 @@
const sp<InputChannel>& toChannel);
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
+ const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
private:
@@ -914,8 +920,8 @@
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
- // Input channels that will receive a copy of all input events.
- Vector<sp<InputChannel> > mMonitoringChannels;
+ // Input channels that will receive a copy of all input events sent to the provided display.
+ std::unordered_map<int32_t, Vector<sp<InputChannel>>> mMonitoringChannelsByDisplay;
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
@@ -1070,7 +1076,7 @@
void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
- void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets);
+ void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId);
void pokeUserActivityLocked(const EventEntry* eventEntry);
bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f75b0b6..c6eaf9f 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -278,68 +278,8 @@
}
};
-class FakeWindowHandle : public InputWindowHandle {
+class FakeInputReceiver {
public:
- static const int32_t WIDTH = 600;
- static const int32_t HEIGHT = 800;
-
- FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<InputDispatcher>& dispatcher, const std::string name) :
- InputWindowHandle(inputApplicationHandle), mDispatcher(dispatcher),
- mName(name), mFocused(false), mDisplayId(ADISPLAY_ID_DEFAULT) {
- InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
- mConsumer = new InputConsumer(mClientChannel);
- mDispatcher->registerInputChannel(mServerChannel, this, false);
- }
-
- virtual ~FakeWindowHandle() {
- mDispatcher->unregisterInputChannel(mServerChannel);
- mServerChannel.clear();
- mClientChannel.clear();
- mDispatcher.clear();
-
- if (mConsumer != nullptr) {
- delete mConsumer;
- }
- }
-
- virtual bool updateInfo() {
- if (!mInfo) {
- mInfo = new InputWindowInfo();
- }
- mInfo->inputChannel = mServerChannel;
- mInfo->name = mName;
- mInfo->layoutParamsFlags = 0;
- mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
- mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
- mInfo->frameLeft = 0;
- mInfo->frameTop = 0;
- mInfo->frameRight = WIDTH;
- mInfo->frameBottom = HEIGHT;
- mInfo->scaleFactor = 1.0;
- mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo->visible = true;
- mInfo->canReceiveKeys = true;
- mInfo->hasFocus = mFocused;
- mInfo->hasWallpaper = false;
- mInfo->paused = false;
- mInfo->layer = 0;
- mInfo->ownerPid = INJECTOR_PID;
- mInfo->ownerUid = INJECTOR_UID;
- mInfo->inputFeatures = 0;
- mInfo->displayId = mDisplayId;
-
- return true;
- }
-
- void setFocus() {
- mFocused = true;
- }
-
- void setDisplayId(int32_t displayId) {
- mDisplayId = displayId;
- }
-
void consumeEvent(int32_t expectedEventType, int32_t expectedDisplayId,
int32_t expectedFlags = 0) {
uint32_t consumeSeq;
@@ -376,7 +316,7 @@
ASSERT_EQ(expectedFlags, flags)
<< mName.c_str() << ": event flags should be the same as expected.";
- status = mConsumer->sendFinishedSignal(consumeSeq, true /*handled*/);
+ status = mConsumer->sendFinishedSignal(consumeSeq, handled());
ASSERT_EQ(OK, status)
<< mName.c_str() << ": consumer sendFinishedSignal should return OK.";
}
@@ -391,17 +331,94 @@
<< ": should not have received any events, so consume(..) should not return OK.";
}
- private:
+protected:
+ explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher,
+ const std::string name, int32_t displayId) :
+ mDispatcher(dispatcher), mName(name), mDisplayId(displayId) {
+ InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
+ mConsumer = new InputConsumer(mClientChannel);
+ }
+
+ virtual ~FakeInputReceiver() {
+ }
+
+ // return true if the event has been handled.
+ virtual bool handled() {
+ return false;
+ }
+
sp<InputDispatcher> mDispatcher;
sp<InputChannel> mServerChannel, mClientChannel;
InputConsumer *mConsumer;
PreallocatedInputEventFactory mEventFactory;
std::string mName;
- bool mFocused;
int32_t mDisplayId;
};
+class FakeWindowHandle : public InputWindowHandle, public FakeInputReceiver {
+public:
+ static const int32_t WIDTH = 600;
+ static const int32_t HEIGHT = 800;
+
+ FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) :
+ InputWindowHandle(inputApplicationHandle),
+ FakeInputReceiver(dispatcher, name, displayId),
+ mFocused(false) {
+ mDispatcher->registerInputChannel(mServerChannel, this, displayId);
+ }
+
+ virtual bool updateInfo() {
+ if (!mInfo) {
+ mInfo = new InputWindowInfo();
+ }
+ mInfo->inputChannel = mServerChannel;
+ mInfo->name = mName;
+ mInfo->layoutParamsFlags = 0;
+ mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+ mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo->frameLeft = 0;
+ mInfo->frameTop = 0;
+ mInfo->frameRight = WIDTH;
+ mInfo->frameBottom = HEIGHT;
+ mInfo->scaleFactor = 1.0;
+ mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
+ mInfo->visible = true;
+ mInfo->canReceiveKeys = true;
+ mInfo->hasFocus = mFocused;
+ mInfo->hasWallpaper = false;
+ mInfo->paused = false;
+ mInfo->layer = 0;
+ mInfo->ownerPid = INJECTOR_PID;
+ mInfo->ownerUid = INJECTOR_UID;
+ mInfo->inputFeatures = 0;
+ mInfo->displayId = mDisplayId;
+
+ return true;
+ }
+
+ void setFocus() {
+ mFocused = true;
+ }
+
+ void assertNoEvents() {
+ uint32_t consumeSeq;
+ InputEvent* event;
+ status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
+ &consumeSeq, &event);
+ ASSERT_NE(OK, status)
+ << mName.c_str()
+ << ": should not have received any events, so consume(..) should not return OK.";
+ }
+protected:
+ virtual bool handled() {
+ return true;
+ }
+
+ bool mFocused;
+};
+
static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher,
int32_t displayId = ADISPLAY_ID_NONE) {
KeyEvent event;
@@ -419,7 +436,8 @@
INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
}
-static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t displayId) {
+static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
+ int32_t displayId) {
MotionEvent event;
PointerProperties pointerProperties[1];
PointerCoords pointerCoords[1];
@@ -434,7 +452,7 @@
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
// Define a valid motion down event.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, displayId,
+ event.initialize(DEVICE_ID, source, displayId,
AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
AMETA_NONE, /* buttonState */ 0, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
/* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
@@ -449,13 +467,15 @@
TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window");
+ sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window",
+ ADISPLAY_ID_DEFAULT);
Vector<sp<InputWindowHandle>> inputWindowHandles;
inputWindowHandles.add(window);
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
// Window should receive motion event.
@@ -465,15 +485,18 @@
// The foreground window should receive the first touch down event.
TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
- sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
Vector<sp<InputWindowHandle>> inputWindowHandles;
inputWindowHandles.add(windowTop);
inputWindowHandles.add(windowSecond);
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
// Top window should receive the touch down event. Second window should not receive anything.
@@ -483,8 +506,10 @@
TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
- sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
// Set focus application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -504,61 +529,70 @@
windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
-TEST_F(InputDispatcherTest, SetInputWindow_MultiDisplayTouch) {
- sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
- sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application, mDispatcher, "D_2");
+/* Test InputDispatcher for MultiDisplay */
+class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
+public:
+ static constexpr int32_t SECOND_DISPLAY_ID = 1;
+ virtual void SetUp() {
+ InputDispatcherTest::SetUp();
- // Test the primary display touch down.
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.push(windowInPrimary);
+ application1 = new FakeApplicationHandle();
+ windowInPrimary = new FakeWindowHandle(application1, mDispatcher, "D_1",
+ ADISPLAY_ID_DEFAULT);
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push(windowInPrimary);
+ // Set focus window for primary display, but focused display would be second one.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
+ windowInPrimary->setFocus();
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ application2 = new FakeApplicationHandle();
+ windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2",
+ SECOND_DISPLAY_ID);
+ // Set focus to second display window.
+ Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+ inputWindowHandles_Second.push(windowInSecondary);
+ // Set focus display to second one.
+ mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
+ // Set focus window for second display.
+ mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
+ windowInSecondary->setFocus();
+ mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+ }
+
+ virtual void TearDown() {
+ InputDispatcherTest::TearDown();
+
+ application1.clear();
+ windowInPrimary.clear();
+ application2.clear();
+ windowInSecondary.clear();
+ }
+
+protected:
+ sp<FakeApplicationHandle> application1;
+ sp<FakeWindowHandle> windowInPrimary;
+ sp<FakeApplicationHandle> application2;
+ sp<FakeWindowHandle> windowInSecondary;
+};
+
+TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) {
+ // Test touch down on primary display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
windowInSecondary->assertNoEvents();
- // Test the second display touch down.
- constexpr int32_t SECOND_DISPLAY_ID = 1;
- windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
- Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
- inputWindowHandles_Second.push(windowInSecondary);
-
- mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, SECOND_DISPLAY_ID))
+ // Test touch down on second display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
windowInPrimary->assertNoEvents();
windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
}
-TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {
- sp<FakeApplicationHandle> application = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
- sp<FakeApplicationHandle> application2 = new FakeApplicationHandle();
- sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2");
-
- constexpr int32_t SECOND_DISPLAY_ID = 1;
-
- // Set focus to primary display window.
- mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- windowInPrimary->setFocus();
-
- // Set focus to second display window.
- mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
- mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
- windowInSecondary->setFocus();
-
- // Update all windows per displays.
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.push(windowInPrimary);
- mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
-
- windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
- Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
- inputWindowHandles_Second.push(windowInSecondary);
- mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
-
+TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
// Test inject a key down with display id specified.
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
<< "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
@@ -572,8 +606,8 @@
windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
// Remove secondary display.
- inputWindowHandles_Second.clear();
- mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+ Vector<sp<InputWindowHandle>> noWindows;
+ mDispatcher->setInputWindows(noWindows, SECOND_DISPLAY_ID);
// Expect old focus should receive a cancel event.
windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE,
@@ -586,4 +620,66 @@
windowInSecondary->assertNoEvents();
}
+class FakeMonitorReceiver : public FakeInputReceiver, public RefBase {
+public:
+ FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
+ int32_t displayId) : FakeInputReceiver(dispatcher, name, displayId) {
+ mDispatcher->registerInputChannel(mServerChannel, nullptr, displayId);
+ }
+};
+
+// Test per-display input monitors for motion event.
+TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
+ sp<FakeMonitorReceiver> monitorInPrimary =
+ new FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
+ sp<FakeMonitorReceiver> monitorInSecondary =
+ new FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID);
+
+ // Test touch down on primary display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+ monitorInPrimary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+ windowInSecondary->assertNoEvents();
+ monitorInSecondary->assertNoEvents();
+
+ // Test touch down on second display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->assertNoEvents();
+ monitorInPrimary->assertNoEvents();
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
+ monitorInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
+
+ // Test inject a non-pointer motion event.
+ // If specific a display, it will dispatch to the focused window of particular display,
+ // or it will dispatch to the focused window of focused display.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->assertNoEvents();
+ monitorInPrimary->assertNoEvents();
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_NONE);
+ monitorInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_NONE);
+}
+
+// Test per-display input monitors for key event.
+TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
+ //Input monitor per display.
+ sp<FakeMonitorReceiver> monitorInPrimary =
+ new FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
+ sp<FakeMonitorReceiver> monitorInSecondary =
+ new FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID);
+
+ // Test inject a key down.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->assertNoEvents();
+ monitorInPrimary->assertNoEvents();
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+ monitorInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+}
+
} // namespace android
diff --git a/services/sensorservice/RecentEventLogger.cpp b/services/sensorservice/RecentEventLogger.cpp
index cec2ae5..207b097 100644
--- a/services/sensorservice/RecentEventLogger.cpp
+++ b/services/sensorservice/RecentEventLogger.cpp
@@ -32,19 +32,26 @@
RecentEventLogger::RecentEventLogger(int sensorType) :
mSensorType(sensorType), mEventSize(eventSizeBySensorType(mSensorType)),
- mRecentEvents(logSizeBySensorType(sensorType)), mMaskData(false) {
+ mRecentEvents(logSizeBySensorType(sensorType)), mMaskData(false),
+ mIsLastEventCurrent(false) {
// blank
}
void RecentEventLogger::addEvent(const sensors_event_t& event) {
std::lock_guard<std::mutex> lk(mLock);
mRecentEvents.emplace(event);
+ mIsLastEventCurrent = true;
}
bool RecentEventLogger::isEmpty() const {
return mRecentEvents.size() == 0;
}
+void RecentEventLogger::setLastEventStale() {
+ std::lock_guard<std::mutex> lk(mLock);
+ mIsLastEventCurrent = false;
+}
+
std::string RecentEventLogger::dump() const {
std::lock_guard<std::mutex> lk(mLock);
@@ -85,10 +92,10 @@
}
}
-bool RecentEventLogger::populateLastEvent(sensors_event_t *event) const {
+bool RecentEventLogger::populateLastEventIfCurrent(sensors_event_t *event) const {
std::lock_guard<std::mutex> lk(mLock);
- if (mRecentEvents.size()) {
+ if (mIsLastEventCurrent && mRecentEvents.size()) {
// Index 0 contains the latest event emplace()'ed
*event = mRecentEvents[0].mEvent;
return true;
diff --git a/services/sensorservice/RecentEventLogger.h b/services/sensorservice/RecentEventLogger.h
index bf1f655..67378b7 100644
--- a/services/sensorservice/RecentEventLogger.h
+++ b/services/sensorservice/RecentEventLogger.h
@@ -37,8 +37,13 @@
public:
explicit RecentEventLogger(int sensorType);
void addEvent(const sensors_event_t& event);
- bool populateLastEvent(sensors_event_t *event) const;
+
+ // Populate event with the last recorded sensor event if it is not stale. An event is
+ // considered stale if the sensor has become deactivated since the event was recorded.
+ // returns true on success, false if no recent event is available or the last event is stale
+ bool populateLastEventIfCurrent(sensors_event_t *event) const;
bool isEmpty() const;
+ void setLastEventStale();
virtual ~RecentEventLogger() {}
// Dumpable interface
@@ -59,6 +64,7 @@
RingBuffer<SensorEventLog> mRecentEvents;
bool mMaskData;
+ bool mIsLastEventCurrent;
private:
static size_t logSizeBySensorType(int sensorType);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 1b9b945..85450f8 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1290,6 +1290,15 @@
ALOGD_IF(DEBUG_CONNECTIONS, "... and it was the last connection");
mActiveSensors.removeItemsAt(i, 1);
mActiveVirtualSensors.erase(handle);
+
+ // If this is the last connection, then mark the RecentEventLogger as stale. This is
+ // critical for on-change events since the previous event is sent to a client if the
+ // sensor is already active. If two clients request the sensor at the same time, one
+ // of the clients would receive a stale event.
+ auto logger = mRecentEvent.find(handle);
+ if (logger != mRecentEvent.end()) {
+ logger->second->setLastEventStale();
+ }
delete rec;
size--;
} else {
@@ -1356,10 +1365,11 @@
auto logger = mRecentEvent.find(handle);
if (logger != mRecentEvent.end()) {
sensors_event_t event;
- // It is unlikely that this buffer is empty as the sensor is already active.
- // One possible corner case may be two applications activating an on-change
- // sensor at the same time.
- if(logger->second->populateLastEvent(&event)) {
+ // Verify that the last sensor event was generated from the current activation
+ // of the sensor. If not, it is possible for an on-change sensor to receive a
+ // sensor event that is stale if two clients re-activate the sensor
+ // simultaneously.
+ if(logger->second->populateLastEventIfCurrent(&event)) {
event.sensor = handle;
if (event.version == sizeof(sensors_event_t)) {
if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 339f83b..16003a2 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -30,6 +30,7 @@
"android.hardware.configstore@1.1",
"android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
@@ -79,6 +80,7 @@
],
export_shared_lib_headers: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index cafe26b..440f1e2 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -70,6 +70,8 @@
mName.string());
destroyAllHwcLayers();
}
+
+ mTimeStats.onDestroy(getSequence());
}
void BufferLayer::useSurfaceDamage() {
@@ -234,27 +236,71 @@
const auto& viewport = display->getViewport();
Region visible = tr.transform(visibleRegion.intersect(viewport));
const auto displayId = display->getId();
+ if (!hasHwcLayer(displayId)) {
+ ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+ mName.string(), displayId);
+ return;
+ }
+ auto& hwcInfo = getBE().mHwcLayers[displayId];
+ auto& hwcLayer = hwcInfo.layer;
+ auto error = hwcLayer->setVisibleRegion(visible);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ visible.dump(LOG_TAG);
+ }
getBE().compositionInfo.hwc.visibleRegion = visible;
+
+ error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ surfaceDamageRegion.dump(LOG_TAG);
+ }
getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
// Sideband layers
if (getBE().compositionInfo.hwc.sidebandStream.get()) {
setCompositionType(displayId, HWC2::Composition::Sideband);
+ ALOGV("[%s] Requesting Sideband composition", mName.string());
+ error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
+ getBE().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
getBE().compositionInfo.compositionType = HWC2::Composition::Sideband;
return;
}
- if (getBE().compositionInfo.hwc.skipGeometry) {
- // Device or Cursor layers
- if (mPotentialCursor) {
- ALOGV("[%s] Requesting Cursor composition", mName.string());
- setCompositionType(displayId, HWC2::Composition::Cursor);
- } else {
- ALOGV("[%s] Requesting Device composition", mName.string());
- setCompositionType(displayId, HWC2::Composition::Device);
- }
+ // Device or Cursor layers
+ if (mPotentialCursor) {
+ ALOGV("[%s] Requesting Cursor composition", mName.string());
+ setCompositionType(displayId, HWC2::Composition::Cursor);
+ } else {
+ ALOGV("[%s] Requesting Device composition", mName.string());
+ setCompositionType(displayId, HWC2::Composition::Device);
}
+ ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
+ error = hwcLayer->setDataspace(mCurrentDataSpace);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ const HdrMetadata& metadata = getDrawingHdrMetadata();
+ error = hwcLayer->setPerFrameMetadata(display->getSupportedPerFrameMetadata(), metadata);
+ if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
+ ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ error = hwcLayer->setColorTransform(getColorTransform());
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
getBE().compositionInfo.hwc.supportedPerFrameMetadata = display->getSupportedPerFrameMetadata();
@@ -291,8 +337,8 @@
nsecs_t desiredPresentTime = getDesiredPresentTime();
mFrameTracker.setDesiredPresentTime(desiredPresentTime);
- const std::string layerName(getName().c_str());
- mTimeStats.setDesiredTime(layerName, mCurrentFrameNumber, desiredPresentTime);
+ const int32_t layerID = getSequence();
+ mTimeStats.setDesiredTime(layerID, mCurrentFrameNumber, desiredPresentTime);
std::shared_ptr<FenceTime> frameReadyFence = getCurrentFenceTime();
if (frameReadyFence->isValid()) {
@@ -304,14 +350,14 @@
}
if (presentFence->isValid()) {
- mTimeStats.setPresentFence(layerName, mCurrentFrameNumber, presentFence);
+ mTimeStats.setPresentFence(layerID, mCurrentFrameNumber, presentFence);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
} else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t actualPresentTime =
mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
- mTimeStats.setPresentTime(layerName, mCurrentFrameNumber, actualPresentTime);
+ mTimeStats.setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
mFrameTracker.setActualPresentTime(actualPresentTime);
}
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e75fbdf..e592a8b 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -227,6 +227,7 @@
// BufferItem's that weren't actually queued. This can happen in shared
// buffer mode.
bool queuedBuffer = false;
+ const int32_t layerID = getSequence();
LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
@@ -247,7 +248,7 @@
// and return early
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
- mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+ mTimeStats.removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
}
@@ -261,7 +262,7 @@
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.clear();
mQueuedFrames = 0;
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
}
// Once we have hit this state, the shadow queue may no longer
@@ -282,14 +283,13 @@
// Remove any stale buffers that have been dropped during
// updateTexImage
while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
- mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+ mTimeStats.removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
}
- const std::string layerName(getName().c_str());
- mTimeStats.setAcquireFence(layerName, currentFrameNumber, mQueueItems[0].mFenceTime);
- mTimeStats.setLatchTime(layerName, currentFrameNumber, latchTime);
+ mTimeStats.setAcquireFence(layerID, currentFrameNumber, mQueueItems[0].mFenceTime);
+ mTimeStats.setLatchTime(layerID, currentFrameNumber, latchTime);
mQueueItems.removeAt(0);
}
@@ -327,8 +327,22 @@
return NO_ERROR;
}
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>&) {
+void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
+ const auto displayId = display->getId();
+ auto& hwcInfo = getBE().mHwcLayers[displayId];
+ auto& hwcLayer = hwcInfo.layer;
+
+ uint32_t hwcSlot = 0;
+ sp<GraphicBuffer> hwcBuffer;
+ hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
+
auto acquireFence = mConsumer->getCurrentFence();
+ auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
+ getBE().compositionInfo.mBuffer->handle, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
getBE().compositionInfo.mBuffer = mActiveBuffer;
getBE().compositionInfo.hwc.fence = acquireFence;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e52b35a..5df8ade 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -377,6 +377,8 @@
return NO_ERROR;
}
+ const int32_t layerID = getSequence();
+
// Reject if the layer is invalid
uint32_t bufferWidth = s.buffer->width;
uint32_t bufferHeight = s.buffer->height;
@@ -397,7 +399,7 @@
ALOGE("[%s] rejecting buffer: "
"bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
- mTimeStats.removeTimeRecord(getName().c_str(), getFrameNumber());
+ mTimeStats.removeTimeRecord(layerID, getFrameNumber());
return BAD_VALUE;
}
@@ -405,7 +407,7 @@
if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
// TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
if (!releaseFence->isValid()) {
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return UNKNOWN_ERROR;
}
@@ -415,7 +417,7 @@
auto currentStatus = s.acquireFence->getStatus();
if (currentStatus == Fence::Status::Invalid) {
ALOGE("Existing fence has invalid state");
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return BAD_VALUE;
}
@@ -423,7 +425,7 @@
if (incomingStatus == Fence::Status::Invalid) {
ALOGE("New fence has invalid state");
mDrawingState.acquireFence = releaseFence;
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return BAD_VALUE;
}
@@ -439,7 +441,7 @@
// synchronization is broken, the best we can do is hope fences
// signal in order so the new fence will act like a union
mDrawingState.acquireFence = releaseFence;
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return BAD_VALUE;
}
mDrawingState.acquireFence = mergedFence;
@@ -462,16 +464,16 @@
// a GL-composited layer) not at all.
status_t err = bindTextureImage();
if (err != NO_ERROR) {
- mTimeStats.clearLayerRecord(getName().c_str());
+ mTimeStats.clearLayerRecord(layerID);
return BAD_VALUE;
}
}
// TODO(marissaw): properly support mTimeStats
- const std::string layerName(getName().c_str());
- mTimeStats.setPostTime(getName().c_str(), getFrameNumber(), latchTime);
- mTimeStats.setAcquireFence(layerName, getFrameNumber(), getCurrentFenceTime());
- mTimeStats.setLatchTime(layerName, getFrameNumber(), latchTime);
+ mTimeStats.setLayerName(layerID, getName().c_str());
+ mTimeStats.setPostTime(layerID, getFrameNumber(), latchTime);
+ mTimeStats.setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
+ mTimeStats.setLatchTime(layerID, getFrameNumber(), latchTime);
return NO_ERROR;
}
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 3a554c9..263f872 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -62,20 +62,64 @@
const auto& viewport = display->getViewport();
Region visible = tr.transform(visibleRegion.intersect(viewport));
const auto displayId = display->getId();
+ if (!hasHwcLayer(displayId)) {
+ ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+ mName.string(), displayId);
+ return;
+ }
+ auto& hwcInfo = getBE().mHwcLayers[displayId];
+ auto& hwcLayer = hwcInfo.layer;
+ auto error = hwcLayer->setVisibleRegion(visible);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ visible.dump(LOG_TAG);
+ }
getBE().compositionInfo.hwc.visibleRegion = visible;
- getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
setCompositionType(displayId, HWC2::Composition::SolidColor);
+
+ error = hwcLayer->setDataspace(mCurrentDataSpace);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
half4 color = getColor();
- getBE().compositionInfo.hwc.color = {static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255};
+ error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
+ static_cast<uint8_t>(std::round(255.0f * color.g)),
+ static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+ getBE().compositionInfo.hwc.color = { static_cast<uint8_t>(std::round(255.0f * color.r)),
+ static_cast<uint8_t>(std::round(255.0f * color.g)),
+ static_cast<uint8_t>(std::round(255.0f * color.b)), 255 };
// Clear out the transform, because it doesn't make sense absent a source buffer
+ error = hwcLayer->setTransform(HWC2::Transform::None);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
getBE().compositionInfo.hwc.transform = HWC2::Transform::None;
+
+ error = hwcLayer->setColorTransform(getColorTransform());
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
getBE().compositionInfo.hwc.colorTransform = getColorTransform();
+
+ error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ surfaceDamageRegion.dump(LOG_TAG);
+ }
+ getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 341dfd5..6f645df 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -37,8 +37,8 @@
#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
-#include <utils/RefBase.h>
#include <utils/Log.h>
+#include <utils/RefBase.h>
#include "DisplayHardware/DisplaySurface.h"
#include "DisplayHardware/HWComposer.h"
@@ -66,7 +66,8 @@
namespace {
// ordered list of known SDR color modes
-const std::array<ColorMode, 2> sSdrColorModes = {
+const std::array<ColorMode, 3> sSdrColorModes = {
+ ColorMode::DISPLAY_BT2020,
ColorMode::DISPLAY_P3,
ColorMode::SRGB,
};
@@ -96,6 +97,8 @@
return Dataspace::SRGB;
case ColorMode::DISPLAY_P3:
return Dataspace::DISPLAY_P3;
+ case ColorMode::DISPLAY_BT2020:
+ return Dataspace::DISPLAY_BT2020;
case ColorMode::BT2100_HLG:
return Dataspace::BT2020_HLG;
case ColorMode::BT2100_PQ:
@@ -767,9 +770,12 @@
*outMode = iter->second.colorMode;
*outIntent = iter->second.renderIntent;
} else {
- ALOGE("map unknown (%s)/(%s) to default color mode",
- dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
- decodeRenderIntent(intent).c_str());
+ // this is unexpected on a WCG display
+ if (hasWideColorGamut()) {
+ ALOGE("map unknown (%s)/(%s) to default color mode",
+ dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+ decodeRenderIntent(intent).c_str());
+ }
*outDataspace = Dataspace::UNKNOWN;
*outMode = ColorMode::NATIVE;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 163b26c..f0bccaa 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -354,16 +354,26 @@
{
Error error = kDefaultError;
- if (mClient_2_2) {
- mClient_2_2->getColorModes_2_2(display,
- [&](const auto& tmpError, const auto& tmpModes) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
+ if (mClient_2_3) {
+ mClient_2_3->getColorModes_2_3(display, [&](const auto& tmpError, const auto& tmpModes) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
- *outModes = tmpModes;
- });
+ *outModes = tmpModes;
+ });
+ } else if (mClient_2_2) {
+ mClient_2_2->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ for (types::V1_1::ColorMode colorMode : tmpModes) {
+ outModes->push_back(static_cast<ColorMode>(colorMode));
+ }
+ });
} else {
mClient->getColorModes(display,
[&](const auto& tmpError, const auto& tmpModes) {
@@ -555,8 +565,11 @@
RenderIntent renderIntent)
{
hardware::Return<Error> ret(kDefaultError);
- if (mClient_2_2) {
- ret = mClient_2_2->setColorMode_2_2(display, mode, renderIntent);
+ if (mClient_2_3) {
+ ret = mClient_2_3->setColorMode_2_3(display, mode, renderIntent);
+ } else if (mClient_2_2) {
+ ret = mClient_2_2->setColorMode_2_2(display, static_cast<types::V1_1::ColorMode>(mode),
+ renderIntent);
} else {
ret = mClient->setColorMode(display,
static_cast<types::V1_0::ColorMode>(mode));
@@ -934,15 +947,22 @@
}
Error error = kDefaultError;
- mClient_2_2->getRenderIntents(display, colorMode,
- [&](const auto& tmpError, const auto& tmpKeys) {
+
+ auto getRenderIntentsLambda = [&](const auto& tmpError, const auto& tmpKeys) {
error = tmpError;
if (error != Error::NONE) {
return;
}
*outRenderIntents = tmpKeys;
- });
+ };
+
+ if (mClient_2_3) {
+ mClient_2_3->getRenderIntents_2_3(display, colorMode, getRenderIntentsLambda);
+ } else {
+ mClient_2_2->getRenderIntents(display, static_cast<types::V1_1::ColorMode>(colorMode),
+ getRenderIntentsLambda);
+ }
return error;
}
@@ -955,14 +975,14 @@
}
Error error = kDefaultError;
- mClient_2_2->getDataspaceSaturationMatrix(dataspace, [&](const auto& tmpError, const auto& tmpMatrix) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outMatrix = mat4(tmpMatrix.data());
- });
+ mClient_2_2->getDataspaceSaturationMatrix(static_cast<types::V1_1::Dataspace>(dataspace),
+ [&](const auto& tmpError, const auto& tmpMatrix) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outMatrix = mat4(tmpMatrix.data());
+ });
return error;
}
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 94be6e9..4188352 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -49,10 +49,10 @@
using types::V1_0::Hdr;
using types::V1_0::Transform;
-using types::V1_1::ColorMode;
-using types::V1_1::Dataspace;
using types::V1_1::PixelFormat;
using types::V1_1::RenderIntent;
+using types::V1_2::ColorMode;
+using types::V1_2::Dataspace;
using V2_1::Config;
using V2_1::Display;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8afd3b3..88c3c8a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -102,6 +102,7 @@
mCurrentState.hdrMetadata.validTypes = 0;
mCurrentState.surfaceDamageRegion.clear();
mCurrentState.api = -1;
+ mCurrentState.hasColorTransform = false;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -457,18 +458,6 @@
}
auto& hwcInfo = getBE().mHwcLayers[displayId];
- // Device or Cursor layers
- if (mPotentialCursor) {
- ALOGV("[%s] Requesting Cursor composition", mName.string());
- setCompositionType(displayId, HWC2::Composition::Cursor);
- } else {
- ALOGV("[%s] Requesting Device composition", mName.string());
- setCompositionType(displayId, HWC2::Composition::Device);
- }
-
- // Need to program geometry parts
- getBE().compositionInfo.hwc.skipGeometry = false;
-
// enable this layer
hwcInfo.forceClientComposition = false;
@@ -476,6 +465,8 @@
hwcInfo.forceClientComposition = true;
}
+ auto& hwcLayer = hwcInfo.layer;
+
// this gives us only the "orientation" component of the transform
const State& s(getDrawingState());
auto blendMode = HWC2::BlendMode::None;
@@ -483,6 +474,12 @@
blendMode =
mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
}
+ auto error = hwcLayer->setBlendMode(blendMode);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[%s] Failed to set blend mode %s:"
+ " %s (%d)",
+ mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
getBE().compositionInfo.hwc.blendMode = blendMode;
// apply the layer's transform, followed by the display's global transform
@@ -522,14 +519,39 @@
}
const ui::Transform& tr = display->getTransform();
Rect transformedFrame = tr.transform(frame);
+ error = hwcLayer->setDisplayFrame(transformedFrame);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", mName.string(),
+ transformedFrame.left, transformedFrame.top, transformedFrame.right,
+ transformedFrame.bottom, to_string(error).c_str(), static_cast<int32_t>(error));
+ } else {
+ hwcInfo.displayFrame = transformedFrame;
+ }
getBE().compositionInfo.hwc.displayFrame = transformedFrame;
FloatRect sourceCrop = computeCrop(display);
+ error = hwcLayer->setSourceCrop(sourceCrop);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
+ "%s (%d)",
+ mName.string(), sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ } else {
+ hwcInfo.sourceCrop = sourceCrop;
+ }
getBE().compositionInfo.hwc.sourceCrop = sourceCrop;
float alpha = static_cast<float>(getAlpha());
+ error = hwcLayer->setPlaneAlpha(alpha);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[%s] Failed to set plane alpha %.3f: "
+ "%s (%d)",
+ mName.string(), alpha, to_string(error).c_str(), static_cast<int32_t>(error));
getBE().compositionInfo.hwc.alpha = alpha;
+ error = hwcLayer->setZOrder(z);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), z,
+ to_string(error).c_str(), static_cast<int32_t>(error));
getBE().compositionInfo.hwc.z = z;
int type = s.type;
@@ -543,6 +565,10 @@
}
}
+ error = hwcLayer->setInfo(type, appId);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", mName.string(),
+ static_cast<int32_t>(error));
+
getBE().compositionInfo.hwc.type = type;
getBE().compositionInfo.hwc.appId = appId;
@@ -582,9 +608,16 @@
if (orientation & ui::Transform::ROT_INVALID) {
// we can only handle simple transformation
hwcInfo.forceClientComposition = true;
+ getBE().mHwcLayers[displayId].compositionType = HWC2::Composition::Client;
} else {
auto transform = static_cast<HWC2::Transform>(orientation);
hwcInfo.transform = transform;
+ auto error = hwcLayer->setTransform(transform);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[%s] Failed to set transform %s: "
+ "%s (%d)",
+ mName.string(), to_string(transform).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
getBE().compositionInfo.hwc.transform = transform;
}
}
@@ -665,16 +698,25 @@
clearWithOpenGL(renderArea, 0, 0, 0, 0);
}
-void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool /*callIntoHwc*/) {
+void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc) {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setCompositionType called without a valid HWC layer");
return;
- } else {
- if (getBE().mHwcLayers[displayId].compositionType != type) {
- ALOGV("setCompositionType: Changing compositionType from %s to %s",
- to_string(getBE().mHwcLayers[displayId].compositionType).c_str(),
- to_string(type).c_str());
- getBE().mHwcLayers[displayId].compositionType = type;
+ }
+ auto& hwcInfo = getBE().mHwcLayers[displayId];
+ auto& hwcLayer = hwcInfo.layer;
+ ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", (hwcLayer)->getId(), to_string(type).c_str(),
+ static_cast<int>(callIntoHwc));
+ if (hwcInfo.compositionType != type) {
+ ALOGV(" actually setting");
+ hwcInfo.compositionType = type;
+ if (callIntoHwc) {
+ auto error = (hwcLayer)->setCompositionType(type);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[%s] Failed to set "
+ "composition type %s: %s (%d)",
+ mName.string(), to_string(type).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
}
}
}
@@ -1428,14 +1470,15 @@
void Layer::onDisconnect() {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.onDisconnect();
- mTimeStats.onDisconnect(getName().c_str());
+ mTimeStats.onDisconnect(getSequence());
}
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) {
if (newTimestamps) {
- mTimeStats.setPostTime(getName().c_str(), newTimestamps->frameNumber,
- newTimestamps->postedTime);
+ const int32_t layerID = getSequence();
+ mTimeStats.setLayerName(layerID, getName().c_str());
+ mTimeStats.setPostTime(layerID, newTimestamps->frameNumber, newTimestamps->postedTime);
}
Mutex::Autolock lock(mFrameEventHistoryMutex);
@@ -1547,11 +1590,15 @@
}
bool Layer::setColorTransform(const mat4& matrix) {
+ static const mat4 identityMatrix = mat4();
+
if (mCurrentState.colorTransform == matrix) {
return false;
}
++mCurrentState.sequence;
mCurrentState.colorTransform = matrix;
+ mCurrentState.hasColorTransform = matrix != identityMatrix;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1561,8 +1608,7 @@
}
bool Layer::hasColorTransform() const {
- static const mat4 identityMatrix = mat4();
- return getDrawingState().colorTransform != identityMatrix;
+ return getDrawingState().hasColorTransform;
}
bool Layer::isLegacyDataSpace() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e2d1178..5d05f05 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -182,6 +182,7 @@
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
+ bool hasColorTransform;
};
explicit Layer(const LayerCreationArgs& args);
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
index c9b7933..70b00dd 100644
--- a/services/surfaceflinger/LayerBE.cpp
+++ b/services/surfaceflinger/LayerBE.cpp
@@ -65,9 +65,7 @@
}
void LayerBE::onLayerDisplayed(const sp<Fence>& releaseFence) {
- if (mLayer) {
- mLayer->onLayerDisplayed(releaseFence);
- }
+ mLayer->onLayerDisplayed(releaseFence);
}
void LayerBE::clear(renderengine::RenderEngine& engine) {
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index d63d16f..463c46c 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -34,14 +34,13 @@
struct CompositionInfo {
std::string layerName;
- HWC2::Composition compositionType = HWC2::Composition::Invalid;
+ HWC2::Composition compositionType;
bool firstClear = false;
sp<GraphicBuffer> mBuffer = nullptr;
int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
std::shared_ptr<LayerBE> layer;
struct {
std::shared_ptr<HWC2::Layer> hwcLayer;
- bool skipGeometry = true;
int32_t displayId = -1;
sp<Fence> fence;
HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
diff --git a/services/surfaceflinger/RenderEngine/TEST_MAPPING b/services/surfaceflinger/RenderEngine/TEST_MAPPING
new file mode 100644
index 0000000..995dba1
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "librenderengine_test"
+ }
+ ]
+}
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
index 5c4c3d5..dbf50c5 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -650,6 +650,13 @@
} while (true);
}
+status_t GLES20RenderEngine::drawLayers(const DisplaySettings& /*settings*/,
+ const std::vector<LayerSettings>& /*layers*/,
+ ANativeWindowBuffer* const /*buffer*/,
+ base::unique_fd* /*displayFence*/) const {
+ return NO_ERROR;
+}
+
void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
ui::Transform::orientation_flags rotation) {
int32_t l = sourceCrop.left;
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
index 4f03a90..b08e096 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
@@ -73,6 +73,10 @@
void unbindFrameBuffer(Framebuffer* framebuffer) override;
void checkErrors() const override;
+ status_t drawLayers(const DisplaySettings& settings, const std::vector<LayerSettings>& layers,
+ ANativeWindowBuffer* const buffer,
+ base::unique_fd* displayFence) const override;
+
// internal to RenderEngine
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
EGLConfig getEGLConfig() const { return mEGLConfig; }
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h b/services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h
new file mode 100644
index 0000000..5941cdf
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <math/mat4.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+namespace android {
+namespace renderengine {
+
+// DisplaySettings contains the settings that are applicable when drawing all
+// layers for a given display.
+struct DisplaySettings {
+ // Rectangle describing the physical display. We will project from the
+ // logical clip onto this rectangle.
+ Rect physicalDisplay;
+
+ // Rectangle bounded by the x,y- clipping planes in the logical display, so
+ // that the orthographic projection matrix can be computed. When
+ // constructing this matrix, z-coordinate bound are assumed to be at z=0 and
+ // z=1.
+ Rect clip;
+
+ // Global transform to apply to all layers.
+ mat4 globalTransform;
+
+ // Maximum luminance pulled from the display's HDR capabilities.
+ float maxLuminence;
+
+ // Output dataspace that will be populated if wide color gamut is used, or
+ // DataSpace::UNKNOWN otherwise.
+ ui::Dataspace outputDataspace;
+
+ // Additional color transform to apply in linear space after transforming
+ // to the output dataspace.
+ mat4 colorTransform;
+
+ // Region that will be cleared to (0, 0, 0, 0) prior to rendering.
+ // clearRegion will first be transformed by globalTransform so that it will
+ // be in the same coordinate space as the rendered layers.
+ Region clearRegion;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h b/services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h
new file mode 100644
index 0000000..facea21
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <math/mat4.h>
+#include <math/vec3.h>
+#include <renderengine/Texture.h>
+#include <ui/FloatRect.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android {
+namespace renderengine {
+
+// Metadata describing the input buffer to render from.
+struct Buffer {
+ // Buffer containing the image that we will render.
+ // If buffer == nullptr, then the rest of the fields in this struct will be
+ // ignored.
+ sp<GraphicBuffer> buffer;
+
+ // Texture identifier to bind the external texture to.
+ // TODO(alecmouri): This is GL-specific...make the type backend-agnostic.
+ uint32_t textureName;
+
+ // Whether to use filtering when rendering the texture.
+ bool useTextureFiltering;
+
+ // Transform matrix to apply to texture coordinates.
+ mat4 textureTransform;
+
+ // Wheteher to use pre-multiplied alpha
+ bool usePremultipliedAlpha;
+
+ // HDR color-space setting for Y410.
+ bool isY410BT2020;
+};
+
+// Metadata describing the layer geometry.
+struct Geometry {
+ // Boundaries of the layer.
+ FloatRect boundaries;
+
+ // Transform matrix to apply to mesh coordinates.
+ mat4 positionTransform;
+};
+
+// Descriptor of the source pixels for this layer.
+struct PixelSource {
+ // Source buffer
+ Buffer buffer;
+
+ // The solid color with which to fill the layer.
+ // This should only be populated if we don't render from an application
+ // buffer.
+ half3 solidColor;
+};
+
+// The settings that RenderEngine requires for correctly rendering a Layer.
+struct LayerSettings {
+ // Geometry information
+ Geometry geometry;
+
+ // Source pixels for this layer.
+ PixelSource source;
+
+ // Alpha option to apply to the source pixels
+ half alpha;
+
+ // Color space describing how the source pixels should be interpreted.
+ ui::Dataspace sourceDataspace;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
index 122271f..f5d3d6b 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
@@ -23,8 +23,10 @@
#include <android-base/unique_fd.h>
#include <math/mat4.h>
+#include <renderengine/DisplaySettings.h>
#include <renderengine/Framebuffer.h>
#include <renderengine/Image.h>
+#include <renderengine/LayerSettings.h>
#include <ui/GraphicTypes.h>
#include <ui/Transform.h>
@@ -64,6 +66,11 @@
virtual ~RenderEngine() = 0;
+ // ----- BEGIN DEPRECATED INTERFACE -----
+ // This interface, while still in use until a suitable replacement is built,
+ // should be considered deprecated, minus some methods which still may be
+ // used to support legacy behavior.
+
virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0;
virtual std::unique_ptr<Surface> createSurface() = 0;
virtual std::unique_ptr<Image> createImage() = 0;
@@ -133,6 +140,37 @@
// queries
virtual size_t getMaxTextureSize() const = 0;
virtual size_t getMaxViewportDims() const = 0;
+
+ // ----- END DEPRECATED INTERFACE -----
+
+ // ----- BEGIN NEW INTERFACE -----
+
+ // Renders layers for a particular display via GPU composition. This method
+ // should be called for every display that needs to be rendered via the GPU.
+ // @param settings The display-wide settings that should be applied prior to
+ // drawing any layers.
+ // @param layers The layers to draw onto the display, in Z-order.
+ // @param buffer The buffer which will be drawn to. This buffer will be
+ // ready once displayFence fires.
+ // @param displayFence A pointer to a fence, which will fire when the buffer
+ // has been drawn to and is ready to be examined. The fence will be
+ // initialized by this method. The caller will be responsible for owning the
+ // fence.
+ // @return An error code indicating whether drawing was successful. For
+ // now, this always returns NO_ERROR.
+ // TODO(alecmouri): Consider making this a multi-display API, so that the
+ // caller deoes not need to handle multiple fences.
+ virtual status_t drawLayers(const DisplaySettings& settings,
+ const std::vector<LayerSettings>& layers,
+ ANativeWindowBuffer* const buffer,
+ base::unique_fd* displayFence) const = 0;
+
+ // TODO(alecmouri): Expose something like bindTexImage() so that devices
+ // that don't support native sync fences can get rid of code duplicated
+ // between BufferStateLayer and BufferQueueLayer for binding an external
+ // texture.
+
+ // TODO(alecmouri): Add API to help with managing a texture pool.
};
class BindNativeBufferAsFramebuffer {
diff --git a/services/surfaceflinger/RenderEngine/tests/Android.bp b/services/surfaceflinger/RenderEngine/tests/Android.bp
new file mode 100644
index 0000000..65b7c82
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/tests/Android.bp
@@ -0,0 +1,36 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+ name: "librenderengine_test",
+ defaults: ["surfaceflinger_defaults"],
+ test_suites: ["device-tests"],
+ srcs: [
+ "RenderEngineTest.cpp",
+ ],
+ static_libs: [
+ "libgmock",
+ "librenderengine",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libgui",
+ "liblog",
+ "libnativewindow",
+ "libui",
+ "libutils",
+ ],
+}
diff --git a/services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp b/services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp
new file mode 100644
index 0000000..345c7ea
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <renderengine/RenderEngine.h>
+#include <ui/PixelFormat.h>
+
+namespace android {
+
+class RenderEngineTest : public ::testing::Test {
+public:
+ RenderEngineTest() {
+ // Initialize with some sane defaults.
+ // TODO(alecmouri): This should probably be the same instance used by
+ // SurfaceFlinger eventually.
+ mRE = renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888),
+ 0);
+ }
+
+ status_t drawEmptyLayers() {
+ renderengine::DisplaySettings settings;
+ std::vector<renderengine::LayerSettings> layers;
+ // Meaningless buffer since we don't do any drawing
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ base::unique_fd fence;
+ return mRE->drawLayers(settings, layers, buffer->getNativeBuffer(), &fence);
+ }
+
+private:
+ std::unique_ptr<renderengine::RenderEngine> mRE;
+};
+
+TEST_F(RenderEngineTest, drawLayers_noLayersToDraw_works) {
+ status_t result = drawEmptyLayers();
+ ASSERT_EQ(NO_ERROR, result);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fe42480..95b750f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -124,6 +124,7 @@
case ColorMode::ADOBE_RGB:
case ColorMode::DCI_P3:
case ColorMode::BT2020:
+ case ColorMode::DISPLAY_BT2020:
case ColorMode::BT2100_PQ:
case ColorMode::BT2100_HLG:
return true;
@@ -1522,13 +1523,8 @@
preComposition();
rebuildLayerStacks();
calculateWorkingSet();
-
for (const auto& [token, display] : mDisplays) {
- const auto displayId = display->getId();
beginFrame(display);
- for (auto& compositionInfo : getBE().mCompositionInfo[displayId]) {
- setUpHWComposer(compositionInfo);
- }
prepareFrame(display);
doDebugFlashRegions(display, repaintEverything);
doComposition(display, repaintEverything);
@@ -1909,6 +1905,8 @@
mTimeStats.incrementClientCompositionFrames();
}
+ mTimeStats.setPresentFenceGlobal(presentFenceTime);
+
if (display && getHwComposer().isConnected(display->getId()) &&
display->getPowerMode() == HWC_POWER_MODE_OFF) {
return;
@@ -2008,6 +2006,7 @@
// can only be one of
// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
// - Dataspace::DISPLAY_P3
+// - Dataspace::DISPLAY_BT2020
// The returned HDR data space is one of
// - Dataspace::UNKNOWN
// - Dataspace::BT2020_HLG
@@ -2021,6 +2020,12 @@
switch (layer->getDataSpace()) {
case Dataspace::V0_SCRGB:
case Dataspace::V0_SCRGB_LINEAR:
+ case Dataspace::BT2020:
+ case Dataspace::BT2020_ITU:
+ case Dataspace::BT2020_LINEAR:
+ case Dataspace::DISPLAY_BT2020:
+ bestDataSpace = Dataspace::DISPLAY_BT2020;
+ break;
case Dataspace::DISPLAY_P3:
bestDataSpace = Dataspace::DISPLAY_P3;
break;
@@ -2081,127 +2086,6 @@
display->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
-void SurfaceFlinger::configureSidebandComposition(const CompositionInfo& compositionInfo) const
-{
- HWC2::Error error;
- LOG_ALWAYS_FATAL_IF(compositionInfo.hwc.sidebandStream == nullptr,
- "CompositionType is sideband, but sideband stream is nullptr");
- error = (compositionInfo.hwc.hwcLayer)
- ->setSidebandStream(compositionInfo.hwc.sidebandStream->handle());
- if (error != HWC2::Error::None) {
- ALOGE("[SF] Failed to set sideband stream %p: %s (%d)",
- compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-}
-
-void SurfaceFlinger::configureHwcCommonData(const CompositionInfo& compositionInfo) const
-{
- HWC2::Error error;
-
- if (!compositionInfo.hwc.skipGeometry) {
- error = (compositionInfo.hwc.hwcLayer)->setBlendMode(compositionInfo.hwc.blendMode);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set blend mode %s:"
- " %s (%d)",
- to_string(compositionInfo.hwc.blendMode).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
-
- error = (compositionInfo.hwc.hwcLayer)->setDisplayFrame(compositionInfo.hwc.displayFrame);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set the display frame [%d, %d, %d, %d] %s (%d)",
- compositionInfo.hwc.displayFrame.left,
- compositionInfo.hwc.displayFrame.right,
- compositionInfo.hwc.displayFrame.top,
- compositionInfo.hwc.displayFrame.bottom,
- to_string(error).c_str(), static_cast<int32_t>(error));
-
- error = (compositionInfo.hwc.hwcLayer)->setSourceCrop(compositionInfo.hwc.sourceCrop);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: %s (%d)",
- compositionInfo.hwc.sourceCrop.left,
- compositionInfo.hwc.sourceCrop.right,
- compositionInfo.hwc.sourceCrop.top,
- compositionInfo.hwc.sourceCrop.bottom,
- to_string(error).c_str(), static_cast<int32_t>(error));
-
- error = (compositionInfo.hwc.hwcLayer)->setPlaneAlpha(compositionInfo.hwc.alpha);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set plane alpha %.3f: "
- "%s (%d)",
- compositionInfo.hwc.alpha,
- to_string(error).c_str(), static_cast<int32_t>(error));
-
-
- error = (compositionInfo.hwc.hwcLayer)->setZOrder(compositionInfo.hwc.z);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set Z %u: %s (%d)",
- compositionInfo.hwc.z,
- to_string(error).c_str(), static_cast<int32_t>(error));
-
- error = (compositionInfo.hwc.hwcLayer)
- ->setInfo(compositionInfo.hwc.type, compositionInfo.hwc.appId);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set info (%d)",
- static_cast<int32_t>(error));
-
- error = (compositionInfo.hwc.hwcLayer)->setTransform(compositionInfo.hwc.transform);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set transform %s: "
- "%s (%d)",
- to_string(compositionInfo.hwc.transform).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- error = (compositionInfo.hwc.hwcLayer)->setCompositionType(compositionInfo.compositionType);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set composition type: %s (%d)",
- to_string(error).c_str(), static_cast<int32_t>(error));
-
- error = (compositionInfo.hwc.hwcLayer)->setDataspace(compositionInfo.hwc.dataspace);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set dataspace: %s (%d)",
- to_string(error).c_str(), static_cast<int32_t>(error));
-
- error = (compositionInfo.hwc.hwcLayer)->setPerFrameMetadata(
- compositionInfo.hwc.supportedPerFrameMetadata, compositionInfo.hwc.hdrMetadata);
- ALOGE_IF(error != HWC2::Error::None && error != HWC2::Error::Unsupported,
- "[SF] Failed to set hdrMetadata: %s (%d)",
- to_string(error).c_str(), static_cast<int32_t>(error));
-
- if (compositionInfo.compositionType == HWC2::Composition::SolidColor) {
- error = (compositionInfo.hwc.hwcLayer)->setColor(compositionInfo.hwc.color);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set color: %s (%d)",
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- error = (compositionInfo.hwc.hwcLayer)->setVisibleRegion(compositionInfo.hwc.visibleRegion);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set visible region: %s (%d)",
- to_string(error).c_str(), static_cast<int32_t>(error));
-
- error = (compositionInfo.hwc.hwcLayer)->setSurfaceDamage(compositionInfo.hwc.surfaceDamage);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set surface damage: %s (%d)",
- to_string(error).c_str(), static_cast<int32_t>(error));
-
- error = (compositionInfo.hwc.hwcLayer)->setColorTransform(compositionInfo.hwc.colorTransform);
-}
-
-void SurfaceFlinger::configureDeviceComposition(const CompositionInfo& compositionInfo) const
-{
- HWC2::Error error;
-
- if (compositionInfo.hwc.fence) {
- error = (compositionInfo.hwc.hwcLayer)->setBuffer(compositionInfo.mBufferSlot,
- compositionInfo.mBuffer, compositionInfo.hwc.fence);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set buffer: %s (%d)",
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-}
-
void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& display)
{
bool dirty = !display->getDirtyRegion(false).isEmpty();
@@ -2247,42 +2131,6 @@
display->getId(), result, strerror(-result));
}
-void SurfaceFlinger::setUpHWComposer(const CompositionInfo& compositionInfo) {
- ATRACE_CALL();
- ALOGV("setUpHWComposer");
-
- switch (compositionInfo.compositionType)
- {
- case HWC2::Composition::Invalid:
- break;
-
- case HWC2::Composition::Client:
- if (compositionInfo.hwc.hwcLayer) {
- auto error = (compositionInfo.hwc.hwcLayer)->
- setCompositionType(compositionInfo.compositionType);
- ALOGE_IF(error != HWC2::Error::None,
- "[SF] Failed to set composition type: %s (%d)",
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- break;
-
- case HWC2::Composition::Sideband:
- configureHwcCommonData(compositionInfo);
- configureSidebandComposition(compositionInfo);
- break;
-
- case HWC2::Composition::SolidColor:
- configureHwcCommonData(compositionInfo);
- break;
-
- case HWC2::Composition::Device:
- case HWC2::Composition::Cursor:
- configureHwcCommonData(compositionInfo);
- configureDeviceComposition(compositionInfo);
- break;
- }
-}
-
void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
ATRACE_CALL();
ALOGV("doComposition");
@@ -2325,14 +2173,15 @@
}
display->onSwapBuffersCompleted();
display->makeCurrent();
- for (auto& compositionInfo : getBE().mCompositionInfo[displayId]) {
+ for (auto& layer : display->getVisibleLayersSortedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
+
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
// signaled. Always get the release fence from HWC first.
- auto hwcLayer = compositionInfo.hwc.hwcLayer;
- if ((displayId >= 0) && hwcLayer) {
- releaseFence = getBE().mHwc->getLayerReleaseFence(displayId, hwcLayer.get());
+ auto hwcLayer = layer->getHwcLayer(displayId);
+ if (displayId >= 0) {
+ releaseFence = getBE().mHwc->getLayerReleaseFence(displayId, hwcLayer);
}
// If the layer was client composited in the previous frame, we
@@ -2340,14 +2189,12 @@
// Since we do not track that, always merge with the current
// client target acquire fence when it is available, even though
// this is suboptimal.
- if (compositionInfo.compositionType == HWC2::Composition::Client) {
+ if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
releaseFence = Fence::merge("LayerRelease", releaseFence,
display->getClientTargetAcquireFence());
}
- if (compositionInfo.layer) {
- compositionInfo.layer->onLayerDisplayed(releaseFence);
- }
+ layer->getBE().onLayerDisplayed(releaseFence);
}
// We've got a list of layers needing fences, that are disjoint with
@@ -4135,6 +3982,10 @@
getHwComposer().setPowerMode(type, mode);
}
+ if (display->isPrimary()) {
+ mTimeStats.setPowerMode(mode);
+ }
+
ALOGD("Finished setting power mode %d on display %d", mode, displayId);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1425818..8045246 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -693,7 +693,6 @@
* to prepare the hardware composer
*/
void prepareFrame(const sp<DisplayDevice>& display);
- void setUpHWComposer(const CompositionInfo& compositionInfo);
void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
void doTracing(const char* where);
@@ -810,11 +809,6 @@
std::atomic<bool> mRepaintEverything{false};
- // helper methods
- void configureHwcCommonData(const CompositionInfo& compositionInfo) const;
- void configureDeviceComposition(const CompositionInfo& compositionInfo) const;
- void configureSidebandComposition(const CompositionInfo& compositionInfo) const;
-
// constant members (no synchronization needed for access)
nsecs_t mBootTime;
bool mGpuToCpuSupported;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 0bc1c0a..43fa262 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -24,6 +24,7 @@
#include <log/log.h>
#include <utils/String8.h>
+#include <utils/Timers.h>
#include <utils/Trace.h>
#include <algorithm>
@@ -82,7 +83,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- timeStats.totalFrames++;
+ mTimeStats.totalFrames++;
}
void TimeStats::incrementMissedFrames() {
@@ -91,7 +92,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- timeStats.missedFrames++;
+ mTimeStats.missedFrames++;
}
void TimeStats::incrementClientCompositionFrames() {
@@ -100,12 +101,12 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- timeStats.clientCompositionFrames++;
+ mTimeStats.clientCompositionFrames++;
}
-bool TimeStats::recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord) {
+bool TimeStats::recordReadyLocked(int32_t layerID, TimeRecord* timeRecord) {
if (!timeRecord->ready) {
- ALOGV("[%s]-[%" PRIu64 "]-presentFence is still not received", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-presentFence is still not received", layerID,
timeRecord->frameTime.frameNumber);
return false;
}
@@ -118,7 +119,7 @@
timeRecord->frameTime.acquireTime = timeRecord->acquireFence->getSignalTime();
timeRecord->acquireFence = nullptr;
} else {
- ALOGV("[%s]-[%" PRIu64 "]-acquireFence signal time is invalid", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-acquireFence signal time is invalid", layerID,
timeRecord->frameTime.frameNumber);
}
}
@@ -131,7 +132,7 @@
timeRecord->frameTime.presentTime = timeRecord->presentFence->getSignalTime();
timeRecord->presentFence = nullptr;
} else {
- ALOGV("[%s]-[%" PRIu64 "]-presentFence signal time invalid", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-presentFence signal time invalid", layerID,
timeRecord->frameTime.frameNumber);
}
}
@@ -145,14 +146,15 @@
return static_cast<int32_t>(delta);
}
+// This regular expression captures the following for instance:
+// StatusBar in StatusBar#0
+// com.appname in com.appname/com.appname.activity#0
+// com.appname in SurfaceView - com.appname/com.appname.activity#0
+static const std::regex packageNameRegex("(?:SurfaceView[-\\s\\t]+)?([^/]+).*#\\d+");
+
static std::string getPackageName(const std::string& layerName) {
- // This regular expression captures the following for instance:
- // StatusBar in StatusBar#0
- // com.appname in com.appname/com.appname.activity#0
- // com.appname in SurfaceView - com.appname/com.appname.activity#0
- const std::regex re("(?:SurfaceView[-\\s\\t]+)?([^/]+).*#\\d+");
std::smatch match;
- if (std::regex_match(layerName.begin(), layerName.end(), match, re)) {
+ if (std::regex_match(layerName.begin(), layerName.end(), match, packageNameRegex)) {
// There must be a match for group 1 otherwise the whole string is not
// matched and the above will return false
return match[1];
@@ -160,60 +162,61 @@
return "";
}
-void TimeStats::flushAvailableRecordsToStatsLocked(const std::string& layerName) {
+void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerID) {
ATRACE_CALL();
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
while (!timeRecords.empty()) {
- if (!recordReadyLocked(layerName, &timeRecords[0])) break;
- ALOGV("[%s]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerName.c_str(),
+ if (!recordReadyLocked(layerID, &timeRecords[0])) break;
+ ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
if (prevTimeRecord.ready) {
- if (!timeStats.stats.count(layerName)) {
- timeStats.stats[layerName].layerName = layerName;
- timeStats.stats[layerName].packageName = getPackageName(layerName);
+ const std::string& layerName = layerRecord.layerName;
+ if (!mTimeStats.stats.count(layerName)) {
+ mTimeStats.stats[layerName].layerName = layerName;
+ mTimeStats.stats[layerName].packageName = getPackageName(layerName);
}
- TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timeStats.stats[layerName];
+ TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[layerName];
timeStatsLayer.totalFrames++;
timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
layerRecord.droppedFrames = 0;
const int32_t postToAcquireMs = msBetween(timeRecords[0].frameTime.postTime,
timeRecords[0].frameTime.acquireTime);
- ALOGV("[%s]-[%" PRIu64 "]-post2acquire[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-post2acquire[%d]", layerID,
timeRecords[0].frameTime.frameNumber, postToAcquireMs);
timeStatsLayer.deltas["post2acquire"].insert(postToAcquireMs);
const int32_t postToPresentMs = msBetween(timeRecords[0].frameTime.postTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-post2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-post2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, postToPresentMs);
timeStatsLayer.deltas["post2present"].insert(postToPresentMs);
const int32_t acquireToPresentMs = msBetween(timeRecords[0].frameTime.acquireTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-acquire2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-acquire2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, acquireToPresentMs);
timeStatsLayer.deltas["acquire2present"].insert(acquireToPresentMs);
const int32_t latchToPresentMs = msBetween(timeRecords[0].frameTime.latchTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-latch2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-latch2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, latchToPresentMs);
timeStatsLayer.deltas["latch2present"].insert(latchToPresentMs);
const int32_t desiredToPresentMs = msBetween(timeRecords[0].frameTime.desiredTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-desired2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-desired2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, desiredToPresentMs);
timeStatsLayer.deltas["desired2present"].insert(desiredToPresentMs);
const int32_t presentToPresentMs = msBetween(prevTimeRecord.frameTime.presentTime,
timeRecords[0].frameTime.presentTime);
- ALOGV("[%s]-[%" PRIu64 "]-present2present[%d]", layerName.c_str(),
+ ALOGV("[%d]-[%" PRIu64 "]-present2present[%d]", layerID,
timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
}
@@ -223,36 +226,48 @@
}
}
+// This regular expression captures the following layer names for instance:
+// 1) StatusBat#0
+// 2) NavigationBar#1
+// 3) co(m).*#0
+// 4) SurfaceView - co(m).*#0
+// Using [-\\s\t]+ for the conjunction part between SurfaceView and co(m).*
+// is a bit more robust in case there's a slight change.
+// The layer name would only consist of . / $ _ 0-9 a-z A-Z in most cases.
+static const std::regex layerNameRegex(
+ "(((SurfaceView[-\\s\\t]+)?com?\\.[./$\\w]+)|((Status|Navigation)Bar))#\\d+");
+
static bool layerNameIsValid(const std::string& layerName) {
- // This regular expression captures the following layer names for instance:
- // 1) StatusBat#0
- // 2) NavigationBar#1
- // 3) co(m).*#0
- // 4) SurfaceView - co(m).*#0
- // Using [-\\s\t]+ for the conjunction part between SurfaceView and co(m).*
- // is a bit more robust in case there's a slight change.
- // The layer name would only consist of . / $ _ 0-9 a-z A-Z in most cases.
- std::regex re("(((SurfaceView[-\\s\\t]+)?com?\\.[./$\\w]+)|((Status|Navigation)Bar))#\\d+");
- return std::regex_match(layerName.begin(), layerName.end(), re);
+ return std::regex_match(layerName.begin(), layerName.end(), layerNameRegex);
}
-void TimeStats::setPostTime(const std::string& layerName, uint64_t frameNumber, nsecs_t postTime) {
+void TimeStats::setLayerName(int32_t layerID, const std::string& layerName) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerName.c_str(), frameNumber, postTime);
+ ALOGV("[%d]-[%s]", layerID, layerName.c_str());
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName) && !layerNameIsValid(layerName)) {
- return;
+ if (!mTimeStatsTracker.count(layerID) && layerNameIsValid(layerName)) {
+ mTimeStatsTracker[layerID].layerName = layerName;
}
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+}
+
+void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ ALOGV("[%d]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerID, frameNumber, postTime);
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
- ALOGV("[%s]-timeRecords is already at its maximum size[%zu]", layerName.c_str(),
- MAX_NUM_TIME_RECORDS);
- // TODO(zzyiwei): if this happens, there must be a present fence missing
- // or waitData is not in the correct position. Need to think out a
- // reasonable way to recover from this state.
+ ALOGE("[%d]-[%s]-timeRecords is already at its maximum size[%zu]. Please file a bug.",
+ layerID, layerRecord.layerName.c_str(), MAX_NUM_TIME_RECORDS);
+ layerRecord.timeRecords.clear();
+ layerRecord.prevTimeRecord.ready = false;
+ layerRecord.waitData = -1;
return;
}
// For most media content, the acquireFence is invalid because the buffer is
@@ -272,84 +287,77 @@
layerRecord.waitData = layerRecord.timeRecords.size() - 1;
}
-void TimeStats::setLatchTime(const std::string& layerName, uint64_t frameNumber,
- nsecs_t latchTime) {
+void TimeStats::setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerName.c_str(), frameNumber, latchTime);
+ ALOGV("[%d]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerID, frameNumber, latchTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.frameTime.latchTime = latchTime;
}
}
-void TimeStats::setDesiredTime(const std::string& layerName, uint64_t frameNumber,
- nsecs_t desiredTime) {
+void TimeStats::setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerName.c_str(), frameNumber,
- desiredTime);
+ ALOGV("[%d]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerID, frameNumber, desiredTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.frameTime.desiredTime = desiredTime;
}
}
-void TimeStats::setAcquireTime(const std::string& layerName, uint64_t frameNumber,
- nsecs_t acquireTime) {
+void TimeStats::setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerName.c_str(), frameNumber,
- acquireTime);
+ ALOGV("[%d]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerID, frameNumber, acquireTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.frameTime.acquireTime = acquireTime;
}
}
-void TimeStats::setAcquireFence(const std::string& layerName, uint64_t frameNumber,
+void TimeStats::setAcquireFence(int32_t layerID, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& acquireFence) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+ ALOGV("[%d]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerID, frameNumber,
acquireFence->getSignalTime());
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.acquireFence = acquireFence;
}
}
-void TimeStats::setPresentTime(const std::string& layerName, uint64_t frameNumber,
- nsecs_t presentTime) {
+void TimeStats::setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerName.c_str(), frameNumber,
- presentTime);
+ ALOGV("[%d]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerID, frameNumber, presentTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.frameTime.presentTime = presentTime;
@@ -357,20 +365,20 @@
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerName);
+ flushAvailableRecordsToStatsLocked(layerID);
}
-void TimeStats::setPresentFence(const std::string& layerName, uint64_t frameNumber,
+void TimeStats::setPresentFence(int32_t layerID, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& presentFence) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+ ALOGV("[%d]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerID, frameNumber,
presentFence->getSignalTime());
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
if (timeRecord.frameTime.frameNumber == frameNumber) {
timeRecord.presentFence = presentFence;
@@ -378,45 +386,57 @@
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerName);
+ flushAvailableRecordsToStatsLocked(layerID);
}
-void TimeStats::onDisconnect(const std::string& layerName) {
+void TimeStats::onDisconnect(int32_t layerID) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-onDisconnect", layerName.c_str());
+ ALOGV("[%d]-onDisconnect", layerID);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- flushAvailableRecordsToStatsLocked(layerName);
- timeStatsTracker.erase(layerName);
+ if (!mTimeStatsTracker.count(layerID)) return;
+ flushAvailableRecordsToStatsLocked(layerID);
+ mTimeStatsTracker.erase(layerID);
}
-void TimeStats::clearLayerRecord(const std::string& layerName) {
+void TimeStats::onDestroy(int32_t layerID) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-clearLayerRecord", layerName.c_str());
+ ALOGV("[%d]-onDestroy", layerID);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ flushAvailableRecordsToStatsLocked(layerID);
+ mTimeStatsTracker.erase(layerID);
+}
+
+void TimeStats::clearLayerRecord(int32_t layerID) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ ALOGV("[%d]-clearLayerRecord", layerID);
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
layerRecord.timeRecords.clear();
layerRecord.prevTimeRecord.ready = false;
layerRecord.waitData = -1;
layerRecord.droppedFrames = 0;
}
-void TimeStats::removeTimeRecord(const std::string& layerName, uint64_t frameNumber) {
+void TimeStats::removeTimeRecord(int32_t layerID, uint64_t frameNumber) {
if (!mEnabled.load()) return;
ATRACE_CALL();
- ALOGV("[%s]-[%" PRIu64 "]-removeTimeRecord", layerName.c_str(), frameNumber);
+ ALOGV("[%d]-[%" PRIu64 "]-removeTimeRecord", layerID, frameNumber);
std::lock_guard<std::mutex> lock(mMutex);
- if (!timeStatsTracker.count(layerName)) return;
- LayerRecord& layerRecord = timeStatsTracker[layerName];
+ if (!mTimeStatsTracker.count(layerID)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerID];
size_t removeAt = 0;
for (const TimeRecord& record : layerRecord.timeRecords) {
if (record.frameTime.frameNumber == frameNumber) break;
@@ -430,6 +450,87 @@
layerRecord.droppedFrames++;
}
+void TimeStats::flushPowerTimeLocked() {
+ nsecs_t curTime = systemTime();
+ // elapsedTime is in milliseconds.
+ int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
+
+ switch (mPowerTime.powerMode) {
+ case HWC_POWER_MODE_NORMAL:
+ mTimeStats.displayOnTime += elapsedTime;
+ break;
+ case HWC_POWER_MODE_OFF:
+ case HWC_POWER_MODE_DOZE:
+ case HWC_POWER_MODE_DOZE_SUSPEND:
+ default:
+ break;
+ }
+
+ mPowerTime.prevTime = curTime;
+}
+
+void TimeStats::setPowerMode(int32_t powerMode) {
+ if (!mEnabled.load()) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mPowerTime.powerMode = powerMode;
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (powerMode == mPowerTime.powerMode) return;
+
+ flushPowerTimeLocked();
+ mPowerTime.powerMode = powerMode;
+}
+
+void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
+ ATRACE_CALL();
+
+ while (!mGlobalRecord.presentFences.empty()) {
+ const nsecs_t curPresentTime = mGlobalRecord.presentFences.front()->getSignalTime();
+ if (curPresentTime == Fence::SIGNAL_TIME_PENDING) break;
+
+ if (curPresentTime == Fence::SIGNAL_TIME_INVALID) {
+ ALOGE("GlobalPresentFence is invalid!");
+ mGlobalRecord.prevPresentTime = 0;
+ mGlobalRecord.presentFences.pop_front();
+ continue;
+ }
+
+ ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
+ mGlobalRecord.presentFences.front()->getSignalTime());
+
+ const int32_t presentToPresentMs = msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
+ ALOGV("Global present2present[%d]", presentToPresentMs);
+
+ mTimeStats.presentToPresent.insert(presentToPresentMs);
+ mGlobalRecord.prevPresentTime = curPresentTime;
+ mGlobalRecord.presentFences.pop_front();
+ }
+}
+
+void TimeStats::setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (presentFence == nullptr) {
+ mGlobalRecord.prevPresentTime = 0;
+ return;
+ }
+
+ if (mGlobalRecord.presentFences.size() == MAX_NUM_TIME_RECORDS) {
+ // The front presentFence must be trapped in pending status in this
+ // case. Try dequeuing the front one to recover.
+ ALOGE("GlobalPresentFences is already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
+ mGlobalRecord.prevPresentTime = 0;
+ mGlobalRecord.presentFences.pop_front();
+ }
+
+ mGlobalRecord.presentFences.emplace_back(presentFence);
+ flushAvailableGlobalRecordsToStatsLocked();
+}
+
void TimeStats::enable() {
if (mEnabled.load()) return;
@@ -438,7 +539,8 @@
std::lock_guard<std::mutex> lock(mMutex);
ALOGD("Enabled");
mEnabled.store(true);
- timeStats.statsStart = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
+ mPowerTime.prevTime = systemTime();
}
void TimeStats::disable() {
@@ -449,7 +551,7 @@
std::lock_guard<std::mutex> lock(mMutex);
ALOGD("Disabled");
mEnabled.store(false);
- timeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
}
void TimeStats::clear() {
@@ -457,12 +559,15 @@
std::lock_guard<std::mutex> lock(mMutex);
ALOGD("Cleared");
- timeStats.stats.clear();
- timeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
- timeStats.statsEnd = 0;
- timeStats.totalFrames = 0;
- timeStats.missedFrames = 0;
- timeStats.clientCompositionFrames = 0;
+ mTimeStats.stats.clear();
+ mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
+ mTimeStats.statsEnd = 0;
+ mTimeStats.totalFrames = 0;
+ mTimeStats.missedFrames = 0;
+ mTimeStats.clientCompositionFrames = 0;
+ mTimeStats.displayOnTime = 0;
+ mTimeStats.presentToPresent.hist.clear();
+ mPowerTime.prevTime = systemTime();
}
bool TimeStats::isEnabled() {
@@ -473,19 +578,21 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- if (timeStats.statsStart == 0) {
+ if (mTimeStats.statsStart == 0) {
return;
}
- timeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+
+ flushPowerTimeLocked();
if (asProto) {
ALOGD("Dumping TimeStats as proto");
- SFTimeStatsGlobalProto timeStatsProto = timeStats.toProto(maxLayers);
+ SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers);
result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
} else {
ALOGD("Dumping TimeStats as text");
- result.append(timeStats.toString(maxLayers).c_str());
+ result.append(mTimeStats.toString(maxLayers).c_str());
result.append("\n");
}
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 5ab3934..d1e554c 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -19,6 +19,8 @@
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
+#include <hardware/hwcomposer_defs.h>
+
#include <ui/FenceTime.h>
#include <utils/String16.h>
@@ -57,6 +59,7 @@
};
struct LayerRecord {
+ std::string layerName;
// This is the index in timeRecords, at which the timestamps for that
// specific frame are still not fully received. This is not waiting for
// fences to signal, but rather waiting to receive those fences/timestamps.
@@ -66,6 +69,16 @@
std::deque<TimeRecord> timeRecords;
};
+ struct PowerTime {
+ int32_t powerMode = HWC_POWER_MODE_OFF;
+ nsecs_t prevTime = 0;
+ };
+
+ struct GlobalRecord {
+ nsecs_t prevPresentTime = 0;
+ std::deque<std::shared_ptr<FenceTime>> presentFences;
+ };
+
public:
static TimeStats& getInstance();
void parseArgs(bool asProto, const Vector<String16>& args, size_t& index, String8& result);
@@ -73,27 +86,35 @@
void incrementMissedFrames();
void incrementClientCompositionFrames();
- void setPostTime(const std::string& layerName, uint64_t frameNumber, nsecs_t postTime);
- void setLatchTime(const std::string& layerName, uint64_t frameNumber, nsecs_t latchTime);
- void setDesiredTime(const std::string& layerName, uint64_t frameNumber, nsecs_t desiredTime);
- void setAcquireTime(const std::string& layerName, uint64_t frameNumber, nsecs_t acquireTime);
- void setAcquireFence(const std::string& layerName, uint64_t frameNumber,
+ void setLayerName(int32_t layerID, const std::string& layerName);
+ void setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime);
+ void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
+ void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
+ void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
+ void setAcquireFence(int32_t layerID, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& acquireFence);
- void setPresentTime(const std::string& layerName, uint64_t frameNumber, nsecs_t presentTime);
- void setPresentFence(const std::string& layerName, uint64_t frameNumber,
+ void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime);
+ void setPresentFence(int32_t layerID, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& presentFence);
// On producer disconnect with BufferQueue.
- void onDisconnect(const std::string& layerName);
+ void onDisconnect(int32_t layerID);
+ // On layer tear down.
+ void onDestroy(int32_t layerID);
// When SF is cleaning up the queue, clear the LayerRecord as well.
- void clearLayerRecord(const std::string& layerName);
+ void clearLayerRecord(int32_t layerID);
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
- void removeTimeRecord(const std::string& layerName, uint64_t frameNumber);
+ void removeTimeRecord(int32_t layerID, uint64_t frameNumber);
+
+ void setPowerMode(int32_t powerMode);
+ void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence);
private:
TimeStats() = default;
- bool recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord);
- void flushAvailableRecordsToStatsLocked(const std::string& layerName);
+ bool recordReadyLocked(int32_t layerID, TimeRecord* timeRecord);
+ void flushAvailableRecordsToStatsLocked(int32_t layerID);
+ void flushPowerTimeLocked();
+ void flushAvailableGlobalRecordsToStatsLocked();
void enable();
void disable();
@@ -103,8 +124,11 @@
std::atomic<bool> mEnabled = false;
std::mutex mMutex;
- TimeStatsHelper::TimeStatsGlobal timeStats;
- std::unordered_map<std::string, LayerRecord> timeStatsTracker;
+ TimeStatsHelper::TimeStatsGlobal mTimeStats;
+ // Hashmap for LayerRecord with layerID as the hash key
+ std::unordered_map<int32_t, LayerRecord> mTimeStatsTracker;
+ PowerTime mPowerTime;
+ GlobalRecord mGlobalRecord;
};
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index b7b2778..c701224 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -49,7 +49,7 @@
float TimeStatsHelper::Histogram::averageTime() const {
int64_t ret = 0;
int64_t count = 0;
- for (auto& ele : hist) {
+ for (const auto& ele : hist) {
count += ele.second;
ret += ele.first * ele.second;
}
@@ -73,13 +73,13 @@
StringAppendF(&result, "packageName = %s\n", packageName.c_str());
StringAppendF(&result, "totalFrames = %d\n", totalFrames);
StringAppendF(&result, "droppedFrames = %d\n", droppedFrames);
- auto iter = deltas.find("present2present");
+ const auto iter = deltas.find("present2present");
if (iter != deltas.end()) {
StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime());
}
- for (auto& ele : deltas) {
+ for (const auto& ele : deltas) {
StringAppendF(&result, "%s histogram is as below:\n", ele.first.c_str());
- StringAppendF(&result, "%s", ele.second.toString().c_str());
+ result.append(ele.second.toString());
}
return result;
@@ -92,9 +92,12 @@
StringAppendF(&result, "totalFrames = %d\n", totalFrames);
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
+ StringAppendF(&result, "displayOnTime = %lld ms\n", static_cast<long long int>(displayOnTime));
+ StringAppendF(&result, "presentToPresent histogram is as below:\n");
+ result.append(presentToPresent.toString());
const auto dumpStats = generateDumpStats(maxLayers);
- for (auto& ele : dumpStats) {
- StringAppendF(&result, "%s", ele->toString().c_str());
+ for (const auto& ele : dumpStats) {
+ result.append(ele->toString());
}
return result;
@@ -106,10 +109,10 @@
layerProto.set_package_name(packageName);
layerProto.set_total_frames(totalFrames);
layerProto.set_dropped_frames(droppedFrames);
- for (auto& ele : deltas) {
+ for (const auto& ele : deltas) {
SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas();
deltaProto->set_delta_name(ele.first);
- for (auto& histEle : ele.second.hist) {
+ for (const auto& histEle : ele.second.hist) {
SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
@@ -126,8 +129,14 @@
globalProto.set_total_frames(totalFrames);
globalProto.set_missed_frames(missedFrames);
globalProto.set_client_composition_frames(clientCompositionFrames);
+ globalProto.set_display_on_time(displayOnTime);
+ for (const auto& histEle : presentToPresent.hist) {
+ SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
+ histProto->set_time_millis(histEle.first);
+ histProto->set_frame_count(histEle.second);
+ }
const auto dumpStats = generateDumpStats(maxLayers);
- for (auto& ele : dumpStats) {
+ for (const auto& ele : dumpStats) {
SFTimeStatsLayerProto* layerProto = globalProto.add_stats();
layerProto->CopyFrom(ele->toProto());
}
@@ -137,7 +146,7 @@
std::vector<TimeStatsHelper::TimeStatsLayer const*>
TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
std::vector<TimeStatsLayer const*> dumpStats;
- for (auto& ele : stats) {
+ for (const auto& ele : stats) {
dumpStats.push_back(&ele.second);
}
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 99c891b..7d0fe79 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -57,6 +57,8 @@
int32_t totalFrames = 0;
int32_t missedFrames = 0;
int32_t clientCompositionFrames = 0;
+ int64_t displayOnTime = 0;
+ Histogram presentToPresent;
std::unordered_map<std::string, TimeStatsLayer> stats;
std::string toString(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index b8f38c2..377612a 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -20,13 +20,12 @@
option optimize_for = LITE_RUNTIME;
-// //depot/google3/java/com/google/android/apps/graphics/stats/proto/
+// //depot/google3/wireless/android/graphics/surfaceflingerstats/proto/
// timestats.proto is based on this proto. Please only make valid protobuf
-// changes to these messages, and keep the other file in sync per Android
-// release. Please also do not include "option optimize_for = LITE_RUNTIME;" at
-// google3 side.
+// changes to these messages, and keep google3 side proto messages in sync if
+// the end to end pipeline needs to be updated.
-// Next tag: 7
+// Next tag: 9
message SFTimeStatsGlobalProto {
// The stats start time in UTC as seconds since January 1, 1970
optional int64 stats_start = 1;
@@ -38,6 +37,10 @@
optional int32 missed_frames = 4;
// Total frames fallback to client composition.
optional int32 client_composition_frames = 5;
+ // Primary display on time in milliseconds.
+ optional int64 display_on_time = 7;
+ // Present to present histogram.
+ repeated SFTimeStatsHistogramBucketProto present_to_present = 8;
// Stats per layer. Apps could have multiple layers.
repeated SFTimeStatsLayerProto stats = 6;
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index f430679..1352df5 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -42,6 +42,7 @@
namespace {
using testing::_;
+using testing::AtLeast;
using testing::ByMove;
using testing::DoAll;
using testing::IsNull;
@@ -515,7 +516,7 @@
// expectations are for appears to make an extra call to them.
// TODO: Investigate this extra call
EXPECT_CALL(*test->mComposer, setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
- .Times(1)
+ .Times(AtLeast(1))
.RetiresOnSaturation();
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b474e42..d32627a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -22,6 +22,7 @@
#include <log/log.h>
+#include <ui/DebugUtils.h>
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplaySurface.h"
@@ -997,6 +998,93 @@
}
/* ------------------------------------------------------------------------
+ * DisplayDevice::GetBestColorMode
+ */
+class GetBestColorModeTest : public DisplayTransactionTest {
+public:
+ GetBestColorModeTest()
+ : DisplayTransactionTest(),
+ mInjector(FakeDisplayDeviceInjector(mFlinger, DisplayDevice::DISPLAY_PRIMARY, 0)) {}
+
+ void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
+
+ void addHwcColorModesMapping(ui::ColorMode colorMode,
+ std::vector<ui::RenderIntent> renderIntents) {
+ mHwcColorModes[colorMode] = renderIntents;
+ }
+
+ void setInputDataspace(ui::Dataspace dataspace) { mInputDataspace = dataspace; }
+
+ void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; }
+
+ void getBestColorMode() {
+ mInjector.setHwcColorModes(mHwcColorModes);
+ mInjector.setHasWideColorGamut(mHasWideColorGamut);
+ auto displayDevice = mInjector.inject();
+
+ displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
+ &mOutColorMode, &mOutRenderIntent);
+ }
+
+ ui::Dataspace mOutDataspace;
+ ui::ColorMode mOutColorMode;
+ ui::RenderIntent mOutRenderIntent;
+
+private:
+ ui::Dataspace mInputDataspace;
+ ui::RenderIntent mInputRenderIntent;
+ bool mHasWideColorGamut = false;
+ std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> mHwcColorModes;
+ FakeDisplayDeviceInjector mInjector;
+};
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) {
+ addHwcColorModesMapping(ui::ColorMode::SRGB,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ setInputDataspace(ui::Dataspace::DISPLAY_P3);
+ setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+ setHasWideColorGamut(true);
+
+ getBestColorMode();
+
+ ASSERT_EQ(ui::Dataspace::SRGB, mOutDataspace);
+ ASSERT_EQ(ui::ColorMode::SRGB, mOutColorMode);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDisplayP3) {
+ addHwcColorModesMapping(ui::ColorMode::DISPLAY_P3,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ addHwcColorModesMapping(ui::ColorMode::SRGB,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ setInputDataspace(ui::Dataspace::DISPLAY_P3);
+ setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+ setHasWideColorGamut(true);
+
+ getBestColorMode();
+
+ ASSERT_EQ(ui::Dataspace::DISPLAY_P3, mOutDataspace);
+ ASSERT_EQ(ui::ColorMode::DISPLAY_P3, mOutColorMode);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) {
+ addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ setInputDataspace(ui::Dataspace::DISPLAY_P3);
+ setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+ setHasWideColorGamut(true);
+
+ getBestColorMode();
+
+ ASSERT_EQ(ui::Dataspace::DISPLAY_BT2020, mOutDataspace);
+ ASSERT_EQ(ui::ColorMode::DISPLAY_BT2020, mOutColorMode);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+/* ------------------------------------------------------------------------
* SurfaceFlinger::setupNewDisplayDeviceInternal
*/
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 2046439..62afde9 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -369,6 +369,18 @@
return *this;
}
+ auto& setHwcColorModes(
+ const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>
+ hwcColorModes) {
+ mCreationArgs.hwcColorModes = hwcColorModes;
+ return *this;
+ }
+
+ auto& setHasWideColorGamut(bool hasWideColorGamut) {
+ mCreationArgs.hasWideColorGamut = hasWideColorGamut;
+ return *this;
+ }
+
sp<DisplayDevice> inject() {
DisplayDeviceState state;
state.type = mCreationArgs.type;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index ecf3181..c0395c0 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -30,10 +30,10 @@
using android::hardware::graphics::common::V1_0::ColorTransform;
using android::hardware::graphics::common::V1_0::Hdr;
using android::hardware::graphics::common::V1_0::Transform;
-using android::hardware::graphics::common::V1_1::ColorMode;
-using android::hardware::graphics::common::V1_1::Dataspace;
using android::hardware::graphics::common::V1_1::PixelFormat;
using android::hardware::graphics::common::V1_1::RenderIntent;
+using android::hardware::graphics::common::V1_2::ColorMode;
+using android::hardware::graphics::common::V1_2::Dataspace;
using android::hardware::graphics::composer::V2_1::Config;
using android::hardware::graphics::composer::V2_1::Display;
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 6813cda..afca63a 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -17,13 +17,15 @@
#pragma once
#include <gmock/gmock.h>
-
+#include <renderengine/DisplaySettings.h>
#include <renderengine/Framebuffer.h>
#include <renderengine/Image.h>
+#include <renderengine/LayerSettings.h>
#include <renderengine/Mesh.h>
#include <renderengine/RenderEngine.h>
#include <renderengine/Surface.h>
#include <renderengine/Texture.h>
+#include <ui/GraphicBuffer.h>
namespace android {
namespace renderengine {
@@ -75,6 +77,9 @@
MOCK_METHOD1(drawMesh, void(const Mesh&));
MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
+ MOCK_CONST_METHOD4(drawLayers,
+ status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
+ ANativeWindowBuffer* const, base::unique_fd*));
};
class Surface : public renderengine::Surface {
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
index 9d5b91a..2f39e41 100644
--- a/services/vr/bufferhubd/IBufferHub.cpp
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -4,14 +4,69 @@
namespace android {
namespace dvr {
+class BpBufferHub : public BpInterface<IBufferHub> {
+ public:
+ explicit BpBufferHub(const sp<IBinder>& impl)
+ : BpInterface<IBufferHub>(impl) {}
+
+ sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage,
+ uint64_t user_metadata_size) override;
+};
+
IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
+// Transaction code
+enum {
+ CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count,
+ uint32_t format, uint64_t usage,
+ uint64_t user_metadata_size) {
+ Parcel data, reply;
+ status_t ret = NO_ERROR;
+ ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
+ ret |= data.writeUint32(width);
+ ret |= data.writeUint32(height);
+ ret |= data.writeUint32(layer_count);
+ ret |= data.writeUint32(format);
+ ret |= data.writeUint64(usage);
+ ret |= data.writeUint64(user_metadata_size);
+
+ if (ret != NO_ERROR) {
+ ALOGE("BpBufferHub::createBuffer: failed to write into parcel");
+ return nullptr;
+ }
+
+ ret = remote()->transact(CREATE_BUFFER, data, &reply);
+ if (ret == NO_ERROR) {
+ return interface_cast<IBufferClient>(reply.readStrongBinder());
+ } else {
+ ALOGE("BpBufferHub::createBuffer: failed to transact; errno=%d", ret);
+ return nullptr;
+ }
+}
+
status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
+ case CREATE_BUFFER: {
+ CHECK_INTERFACE(IBufferHub, data, reply);
+ uint32_t width = data.readUint32();
+ uint32_t height = data.readUint32();
+ uint32_t layer_count = data.readUint32();
+ uint32_t format = data.readUint32();
+ uint64_t usage = data.readUint64();
+ uint64_t user_metadata_size = data.readUint64();
+ sp<IBufferClient> ret = createBuffer(width, height, layer_count, format,
+ usage, user_metadata_size);
+ return reply->writeStrongBinder(IInterface::asBinder(ret));
+ } break;
default:
- // Should not reach
- ALOGE("onTransact(): unknown code %u received!", code);
+ // Should not reach except binder defined transactions such as dumpsys
return BBinder::onTransact(code, data, reply, flags);
}
}
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
index dcc6ea4..ee85746 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -1,3 +1,4 @@
+#include <errno.h>
#include <private/dvr/buffer_channel.h>
#include <private/dvr/producer_channel.h>
@@ -16,9 +17,8 @@
size_t user_metadata_size)
: BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
buffer_node_(
- std::make_shared<BufferNode>(std::move(buffer), user_metadata_size)),
- buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
- buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+ std::make_shared<BufferNode>(std::move(buffer), user_metadata_size)) {
+ buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
}
BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
@@ -27,24 +27,28 @@
uint64_t usage, size_t user_metadata_size)
: BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
buffer_node_(std::make_shared<BufferNode>(
- width, height, layer_count, format, usage, user_metadata_size)),
- buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
- buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+ width, height, layer_count, format, usage, user_metadata_size)) {
+ buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
}
BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
int channel_id,
- std::shared_ptr<BufferNode> buffer_node,
- uint64_t buffer_state_bit)
+ std::shared_ptr<BufferNode> buffer_node)
: BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
- buffer_node_(buffer_node),
- buffer_state_bit_(buffer_state_bit) {
- buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+ buffer_node_(buffer_node) {
+ buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
+ if (buffer_state_bit_ == 0ULL) {
+ ALOGE("BufferChannel::BufferChannel: %s", strerror(errno));
+ buffer_node_ = nullptr;
+ }
}
BufferChannel::~BufferChannel() {
ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
channel_id(), buffer_id());
+ if (buffer_state_bit_ != 0ULL) {
+ buffer_node_->RemoveClientsBitFromMask(buffer_state_bit_);
+ }
Hangup();
}
@@ -74,11 +78,6 @@
*this, &BufferChannel::OnDuplicate, message);
return true;
- case DetachedBufferRPC::Promote::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Promote>(
- *this, &BufferChannel::OnPromote, message);
- return true;
-
default:
return false;
}
@@ -106,38 +105,22 @@
/*released_fence_fd=*/BorrowedHandle{}};
}
-Status<RemoteChannelHandle> BufferChannel::OnDuplicate(
- Message& message) {
+Status<RemoteChannelHandle> BufferChannel::OnDuplicate(Message& message) {
ATRACE_NAME("BufferChannel::OnDuplicate");
- ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.",
- buffer_id());
+ ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.", buffer_id());
int channel_id;
auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status) {
- ALOGE(
- "BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
- status.GetErrorMessage().c_str());
+ if (!status.ok()) {
+ ALOGE("BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
+ status.GetErrorMessage().c_str());
return ErrorStatus(ENOMEM);
}
- // Try find the next buffer state bit which has not been claimed by any
- // other buffers yet.
- uint64_t buffer_state_bit =
- BufferHubDefs::FindNextClearedBit(buffer_node_->active_buffer_bit_mask() |
- BufferHubDefs::kProducerStateBit);
- if (buffer_state_bit == 0ULL) {
- ALOGE(
- "BufferChannel::OnDuplicate: reached the maximum mumber of channels "
- "per buffer node: 63.");
- return ErrorStatus(E2BIG);
- }
-
- auto channel =
- std::shared_ptr<BufferChannel>(new BufferChannel(
- service(), buffer_id(), channel_id, buffer_node_, buffer_state_bit));
- if (!channel) {
- ALOGE("BufferChannel::OnDuplicate: Invalid buffer.");
+ auto channel = std::shared_ptr<BufferChannel>(
+ new BufferChannel(service(), buffer_id(), channel_id, buffer_node_));
+ if (!channel->IsValid()) {
+ ALOGE("BufferChannel::OnDuplicate: Invalid buffer. %s", strerror(errno));
return ErrorStatus(EINVAL);
}
@@ -154,69 +137,5 @@
return status;
}
-Status<RemoteChannelHandle> BufferChannel::OnPromote(
- Message& message) {
- ATRACE_NAME("BufferChannel::OnPromote");
- ALOGD_IF(TRACE, "BufferChannel::OnPromote: buffer_id=%d", buffer_id());
-
- // Check whether this is the channel exclusive owner of the buffer_node_.
- if (buffer_state_bit_ != buffer_node_->active_buffer_bit_mask()) {
- ALOGE(
- "BufferChannel::OnPromote: Cannot promote this BufferChannel as its "
- "BufferNode is shared between multiple channels. This channel's state "
- "bit=0x%" PRIx64 ", acitve_buffer_bit_mask=0x%" PRIx64 ".",
- buffer_state_bit_, buffer_node_->active_buffer_bit_mask());
- return ErrorStatus(EINVAL);
- }
-
- // Note that the new ProducerChannel will have different channel_id, but
- // inherits the buffer_id from the DetachedBuffer.
- int channel_id;
- auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status) {
- ALOGE(
- "BufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
- status.GetErrorMessage().c_str());
- return ErrorStatus(ENOMEM);
- }
-
- IonBuffer buffer = std::move(buffer_node_->buffer());
- IonBuffer metadata_buffer;
- if (int ret = metadata_buffer.Alloc(buffer_node_->metadata().metadata_size(),
- /*height=*/1,
- /*layer_count=*/1,
- BufferHubDefs::kMetadataFormat,
- BufferHubDefs::kMetadataUsage)) {
- ALOGE("BufferChannel::OnPromote: Failed to allocate metadata: %s",
- strerror(-ret));
- return ErrorStatus(EINVAL);
- }
-
- size_t user_metadata_size = buffer_node_->user_metadata_size();
-
- std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
- service(), buffer_id(), channel_id, std::move(buffer),
- std::move(metadata_buffer), user_metadata_size);
- if (!channel) {
- ALOGE(
- "BufferChannel::OnPromote: Failed to create ProducerChannel from a "
- "BufferChannel, buffer_id=%d.",
- buffer_id());
- }
-
- const auto channel_status =
- service()->SetChannel(channel_id, std::move(channel));
- if (!channel_status) {
- // Technically, this should never fail, as we just pushed the channel. Note
- // that LOG_FATAL will be stripped out in non-debug build.
- LOG_FATAL(
- "BufferChannel::OnPromote: Failed to set new producer buffer channel: "
- "%s.",
- channel_status.GetErrorMessage().c_str());
- }
-
- return status;
-}
-
} // namespace dvr
} // namespace android
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 15391da..6421a0b 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -265,14 +265,6 @@
SetChannel(channel->channel_id(), nullptr);
return {};
- case DetachedBufferRPC::Promote::Opcode:
- // In addition to the message handler in the BufferChannel's
- // HandleMessage method, we also need to invalid the channel. Note that
- // this has to be done after HandleMessage returns to make sure the IPC
- // request has went back to the client first.
- SetChannel(channel->channel_id(), nullptr);
- return {};
-
default:
return DefaultHandleMessage(message);
}
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index b507717..017a2ab 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -5,6 +5,7 @@
#include <binder/ProcessState.h>
#include <log/log.h>
#include <private/dvr/buffer_hub_binder.h>
+#include <private/dvr/buffer_node.h>
namespace android {
namespace dvr {
@@ -13,7 +14,7 @@
const std::shared_ptr<BufferHubService>& pdx_service) {
IPCThreadState::self()->disableBackgroundScheduling(true);
- BufferHubBinderService* service = new BufferHubBinderService();
+ sp<BufferHubBinderService> service = new BufferHubBinderService();
service->pdx_service_ = pdx_service;
// Not using BinderService::publish because need to get an instance of this
@@ -45,8 +46,14 @@
"Input arguments are ignored.\n");
}
- // TODO(b/116526156): output real data in this class once we have it
+ fprintf(out, "Binder service:\n");
+ // Active buffers
+ fprintf(out, "Active BufferClients: %zu\n", client_list_.size());
+ // TODO(b/117790952): print buffer information after BufferNode has it
+ // TODO(b/116526156): print more information once we have them
+
if (pdx_service_) {
+ fprintf(out, "\nPDX service:\n");
// BufferHubService::Dumpstate(size_t) is not actually using the param
// So just using 0 as the length
fprintf(out, "%s", pdx_service_->DumpState(0).c_str());
@@ -77,5 +84,18 @@
return ret;
}
+sp<IBufferClient> BufferHubBinderService::createBuffer(
+ uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, uint64_t user_metadata_size) {
+ std::shared_ptr<BufferNode> node = std::make_shared<BufferNode>(
+ width, height, layer_count, format, usage, user_metadata_size);
+
+ sp<BufferClient> client = new BufferClient(node);
+ // Add it to list for bookkeeping and dumpsys.
+ client_list_.push_back(client);
+
+ return client;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
index 782b9c2..bedec6f 100644
--- a/services/vr/bufferhubd/buffer_node.cpp
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -1,12 +1,24 @@
+#include <errno.h>
#include <private/dvr/buffer_hub_defs.h>
#include <private/dvr/buffer_node.h>
namespace android {
namespace dvr {
+void BufferNode::InitializeMetadata() {
+ // Using placement new here to reuse shared memory instead of new allocation
+ // Initialize the atomic variables to zero.
+ BufferHubDefs::MetadataHeader* metadata_header = metadata_.metadata_header();
+ buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint64_t>(0);
+ fence_state_ = new (&metadata_header->fence_state) std::atomic<uint64_t>(0);
+ active_clients_bit_mask_ =
+ new (&metadata_header->active_clients_bit_mask) std::atomic<uint64_t>(0);
+}
+
BufferNode::BufferNode(IonBuffer buffer, size_t user_metadata_size)
: buffer_(std::move(buffer)) {
metadata_ = BufferHubMetadata::Create(user_metadata_size);
+ InitializeMetadata();
}
// Allocates a new BufferNode.
@@ -22,6 +34,37 @@
}
metadata_ = BufferHubMetadata::Create(user_metadata_size);
+ InitializeMetadata();
+}
+
+uint64_t BufferNode::GetActiveClientsBitMask() const {
+ return active_clients_bit_mask_->load(std::memory_order_acquire);
+}
+
+uint64_t BufferNode::AddNewActiveClientsBitToMask() {
+ uint64_t current_active_clients_bit_mask = GetActiveClientsBitMask();
+ uint64_t buffer_state_bit = 0ULL;
+ uint64_t updated_active_clients_bit_mask = 0ULL;
+ do {
+ buffer_state_bit =
+ BufferHubDefs::FindNextClearedBit(current_active_clients_bit_mask);
+ if (buffer_state_bit == 0ULL) {
+ ALOGE(
+ "BufferNode::AddNewActiveClientsBitToMask: reached the maximum "
+ "mumber of channels per buffer node: 32.");
+ errno = E2BIG;
+ return 0ULL;
+ }
+ updated_active_clients_bit_mask =
+ current_active_clients_bit_mask | buffer_state_bit;
+ } while (!(active_clients_bit_mask_->compare_exchange_weak(
+ current_active_clients_bit_mask, updated_active_clients_bit_mask,
+ std::memory_order_acq_rel, std::memory_order_acquire)));
+ return buffer_state_bit;
+}
+
+void BufferNode::RemoveClientsBitFromMask(const uint64_t& value) {
+ active_clients_bit_mask_->fetch_and(~value);
}
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
index 266ae88..0442881 100644
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -3,6 +3,7 @@
#include <binder/IInterface.h>
#include <binder/Parcel.h>
+#include <private/dvr/IBufferClient.h>
namespace android {
namespace dvr {
@@ -10,6 +11,11 @@
class IBufferHub : public IInterface {
public:
DECLARE_META_INTERFACE(BufferHub);
+
+ virtual sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage,
+ uint64_t user_metadata_size) = 0;
};
class BnBufferHub : public BnInterface<IBufferHub> {
@@ -18,13 +24,7 @@
uint32_t flags = 0);
};
-class BpBufferHub : public BpInterface<IBufferHub> {
- public:
- explicit BpBufferHub(const sp<IBinder>& impl)
- : BpInterface<IBufferHub>(impl) {}
-};
-
} // namespace dvr
} // namespace android
-#endif
\ No newline at end of file
+#endif // ANDROID_DVR_IBUFFERHUB_H
\ No newline at end of file
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
index 1697251..e9bdb37 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
@@ -42,21 +42,20 @@
uint32_t height, uint32_t layer_count, uint32_t format,
uint64_t usage, size_t user_metadata_size);
- // Creates a detached buffer from an existing BufferNode.
+ // Creates a detached buffer from an existing BufferNode. This method is used
+ // in OnDuplicate method.
BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
- std::shared_ptr<BufferNode> buffer_node,
- uint64_t buffer_state_bit);
+ std::shared_ptr<BufferNode> buffer_node);
pdx::Status<BufferTraits<pdx::BorrowedHandle>> OnImport(
pdx::Message& message);
pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
- pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
// The concrete implementation of the Buffer object.
- std::shared_ptr<BufferNode> buffer_node_;
+ std::shared_ptr<BufferNode> buffer_node_ = nullptr;
// The state bit of this buffer. Must be one the lower 63 bits.
- uint64_t buffer_state_bit_;
+ uint64_t buffer_state_bit_ = 0ULL;
};
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_client.h b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
new file mode 100644
index 0000000..20d51ee
--- /dev/null
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
@@ -0,0 +1,29 @@
+#ifndef ANDROID_DVR_BUFFERCLIENT_H
+#define ANDROID_DVR_BUFFERCLIENT_H
+
+#include <private/dvr/IBufferClient.h>
+#include <private/dvr/buffer_node.h>
+
+namespace android {
+namespace dvr {
+
+class BufferClient : public BnBufferClient {
+ public:
+ // Creates a server-side buffer client from an existing BufferNode. Note that
+ // this funciton takes ownership of the shared_ptr.
+ explicit BufferClient(std::shared_ptr<BufferNode> node)
+ : buffer_node_(std::move(node)){};
+
+ // Binder IPC functions
+ bool isValid() override {
+ return buffer_node_ ? buffer_node_->IsValid() : false;
+ };
+
+ private:
+ std::shared_ptr<BufferNode> buffer_node_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_IBUFFERCLIENT_H
\ No newline at end of file
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
index e266ff8..11272ae 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -1,8 +1,11 @@
#ifndef ANDROID_DVR_BUFFER_HUB_BINDER_H
#define ANDROID_DVR_BUFFER_HUB_BINDER_H
+#include <vector>
+
#include <binder/BinderService.h>
#include <private/dvr/IBufferHub.h>
+#include <private/dvr/buffer_client.h>
#include <private/dvr/buffer_hub.h>
namespace android {
@@ -20,8 +23,16 @@
// Helper function to get the BpReference to this service
static sp<IBufferHub> getServiceProxy();
+ // Binder IPC functions
+ sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage,
+ uint64_t user_metadata_size) override;
+
private:
std::shared_ptr<BufferHubService> pdx_service_;
+
+ std::vector<sp<BufferClient>> client_list_;
};
} // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_node.h b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
index d6c6105..e1e8057 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_node.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
@@ -10,7 +10,7 @@
class BufferNode {
public:
// Creates a BufferNode from existing IonBuffers, i.e. creating from an
- // existing ProducerChannel.
+ // existing ProducerChannel. Allocate a new BufferHubMetadata.
BufferNode(IonBuffer buffer, size_t user_metadata_size);
// Allocates a new BufferNode.
@@ -21,26 +21,56 @@
bool IsValid() const { return buffer_.IsValid() && metadata_.IsValid(); }
size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
- uint64_t active_buffer_bit_mask() const { return active_buffer_bit_mask_; }
- void set_buffer_state_bit(uint64_t buffer_state_bit) {
- active_buffer_bit_mask_ |= buffer_state_bit;
- }
- // Accessor of the IonBuffer.
+ // Accessors of the IonBuffer.
IonBuffer& buffer() { return buffer_; }
const IonBuffer& buffer() const { return buffer_; }
- // Accessor of the metadata.
+ // Accessors of metadata.
const BufferHubMetadata& metadata() const { return metadata_; }
+ // Gets the current value of active_clients_bit_mask in metadata_ with
+ // std::memory_order_acquire, so that all previous releases of
+ // active_clients_bit_mask from all threads will be returned here.
+ uint64_t GetActiveClientsBitMask() const;
+
+ // Find and add a new buffer_state_bit to active_clients_bit_mask in
+ // metadata_.
+ // Return the new buffer_state_bit that is added to active_clients_bit_mask.
+ // Return 0ULL if there are already 32 bp clients of the buffer.
+ uint64_t AddNewActiveClientsBitToMask();
+
+ // Removes the value from active_clients_bit_mask in metadata_ with
+ // std::memory_order_release, so that the change will be visible to any
+ // acquire of active_clients_bit_mask_ in any threads after the succeed of
+ // this operation.
+ void RemoveClientsBitFromMask(const uint64_t& value);
+
private:
+ // Helper method for constructors to initialize atomic metadata header
+ // variables in shared memory.
+ void InitializeMetadata();
+
// Gralloc buffer handles.
IonBuffer buffer_;
+
+ // Metadata in shared memory.
BufferHubMetadata metadata_;
- // All active buffer bits. Valid bits are the lower 63 bits, while the
- // highest bit is reserved for the exclusive writing and should not be set.
- uint64_t active_buffer_bit_mask_ = 0ULL;
+ // The following variables are atomic variables in metadata_ that are visible
+ // to Bn object and Bp objects. Please find more info in
+ // BufferHubDefs::MetadataHeader.
+
+ // buffer_state_ tracks the state of the buffer. Buffer can be in one of these
+ // four states: gained, posted, acquired, released.
+ std::atomic<uint64_t>* buffer_state_ = nullptr;
+
+ // TODO(b/112012161): add comments to fence_state_.
+ std::atomic<uint64_t>* fence_state_ = nullptr;
+
+ // active_clients_bit_mask_ tracks all the bp clients of the buffer. It is the
+ // union of all buffer_state_bit of all bp clients.
+ std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
};
} // namespace dvr
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
index bf8ea5b..a80691f 100644
--- a/services/vr/bufferhubd/tests/Android.bp
+++ b/services/vr/bufferhubd/tests/Android.bp
@@ -23,4 +23,31 @@
// TODO(b/117568153): Temporarily opt out using libcrt.
no_libcrt: true,
-}
\ No newline at end of file
+}
+
+cc_test {
+ name: "buffer_node-test",
+ srcs: ["buffer_node-test.cpp"],
+ cflags: [
+ "-DLOG_TAG=\"buffer_node-test\"",
+ "-DTRACE=0",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+ ],
+ header_libs: ["libdvr_headers"],
+ static_libs: [
+ "libbufferhub",
+ "libbufferhubd",
+ "libgmock",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libpdx_default_transport",
+ "libui",
+ "libutils",
+ ],
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
+}
+
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
index 587e6db..c4703f1 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -1,6 +1,8 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <private/dvr/IBufferClient.h>
#include <private/dvr/buffer_hub_binder.h>
+#include <ui/PixelFormat.h>
namespace android {
namespace dvr {
@@ -8,16 +10,30 @@
namespace {
using testing::Ne;
+using testing::NotNull;
+
+const int kWidth = 640;
+const int kHeight = 480;
+const int kLayerCount = 1;
+const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+const int kUsage = 0;
+const size_t kUserMetadataSize = 0;
class BufferHubBinderServiceTest : public ::testing::Test {
- // Add setup and teardown if necessary
+ protected:
+ void SetUp() override {
+ service = BufferHubBinderService::getServiceProxy();
+ ASSERT_THAT(service, Ne(nullptr));
+ }
+
+ sp<IBufferHub> service;
};
-TEST_F(BufferHubBinderServiceTest, TestInitialize) {
- // Create a new service will kill the current one.
- // So just check if Binder service is running
- sp<IBufferHub> service = BufferHubBinderService::getServiceProxy();
- EXPECT_THAT(service, Ne(nullptr));
+TEST_F(BufferHubBinderServiceTest, TestCreateBuffer) {
+ sp<IBufferClient> bufferClient = service->createBuffer(
+ kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+ ASSERT_THAT(bufferClient, NotNull());
+ EXPECT_TRUE(bufferClient->isValid());
}
} // namespace
diff --git a/services/vr/bufferhubd/tests/buffer_node-test.cpp b/services/vr/bufferhubd/tests/buffer_node-test.cpp
new file mode 100644
index 0000000..c2526fe
--- /dev/null
+++ b/services/vr/bufferhubd/tests/buffer_node-test.cpp
@@ -0,0 +1,89 @@
+#include <errno.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <private/dvr/buffer_node.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+const uint32_t kWidth = 640;
+const uint32_t kHeight = 480;
+const uint32_t kLayerCount = 1;
+const uint32_t kFormat = 1;
+const uint64_t kUsage = 0;
+const size_t kUserMetadataSize = 0;
+
+class BufferNodeTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ buffer_node = new BufferNode(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ kUserMetadataSize);
+ ASSERT_TRUE(buffer_node->IsValid());
+ }
+
+ void TearDown() override {
+ if (buffer_node != nullptr) {
+ delete buffer_node;
+ }
+ }
+
+ BufferNode* buffer_node = nullptr;
+};
+
+TEST_F(BufferNodeTest, TestCreateBufferNode) {
+ EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
+}
+
+TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
+ uint64_t new_buffer_state_bit_1 = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), new_buffer_state_bit_1);
+
+ // Request and add a new buffer_state_bit again.
+ // Active clients bit mask should be the union of the two new
+ // buffer_state_bits.
+ uint64_t new_buffer_state_bit_2 = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(),
+ new_buffer_state_bit_1 | new_buffer_state_bit_2);
+}
+
+TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_32NewClients) {
+ uint64_t new_buffer_state_bit = 0ULL;
+ uint64_t current_mask = 0ULL;
+ uint64_t expected_mask = 0ULL;
+
+ for (int i = 0; i < 64; ++i) {
+ new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_NE(new_buffer_state_bit, 0);
+ EXPECT_FALSE(new_buffer_state_bit & current_mask);
+ expected_mask = current_mask | new_buffer_state_bit;
+ current_mask = buffer_node->GetActiveClientsBitMask();
+ EXPECT_EQ(current_mask, expected_mask);
+ }
+
+ // Method should fail upon requesting for more than maximum allowable clients.
+ new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_EQ(new_buffer_state_bit, 0ULL);
+ EXPECT_EQ(errno, E2BIG);
+}
+
+TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) {
+ buffer_node->AddNewActiveClientsBitToMask();
+ uint64_t current_mask = buffer_node->GetActiveClientsBitMask();
+ uint64_t new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
+ EXPECT_NE(buffer_node->GetActiveClientsBitMask(), current_mask);
+
+ buffer_node->RemoveClientsBitFromMask(new_buffer_state_bit);
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+
+ // Remove the test_mask again to the active client bit mask should not modify
+ // the value of active clients bit mask.
+ buffer_node->RemoveClientsBitFromMask(new_buffer_state_bit);
+ EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+}
+
+} // namespace
+
+} // namespace dvr
+} // namespace android
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index 313d095..05d4dfe 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -353,7 +353,7 @@
1,
"",
0,
- VK_API_VERSION_1_0};
+ VK_API_VERSION_1_1};
VkInstanceCreateInfo instance_info = {
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
nullptr,