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)(