Merge "Negate condition to reduce nesting in InputDispatcher"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 19c2830..53b3a00 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -228,6 +228,10 @@
{ OPT, "events/kmem/rss_stat/enable" },
{ OPT, "events/kmem/ion_heap_grow/enable" },
{ OPT, "events/kmem/ion_heap_shrink/enable" },
+ { OPT, "events/oom/oom_score_adj_update/enable" },
+ { OPT, "events/sched/sched_process_exit/enable" },
+ { OPT, "events/task/task_rename/enable" },
+ { OPT, "events/task/task_newtask/enable" },
} },
};
@@ -435,14 +439,10 @@
const char* path = category.sysfiles[i].path;
bool req = category.sysfiles[i].required == REQ;
if (path != nullptr) {
- if (req) {
- if (!fileIsWritable(path)) {
- return false;
- } else {
- ok = true;
- }
- } else {
+ if (fileIsWritable(path)) {
ok = true;
+ } else if (req) {
+ return false;
}
}
}
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 854244f..2e9701f 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -139,16 +139,7 @@
srcs: ["otapreopt_chroot.cpp"],
shared_libs: [
"libbase",
- "libjsoncpp",
"liblog",
- "libselinux",
- "libziparchive",
- ],
- static_libs: [
- "libapex",
- "libapexd",
- "libavb",
- "libdm",
],
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 25e5247..32c1313 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -660,7 +660,8 @@
const unique_fd& reference_profile_fd,
const std::vector<unique_fd>& apk_fds,
const std::vector<std::string>& dex_locations,
- bool copy_and_update) {
+ bool copy_and_update,
+ bool store_aggregation_counters) {
const char* profman_bin =
is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
@@ -688,6 +689,10 @@
AddArg("--copy-and-update-profile-key");
}
+ if (store_aggregation_counters) {
+ AddArg("--store-aggregation-counters");
+ }
+
// Do not add after dex2oat_flags, they should override others for debugging.
PrepareArgs(profman_bin);
}
@@ -695,12 +700,14 @@
void SetupMerge(const std::vector<unique_fd>& profiles_fd,
const unique_fd& reference_profile_fd,
const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(),
- const std::vector<std::string>& dex_locations = std::vector<std::string>()) {
+ const std::vector<std::string>& dex_locations = std::vector<std::string>(),
+ bool store_aggregation_counters = false) {
SetupArgs(profiles_fd,
- reference_profile_fd,
- apk_fds,
- dex_locations,
- /*copy_and_update=*/false);
+ reference_profile_fd,
+ apk_fds,
+ dex_locations,
+ /*copy_and_update=*/false,
+ store_aggregation_counters);
}
void SetupCopyAndUpdate(unique_fd&& profile_fd,
@@ -713,8 +720,12 @@
apk_fds_.push_back(std::move(apk_fd));
reference_profile_fd_ = std::move(reference_profile_fd);
std::vector<std::string> dex_locations = {dex_location};
- SetupArgs(profiles_fd_, reference_profile_fd_, apk_fds_, dex_locations,
- /*copy_and_update=*/true);
+ SetupArgs(profiles_fd_,
+ reference_profile_fd_,
+ apk_fds_,
+ dex_locations,
+ /*copy_and_update=*/true,
+ /*store_aggregation_counters=*/false);
}
void SetupDump(const std::vector<unique_fd>& profiles_fd,
@@ -724,8 +735,12 @@
const unique_fd& output_fd) {
AddArg("--dump-only");
AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
- SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
- /*copy_and_update=*/false);
+ SetupArgs(profiles_fd,
+ reference_profile_fd,
+ apk_fds,
+ dex_locations,
+ /*copy_and_update=*/false,
+ /*store_aggregation_counters=*/false);
}
void Exec() {
@@ -2618,7 +2633,11 @@
}
}
RunProfman args;
- args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
+ args.SetupMerge(profiles_fd,
+ snapshot_fd,
+ apk_fds,
+ dex_locations,
+ /*store_aggregation_counters=*/true);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index a3dfa2d..e90cf3b 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -17,7 +17,6 @@
#include <fcntl.h>
#include <linux/unistd.h>
#include <sys/mount.h>
-#include <sys/stat.h>
#include <sys/wait.h>
#include <sstream>
@@ -25,9 +24,6 @@
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
-#include <selinux/android.h>
-
-#include <apexd.h>
#include "installd_constants.h"
#include "otapreopt_utils.h"
@@ -142,32 +138,6 @@
UNUSED(product_result);
}
- // Setup APEX mount point and its security context.
- // The logic here is similar to the one in system/core/rootdir/init.rc:
- //
- // mount tmpfs tmpfs /apex nodev noexec nosuid
- // chmod 0755 /apex
- // chown root root /apex
- // restorecon /apex
- //
- if (mount("tmpfs", "/postinstall/apex", "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr)
- != 0) {
- PLOG(ERROR) << "Failed to mount tmpfs in /postinstall/apex";
- exit(209);
- }
- if (chmod("/postinstall/apex", 0755) != 0) {
- PLOG(ERROR) << "Failed to chmod /postinstall/apex to 0755";
- exit(210);
- }
- if (chown("/postinstall/apex", 0, 0) != 0) {
- PLOG(ERROR) << "Failed to chown /postinstall/apex to root:root";
- exit(211);
- }
- if (selinux_android_restorecon("/postinstall/apex", 0) < 0) {
- PLOG(ERROR) << "Failed to restorecon /postinstall/apex";
- exit(212);
- }
-
// Chdir into /postinstall.
if (chdir("/postinstall") != 0) {
PLOG(ERROR) << "Unable to chdir into /postinstall.";
@@ -185,18 +155,6 @@
exit(205);
}
- // Try to mount APEX packages in "/apex" in the chroot dir. We need at least
- // the Android Runtime APEX, as it is required by otapreopt to run dex2oat.
- {
- // The logic here is (partially) copied and adapted from
- // system/apex/apexd/apexd_main.cpp.
-
- // Only scan the APEX directory under /system (within the chroot dir).
- // Note that this leaves around the loop devices created and used by
- // libapexd's code, but this is fine, as we expect to reboot soon after.
- apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
- }
-
// Now go on and run otapreopt.
// Incoming: cmd + status-fd + target-slot + cmd... + null | Incoming | = argc + 1
diff --git a/headers/media_plugin/media/hardware/HardwareAPI.h b/headers/media_plugin/media/hardware/HardwareAPI.h
index 6c1ba3d..ae0220a 100644
--- a/headers/media_plugin/media/hardware/HardwareAPI.h
+++ b/headers/media_plugin/media/hardware/HardwareAPI.h
@@ -425,7 +425,7 @@
// HDR color description parameters.
// This is passed via OMX_SetConfig or OMX_GetConfig to video encoders and decoders when the
-// 'OMX.google.android.index.describeHDRColorInfo' extension is given and an HDR stream
+// 'OMX.google.android.index.describeHDRStaticInfo' extension is given and an HDR stream
// is detected. Component SHALL behave as described below if it supports this extension.
//
// Currently, only Static Metadata Descriptor Type 1 support is required.
@@ -496,6 +496,64 @@
HDRStaticInfo sInfo; // IN/OUT
};
+// HDR10+ metadata configuration.
+//
+// nParamSize: size of the storage starting at nValue (must be at least 1 and at most
+// MAX_HDR10PLUSINFO_SIZE). This field must not be modified by the component.
+// nParamSizeUsed: size of the actual HDR10+ metadata starting at nValue. For OMX_SetConfig,
+// it must not be modified by the component. For OMX_GetConfig, the component
+// should put the actual size of the retrieved config in this field (and in
+// case where nParamSize is smaller than nParamSizeUsed, the component should
+// still update nParamSizeUsed without actually copying the metadata to nValue).
+// nValue: storage of the HDR10+ metadata conforming to the user_data_registered_itu_t_t35()
+// syntax of SEI message for ST 2094-40.
+//
+// This is passed via OMX_SetConfig or OMX_GetConfig to video encoders and decoders when the
+// 'OMX.google.android.index.describeHDR10PlusInfo' extension is given. In general, this config
+// is associated with a particular frame. A typical sequence of usage is as follows:
+//
+// a) OMX_SetConfig associates the config with the next input buffer sent in OMX_EmptyThisBuffer
+// (input A);
+// b) The component sends OMX_EventConfigUpdate to notify the client that there is a config
+// update on the output port that is associated with the next output buffer that's about to
+// be sent via FillBufferDone callback (output A);
+// c) The client, upon receiving the OMX_EventConfigUpdate, calls OMX_GetConfig to retrieve
+// the config and associates it with output A.
+//
+// All config updates will be retrieved in the order reported, and the client is required to
+// call OMX_GetConfig for each OMX_EventConfigUpdate for this config. Note that the order of
+// OMX_EventConfigUpdate relative to FillBufferDone callback determines which output frame
+// the config should be associated with, the actual OMX_GetConfig for the config could happen
+// before or after the component calls the FillBufferDone callback.
+//
+// Depending on the video codec type (in particular, whether the codec uses in-band or out-of-
+// band HDR10+ metadata), the component shall behave as detailed below:
+//
+// VIDEO DECODERS:
+// 1) If the codec utilizes out-of-band HDR10+ metadata, the decoder must support the sequence
+// a) ~ c) outlined above;
+// 2) If the codec utilizes in-band HDR10+ metadata, OMX_SetConfig for this config should be
+// ignored (as the metadata is embedded in the input buffer), while the notification and
+// retrieval of the config on the output as outlined in b) & c) must be supported.
+//
+// VIDEO ENCODERS:
+// 1) If the codec utilizes out-of-band HDR10+ metadata, the decoder must support the sequence
+// a) ~ c) outlined above;
+// 2) If the codec utilizes in-band HDR10+ metadata, OMX_SetConfig for this config outlined in
+// a) must be supported. The notification as outlined in b) must not be sent, and the
+// retrieval of the config via OMX_GetConfig should be ignored (as the metadata is embedded
+// in the output buffer).
+
+#define MAX_HDR10PLUSINFO_SIZE 1024
+struct DescribeHDR10PlusInfoParams {
+ OMX_U32 nSize; // IN
+ OMX_VERSIONTYPE nVersion; // IN
+ OMX_U32 nPortIndex; // IN
+ OMX_U32 nParamSize; // IN
+ OMX_U32 nParamSizeUsed; // IN/OUT
+ OMX_U8 nValue[1]; // IN/OUT
+};
+
} // namespace android
extern android::OMXPluginBase *createOMXPlugin();
diff --git a/headers/media_plugin/media/openmax/OMX_Core.h b/headers/media_plugin/media/openmax/OMX_Core.h
index bb974b3..9ff934e 100644
--- a/headers/media_plugin/media/openmax/OMX_Core.h
+++ b/headers/media_plugin/media/openmax/OMX_Core.h
@@ -542,6 +542,20 @@
* fool-proof way to do that for video encoders.
*/
OMX_EventDataSpaceChanged,
+
+ /**
+ * Event when a component has an updated configuration on output for the client to retrieve.
+ * |arg1| contains the port index (currently only output port is valid). |arg2| contains the
+ * index of the updated config.
+ *
+ * For config updates that's associated with one frame, the update should be applied to the
+ * next output frame that comes in EmptyBufferDone callback.
+ *
+ * Upon receiving this event, the client must call the corresponding OMX_GetConfig to retrieve
+ * the config update.
+ */
+ OMX_EventConfigUpdate,
+
OMX_EventMax = 0x7FFFFFFF
} OMX_EVENTTYPE;
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index bbf157b..435fcc8 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -164,6 +164,8 @@
// HDR profiles also support passing HDR metadata
OMX_VIDEO_VP9Profile2HDR = 0x1000,
OMX_VIDEO_VP9Profile3HDR = 0x2000,
+ OMX_VIDEO_VP9Profile2HDR10Plus = 0x4000,
+ OMX_VIDEO_VP9Profile3HDR10Plus = 0x8000,
OMX_VIDEO_VP9ProfileUnknown = 0x6EFFFFFF,
OMX_VIDEO_VP9ProfileMax = 0x7FFFFFFF
} OMX_VIDEO_VP9PROFILETYPE;
@@ -216,6 +218,7 @@
OMX_VIDEO_HEVCProfileMainStill = 0x4,
// Main10 profile with HDR SEI support.
OMX_VIDEO_HEVCProfileMain10HDR10 = 0x1000,
+ OMX_VIDEO_HEVCProfileMain10HDR10Plus = 0x2000,
OMX_VIDEO_HEVCProfileMax = 0x7FFFFFFF
} OMX_VIDEO_HEVCPROFILETYPE;
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index ed9531e..fa7d908 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -131,7 +131,7 @@
* POSIX error code (see errno.h) if an immediate error occurs.
*/
int android_res_nsend(net_handle_t network,
- const unsigned char *msg, int msglen) __INTRODUCED_IN(29);
+ const uint8_t *msg, size_t msglen) __INTRODUCED_IN(29);
/**
* Read a result for the query associated with the |fd| descriptor.
@@ -141,7 +141,7 @@
* >= 0: length of |answer|. |rcode| is the resolver return code (e.g., ns_r_nxdomain)
*/
int android_res_nresult(int fd,
- int *rcode, unsigned char *answer, int anslen) __INTRODUCED_IN(29);
+ int *rcode, uint8_t *answer, size_t anslen) __INTRODUCED_IN(29);
/**
* Attempts to cancel the in-progress query associated with the |nsend_fd|
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
new file mode 100644
index 0000000..d68f274
--- /dev/null
+++ b/include/input/TouchVideoFrame.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _LIBINPUT_TOUCHVIDEOFRAME_H
+#define _LIBINPUT_TOUCHVIDEOFRAME_H
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <vector>
+
+namespace android {
+
+/**
+ * Represents data from a single scan of the touchscreen device.
+ * Similar in concept to a video frame, but the touch strength is used as
+ * the values instead.
+ */
+class TouchVideoFrame {
+public:
+ TouchVideoFrame(uint32_t width, uint32_t height, std::vector<int16_t> data,
+ const struct timeval& timestamp) :
+ mWidth(width), mHeight(height), mData(std::move(data)), mTimestamp(timestamp) {
+ }
+
+ /**
+ * Width of the frame
+ */
+ uint32_t getWidth() const { return mWidth; }
+ /**
+ * Height of the frame
+ */
+ uint32_t getHeight() const { return mHeight; }
+ /**
+ * The touch strength data.
+ * The array is a 2-D row-major matrix, with dimensions (height, width).
+ * Total size of the array should equal getHeight() * getWidth().
+ * Data is allowed to be negative.
+ */
+ const std::vector<int16_t>& getData() const { return mData; }
+ /**
+ * Time at which the heatmap was taken.
+ */
+ const struct timeval& getTimestamp() const { return mTimestamp; }
+
+private:
+ uint32_t mWidth;
+ uint32_t mHeight;
+ std::vector<int16_t> mData;
+ struct timeval mTimestamp;
+};
+
+} // namespace android
+
+#endif // _LIBINPUT_TOUCHVIDEOFRAME_H
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 fcdf7af..f3bc31b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -43,7 +43,7 @@
if (length < 0) return false;
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
- if (length > vec->max_size()) return false;
+ if (static_cast<size_t>(length) > vec->max_size()) return false;
vec->resize(length);
*outBuffer = vec->data();
@@ -65,7 +65,7 @@
*vec = std::optional<std::vector<T>>(std::vector<T>{});
- if (length > (*vec)->max_size()) return false;
+ if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
(*vec)->resize(length);
*outBuffer = (*vec)->data();
@@ -88,7 +88,7 @@
if (length < 0) return false;
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
- if (length > vec->max_size()) return false;
+ if (static_cast<size_t>(length) > vec->max_size()) return false;
vec->resize(length);
return true;
@@ -116,7 +116,7 @@
*vec = std::optional<std::vector<T>>(std::vector<T>{});
- if (length > (*vec)->max_size()) return false;
+ if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
(*vec)->resize(length);
return true;
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 7106cbb..512b069 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -24,11 +24,13 @@
"IPCThreadStateBase.cpp",
],
+ header_libs: [
+ "libbase_headers",
+ "libutils_headers",
+ ],
+
shared_libs: [
- "libbase",
"liblog",
- "libcutils",
- "libutils",
],
export_include_dirs: ["include"],
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index dfdda0c..9dc7431 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -19,6 +19,7 @@
#include <graphicsenv/GraphicsEnv.h>
#include <dlfcn.h>
+#include <unistd.h>
#include <android-base/file.h>
#include <android-base/properties.h>
@@ -28,7 +29,11 @@
#include <log/log.h>
#include <sys/prctl.h>
+#include <memory>
#include <mutex>
+#include <string>
+
+#include <dlfcn.h>
// TODO(b/37049319) Get this from a header once one exists
extern "C" {
@@ -46,6 +51,20 @@
};
}
+// TODO(ianelliott@): Get the following from an ANGLE header:
+#define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting
+// Version-2 API:
+typedef bool (*fpANGLEGetFeatureSupportUtilAPIVersion)(unsigned int* versionToUse);
+typedef bool (*fpANGLEAndroidParseRulesString)(const char* rulesString, void** rulesHandle,
+ int* rulesVersion);
+typedef bool (*fpANGLEGetSystemInfo)(void** handle);
+typedef bool (*fpANGLEAddDeviceInfoToSystemInfo)(const char* deviceMfr, const char* deviceModel,
+ void* handle);
+typedef bool (*fpANGLEShouldBeUsedForApplication)(void* rulesHandle, int rulesVersion,
+ void* systemInfoHandle, const char* appName);
+typedef bool (*fpANGLEFreeRulesHandle)(void* handle);
+typedef bool (*fpANGLEFreeSystemInfoHandle)(void* handle);
+
namespace android {
enum NativeLibrary {
@@ -134,39 +153,186 @@
mDriverPath = path;
}
+void* GraphicsEnv::loadLibrary(std::string name) {
+ const android_dlextinfo dlextinfo = {
+ .flags = ANDROID_DLEXT_USE_NAMESPACE,
+ .library_namespace = getAngleNamespace(),
+ };
+
+ std::string libName = std::string("lib") + name + "_angle.so";
+
+ void* so = android_dlopen_ext(libName.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+
+ if (so) {
+ ALOGD("dlopen_ext from APK (%s) success at %p", libName.c_str(), so);
+ return so;
+ } else {
+ ALOGE("dlopen_ext(\"%s\") failed: %s", libName.c_str(), dlerror());
+ }
+
+ return nullptr;
+}
+
+bool GraphicsEnv::checkAngleRules(void* so) {
+ char manufacturer[PROPERTY_VALUE_MAX];
+ char model[PROPERTY_VALUE_MAX];
+ property_get("ro.product.manufacturer", manufacturer, "UNSET");
+ property_get("ro.product.model", model, "UNSET");
+
+ auto ANGLEGetFeatureSupportUtilAPIVersion =
+ (fpANGLEGetFeatureSupportUtilAPIVersion)dlsym(so,
+ "ANGLEGetFeatureSupportUtilAPIVersion");
+
+ if (!ANGLEGetFeatureSupportUtilAPIVersion) {
+ ALOGW("Cannot find ANGLEGetFeatureSupportUtilAPIVersion function");
+ return false;
+ }
+
+ // Negotiate the interface version by requesting most recent known to the platform
+ unsigned int versionToUse = CURRENT_ANGLE_API_VERSION;
+ if (!(ANGLEGetFeatureSupportUtilAPIVersion)(&versionToUse)) {
+ ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, "
+ "requested version %u",
+ versionToUse);
+ return false;
+ }
+
+ // Add and remove versions below as needed
+ bool useAngle = false;
+ switch (versionToUse) {
+ case 2: {
+ ALOGV("Using version %d of ANGLE feature-support library", versionToUse);
+ void* rulesHandle = nullptr;
+ int rulesVersion = 0;
+ void* systemInfoHandle = nullptr;
+
+ // Get the symbols for the feature-support-utility library:
+#define GET_SYMBOL(symbol) \
+ fp##symbol symbol = (fp##symbol)dlsym(so, #symbol); \
+ if (!symbol) { \
+ ALOGW("Cannot find " #symbol " in ANGLE feature-support library"); \
+ break; \
+ }
+ GET_SYMBOL(ANGLEAndroidParseRulesString);
+ GET_SYMBOL(ANGLEGetSystemInfo);
+ GET_SYMBOL(ANGLEAddDeviceInfoToSystemInfo);
+ GET_SYMBOL(ANGLEShouldBeUsedForApplication);
+ GET_SYMBOL(ANGLEFreeRulesHandle);
+ GET_SYMBOL(ANGLEFreeSystemInfoHandle);
+
+ // Parse the rules, obtain the SystemInfo, and evaluate the
+ // application against the rules:
+ if (!(ANGLEAndroidParseRulesString)(mRulesBuffer.data(), &rulesHandle, &rulesVersion)) {
+ ALOGW("ANGLE feature-support library cannot parse rules file");
+ break;
+ }
+ if (!(ANGLEGetSystemInfo)(&systemInfoHandle)) {
+ ALOGW("ANGLE feature-support library cannot obtain SystemInfo");
+ break;
+ }
+ if (!(ANGLEAddDeviceInfoToSystemInfo)(manufacturer, model, systemInfoHandle)) {
+ ALOGW("ANGLE feature-support library cannot add device info to SystemInfo");
+ break;
+ }
+ useAngle = (ANGLEShouldBeUsedForApplication)(rulesHandle, rulesVersion,
+ systemInfoHandle, mAngleAppName.c_str());
+ (ANGLEFreeRulesHandle)(rulesHandle);
+ (ANGLEFreeSystemInfoHandle)(systemInfoHandle);
+ } break;
+
+ default:
+ ALOGW("Version %u of ANGLE feature-support library is NOT supported.", versionToUse);
+ }
+
+ ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
+ return useAngle;
+}
+
+bool GraphicsEnv::shouldUseAngle(std::string appName) {
+ if (appName != mAngleAppName) {
+ // Make sure we are checking the app we were init'ed for
+ ALOGE("App name does not match: expected '%s', got '%s'", mAngleAppName.c_str(),
+ appName.c_str());
+ return false;
+ }
+
+ return shouldUseAngle();
+}
+
+bool GraphicsEnv::shouldUseAngle() {
+ // Make sure we are init'ed
+ if (mAngleAppName.empty()) {
+ ALOGE("App name is empty. setAngleInfo() must be called first to enable ANGLE.");
+ return false;
+ }
+
+ return mUseAngle;
+}
+
+void GraphicsEnv::updateUseAngle() {
+ mUseAngle = false;
+
+ const char* ANGLE_PREFER_ANGLE = "angle";
+ const char* ANGLE_PREFER_NATIVE = "native";
+
+ if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
+ ALOGV("User set \"Developer Options\" to force the use of ANGLE");
+ mUseAngle = true;
+ } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
+ ALOGV("User set \"Developer Options\" to force the use of Native");
+ mUseAngle = false;
+ } else {
+ // The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily
+ // load ANGLE and call the updatable opt-in/out logic:
+
+ // Check if ANGLE is enabled. Workaround for several bugs:
+ // b/119305693 b/119322355 b/119305887
+ // Something is not working correctly in the feature library
+ char prop[PROPERTY_VALUE_MAX];
+ property_get("debug.angle.enable", prop, "0");
+ void* featureSo = nullptr;
+ if (atoi(prop)) {
+ featureSo = loadLibrary("feature_support");
+ }
+ if (featureSo) {
+ ALOGV("loaded ANGLE's opt-in/out logic from namespace");
+ mUseAngle = checkAngleRules(featureSo);
+ dlclose(featureSo);
+ featureSo = nullptr;
+ } else {
+ ALOGV("Could not load the ANGLE opt-in/out logic, cannot use ANGLE.");
+ }
+ }
+}
+
void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
const std::string 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());
- } else {
- ALOGV("setting ANGLE path to '%s'", path.c_str());
- mAnglePath = path;
- }
+ ALOGV("setting ANGLE path to '%s'", path.c_str());
+ mAnglePath = path;
+ ALOGV("setting ANGLE app name to '%s'", appName.c_str());
+ mAngleAppName = appName;
+ ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str());
+ mAngleDeveloperOptIn = developerOptIn;
- if (!mAngleAppName.empty()) {
- ALOGV("ignoring attempt to change ANGLE app name from '%s' to '%s'", mAngleAppName.c_str(),
- appName.c_str());
- } else {
- ALOGV("setting ANGLE app name to '%s'", appName.c_str());
- mAngleAppName = appName;
+ lseek(rulesFd, rulesOffset, SEEK_SET);
+ mRulesBuffer = std::vector<char>(rulesLength + 1);
+ ssize_t numBytesRead = read(rulesFd, mRulesBuffer.data(), rulesLength);
+ if (numBytesRead < 0) {
+ ALOGE("Cannot read rules file: numBytesRead = %zd", numBytesRead);
+ numBytesRead = 0;
+ } else if (numBytesRead == 0) {
+ ALOGW("Empty rules file");
}
-
- if (!mAngleDeveloperOptIn.empty()) {
- ALOGV("ignoring attempt to change ANGLE application opt-in from '%s' to '%s'",
- mAngleDeveloperOptIn.c_str(), developerOptIn.c_str());
- } else {
- ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str());
- mAngleDeveloperOptIn = developerOptIn;
+ if (numBytesRead != rulesLength) {
+ ALOGW("Did not read all of the necessary bytes from the rules file."
+ "expected: %ld, got: %zd",
+ rulesLength, numBytesRead);
}
+ mRulesBuffer[numBytesRead] = '\0';
- 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;
+ // Update the current status of whether we should use ANGLE or not
+ updateUseAngle();
}
void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
@@ -183,25 +349,8 @@
return mAppNamespace;
}
-const char* GraphicsEnv::getAngleAppName() {
- if (mAngleAppName.empty()) return nullptr;
- return mAngleAppName.c_str();
-}
-
-const char* GraphicsEnv::getAngleDeveloperOptIn() {
- return mAngleDeveloperOptIn.c_str();
-}
-
-int GraphicsEnv::getAngleRulesFd() {
- return mAngleRulesFd;
-}
-
-long GraphicsEnv::getAngleRulesOffset() {
- return mAngleRulesOffset;
-}
-
-long GraphicsEnv::getAngleRulesLength() {
- return mAngleRulesLength;
+std::string& GraphicsEnv::getAngleAppName() {
+ return mAngleAppName;
}
const std::string& GraphicsEnv::getLayerPaths() {
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 4ec53f1..37c24ef 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -18,6 +18,7 @@
#define ANDROID_UI_GRAPHICS_ENV_H 1
#include <string>
+#include <vector>
struct android_namespace_t;
@@ -39,6 +40,8 @@
void setDriverPath(const std::string path);
android_namespace_t* getDriverNamespace();
+ bool shouldUseAngle(std::string appName);
+ bool shouldUseAngle();
// Set a search path for loading ANGLE libraries. The path is a list of
// directories separated by ':'. A directory can be contained in a zip file
// (libraries must be stored uncompressed and page aligned); such elements
@@ -47,12 +50,7 @@
void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn,
const int rulesFd, const long rulesOffset, const long rulesLength);
android_namespace_t* getAngleNamespace();
- const char* getAngleAppName();
- const char* getAngleAppPref();
- const char* getAngleDeveloperOptIn();
- int getAngleRulesFd();
- long getAngleRulesOffset();
- long getAngleRulesLength();
+ std::string& getAngleAppName();
void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
NativeLoaderNamespace* getAppNamespace();
@@ -65,14 +63,17 @@
const std::string& getDebugLayersGLES();
private:
+ void* loadLibrary(std::string name);
+ bool checkAngleRules(void* so);
+ void updateUseAngle();
+
GraphicsEnv() = default;
std::string mDriverPath;
std::string mAnglePath;
std::string mAngleAppName;
std::string mAngleDeveloperOptIn;
- int mAngleRulesFd;
- long mAngleRulesOffset;
- long mAngleRulesLength;
+ std::vector<char> mRulesBuffer;
+ bool mUseAngle;
std::string mDebugLayers;
std::string mDebugLayersGLES;
std::string mLayerPaths;
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 95b1038..1be55e6 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -59,7 +59,15 @@
if (err != NO_ERROR) {
return err;
}
- err = output->writeInt64(presentTime);
+ if (presentFence) {
+ err = output->writeBool(true);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->write(*presentFence);
+ } else {
+ err = output->writeBool(false);
+ }
if (err != NO_ERROR) {
return err;
}
@@ -71,10 +79,18 @@
if (err != NO_ERROR) {
return err;
}
- err = input->readInt64(&presentTime);
+ bool hasFence = false;
+ err = input->readBool(&hasFence);
if (err != NO_ERROR) {
return err;
}
+ if (hasFence) {
+ presentFence = new Fence();
+ err = input->read(*presentFence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
return input->readParcelableVector(&surfaceStats);
}
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 5c41c21..8acfa7a 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -21,6 +21,7 @@
#include <binder/Parcelable.h>
#include <binder/SafeInterface.h>
+#include <ui/Fence.h>
#include <utils/Timers.h>
#include <cstdint>
@@ -65,7 +66,7 @@
status_t readFromParcel(const Parcel* input) override;
nsecs_t latchTime = -1;
- nsecs_t presentTime = -1;
+ sp<Fence> presentFence = nullptr;
std::vector<SurfaceStats> surfaceStats;
};
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 86e9c23..60542bd 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -24,11 +24,15 @@
#include <memory>
+#include <android/native_window.h>
+
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
@@ -37,6 +41,7 @@
#include <input/InputTransport.h>
#include <input/Input.h>
+#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -44,6 +49,8 @@
namespace android {
namespace test {
+using Transaction = SurfaceComposerClient::Transaction;
+
sp<IInputFlinger> getInputFlinger() {
sp<IBinder> input(defaultServiceManager()->getService(
String16("inputflinger")));
@@ -58,9 +65,8 @@
class InputSurface {
public:
- InputSurface(const sp<SurfaceComposerClient>& scc, int width, int height) {
- mSurfaceControl = scc->createSurface(String8("Test Surface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
+ mSurfaceControl = sc;
InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
mServerChannel->setToken(new BBinder());
@@ -73,6 +79,31 @@
mInputConsumer = new InputConsumer(mClientChannel);
}
+ static std::unique_ptr<InputSurface> makeColorInputSurface(const sp<SurfaceComposerClient> &scc,
+ int width, int height) {
+ sp<SurfaceControl> surfaceControl =
+ scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ return std::make_unique<InputSurface>(surfaceControl, width, height);
+ }
+
+ static std::unique_ptr<InputSurface> makeBufferInputSurface(
+ const sp<SurfaceComposerClient> &scc, int width, int height) {
+ sp<SurfaceControl> surfaceControl =
+ scc->createSurface(String8("Test Buffer Surface"), width, height,
+ PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
+ return std::make_unique<InputSurface>(surfaceControl, width, height);
+ }
+
+ static std::unique_ptr<InputSurface> makeContainerInputSurface(
+ const sp<SurfaceComposerClient> &scc, int width, int height) {
+ sp<SurfaceControl> surfaceControl =
+ scc->createSurface(String8("Test Container Surface"), 0 /* bufHeight */,
+ 0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceContainer);
+ return std::make_unique<InputSurface>(surfaceControl, width, height);
+ }
+
InputEvent* consumeEvent() {
waitForEventAvailable();
@@ -180,6 +211,15 @@
void SetUp() {
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ DisplayInfo info;
+ auto display = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ SurfaceComposerClient::getDisplayInfo(display, &info);
+
+ // After a new buffer is queued, SurfaceFlinger is notified and will
+ // latch the new buffer on next vsync. Let's heuristically wait for 3
+ // vsyncs.
+ mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
}
void TearDown() {
@@ -187,10 +227,23 @@
}
std::unique_ptr<InputSurface> makeSurface(int width, int height) {
- return std::make_unique<InputSurface>(mComposerClient, width, height);
+ return InputSurface::makeColorInputSurface(mComposerClient, width, height);
+ }
+
+ void postBuffer(const sp<SurfaceControl> &layer) {
+ // wait for previous transactions (such as setSize) to complete
+ Transaction().apply(true);
+ ANativeWindow_Buffer buffer = {};
+ EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
+ ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
+ // Request an empty transaction to get applied synchronously to ensure the buffer is
+ // latched.
+ Transaction().apply(true);
+ usleep(mBufferPostDelay);
}
sp<SurfaceComposerClient> mComposerClient;
+ int32_t mBufferPostDelay;
};
void injectTap(int x, int y) {
@@ -267,5 +320,124 @@
surface->expectTap(1, 1);
}
+// Surface Insets are set to offset the client content and draw a border around the client surface
+// (such as shadows in dialogs). Inputs sent to the client are offset such that 0,0 is the start
+// of the client content.
+TEST_F(InputSurfacesTest, input_respects_surface_insets) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ bgSurface->showAt(100, 100);
+
+ fgSurface->mInputInfo.surfaceInset = 5;
+ fgSurface->showAt(100, 100);
+
+ injectTap(106, 106);
+ fgSurface->expectTap(1, 1);
+
+ injectTap(101, 101);
+ bgSurface->expectTap(1, 1);
+}
+
+// Ensure a surface whose insets are cropped, handles the touch offset correctly. ref:b/120413463
+TEST_F(InputSurfacesTest, input_respects_cropped_surface_insets) {
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100);
+ parentSurface->showAt(100, 100);
+
+ childSurface->mInputInfo.surfaceInset = 10;
+ childSurface->showAt(100, 100);
+
+ childSurface->doTransaction([&](auto &t, auto &sc) {
+ t.setPosition(sc, -5, -5);
+ t.reparent(sc, parentSurface->mSurfaceControl->getHandle());
+ });
+
+ injectTap(106, 106);
+ childSurface->expectTap(1, 1);
+
+ injectTap(101, 101);
+ parentSurface->expectTap(1, 1);
+}
+
+// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
+TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction([](auto &t, auto &sc) {
+ Region transparentRegion(Rect(0, 0, 10, 10));
+ t.setTransparentRegionHint(sc, transparentRegion);
+ });
+ surface->showAt(100, 100);
+ injectTap(101, 101);
+ surface->expectTap(1, 1);
+}
+
+// Ensure we send the input to the right surface when the surface visibility changes due to the
+// first buffer being submitted. ref: b/120839715
+TEST_F(InputSurfacesTest, input_respects_buffer_layer_buffer) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bufferSurface =
+ InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
+
+ bgSurface->showAt(10, 10);
+ bufferSurface->showAt(10, 10);
+
+ injectTap(11, 11);
+ bgSurface->expectTap(1, 1);
+
+ postBuffer(bufferSurface->mSurfaceControl);
+ injectTap(11, 11);
+ bufferSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_buffer_layer_alpha) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bufferSurface =
+ InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
+ postBuffer(bufferSurface->mSurfaceControl);
+
+ bgSurface->showAt(10, 10);
+ bufferSurface->showAt(10, 10);
+
+ injectTap(11, 11);
+ bufferSurface->expectTap(1, 1);
+
+ bufferSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
+
+ injectTap(11, 11);
+ bgSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_color_layer_alpha) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+
+ bgSurface->showAt(10, 10);
+ fgSurface->showAt(10, 10);
+
+ injectTap(11, 11);
+ fgSurface->expectTap(1, 1);
+
+ fgSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
+
+ injectTap(11, 11);
+ bgSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) {
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> containerSurface =
+ InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
+
+ bgSurface->showAt(10, 10);
+ containerSurface->showAt(10, 10);
+
+ injectTap(11, 11);
+ containerSurface->expectTap(1, 1);
+
+ containerSurface->doTransaction([](auto &t, auto &sc) { t.hide(sc); });
+
+ injectTap(11, 11);
+ bgSurface->expectTap(1, 1);
+}
}
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 53b0e4c..51cf188 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -648,27 +648,89 @@
return success;
}
-status_t GLESRenderEngine::drawLayers(const DisplaySettings& /*settings*/,
- const std::vector<LayerSettings>& /*layers*/,
- ANativeWindowBuffer* const /*buffer*/,
- base::unique_fd* /*displayFence*/) const {
+status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
+ const std::vector<LayerSettings>& layers,
+ ANativeWindowBuffer* const buffer,
+ base::unique_fd* drawFence) {
+ if (layers.empty()) {
+ ALOGV("Drawing empty layer stack");
+ return NO_ERROR;
+ }
+
+ BindNativeBufferAsFramebuffer fbo(*this, buffer);
+
+ if (fbo.getStatus() != NO_ERROR) {
+ ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+ buffer->handle);
+ checkErrors();
+ return fbo.getStatus();
+ }
+
+ setViewportAndProjection(display.physicalDisplay, display.clip);
+
+ setOutputDataSpace(display.outputDataspace);
+ setDisplayMaxLuminance(display.maxLuminance);
+
+ mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
+
+ Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
+ for (auto layer : layers) {
+ // for now, assume that all pixel sources are solid colors.
+ // TODO(alecmouri): support buffer sources
+ if (layer.source.buffer.buffer != nullptr) {
+ continue;
+ }
+
+ setColorTransform(display.colorTransform * layer.colorTransform);
+
+ mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
+
+ FloatRect bounds = layer.geometry.boundaries;
+ Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+ position[0] = vec2(bounds.left, bounds.top);
+ position[1] = vec2(bounds.left, bounds.bottom);
+ position[2] = vec2(bounds.right, bounds.bottom);
+ position[3] = vec2(bounds.right, bounds.top);
+
+ half3 solidColor = layer.source.solidColor;
+ half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
+ setupLayerBlending(/*premultipliedAlpha=*/true, /*opaque=*/false, /*disableTexture=*/true,
+ color, /*cornerRadius=*/0.0);
+ setSourceDataSpace(layer.sourceDataspace);
+
+ drawMesh(mesh);
+ }
+
+ *drawFence = flush();
+ // If flush failed or we don't support native fences, we need to force the
+ // gl command stream to be executed.
+ if (drawFence->get() < 0) {
+ bool success = finish();
+ if (!success) {
+ ALOGE("Failed to flush RenderEngine commands");
+ checkErrors();
+ // Chances are, something illegal happened (either the caller passed
+ // us bad parameters, or we messed up our shader generation).
+ return INVALID_OPERATION;
+ }
+ }
+
+ checkErrors();
return NO_ERROR;
}
void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
ui::Transform::orientation_flags rotation) {
- int32_t l = sourceCrop.left;
- int32_t r = sourceCrop.right;
- int32_t b = sourceCrop.bottom;
- int32_t t = sourceCrop.top;
- std::swap(t, b);
- mat4 m = mat4::ortho(l, r, b, t, 0, 1);
+ setViewportAndProjection(Rect(vpw, vph), sourceCrop);
+
+ if (rotation == ui::Transform::ROT_0) {
+ return;
+ }
// Apply custom rotation to the projection.
float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
+ mat4 m = mState.projectionMatrix;
switch (rotation) {
- case ui::Transform::ROT_0:
- break;
case ui::Transform::ROT_90:
m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
break;
@@ -681,11 +743,18 @@
default:
break;
}
-
- glViewport(0, 0, vpw, vph);
mState.projectionMatrix = m;
- mVpWidth = vpw;
- mVpHeight = vph;
+}
+
+void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
+ mVpWidth = viewport.getWidth();
+ mVpHeight = viewport.getHeight();
+
+ // We pass the the top left corner instead of the bottom left corner,
+ // because since we're rendering off-screen first.
+ glViewport(viewport.left, viewport.top, mVpWidth, mVpHeight);
+
+ mState.projectionMatrix = mat4::ortho(clip.left, clip.right, clip.top, clip.bottom, 0, 1);
}
void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 07e5585..b6fff33 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -72,9 +72,8 @@
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
- status_t drawLayers(const DisplaySettings& settings, const std::vector<LayerSettings>& layers,
- ANativeWindowBuffer* const buffer,
- base::unique_fd* displayFence) const override;
+ status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
+ ANativeWindowBuffer* buffer, base::unique_fd* drawFence) override;
// internal to RenderEngine
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
@@ -125,6 +124,9 @@
// with PQ or HLG transfer function.
bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
bool needsXYZTransformMatrix() const;
+ // Defines the viewport, and sets the projection matrix to the projection
+ // defined by the clip.
+ void setViewportAndProjection(Rect viewport, Rect clip);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index aa4e319..0c92353 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -41,7 +41,7 @@
mat4 globalTransform = mat4();
// Maximum luminance pulled from the display's HDR capabilities.
- float maxLuminence = 1.0f;
+ float maxLuminance = 1.0f;
// Output dataspace that will be populated if wide color gamut is used, or
// DataSpace::UNKNOWN otherwise.
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 38dee40..93abf5c 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -85,7 +85,11 @@
half alpha = half(0.0);
// Color space describing how the source pixels should be interpreted.
- ui::Dataspace sourceDataspace = ui::Dataspace::UNKNOWN;
+ ui::Dataspace sourceDataspace;
+
+ // Additional layer-specific color transform to be applied before the global
+ // transform.
+ mat4 colorTransform;
};
} // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 5e88159..20dd996 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -161,12 +161,12 @@
// 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
+ // @param display 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
+ // @param drawFence 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.
@@ -174,10 +174,9 @@
// 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,
+ virtual status_t drawLayers(const DisplaySettings& display,
const std::vector<LayerSettings>& layers,
- ANativeWindowBuffer* const buffer,
- base::unique_fd* displayFence) const = 0;
+ ANativeWindowBuffer* buffer, base::unique_fd* drawFence) = 0;
// TODO(alecmouri): Expose something like bindTexImage() so that devices
// that don't support native sync fences can get rid of code duplicated
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 051b8b6..9b483ef 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -31,6 +31,7 @@
"libgui",
"liblog",
"libnativewindow",
+ "libsync",
"libui",
"libutils",
],
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 345c7ea..a0542dd 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -17,36 +17,430 @@
#include <gtest/gtest.h>
#include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
#include <ui/PixelFormat.h>
+constexpr int DEFAULT_DISPLAY_WIDTH = 128;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 256;
+constexpr int DEFAULT_DISPLAY_OFFSET = 64;
+
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);
+struct RenderEngineTest : public ::testing::Test {
+ sp<GraphicBuffer> allocateDefaultBuffer() {
+ return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ "output");
}
- status_t drawEmptyLayers() {
+ RenderEngineTest() { mBuffer = allocateDefaultBuffer(); }
+
+ void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a,
+ uint8_t tolerance = 0) {
+ uint8_t* pixels;
+ mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+
+ auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
+ uint8_t tmp = a >= b ? a - b : b - a;
+ return tmp <= tolerance;
+ };
+ int32_t maxFails = 10;
+ int32_t fails = 0;
+ for (int32_t j = 0; j < region.getHeight(); j++) {
+ const uint8_t* src =
+ pixels + (mBuffer->getStride() * (region.top + j) + region.left) * 4;
+ for (int32_t i = 0; i < region.getWidth(); i++) {
+ const uint8_t expected[4] = {r, g, b, a};
+ bool equal = std::equal(src, src + 4, expected, colorCompare);
+ EXPECT_TRUE(equal)
+ << "pixel @ (" << region.left + i << ", " << region.top + j << "): "
+ << "expected (" << static_cast<uint32_t>(r) << ", "
+ << static_cast<uint32_t>(g) << ", " << static_cast<uint32_t>(b) << ", "
+ << static_cast<uint32_t>(a) << "), "
+ << "got (" << static_cast<uint32_t>(src[0]) << ", "
+ << static_cast<uint32_t>(src[1]) << ", " << static_cast<uint32_t>(src[2])
+ << ", " << static_cast<uint32_t>(src[3]) << ")";
+ src += 4;
+ if (!equal && ++fails >= maxFails) {
+ break;
+ }
+ }
+ if (fails >= maxFails) {
+ break;
+ }
+ }
+ mBuffer->unlock();
+ }
+
+ static Rect fullscreenRect() { return Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT); }
+
+ static Rect offsetRect() {
+ return Rect(DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT);
+ }
+
+ static Rect offsetRectAtZero() {
+ return Rect(DEFAULT_DISPLAY_WIDTH - DEFAULT_DISPLAY_OFFSET,
+ DEFAULT_DISPLAY_HEIGHT - DEFAULT_DISPLAY_OFFSET);
+ }
+
+ static void invokeDraw(renderengine::DisplaySettings settings,
+ std::vector<renderengine::LayerSettings> layers,
+ sp<GraphicBuffer> buffer) {
+ base::unique_fd fence;
+ status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), &fence);
+
+ int fd = fence.release();
+ if (fd >= 0) {
+ sync_wait(fd, -1);
+ close(fd);
+ }
+
+ ASSERT_EQ(NO_ERROR, status);
+ }
+
+ static void 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);
+ invokeDraw(settings, layers, buffer);
}
-private:
- std::unique_ptr<renderengine::RenderEngine> mRE;
+ template <typename SourceVariant>
+ void fillBuffer(half r, half g, half b, half a);
+
+ template <typename SourceVariant>
+ void fillRedBuffer();
+
+ template <typename SourceVariant>
+ void fillGreenBuffer();
+
+ template <typename SourceVariant>
+ void fillBlueBuffer();
+
+ template <typename SourceVariant>
+ void fillRedTransparentBuffer();
+
+ template <typename SourceVariant>
+ void fillRedOffsetBuffer();
+
+ template <typename SourceVariant>
+ void fillBufferPhysicalOffset();
+
+ template <typename SourceVariant>
+ void fillBufferCheckers(mat4 transform);
+
+ template <typename SourceVariant>
+ void fillBufferCheckersRotate0();
+
+ template <typename SourceVariant>
+ void fillBufferCheckersRotate90();
+
+ template <typename SourceVariant>
+ void fillBufferCheckersRotate180();
+
+ template <typename SourceVariant>
+ void fillBufferCheckersRotate270();
+
+ template <typename SourceVariant>
+ void fillBufferLayerTransform();
+
+ template <typename SourceVariant>
+ void fillBufferColorTransform();
+
+ // Dumb hack to get aroud the fact that tear-down for renderengine isn't
+ // well defined right now, so we can't create multiple instances
+ static std::unique_ptr<renderengine::RenderEngine> sRE;
+
+ sp<GraphicBuffer> mBuffer;
};
-TEST_F(RenderEngineTest, drawLayers_noLayersToDraw_works) {
- status_t result = drawEmptyLayers();
- ASSERT_EQ(NO_ERROR, result);
+std::unique_ptr<renderengine::RenderEngine> RenderEngineTest::sRE =
+ renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), 0);
+
+struct ColorSourceVariant {
+ static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b) {
+ layer.source.solidColor = half3(r, g, b);
+ }
+};
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBuffer(half r, half g, half b, half a) {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ layer.geometry.boundaries = fullscreenRect().toFloatRect();
+ SourceVariant::fillColor(layer, r, g, b);
+ layer.alpha = a;
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillRedBuffer() {
+ fillBuffer<SourceVariant>(1.0f, 0.0f, 0.0f, 1.0f);
+ expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillGreenBuffer() {
+ fillBuffer<SourceVariant>(0.0f, 1.0f, 0.0f, 1.0f);
+ expectBufferColor(fullscreenRect(), 0, 255, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBlueBuffer() {
+ fillBuffer<SourceVariant>(0.0f, 0.0f, 1.0f, 1.0f);
+ expectBufferColor(fullscreenRect(), 0, 0, 255, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillRedTransparentBuffer() {
+ fillBuffer<SourceVariant>(1.0f, 0.0f, 0.0f, .2f);
+ expectBufferColor(fullscreenRect(), 51, 0, 0, 51);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillRedOffsetBuffer() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = offsetRect();
+ settings.clip = offsetRectAtZero();
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ layer.geometry.boundaries = offsetRectAtZero().toFloatRect();
+ SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f);
+ layer.alpha = 1.0f;
+
+ layers.push_back(layer);
+ invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferPhysicalOffset() {
+ fillRedOffsetBuffer<SourceVariant>();
+
+ expectBufferColor(Rect(DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT),
+ 255, 0, 0, 255);
+ Rect offsetRegionLeft(DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_HEIGHT);
+ Rect offsetRegionTop(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_OFFSET);
+
+ expectBufferColor(offsetRegionLeft, 0, 0, 0, 0);
+ expectBufferColor(offsetRegionTop, 0, 0, 0, 0);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckers(mat4 transform) {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ // Here logical space is 2x2
+ settings.clip = Rect(2, 2);
+ settings.globalTransform = transform;
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layerOne;
+ Rect rectOne(0, 0, 1, 1);
+ layerOne.geometry.boundaries = rectOne.toFloatRect();
+ SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f);
+ layerOne.alpha = 1.0f;
+
+ renderengine::LayerSettings layerTwo;
+ Rect rectTwo(0, 1, 1, 2);
+ layerTwo.geometry.boundaries = rectTwo.toFloatRect();
+ SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f);
+ layerTwo.alpha = 1.0f;
+
+ renderengine::LayerSettings layerThree;
+ Rect rectThree(1, 0, 2, 1);
+ layerThree.geometry.boundaries = rectThree.toFloatRect();
+ SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f);
+ layerThree.alpha = 1.0f;
+
+ layers.push_back(layerOne);
+ layers.push_back(layerTwo);
+ layers.push_back(layerThree);
+
+ invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckersRotate0() {
+ fillBufferCheckers<SourceVariant>(mat4());
+ expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0,
+ 255);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT / 2),
+ 0, 0, 255, 255);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 0, 0, 0, 0);
+ expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
+ DEFAULT_DISPLAY_HEIGHT),
+ 0, 255, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckersRotate90() {
+ mat4 matrix = mat4(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1);
+ fillBufferCheckers<SourceVariant>(matrix);
+ expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 255, 0,
+ 255);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT / 2),
+ 255, 0, 0, 255);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 0, 0, 255, 255);
+ expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
+ DEFAULT_DISPLAY_HEIGHT),
+ 0, 0, 0, 0);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckersRotate180() {
+ mat4 matrix = mat4(-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 2, 2, 0, 1);
+ fillBufferCheckers<SourceVariant>(matrix);
+ expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 0,
+ 0);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT / 2),
+ 0, 255, 0, 255);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 255, 0, 0, 255);
+ expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
+ DEFAULT_DISPLAY_HEIGHT),
+ 0, 0, 255, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckersRotate270() {
+ mat4 matrix = mat4(0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1);
+ fillBufferCheckers<SourceVariant>(matrix);
+ expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 255,
+ 255);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT / 2),
+ 0, 0, 0, 0);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 0, 255, 0, 255);
+ expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
+ DEFAULT_DISPLAY_HEIGHT),
+ 255, 0, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferLayerTransform() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ // Here logical space is 2x2
+ settings.clip = Rect(2, 2);
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+ // Translate one pixel diagonally
+ layer.geometry.positionTransform = mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1);
+ layer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
+ layer.alpha = 1.0f;
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers, mBuffer);
+
+ expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 0, 0);
+ expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 255, 0, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransform() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = Rect(1, 1);
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+ layer.source.solidColor = half3(0.5f, 0.25f, 0.125f);
+ layer.alpha = 1.0f;
+
+ // construct a fake color matrix
+ // annihilate green and blue channels
+ settings.colorTransform = mat4::scale(vec4(1, 0, 0, 1));
+ // set red channel to red + green
+ layer.colorTransform = mat4(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers, mBuffer);
+
+ expectBufferColor(fullscreenRect(), 191, 0, 0, 255);
+}
+
+TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
+ drawEmptyLayers();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
+ fillRedBuffer<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
+ fillGreenBuffer<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
+ fillBlueBuffer<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
+ fillRedTransparentBuffer<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
+ fillBufferPhysicalOffset<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
+ fillBufferCheckersRotate0<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
+ fillBufferCheckersRotate90<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
+ fillBufferCheckersRotate180<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
+ fillBufferCheckersRotate270<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
+ fillBufferLayerTransform<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
+ fillBufferLayerTransform<ColorSourceVariant>();
}
} // namespace android
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 226b6ee..0582e1a 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -169,6 +169,13 @@
buffer_state_ = &metadata_header->buffer_state;
fence_state_ = &metadata_header->fence_state;
active_clients_bit_mask_ = &metadata_header->active_clients_bit_mask;
+ // The C++ standard recommends (but does not require) that lock-free atomic operations are
+ // also address-free, that is, suitable for communication between processes using shared
+ // memory.
+ LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(buffer_state_) ||
+ !std::atomic_is_lock_free(fence_state_) ||
+ !std::atomic_is_lock_free(active_clients_bit_mask_),
+ "Atomic variables in ashmen are not lock free.");
// Import the buffer: We only need to hold on the native_handle_t here so that
// GraphicBuffer instance can be created in future.
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 6cb6541..1359f4c 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -1,7 +1,8 @@
#include <gtest/gtest.h>
#include <poll.h>
-#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/bufferhub_rpc.h>
+#include <private/dvr/consumer_buffer.h>
+#include <private/dvr/producer_buffer.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <ui/BufferHubBuffer.h>
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
deleted file mode 100644
index 1daeed9..0000000
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_HUB_CLIENT_H_
-#define ANDROID_DVR_BUFFER_HUB_CLIENT_H_
-
-// TODO(b/116855254): This header is completely deprecated and replaced by
-// consumer_buffer.h and producer_buffer.h. Remove this file once all references
-// to it has been removed.
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/producer_buffer.h>
-
-#endif // ANDROID_DVR_BUFFER_HUB_CLIENT_H_
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index def7c6b..53ab2b2 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -13,10 +13,11 @@
// in these headers and their dependencies.
#include <pdx/client.h>
#include <pdx/status.h>
-#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_parcelable.h>
#include <private/dvr/bufferhub_rpc.h>
+#include <private/dvr/consumer_buffer.h>
#include <private/dvr/epoll_file_descriptor.h>
+#include <private/dvr/producer_buffer.h>
#if defined(__clang__)
#pragma clang diagnostic pop
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index fd6ca43..159d6dc 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -1,8 +1,9 @@
#include <base/logging.h>
#include <binder/Parcel.h>
#include <dvr/dvr_api.h>
-#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/consumer_buffer.h>
+#include <private/dvr/producer_buffer.h>
#include <gtest/gtest.h>
#include <poll.h>
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index 974c231..fdeeb70 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -1,7 +1,6 @@
#include "include/private/dvr/display_manager_client.h"
#include <pdx/default_transport/client_channel_factory.h>
-#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
#include <private/dvr/display_protocol.h>
#include <utils/Log.h>
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index caf3182..f8f5b3d 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -5,7 +5,6 @@
#include <hardware/hwcomposer.h>
#include <pdx/client.h>
#include <pdx/file_handle.h>
-#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
#include <private/dvr/display_protocol.h>
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index baf1f2f..c11706f 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -2,7 +2,8 @@
#include <android/hardware_buffer.h>
#include <dvr/dvr_shared_buffers.h>
-#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/consumer_buffer.h>
+#include <private/dvr/producer_buffer.h>
#include <ui/GraphicBuffer.h>
#include "dvr_internal.h"
diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp
index 852f9a4..fe91b14 100644
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ b/libs/vr/libdvr/dvr_display_manager.cpp
@@ -2,8 +2,8 @@
#include <dvr/dvr_buffer.h>
#include <pdx/rpc/variant.h>
-#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/consumer_buffer.h>
#include <private/dvr/display_client.h>
#include <private/dvr/display_manager_client.h>
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index 1a200aa..9e35a39 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -2,7 +2,7 @@
#define ANDROID_DVR_SERVICES_DISPLAYD_ACQUIRED_BUFFER_H_
#include <pdx/file_handle.h>
-#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/consumer_buffer.h>
#include <memory>
@@ -43,7 +43,7 @@
// Accessors for the underlying BufferConsumer, the acquire fence, and the
// use-case specific sequence value from the acquisition (see
- // private/dvr/buffer_hub_client.h).
+ // private/dvr/consumer_buffer.h).
std::shared_ptr<BufferConsumer> buffer() const { return buffer_; }
int acquire_fence() const { return acquire_fence_.Get(); }
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 6fad58e..e0f2edd 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -4,7 +4,6 @@
#include <dvr/dvr_api.h>
#include <pdx/service.h>
#include <pdx/status.h>
-#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/display_protocol.h>
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 94a2337..6c25b3e 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -22,7 +22,6 @@
#include <dvr/dvr_vsync.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/variant.h>
-#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/shared_buffer_helpers.h>
#include <private/dvr/vsync_service.h>
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
index 710d75a..c72f75e 100644
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ b/libs/vr/libvrsensor/pose_client.cpp
@@ -8,8 +8,8 @@
#include <pdx/client.h>
#include <pdx/default_transport/client_channel_factory.h>
#include <pdx/file_handle.h>
-#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/consumer_buffer.h>
#include <private/dvr/display_client.h>
#include <private/dvr/pose-ipc.h>
#include <private/dvr/shared_buffer_helpers.h>
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index f5cf3dc..8a409ae 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -17,7 +17,7 @@
//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "Loader.h"
+#include <EGL/Loader.h>
#include <string>
@@ -38,38 +38,6 @@
#include "egldefs.h"
#include <EGL/eglext_angle.h>
-extern "C" {
- android_namespace_t* android_get_exported_namespace(const char*);
-
- typedef enum ANGLEPreference {
- ANGLE_PREFER_DEFAULT = 0,
- ANGLE_PREFER_NATIVE = 1,
- ANGLE_PREFER_ANGLE = 2,
- } ANGLEPreference;
-
- // TODO(ianelliott@): Get the following from an ANGLE header:
- // Version-1 API:
- typedef bool (*fpANGLEGetUtilityAPI)(unsigned int* versionToUse);
- typedef bool (*fpAndroidUseANGLEForApplication)(int fd, long offset, long length,
- const char* appName, const char* deviceMfr,
- const char* deviceModel);
- // Version-2 API:
- typedef bool (*fpANGLEGetFeatureSupportUtilAPIVersion)(unsigned int* versionToUse);
- typedef bool (*fpANGLEAndroidParseRulesString)(const char *rulesString,
- void** rulesHandle, int* rulesVersion);
- typedef bool (*fpANGLEGetSystemInfo)(void** handle);
- typedef bool (*fpANGLEAddDeviceInfoToSystemInfo)(const char* deviceMfr,
- const char* deviceModel,
- void* handle);
- typedef bool (*fpANGLEShouldBeUsedForApplication)(void* rules_handle,
- int rules_version,
- void* system_info_handle,
- const char *appName);
- typedef bool (*fpANGLEFreeRulesHandle)(void* handle);
- typedef bool (*fpANGLEFreeSystemInfoHandle)(void* handle);
-
-}
-
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -255,6 +223,13 @@
setEmulatorGlesValue();
+ // Check if we should use ANGLE early, so loading each driver doesn't require repeated queries.
+ if (android::GraphicsEnv::getInstance().shouldUseAngle()) {
+ cnx->shouldUseAngle = true;
+ } else {
+ cnx->shouldUseAngle = false;
+ }
+
dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2);
if (dso) {
hnd = new driver_t(dso);
@@ -289,11 +264,7 @@
delete hnd;
cnx->dso = nullptr;
- if (cnx->featureSo) {
- dlclose(cnx->featureSo);
- cnx->featureSo = nullptr;
- }
-
+ cnx->shouldUseAngle = false;
cnx->angleDecided = false;
cnx->useAngle = false;
@@ -530,173 +501,32 @@
return nullptr;
}
-static ANGLEPreference getAngleDevOption(const char* devOption) {
- if (devOption == nullptr)
- return ANGLE_PREFER_DEFAULT;
-
- if (strcmp(devOption, "angle") == 0) {
- return ANGLE_PREFER_ANGLE;
- } else if (strcmp(devOption, "native") == 0) {
- return ANGLE_PREFER_NATIVE;
- }
- return ANGLE_PREFER_DEFAULT;
-}
-
-static bool check_angle_rules(void* so, const char* app_name) {
- bool use_angle = false;
- const int rules_fd = android::GraphicsEnv::getInstance().getAngleRulesFd();
- const long rules_offset = android::GraphicsEnv::getInstance().getAngleRulesOffset();
- const long rules_length = android::GraphicsEnv::getInstance().getAngleRulesLength();
-
- std::string app_name_str = app_name ? app_name : "";
- char manufacturer[PROPERTY_VALUE_MAX];
- char model[PROPERTY_VALUE_MAX];
- property_get("ro.product.manufacturer", manufacturer, "UNSET");
- property_get("ro.product.model", model, "UNSET");
-
- fpANGLEGetFeatureSupportUtilAPIVersion ANGLEGetFeatureSupportUtilAPIVersion =
- (fpANGLEGetFeatureSupportUtilAPIVersion)dlsym(so, "ANGLEGetFeatureSupportUtilAPIVersion");
-
- if (ANGLEGetFeatureSupportUtilAPIVersion) {
-
- // Negotiate the interface version by requesting most recent known to the platform
- unsigned int versionToUse = 2;
- if ((ANGLEGetFeatureSupportUtilAPIVersion)(&versionToUse)) {
-
- // Add and remove versions below as needed
- switch(versionToUse) {
- case 2: {
- ALOGV("Using version 2 of ANGLE feature-support library");
- void* rules_handle = nullptr;
- int rules_version = 0;
- void* system_info_handle = nullptr;
-
- // Get the symbols for the feature-support-utility library:
-#define GET_SYMBOL(symbol) \
- fp##symbol symbol = (fp##symbol)dlsym(so, #symbol); \
- if (!symbol) { \
- ALOGW("Cannot find "#symbol" in ANGLE feature-support library"); \
- break; \
- }
- GET_SYMBOL(ANGLEAndroidParseRulesString);
- GET_SYMBOL(ANGLEGetSystemInfo);
- GET_SYMBOL(ANGLEAddDeviceInfoToSystemInfo);
- GET_SYMBOL(ANGLEShouldBeUsedForApplication);
- GET_SYMBOL(ANGLEFreeRulesHandle);
- GET_SYMBOL(ANGLEFreeSystemInfoHandle);
-
- // Read the contents of the file into a string:
- off_t fileSize = rules_length;
- off_t startOfContent = rules_offset;
- lseek(rules_fd, startOfContent, SEEK_SET);
- char *buffer = new char[fileSize + 1];
- ssize_t numBytesRead = read(rules_fd, buffer, fileSize);
- if (numBytesRead < 0) {
- ALOGW("Cannot read rules file");
- break;
- }
- if (numBytesRead == 0) {
- ALOGW("Empty rules file");
- break;
- }
- buffer[numBytesRead] = '\0';
- std::string rule_file_contents = std::string(buffer);
- delete[] buffer;
-
- // Parse the rules, obtain the SystemInfo, and evaluate the
- // application against the rules:
- if (!(ANGLEAndroidParseRulesString)(rule_file_contents.c_str(),
- &rules_handle, &rules_version)) {
- ALOGW("ANGLE feature-support library cannot parse rules file");
- break;
- }
- if (!(ANGLEGetSystemInfo)(&system_info_handle)) {
- ALOGW("ANGLE feature-support library cannot obtain SystemInfo");
- break;
- }
- if (!(ANGLEAddDeviceInfoToSystemInfo)(manufacturer, model, system_info_handle)) {
- ALOGW("ANGLE feature-support library cannot add device info to SystemInfo");
- break;
- }
- use_angle = (ANGLEShouldBeUsedForApplication)(rules_handle, rules_version,
- system_info_handle, app_name_str.c_str());
- (ANGLEFreeRulesHandle)(rules_handle);
- (ANGLEFreeSystemInfoHandle)(system_info_handle);
- }
- break;
- default:
- ALOGW("Cannot find supported version of ANGLE feature-support library, found version %u", versionToUse);
- }
- } else {
- ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, requested version %u", versionToUse);
- }
- } else {
- ALOGW("Cannot find ANGLEGetFeatureSupportUtilAPIVersion function");
- }
-
- ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
- return use_angle;
-}
-
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)
+ if (strcmp(kind, "EGL") != 0 && strcmp(kind, "GLESv2") != 0 && strcmp(kind, "GLESv1_CM") != 0) {
return nullptr;
-
- std::string name;
- char prop[PROPERTY_VALUE_MAX];
-
- const char* app_name = android::GraphicsEnv::getInstance().getAngleAppName();
- const char* developer_opt_in = android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
-
- // Determine whether or not to use ANGLE:
- ANGLEPreference developer_option = getAngleDevOption(developer_opt_in);
- bool use_angle = (developer_option == ANGLE_PREFER_ANGLE);
-
- if (use_angle) {
- ALOGV("User set \"Developer Options\" to force the use of ANGLE");
- } else if (cnx->angleDecided) {
- use_angle = cnx->useAngle;
- } else if (developer_option == ANGLE_PREFER_NATIVE) {
- ALOGV("User set \"Developer Options\" to force the use of Native");
- use_angle = false;
- } else {
- // The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily
- // load ANGLE and call the updatable opt-in/out logic:
-
- // Check if ANGLE is enabled. Workaround for several bugs:
- // b/119305693 b/119322355 b/119305887
- // Something is not working correctly in the feature library
- property_get("debug.angle.enable", prop, "0");
- if (atoi(prop)) {
- cnx->featureSo = load_angle_from_namespace("feature_support", ns);
- }
- if (cnx->featureSo) {
- ALOGV("loaded ANGLE's opt-in/out logic from namespace");
- use_angle = check_angle_rules(cnx->featureSo, app_name);
- } else {
- // We weren't able to load and call the updateable opt-in/out logic.
- // If we can't load the library, there is no ANGLE available.
- use_angle = false;
- ALOGV("Could not load the ANGLE opt-in/out logic, cannot use ANGLE.");
- }
- cnx->angleDecided = true;
}
+
void* so = nullptr;
- if (use_angle) {
+
+ if ((cnx->shouldUseAngle) || android::GraphicsEnv::getInstance().shouldUseAngle()) {
so = load_angle_from_namespace(kind, ns);
+ cnx->shouldUseAngle = true;
+ } else {
+ cnx->shouldUseAngle = false;
}
if (so) {
- ALOGV("Loaded ANGLE %s library for %s (instead of native)",
- kind, app_name ? app_name : "nullptr");
- property_get("debug.hwui.renderer", prop, "UNSET");
- ALOGV("Skia's renderer set to %s", prop);
+ ALOGV("Loaded ANGLE %s library for '%s' (instead of native)", kind,
+ android::GraphicsEnv::getInstance().getAngleAppName().c_str());
cnx->useAngle = true;
- EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
-
char prop[PROPERTY_VALUE_MAX];
+
+ property_get("debug.hwui.renderer", prop, "UNSET");
+ ALOGV("Skia's renderer set to %s", prop);
+
+ EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
property_get("debug.angle.backend", prop, "0");
switch (atoi(prop)) {
case 1:
@@ -716,13 +546,14 @@
// Find and load vendor libEGL for ANGLE's GL back-end to use.
cnx->vendorEGL = load_system_driver("EGL");
}
- return so;
} else {
- ALOGV("Loaded native %s library for %s (instead of ANGLE)",
- kind, app_name ? app_name : "nullptr");
+ ALOGV("Loaded native %s library for '%s' (instead of ANGLE)", kind,
+ android::GraphicsEnv::getInstance().getAngleAppName().c_str());
+ cnx->useAngle = false;
}
+ cnx->angleDecided = true;
- return nullptr;
+ return so;
}
static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index cca0053..9e112cc 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -76,11 +76,11 @@
void* libGles1;
void* libGles2;
- bool angleDecided;
- bool useAngle;
+ bool shouldUseAngle; // Should we attempt to load ANGLE
+ bool angleDecided; // Have we tried to load ANGLE
+ bool useAngle; // Was ANGLE successfully loaded
EGLint angleBackend;
void* vendorEGL;
- void* featureSo;
};
// clang-format on
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index b0869fe..2663812 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -39,7 +39,8 @@
BufferHubIdGenerator::getInstance().getId());
if (node == nullptr || !node->IsValid()) {
ALOGE("%s: creating BufferNode failed.", __FUNCTION__);
- _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::ALLOCATION_FAILED);
+ _hidl_cb(/*status=*/BufferHubStatus::ALLOCATION_FAILED, /*bufferClient=*/nullptr,
+ /*bufferTraits=*/{});
return Void();
}
@@ -48,7 +49,13 @@
std::lock_guard<std::mutex> lock(mClientSetMutex);
mClientSet.emplace(client);
- _hidl_cb(/*bufferClient=*/client, /*status=*/BufferHubStatus::NO_ERROR);
+ BufferTraits bufferTraits = {/*bufferDesc=*/description,
+ /*bufferHandle=*/hidl_handle(node->buffer_handle()),
+ // TODO(b/116681016): return real data to client
+ /*bufferInfo=*/hidl_handle()};
+
+ _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
+ /*bufferTraits=*/bufferTraits);
return Void();
}
@@ -56,7 +63,8 @@
importBuffer_cb _hidl_cb) {
if (!tokenHandle.getNativeHandle() || tokenHandle->numFds != 0 || tokenHandle->numInts != 1) {
// nullptr handle or wrong format
- _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::INVALID_TOKEN);
+ _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+ /*bufferTraits=*/{});
return Void();
}
@@ -68,7 +76,8 @@
auto iter = mTokenMap.find(token);
if (iter == mTokenMap.end()) {
// Invalid token
- _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::INVALID_TOKEN);
+ _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+ /*bufferTraits=*/{});
return Void();
}
@@ -81,15 +90,37 @@
if (!originClient) {
// Should not happen since token should be removed if already gone
ALOGE("%s: original client %p gone!", __FUNCTION__, originClientWp.unsafe_get());
- _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::BUFFER_FREED);
+ _hidl_cb(/*status=*/BufferHubStatus::BUFFER_FREED, /*bufferClient=*/nullptr,
+ /*bufferTraits=*/{});
return Void();
}
sp<BufferClient> client = new BufferClient(*originClient);
+ uint32_t clientStateMask = client->getBufferNode()->AddNewActiveClientsBitToMask();
+ if (clientStateMask == 0U) {
+ // Reach max client count
+ ALOGE("%s: import failed, BufferNode#%u reached maximum clients.", __FUNCTION__,
+ client->getBufferNode()->id());
+ _hidl_cb(/*status=*/BufferHubStatus::MAX_CLIENT, /*bufferClient=*/nullptr,
+ /*bufferTraits=*/{});
+ return Void();
+ }
std::lock_guard<std::mutex> lock(mClientSetMutex);
mClientSet.emplace(client);
- _hidl_cb(/*bufferClient=*/client, /*status=*/BufferHubStatus::NO_ERROR);
+
+ std::shared_ptr<BufferNode> node = client->getBufferNode();
+
+ HardwareBufferDescription bufferDesc;
+ memcpy(&bufferDesc, &node->buffer_desc(), sizeof(HardwareBufferDescription));
+
+ BufferTraits bufferTraits = {/*bufferDesc=*/bufferDesc,
+ /*bufferHandle=*/hidl_handle(node->buffer_handle()),
+ // TODO(b/116681016): return real data to client
+ /*bufferInfo=*/hidl_handle()};
+
+ _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
+ /*bufferTraits=*/bufferTraits);
return Void();
}
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index cc87e15..da19a6f 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -2,6 +2,7 @@
#include <bufferhub/BufferHubService.h>
#include <bufferhub/BufferNode.h>
+#include <log/log.h>
#include <ui/GraphicBufferAllocator.h>
namespace android {
@@ -18,6 +19,13 @@
fence_state_ = new (&metadata_header->fence_state) std::atomic<uint32_t>(0);
active_clients_bit_mask_ =
new (&metadata_header->active_clients_bit_mask) std::atomic<uint32_t>(0);
+ // The C++ standard recommends (but does not require) that lock-free atomic operations are
+ // also address-free, that is, suitable for communication between processes using shared
+ // memory.
+ LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(buffer_state_) ||
+ !std::atomic_is_lock_free(fence_state_) ||
+ !std::atomic_is_lock_free(active_clients_bit_mask_),
+ "Atomic variables in ashmen are not lock free.");
}
// Allocates a new BufferNode.
diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h
index 7f5d3a6..66ed4bd 100644
--- a/services/bufferhub/include/bufferhub/BufferClient.h
+++ b/services/bufferhub/include/bufferhub/BufferClient.h
@@ -49,6 +49,9 @@
Return<BufferHubStatus> close() override;
Return<void> duplicate(duplicate_cb _hidl_cb) override;
+ // Non-binder functions
+ const std::shared_ptr<BufferNode>& getBufferNode() const { return mBufferNode; }
+
private:
BufferClient(wp<BufferHubService> service, const std::shared_ptr<BufferNode>& node)
: mService(service), mBufferNode(node) {}
diff --git a/services/bufferhub/tests/Android.bp b/services/bufferhub/tests/Android.bp
index e565374..8d29923 100644
--- a/services/bufferhub/tests/Android.bp
+++ b/services/bufferhub/tests/Android.bp
@@ -8,6 +8,8 @@
"-DLOG_TAG=\"BufferHubServer_test\"",
"-DTRACE=0",
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+ "-Wall",
+ "-Werror",
],
header_libs: [
"libdvr_headers",
diff --git a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
index 4eddfe0..fe01013 100644
--- a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
+++ b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
@@ -27,7 +27,7 @@
// resulting IDs should still keep incresing.
const size_t kTestSize = 10U;
uint32_t ids[kTestSize];
- for (int i = 0; i < kTestSize; ++i) {
+ for (size_t i = 0UL; i < kTestSize; ++i) {
ids[i] = mIdGenerator->getId();
EXPECT_NE(ids[i], BufferHubIdGenerator::kInvalidId);
if (i >= 1) {
diff --git a/services/bufferhub/tests/BufferNode_test.cpp b/services/bufferhub/tests/BufferNode_test.cpp
index dbf10e8..ccb1197 100644
--- a/services/bufferhub/tests/BufferNode_test.cpp
+++ b/services/bufferhub/tests/BufferNode_test.cpp
@@ -74,7 +74,7 @@
for (int i = 0; i < BufferHubDefs::kMaxNumberOfClients; ++i) {
new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
- EXPECT_NE(new_client_state_mask, 0);
+ EXPECT_NE(new_client_state_mask, 0U);
EXPECT_FALSE(new_client_state_mask & current_mask);
expected_mask = current_mask | new_client_state_mask;
current_mask = buffer_node->GetActiveClientsBitMask();
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index a025f31..f7802b9 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -73,6 +73,8 @@
static const char *WAKE_LOCK_ID = "KeyEvents";
static const char *DEVICE_PATH = "/dev/input";
+// v4l2 devices go directly into /dev
+static const char *VIDEO_DEVICE_PATH = "/dev";
static inline const char* toString(bool value) {
return value ? "true" : "false";
@@ -100,6 +102,13 @@
}
}
+/**
+ * Return true if name matches "v4l-touch*"
+ */
+static bool isV4lTouchNode(const char* name) {
+ return strstr(name, "v4l-touch") == name;
+}
+
// --- Global Functions ---
uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
@@ -206,18 +215,21 @@
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
- LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
+ LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
mINotifyFd = inotify_init();
- int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
- LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d",
- DEVICE_PATH, errno);
+ mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
+ LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
+ DEVICE_PATH, strerror(errno));
+ mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
+ LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
+ VIDEO_DEVICE_PATH, strerror(errno));
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.fd = mINotifyFd;
- result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
+ int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
int wakeFds[2];
@@ -1667,8 +1679,6 @@
status_t EventHub::readNotifyLocked() {
int res;
- char devname[PATH_MAX];
- char *filename;
char event_buf[512];
int event_size;
int event_pos = 0;
@@ -1682,21 +1692,27 @@
ALOGW("could not get event, %s\n", strerror(errno));
return -1;
}
- //printf("got %d bytes of event information\n", res);
-
- strcpy(devname, DEVICE_PATH);
- filename = devname + strlen(devname);
- *filename++ = '/';
while(res >= (int)sizeof(*event)) {
event = (struct inotify_event *)(event_buf + event_pos);
if(event->len) {
- strcpy(filename, event->name);
- if(event->mask & IN_CREATE) {
- openDeviceLocked(devname);
- } else {
- ALOGI("Removing device '%s' due to inotify event\n", devname);
- closeDeviceByPathLocked(devname);
+ if (event->wd == mInputWd) {
+ std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
+ if(event->mask & IN_CREATE) {
+ openDeviceLocked(filename.c_str());
+ } else {
+ ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
+ closeDeviceByPathLocked(filename.c_str());
+ }
+ }
+ else if (event->wd == mVideoWd) {
+ if (isV4lTouchNode(event->name)) {
+ std::string filename = StringPrintf("%s/%s", VIDEO_DEVICE_PATH, event->name);
+ ALOGV("Received an inotify event for a video device %s", filename.c_str());
+ }
+ }
+ else {
+ LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd);
}
}
event_size = sizeof(*event) + event->len;
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 23cceb4..b4eb370 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -74,14 +74,16 @@
int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
- float xPrecision, float yPrecision, nsecs_t downTime) :
+ float xPrecision, float yPrecision, nsecs_t downTime,
+ const std::vector<TouchVideoFrame>& videoFrames) :
NotifyArgs(sequenceNum), eventTime(eventTime), deviceId(deviceId), source(source),
displayId(displayId), policyFlags(policyFlags),
action(action), actionButton(actionButton),
flags(flags), metaState(metaState), buttonState(buttonState),
edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
pointerCount(pointerCount),
- xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
+ xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime),
+ videoFrames(videoFrames) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
this->pointerCoords[i].copyFrom(pointerCoords[i]);
@@ -95,7 +97,8 @@
metaState(other.metaState), buttonState(other.buttonState),
edgeFlags(other.edgeFlags),
deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
- xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
+ xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime),
+ videoFrames(other.videoFrames) {
for (uint32_t i = 0; i < pointerCount; i++) {
pointerProperties[i].copyFrom(other.pointerProperties[i]);
pointerCoords[i].copyFrom(other.pointerCoords[i]);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 5d0b894..73fcb11 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -254,7 +254,6 @@
}
-
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
@@ -2832,7 +2831,7 @@
AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- mXPrecision, mYPrecision, downTime);
+ mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&releaseArgs);
}
}
@@ -2841,7 +2840,7 @@
displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- mXPrecision, mYPrecision, downTime);
+ mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
if (buttonsPressed) {
@@ -2853,7 +2852,7 @@
mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS,
actionButton, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- mXPrecision, mYPrecision, downTime);
+ mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&pressArgs);
}
}
@@ -2867,7 +2866,7 @@
mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- mXPrecision, mYPrecision, downTime);
+ mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&hoverArgs);
}
@@ -2881,7 +2880,7 @@
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- mXPrecision, mYPrecision, downTime);
+ mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&scrollArgs);
}
}
@@ -3013,7 +3012,7 @@
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- 0, 0, 0);
+ 0, 0, 0, /* videoFrames */ {});
getListener()->notifyMotion(&scrollArgs);
}
@@ -3446,7 +3445,17 @@
} else {
viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
}
- return mConfig.getDisplayViewportByType(viewportTypeToUse);
+
+ std::optional<DisplayViewport> viewport =
+ mConfig.getDisplayViewportByType(viewportTypeToUse);
+ if (!viewport && viewportTypeToUse == ViewportType::VIEWPORT_EXTERNAL) {
+ ALOGW("Input device %s should be associated with external display, "
+ "fallback to internal one for the external viewport is not found.",
+ getDeviceName().c_str());
+ viewport = mConfig.getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ }
+
+ return viewport;
}
DisplayViewport newViewport;
@@ -5400,7 +5409,7 @@
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- 0, 0, mPointerGesture.downTime);
+ 0, 0, mPointerGesture.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -6319,13 +6328,13 @@
mPointerSimple.down = false;
// Send up.
- NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
+ NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
mSource, mViewport.displayId, policyFlags,
AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
- mPointerSimple.downTime);
+ mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -6339,7 +6348,7 @@
/* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
- mPointerSimple.downTime);
+ mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -6355,7 +6364,7 @@
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
- mPointerSimple.downTime);
+ mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -6366,7 +6375,7 @@
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
- mPointerSimple.downTime);
+ mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -6382,7 +6391,7 @@
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
- mPointerSimple.downTime);
+ mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -6394,7 +6403,7 @@
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
- mPointerSimple.downTime);
+ mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -6416,7 +6425,7 @@
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &pointerCoords,
mOrientedXPrecision, mOrientedYPrecision,
- mPointerSimple.downTime);
+ mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -6478,7 +6487,7 @@
source, mViewport.displayId, policyFlags,
action, actionButton, flags, metaState, buttonState, edgeFlags,
deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
- xPrecision, yPrecision, downTime);
+ xPrecision, yPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -7403,7 +7412,7 @@
AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- 0, 0, 0);
+ 0, 0, 0, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
diff --git a/services/inputflinger/include/EventHub.h b/services/inputflinger/include/EventHub.h
index 5db7c0a..1ddb978 100644
--- a/services/inputflinger/include/EventHub.h
+++ b/services/inputflinger/include/EventHub.h
@@ -452,6 +452,9 @@
int mWakeReadPipeFd;
int mWakeWritePipeFd;
+ int mInputWd;
+ int mVideoWd;
+
// Epoll FD list size hint.
static const int EPOLL_SIZE_HINT = 8;
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index f3a30ab..2442cc0 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -17,7 +17,10 @@
#ifndef _UI_INPUT_LISTENER_H
#define _UI_INPUT_LISTENER_H
+#include <vector>
+
#include <input/Input.h>
+#include <input/TouchVideoFrame.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
@@ -110,6 +113,7 @@
float xPrecision;
float yPrecision;
nsecs_t downTime;
+ std::vector<TouchVideoFrame> videoFrames;
inline NotifyMotionArgs() { }
@@ -119,7 +123,8 @@
int32_t metaState, int32_t buttonState,
int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
- float xPrecision, float yPrecision, nsecs_t downTime);
+ float xPrecision, float yPrecision, nsecs_t downTime,
+ const std::vector<TouchVideoFrame>& videoFrames);
NotifyMotionArgs(const NotifyMotionArgs& other);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 167a624..b5d2090 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -6284,4 +6284,34 @@
ASSERT_EQ(DISPLAY_ID, args.displayId);
}
+/**
+ * Expect fallback to internal viewport if device is external and external viewport is not present.
+ */
+TEST_F(MultiTouchInputMapperTest, Viewports_Fallback) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ mDevice->setExternal(true);
+ addMapperAndConfigure(mapper);
+
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources());
+
+ NotifyMotionArgs motionArgs;
+
+ // Expect the event to be sent to the internal viewport,
+ // because an external viewport is not present.
+ processPosition(mapper, 100, 100);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(ADISPLAY_ID_DEFAULT, motionArgs.displayId);
+
+ // Expect the event to be sent to the external viewport if it is present.
+ prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL);
+ processPosition(mapper, 100, 100);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 20e7f70..4a93be6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2736,7 +2736,7 @@
commitTransaction();
- if ((inputChanged || mVisibleRegionsDirty) && mInputFlinger) {
+ if (inputChanged || mVisibleRegionsDirty) {
updateInputWindows();
}
@@ -2746,6 +2746,10 @@
void SurfaceFlinger::updateInputWindows() {
ATRACE_CALL();
+ if (mInputFlinger == nullptr) {
+ return;
+ }
+
Vector<InputWindowInfo> inputHandles;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3015,6 +3019,11 @@
mVisibleRegionsDirty |= visibleRegions;
+ if (visibleRegions) {
+ // Update input window info if the layer receives its first buffer.
+ updateInputWindows();
+ }
+
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
@@ -3902,10 +3911,11 @@
setTransactionFlags(eTransactionNeeded);
}
-void SurfaceFlinger::onHandleDestroyed(const sp<Layer>& layer)
+void SurfaceFlinger::onHandleDestroyed(sp<Layer>& layer)
{
Mutex::Autolock lock(mStateLock);
markLayerPendingRemovalLocked(mStateLock, layer);
+ layer.clear();
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index d3f0ece..b1bfb3a 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -601,7 +601,7 @@
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
// resources associated to this layer.
- void onHandleDestroyed(const sp<Layer>& layer);
+ void onHandleDestroyed(sp<Layer>& layer);
// remove a layer from SurfaceFlinger immediately
status_t removeLayer(const sp<Layer>& layer);
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 389118a..a1a8692 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -151,18 +151,6 @@
while (mKeepRunning) {
mConditionVariable.wait(mMutex);
- // Present fence should fire almost immediately. If the fence has not signaled in 100ms,
- // there is a major problem and it will probably never fire.
- nsecs_t presentTime = -1;
- if (mPresentFence) {
- status_t status = mPresentFence->wait(100);
- if (status == NO_ERROR) {
- presentTime = mPresentFence->getSignalTime();
- } else {
- ALOGE("present fence has not signaled, err %d", status);
- }
- }
-
// We should never hit this case. The release fences from the previous frame should have
// signaled long before the current frame is presented.
for (const auto& fence : mPreviousReleaseFences) {
@@ -188,17 +176,11 @@
// If the transaction has been latched
if (transactionStats.latchTime >= 0) {
- // If the present time is < 0, this transaction has been latched but not
- // presented. Skip it for now. This can happen when a new transaction comes
- // in between the latch and present steps. sendCallbacks is called by
- // SurfaceFlinger when the transaction is received to ensure that if the
- // transaction that didn't update state it still got a callback.
- if (presentTime < 0) {
+ if (!mPresentFence) {
sendCallback = false;
break;
}
-
- transactionStats.presentTime = presentTime;
+ transactionStats.presentFence = mPresentFence;
}
}
// If the listener has no pending transactions and all latched transactions have been
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index cef598c..e62fc6e 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2502,12 +2502,12 @@
}
void verifyTransactionStats(const TransactionStats& transactionStats) const {
- const auto& [latchTime, presentTime, surfaceStats] = transactionStats;
+ const auto& [latchTime, presentFence, surfaceStats] = transactionStats;
if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
ASSERT_GE(latchTime, 0) << "bad latch time";
- ASSERT_GE(presentTime, 0) << "bad present time";
+ ASSERT_NE(presentFence, nullptr);
} else {
- ASSERT_EQ(presentTime, -1) << "transaction shouldn't have been presented";
+ ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
}
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 1bee271..81a7768 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -77,9 +77,9 @@
MOCK_CONST_METHOD0(isProtected, bool());
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
MOCK_METHOD1(useProtectedContext, bool(bool));
- MOCK_CONST_METHOD4(drawLayers,
- status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
- ANativeWindowBuffer* const, base::unique_fd*));
+ MOCK_METHOD4(drawLayers,
+ status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
+ ANativeWindowBuffer*, base::unique_fd*));
};
class Image : public renderengine::Image {
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 6c971be..7f6b9aa 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
// API version (major.minor.patch)
define VERSION_MAJOR 1
define VERSION_MINOR 1
-define VERSION_PATCH 94
+define VERSION_PATCH 95
// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -287,6 +287,10 @@
@extension("VK_EXT_conditional_rendering") define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 1
@extension("VK_EXT_conditional_rendering") define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering"
+// 83
+@extension("VK_KHR_shader_float16_int8") define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1
+@extension("VK_KHR_shader_float16_int8") define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8"
+
// 84
@extension("VK_KHR_16bit_storage") define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1
@extension("VK_KHR_16bit_storage") define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage"
@@ -575,6 +579,10 @@
@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1
@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties"
+// 198
+@extension("VK_KHR_shader_float_controls") define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 1
+@extension("VK_KHR_shader_float_controls") define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls"
+
// 199
@extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1
@extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned"
@@ -1615,6 +1623,9 @@
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001,
VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002,
+ //@extension("VK_KHR_shader_float16_int8") // 83
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = 1000082000,
+
//@extension("VK_KHR_descriptor_update_template") // 86
VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000,
@@ -1848,6 +1859,9 @@
//@extension("VK_KHR_driver_properties") // 197
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000,
+ //@extension("VK_KHR_shader_float_controls") // 198
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = 1000197000,
+
//@extension("VK_AMD_shader_core_properties") // 186
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
@@ -6092,6 +6106,14 @@
VkBool32 conditionalRenderingEnable
}
+@extension("VK_KHR_shader_float16_int8") // 83
+class VkPhysicalDeviceFloat16Int8FeaturesKHR {
+ VkStructureType sType
+ void* pNext
+ VkBool32 shaderFloat16
+ VkBool32 shaderInt8
+}
+
@extension("VK_KHR_16bit_storage") // 84
class VkPhysicalDevice16BitStorageFeaturesKHR {
VkStructureType sType
@@ -6776,11 +6798,11 @@
s32 messageIdNumber
const char* pMessage
u32 queueLabelCount
- VkDebugUtilsLabelEXT* pQueueLabels
+ const VkDebugUtilsLabelEXT* pQueueLabels
u32 cmdBufLabelCount
- VkDebugUtilsLabelEXT* pCmdBufLabels
+ const VkDebugUtilsLabelEXT* pCmdBufLabels
u32 objectCount
- VkDebugUtilsObjectNameInfoEXT* pObjects
+ const VkDebugUtilsObjectNameInfoEXT* pObjects
}
@extension("VK_EXT_debug_utils") // 129
@@ -7598,6 +7620,29 @@
VkConformanceVersionKHR conformanceVersion
}
+@extension("VK_KHR_shader_float_controls") // 198
+class VkPhysicalDeviceFloatControlsPropertiesKHR {
+ VkStructureType sType
+ void* pNext
+ VkBool32 separateDenormSettings
+ VkBool32 separateRoundingModeSettings
+ VkBool32 shaderSignedZeroInfNanPreserveFloat16
+ VkBool32 shaderSignedZeroInfNanPreserveFloat32
+ VkBool32 shaderSignedZeroInfNanPreserveFloat64
+ VkBool32 shaderDenormPreserveFloat16
+ VkBool32 shaderDenormPreserveFloat32
+ VkBool32 shaderDenormPreserveFloat64
+ VkBool32 shaderDenormFlushToZeroFloat16
+ VkBool32 shaderDenormFlushToZeroFloat32
+ VkBool32 shaderDenormFlushToZeroFloat64
+ VkBool32 shaderRoundingModeRTEFloat16
+ VkBool32 shaderRoundingModeRTEFloat32
+ VkBool32 shaderRoundingModeRTEFloat64
+ VkBool32 shaderRoundingModeRTZFloat16
+ VkBool32 shaderRoundingModeRTZFloat32
+ VkBool32 shaderRoundingModeRTZFloat64
+}
+
@extension("VK_NV_compute_shader_derivatives") // 202
class VkPhysicalDeviceComputeShaderDerivativesFeaturesNV {
VkStructureType sType
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index bdbf800..5006410 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,7 +43,7 @@
#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
// Version of this file
-#define VK_HEADER_VERSION 94
+#define VK_HEADER_VERSION 95
#define VK_NULL_HANDLE 0
@@ -327,6 +327,7 @@
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001,
VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = 1000082000,
VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
@@ -442,6 +443,7 @@
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = 1000197000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001,
@@ -5493,6 +5495,19 @@
const void* pData);
#endif
+#define VK_KHR_shader_float16_int8 1
+#define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1
+#define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8"
+
+typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 shaderFloat16;
+ VkBool32 shaderInt8;
+} VkPhysicalDeviceFloat16Int8FeaturesKHR;
+
+
+
#define VK_KHR_16bit_storage 1
#define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1
#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage"
@@ -6149,6 +6164,34 @@
+#define VK_KHR_shader_float_controls 1
+#define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 1
+#define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls"
+
+typedef struct VkPhysicalDeviceFloatControlsPropertiesKHR {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 separateDenormSettings;
+ VkBool32 separateRoundingModeSettings;
+ VkBool32 shaderSignedZeroInfNanPreserveFloat16;
+ VkBool32 shaderSignedZeroInfNanPreserveFloat32;
+ VkBool32 shaderSignedZeroInfNanPreserveFloat64;
+ VkBool32 shaderDenormPreserveFloat16;
+ VkBool32 shaderDenormPreserveFloat32;
+ VkBool32 shaderDenormPreserveFloat64;
+ VkBool32 shaderDenormFlushToZeroFloat16;
+ VkBool32 shaderDenormFlushToZeroFloat32;
+ VkBool32 shaderDenormFlushToZeroFloat64;
+ VkBool32 shaderRoundingModeRTEFloat16;
+ VkBool32 shaderRoundingModeRTEFloat32;
+ VkBool32 shaderRoundingModeRTEFloat64;
+ VkBool32 shaderRoundingModeRTZFloat16;
+ VkBool32 shaderRoundingModeRTZFloat32;
+ VkBool32 shaderRoundingModeRTZFloat64;
+} VkPhysicalDeviceFloatControlsPropertiesKHR;
+
+
+
#define VK_KHR_swapchain_mutable_format 1
#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1
#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format"
@@ -7475,11 +7518,11 @@
int32_t messageIdNumber;
const char* pMessage;
uint32_t queueLabelCount;
- VkDebugUtilsLabelEXT* pQueueLabels;
+ const VkDebugUtilsLabelEXT* pQueueLabels;
uint32_t cmdBufLabelCount;
- VkDebugUtilsLabelEXT* pCmdBufLabels;
+ const VkDebugUtilsLabelEXT* pCmdBufLabels;
uint32_t objectCount;
- VkDebugUtilsObjectNameInfoEXT* pObjects;
+ const VkDebugUtilsObjectNameInfoEXT* pObjects;
} VkDebugUtilsMessengerCallbackDataEXT;
typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)(